Say, a memory-to-memory copy from $C000 to $4000, $1B00 bytes long.
Happy even if you just list out the bytes. Decoding them will help me cement my understanding

Cheers, Robs
Moderator: Programming Moderators
Code: Select all
; dmatest.asm
zeusemulate "128K"
zoLogicOperatorsHighPri = false
zoSupportStringEscapes = false
Zeus_PC = Start
Stack equ Start
optionsize 5
UseDMA optionbool 15, -15, "Use LDIR instead of DMA", false
org $8000
Start proc
di
ld sp, Stack
ld a, $BE
ld i, a
im 2
call Cls
call ClsAttr
ei
if not enabled UseDMA
; REGISTER 0 GROUP
; ----------------
; Bit Effect
; 7 Must be 0 (register bitmask)
; 6 Write associated register flag -> Block length high byte
; 5 Write associated register flag -> Block length low byte
; 4 Write associated register flag -> Port A address high byte
; 3 Write associated register flag -> Port A address low byte
; 2 Direction: 0 B->A, 1 A->B
; 1-0 Operation: 01 transfer, 10 search, 11 search/transfer. Must not
; be 00 or will conflict with bitmasks for registers 1/2.
DMA(%0 11 11 1 01) ; A->B transfer, Port A address and block length to follow.
DMA($00) ; Port A address low byte (no need to send this byte if $00?)
DMA($C0) ; Port A address high byte
DMA($00) ; Block length address low byte (no need to send this byte if $00?)
DMA($1B) ; Block length address high byte
; REGISTER 1 GROUP
; ----------------
; Bit Effect
; 7 Must be 0 (register bitmask)
; 6 Write associated register flag -> Port A timing byte
; 4-5 Port A behavior: 00 decrements, 01 increments, 10/11 fixed
; 3 Port A type: 0 Memory, 1 I/O port
; 2-0 Must be %100 (register bitmask)
DMA(%0 1 01 0 100) ; Port A increments, type memory, timing byte follows
; PORT A TIMING BYTE
; -----------------
; Bit Effect
; 7 0 /WR ends 1/2 cycle early
; 6 0 /RD ends 1/2 cycle early
; 5 Must be 0
; 4 Must be 0
; 3 0 /MREQ ends 1/2 cycle early
; 2 0 /IORQ ends 1/2 cycle early
; 1-0 00 Cycle length 4
; 01 Cycle length 3
; 10 Cycle length 2
; 11 Do not use
DMA(%11 00 11 10) ; Port A cycle length 2
; REGISTER 2 GROUP
; ----------------
; Bit Effect
; 7 Must be 0 (register bitmask)
; 6 Write associated register flag -> Port B timing byte
; 4-5 Port B behavior: 00 decrements, 01 increments, 10/11 fixed
; 3 Port B type: 0 Memory, 1 I/O port
; 2-0 Must be %000 (register bitmask)
DMA(%0 1 01 0 000) ; Port B increments, type memory, timing byte follows
; PORT B TIMING BYTE
; -----------------
; Bit Effect
; 7 0 /WR ends 1/2 cycle early
; 6 0 /RD ends 1/2 cycle early
; 5 Must be 0
; 4 Must be 0
; 3 0 /MREQ ends 1/2 cycle early
; 2 0 /IORQ ends 1/2 cycle early
; 1-0 00 Cycle length 4
; 01 Cycle length 3
; 10 Cycle length 2
; 11 Do not use
DMA(%11 00 11 10) ; Port B cycle length 2
; REGISTER 3 GROUP
; ----------------
; Controls search match behaviour, not needed
; REGISTER 4 GROUP
; ----------------
; Bit Effect
; 7 Must be 1 (register bitmask)
; 6-5 Operation mode: 00 byte at a time (releases and reclaims bus after every byte)
; 01 continuous (holds bus continuously, if a port is not ready,
; stops and waits until it is)
; 10 burst (holds but continuously, if a port is not ready,
; stops and releases busses)
; 11 do not change
; 4 Write associated register flag -> Interrupt control byte
; 3 Write associated register flag -> Port B address high byte
; 2 Write associated register flag -> Port B address low byte
; 1-0 Must be %01 (register bitmask)
DMA(%1 10 x 11 01) ; Burst, port B address follows
DMA($00) ; Port B address low byte (no need to send this byte if $00?)
DMA($40) ; Port B address high byte
; REGISTER 5 GROUP
; ----------------
; Bit Effect
; 7-6 Must be %10 (register bitmask)
; 5 Restart (1) or stop (0) on end of block
; 4 CE/Wait multiplex (1) or CE only (0)
; 3 Ready active low (0) or high (1)
; 2-0 Must be %010 (register bitmask)
DMA(%10 0 x x 010) ; Stop on end of block
; REGISTER 6 GROUP
; ----------------
; Rather than setting bits, register 6 accepts commands which take instant effect.
; The command codes below include the bitmask for register 6.
;
; Command Effect
; $C3 (%11000011) Reset
; $C7 (%11000111) Reset Port A Timing
; $CB (%11001011) Reset Port B Timing
; $CF (%11001111) Load
; $D3 (%11010011) Continue
; $AF (%10101111) Disable Interrupts
; $AB (%10101011) Enable Interrupts
; $A3 (%10100011) Reset and disable interrupts
; $B7 (%10110111) Enable after RETI
; $BF (%10111111) Read status byte
; $BF (%10001011) Reinitialize status byte
; $A7 (%10100111) Start read sequence
; $B3 (%10110011) Force ready
; $87 (%10000111) Enable DMA
; $83 (%10000011) Disable DMA
; $BB (%10111011) Write associated register command -> Read Mask
DMA($B3) ; Force ready (maybe not needed?)
DMA($87) ; Finally, enable DMA to begin
Border(Green) ; Green border means we did (or failed to do!) DMA
else
ld hl, $C000
ld de, $4000
ld bc, $1B00
ldir
Border(Blue) ; Blue border means we did LDIR
endif
Loop:
halt
jp Loop
pend
DMA macro(Byte) ; Can use OTIR for the entire DMA programming sequence,
ld a, Byte ; but get it working with a regular OUT first...
out ($0B), a ; $xx0B = MB02 DMA Port (can also use $xx6B)
mend
Cls proc
di
ld (EXIT+1), sp ; Save the stack
ld sp, $5800 ; Set stack to end of screen
ld de, $0000 ; All pixels unset
ld b, e ; Loop 256 times: 12 words * 256 = 6144 bytes
noflow
CLS_LOOP: defs 12, $D5 ; 12 lots of push de
djnz CLS_LOOP
EXIT: ld sp, $0000 ; Restore the stack
ei
ret
pend
ClsAttr proc
ClsAttrFull(DimBlackWhiteP)
ret
pend
ClsAttrFull macro(Colour)
ld a, Colour
ld hl, ATTRS_8x8
ld (hl), a
ld de, ATTRS_8x8+1
ld bc, ATTRS_8x8_COUNT-1
ldir
mend
Border macro(Colour)
if Colour=0
xor a
else
ld a, Colour
endif
out (ULA_PORT), a
mend
SCREEN equ $4000 ; Start of screen bitmap
ATTRS_8x8 equ $5800 ; Start of 8x8 attributes
ATTRS_8x8_END equ $5B00 ; End of 8x8 attributes
ATTRS_8x8_COUNT equ ATTRS_8x8_END-ATTRS_8x8 ; 768
ULA_PORT equ $FE ; out (254), a
DimBlackWhiteP equ $38
Black equ 0
Blue equ 1
Red equ 2
Magenta equ 3
Green equ 4
Cyan equ 5
Yellow equ 6
White equ 7
include "ParaBootStub.inc" ; Parasys remote debugger slave stub
org $BE00 ; Have an IM 2 ISR at $BE00...
loop 257
db $BF
lend
org $BFBF
ei ; ...which doesn't do anything
reti ; except avoid the ROM IM 1 ISR being called
org $C000
import_bin "..\images\test.scr" ; Test screen used as the source of the copy
if zeusver < 72 ; Make sure we have the latest features ('don't care' x bits in binary literals)
zeuserror "Upgrade to Zeus v3.99 or above, available at http://www.desdes.com/products/oldfiles/zeus.htm."
endif
output_z80 "..\bin\dmatest.z80", $0000, Start
Thanks for providing all the code. I guess the “ParaSys boot stub - it asks Zeus to provide the slave code, loads it into memory and runs it“. Do I need to include this? I notice you have a CSpect flag, I guess for emulation, to ignore if running in CSpect (where is this set?)SevenFFF wrote: ↑Tue Apr 17, 2018 3:51 pmThere's a DMA copy and a DMA fill here, with LDIR copy and LDIR fill for comparison. See the DMACopy.asm file.
Sorry Rob, yes you can remove all the ParaSys code. I have Zeus set up to send code down a USB cable to the ESP socket on the board every time I assemble. Let me know if you're interested in getting that working, otherwise you can remove it all.robpearmain wrote: ↑Sun Apr 22, 2018 6:59 amThanks for providing all the code. I guess the “ParaSys boot stub - it asks Zeus to provide the slave code, loads it into memory and runs it“. Do I need to include this? I notice you have a CSpect flag, I guess for emulation, to ignore if running in CSpect (where is this set?)
Code: Select all
optionsize 12
Mode optionlist 15, -15, "Mode","DMA Copy","DMA Fill","LDIR Copy","LDIR Fill"
Cspect optionbool 155, -13, "Cspect", false