Obsah

DMA (direct memory access)

DMA umožňuje využít až 8 kanálú pro rychlej přenost dat ze zařízení do paměti nebo obráceně.
Múže používat pouze prvních 16 MiB paměti.

DMA_MODE_DEMAND = 0
DMA_MODE_SINGLE = 40h
DMA_MODE_BLOCK = 80h
DMA_MODE_CASCADE = 0C0h
DMA_MODE_INC = 0
DMA_MODE_DEC = 20h
DMA_MODE_AUTOINIT = 10h
DMA_MODE_VERIFY = 0
DMA_MODE_READ = 6
DMA_MODE_WRITE = 0Ah

DMA_PORTOFS_MODE = 0
DMA_PORTOFS_MASK = 1
DMA_PORTOFS_CLEARFF = 2
DMA_PORTOFS_PAGE = 3
DMA_PORTOFS_ADR = 4
DMA_PORTOFS_COUNT = 5

DMA_ERC_INVALID_CHANNEL_NUMBER = 13h
DMA_ERC_INVALID_MEMORY_ADDRESS = 14h
DMA_ERC_INVALID_COUNT = 15h

dma_ports_const:
// mode, mask, clear flip-flop, page, address, count, -, -
// DMA 0
db 0Bh, 0Ah, 0Ch, 87h, 0, 1, 0, 0
// DMA 1
db 0Bh, 0Ah, 0Ch, 83h, 2, 3, 0, 0
// DMA 2
db 0Bh, 0Ah, 0Ch, 81h, 4, 5, 0, 0
// DMA 3
db 0Bh, 0Ah, 0Ch, 82h, 6, 7, 0, 0
// DMA 4
db 0D6h, 0D4h, 0D8h, 8Fh, 0C0h, 0C2h, 0, 0
// DMA 5
db 0D6h, 0D4h, 0D8h, 8Bh, 0C4h, 0C6h, 0, 0
// DMA 6
db 0D6h, 0D4h, 0D8h, 89h, 0C8h, 0CAh, 0, 0
// DMA 7
db 0D6h, 0D4h, 0D8h, 8Ah, 0CCh, 0CEh, 0, 0

h_dma_init:
ret

l_h_dma_read_xchn:
mov al, DMA_ERC_INVALID_CHANNEL_NUMBER
ret

l_h_dma_read_xmemadr:
mov al, DMA_ERC_INVALID_MEMORY_ADDRESS
ret

l_h_dma_read_xcount:
mov al, DMA_ERC_INVALID_COUNT
ret


// DMA Read - transfer data from device to memory
// IN: al = channel, ah = mode
// ecx = count, ebx = memory addr
// DESTROY: edx, esi
// OUT: al = 0 || errorcode
h_dma_read:
or ah, DMA_MODE_READ

l_h_dma_common: // h_dma_write jumps here too
cmp al, 8
jnb l_h_dma_read_xchn

movzx esi, al
shl esi, 3 // esi = channel offset

cmp ebx, 0xFFFFFF
ja l_h_dma_read_xmemadr

dec ecx
cmp ecx, 65536
jnb l_h_dma_read_xcount

pushfd
cli

// Disable Channel
and al, 3
xor edx, edx
or al, 4 // al = 4 + (channel & 3)
mov dl, [cs:offset dma_ports_const + esi + DMA_PORTOFS_MASK]
out dx, al

// Set Transfer Count
mov dl, [cs:offset dma_ports_const + esi + DMA_PORTOFS_CLEARFF]
out dx, al
mov dl, [cs:offset dma_ports_const + esi + DMA_PORTOFS_COUNT]
mov al, cl
out dx, al
call delay
mov al, ch
out dx, al

// Set Memory Address
mov dl, [cs:offset dma_ports_const + esi + DMA_PORTOFS_CLEARFF]
out dx, al
mov dl, [cs:offset dma_ports_const + esi + DMA_PORTOFS_ADR]
mov al, bl
out dx, al
call delay
mov al, bh
out dx, al
shr ebx, 16
mov dl, [cs:offset dma_ports_const + esi + DMA_PORTOFS_PAGE]
mov al, bl
out dx, al

// Set Mode
mov dl, [cs:offset dma_ports_const + esi + DMA_PORTOFS_MODE]
mov al, ah
out dx, al

// Enable Channel
mov dl, [cs:offset dma_ports_const + esi + DMA_PORTOFS_MASK]
mov eax, esi
shr eax, 3
and al, 3
out dx, al

popfd

mov al, 0
ret


// DMA Write - transfer data from memory to device
// IN: al = channel, ah = mode
// ecx = count, ebx = memory addr
// DESTROY: edx, esi
// OUT: al = 0 || errorcode
h_dma_write:
or ah, DMA_MODE_WRITE

jmp l_h_dma_common


// Finalize transfer
// IN: al = channel
// DESTROY: eax, edx, esi
h_dma_release:
and al, 7
movzx esi, al
shl esi, 3 // esi = channel offset
and al, 3
xor edx, edx
or al, 4 // al = 4 + (channel & 3)
mov dl, [cs:offset dma_ports_const + esi + DMA_PORTOFS_MASK]
out dx, al
ret