I seem to have run out of puff coding this, would REALLY appreciate some help!
I'm trying to code a DMA transfer routine to drop into the xtide-universal BIOS. It can be hard-coded to work with XT architecture, DMA channel 3. I want to use block-mode transfers. Communication with the IDE controller except for the actual transfer is via XT-IDE style port 300h access. The card will assert DRQ3 when value 04h is written port port 30Fh and clear it when TC is asserted.
Here we go so far:
In particular, I'm not sure about the part dealing with ES: DI + transfer size straddling a physical 64K boundary.
Any thoughts or help on this would be greatly appreciated!
I'm trying to code a DMA transfer routine to drop into the xtide-universal BIOS. It can be hard-coded to work with XT architecture, DMA channel 3. I want to use block-mode transfers. Communication with the IDE controller except for the actual transfer is via XT-IDE style port 300h access. The card will assert DRQ3 when value 04h is written port port 30Fh and clear it when TC is asserted.
Here we go so far:
Code:
; Parameters:
; CX: Block size in 512 byte sectors
; DX: IDE Data port address
; ES:DI: Normalized ptr to buffer to receive data
; Returns:
; Nothing
; Corrupts registers:
; AX, BX, CX
; work out how much we're transferring. We can't cross a physical 64KB boundary
; but since the max transfer size is 64KB, we only ever need to do one or two DMA operations
mov ax, 0xffff
sub ax, di ; 64k - DI = number of bytes we could transfer, in AX
xchg cl, ch ; sectors to words
shl cx, 1 ; words to bytes; CX has total byte count
.StartDMA:
cmp ax, cx ; can we do it in one hit?
jb .NextDMA
; if we're here we need to do only one DMA operation
.LastDMA:
mov ax, cx ; move bytes left to ax
.NextDMA:
mov bx, ax ; save the byte count
; set up the DMA controller for this transfer
cli ; clear interrupts while we set up the actual DMA transfer
mov al, 0x07 ; mask (4) + channel (3)
out 0x0a, al ; send to DMA mask register
xor al, al ; clear al
out 0x0c, al ; send 0 to DMA clear register, i.e. clear the channel config
mov al, 0x97 ; required mode is block/inc/non-auto-init/write(to memory)/ch3
out 0x0b, al ; and send mode to DMA mode register
mov ax, di
out 0x06, al
mov al, ah
out 0x06, al ; send offset to DMA controller address port for ch.3
mov ax, es
xchg al, ah ; high 8 bits of ES now in AL
shr al, 1
shr al, 1
shr al, 1
shr al, 1 ; shr al, 4 => high 4-bits of ES now in low 4-bits of AL
out 0x83, al ; send those 4-bits to DMA controller page for ch.3 (XT port)
mov ax, bx
out 0x07, al ; send low-byte of transfer size in bytes...
xchg al, ah ; switch...
out 0x07, al ; ...and high byte to DMA controller count port for ch.3
mov al, 0x03 ; clear bit mask (0) + channel (3)
out 0x0a, al ; send to DMA mask register - enable the DMA!
sti ; enable interrutps; let the CPU see to anything outstanding
; now get the card to trigger the actual transfer
mov dx, 0x030f ; XT-CF card control register
mox al, 0x40 ; special DMA enable code
out dx, al ; send to card - this will assert DRQ.. and we're off...
nop
nop ; a couple of padding instructions, but once we're here
nop ; the DMA should be done
; DMA is done - any more to do?
add di, bx
jc .AddPageToES
.CheckMoreDMATransfers:
sub cx, bx ; total bytes - bytes we just transferred
jnz .LastDMA ; do next transfer, if there's bytes left
ret
.AddPageToES:
add es, 0x1000
jmp .CheckMoreDMATransfers
In particular, I'm not sure about the part dealing with ES: DI + transfer size straddling a physical 64K boundary.
Any thoughts or help on this would be greatly appreciated!