[Back to DRIVES SWAG index] [Back to Main SWAG index] [Original]

    {
     BB> Question: How can I make sure that my data for DMA transfer
     BB> (yes: SB-stuff) isn't going beyond "page-boundaries"?
     BB> (And what the h@#$ is a page-boudarie (?) anyway)

    The DMA controller has only 16 address bits, and to use it in 20-bits PC's and
    24-bits AT's (address bits), they added a page register, to hold the other 4/8
    bits. Bit the DMA controller knows nothing about it, so it can't increment it.
    This is all about absolute addresses, i.e. seg*16+ofs in real mode.
    Example: you want to 'DMA' 32768 bytes from $1234:0. Absolute address is
    $1234*16+0=$12340. The lower 16 bits go to the dma ($2340), and the other bit
    s to the page register ($1). After the DMA the offset is $2340+$8000=$A340, so
    no problems here. But if you use $7890:0 the absolute address is $78900, and
    if you add $8000 to the lower 16 bits ($8900), it becomes $10900, so larger
    than 16 bits, and the transfer can't be completed (it halts after
    $8000-$0900=$7700 bytes). That's why you need to keep the page of the 'end'
    absolute address the same as from the start address.

    I've written some pascal code to do that, but it assumes the heap is not
    fragmented (i.e. it assumes if it allocates two blocks the second starts were
    the first ends) (not sure it works always too, haven't tested it much).

    ===}

    function Alloc64kBound(Size:word):pointer;
    { Allocate a <Size> bytes buffer so that you can do a DMA transfer from/to it
    }{ Assumes the heap is not fragmented }
    { Arne de Bruijn, 1995, PD }
    {$ifopt Q+}{$define Temp}{$Q-}{$endif}
    { overflow checking should be off for word(seg shl 4), to avoid }
    { word(seg and $0fff shl 4). }
    type
     TPointer=record
      Ofs,Seg:word;
     end;
    var
     P,P2:pointer;
     NewSize:word;
    begin
     Alloc64kBound:=NIL;
     if MaxAvail<Size then exit;
     GetMem(P,Size);
     if word(TPointer(P).Seg shl 4)+TPointer(P).Ofs>word(-Size) then
      begin
       NewSize:=((longint((TPointer(P).Seg and $F000)+$1000) shl 4)-
        (longint(longint(TPointer(P).Seg) shl 4)+TPointer(P).Ofs));
       FreeMem(P,Size);
       if MaxAvail<NewSize then exit;
       GetMem(P2,NewSize);
       if MaxAvail<Size then P:=NIL else GetMem(P,Size);
       FreeMem(P2,NewSize);
      end;
     Alloc64kBound:=P;
    end;
    {$ifdef Temp}{$undef Temp}{$Q+}{$endif}

[Back to DRIVES SWAG index] [Back to Main SWAG index] [Original]