Last active
October 23, 2024 19:31
-
-
Save flamewing/ac4b8586f74c74fe24fe30e5e0261fb0 to your computer and use it in GitHub Desktop.
Some improved DMA macros, and a couple new DMA macros, for the Mega Drive
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dmaSource function addr,((addr>>1)&$7FFFFF) | |
dmaLength function length,((length>>1)&$7FFF) | |
dmaCommLength function length,(($9400|((length&$FF00)>>8))<<16)|($9300|(length&$FF)) | |
dmaCommSrcLow function source,(($9600|((source&$FF00)>>8))<<16)|($9500|(source&$FF)) | |
dmaCommSrcHigh function source,$9700|(((source&$FF0000)>>16)&$7F) | |
; Tells the VDP to copy a region of 68k memory to VRAM or CRAM or VSRAM. | |
dma68kToVDP macro src,dest,length,type,bswap | |
if MOMPASS>1 | |
if ((src)&1)<>0 | |
fatal "DMA is transferring from odd source $\{src}! This will transfer the wrong data, because the VDP ignores the low bit of source address. Please align the data to an even address." | |
endif | |
if ((dest)&1)<>0 | |
if (type)<>VRAM | |
fatal "DMA is transferring to odd destination $\{dest}! This is ignored on real hardware for CRAM and VSRAM, and may behave inconsistently on emulators. Please ensure that you transfer to even destinations only." | |
else | |
fatal "DMA is transferring to odd destination $\{dest}! This will byte-swap the data copied. If you want to do this, then set the last parameter of the macro to 1 instead." | |
endif | |
endif | |
if ((length)&1)<>0 | |
fatal "DMA is transferring an odd number of bytes $\{length}! DMA can only transfer an even number of bytes." | |
endif | |
if (length)==0 | |
fatal "DMA is transferring 0 bytes (becomes a 128kB transfer). If you really mean it, pass 128kB (131072) instead." | |
endif | |
if (((src)+(length)-1)>>17)<>((src)>>17) | |
fatal "DMA crosses a 128kB boundary. You should either split the DMA manually or align the source adequately." | |
endif | |
endif | |
if ~~(bswap) | |
set .c,0 | |
else | |
if (type)<>VRAM | |
fatal "Only VRAM supports byte-swap on DMA." | |
endif | |
set .c,1 | |
endif | |
lea (VDP_control_port).l,a5 | |
move.l #dmaCommLength(dmaLength(length)),(a5) | |
move.l #dmaCommSrcLow(dmaSource(src)),(a5) | |
move.l #(dmaCommSrcHigh(dmaSource(src))<<16)|((vdpComm((dest)|.c,type,DMA)>>16)&$FFFF),(a5) | |
move.w #(vdpComm((dest)|.c,type,DMA)&$FFFF),(DMA_data_thunk).w | |
move.w (DMA_data_thunk).w,(a5) | |
endm | |
; Tells the VDP to fill a region of VRAM with a certain byte. | |
; VRAM fill works like this: the write to the data port happens as normal; that is: | |
; * the high byte is written to address^1 | |
; * the low byte is written to address | |
; Then, the remainder of the fill goes like: | |
; * the address is incremented by the autoincrement register value | |
; * high byte of word written to data port is written to address^1 | |
; * repeat until done | |
; For an even target address, this means: | |
; * the high byte is written to address+1 | |
; * the low byte is written to address | |
; * the high byte is written to address (overwrites previous write) | |
; * the high byte is written to address+3 | |
; * the high byte is written to address+2 | |
; * etc. | |
; For an odd target address, this means: | |
; * the high byte is written to address | |
; * the low byte is written to address+1 | |
; * the high byte is written to address+3 | |
; * the high byte is written to address+2 | |
; * etc. | |
; This allows reducing the length of the fill by 1. | |
; It is possible to fill to CRAM and to VSRAM, but it is buggy, | |
; and not emulated in most emulators. | |
dmaFillVRAM macro byte,addr,length | |
if MOMPASS>1 | |
if ((addr)&1)<>0 | |
fatal "DMA is filling an odd destination $\{addr}! This will cause a spurious write to the address immediately before. Please ensure you fill starting at even addresses only." | |
endif | |
if (length)==0 | |
fatal "DMA is filling 0 bytes (becomes a 64kB fill). If you really mean it, pass 64kB (65536) instead." | |
endif | |
endif | |
lea (VDP_control_port).l,a5 | |
move.l #dmaCommLength(2*(length-2)),(a5) | |
move.l #$8F019780,(a5) ; VRAM pointer increment: $0001, VRAM fill | |
; Forcing the low bit of address to be 1, as described before. | |
move.l #vdpComm((addr)|1,VRAM,DMA),(a5) | |
move.w #((byte)<<8)|(byte),(VDP_data_port).l | |
.loop: | |
move.w (a5),d1 | |
btst #1,d1 | |
bne.s .loop ; busy loop until the VDP is finished filling... | |
move.w #$8F02,(a5) ; VRAM pointer increment: $0002 | |
endm | |
; Tells the VDP to copy from a region of VRAM to another. | |
dmaCopyVRAM macro src,dest,length | |
if MOMPASS>1 | |
if (length)==0 | |
fatal "DMA is copying 0 bytes (becomes a 64kB copy). If you really mean it, pass 64kB (65536) instead." | |
endif | |
endif | |
lea (VDP_control_port).l,a5 | |
move.l #dmaCommLength(2*length),(a5) | |
move.l #dmaCommSrcLow(src),(a5) | |
move.l #$8F0197C0,(a5) ; VRAM pointer increment: $0001, VRAM copy | |
move.l #vdpComm(addr,VRAM,DMA),(a5) | |
.loop: | |
move.w (a5),d1 | |
btst #1,d1 | |
bne.s .loop ; busy loop until the VDP is finished filling... | |
move.w #$8F02,(a5) ; VRAM pointer increment: $0002 | |
endm | |
KosArt_To_VDP macro art,dest,bswap | |
if MOMPASS>1 | |
if ((dest)&1)<>0 | |
fatal "DMA is transferring to odd destination $\{dest}! This will byte-swap the data copied. If you want to do this, then set the last parameter of the macro to 1 instead." | |
endif | |
endif | |
if ~~(bswap) | |
set .c,0 | |
else | |
set .c,1 | |
endif | |
lea (art).l,a0 ; Decompress source | |
lea (Chunk_Table).l,a1 ; Decompress destination/transfer source | |
jsr (KosDec).w | |
move.l a1,d0 ; Move end address of decompressed art to d0 | |
lsr.w #1,d0 ; d0 is the transfer length in words because (Chunk_Table&$FFFF) == 0 | |
pea ($94009300).l ; Values for setting DMA length registers | |
movep.w d0,1(sp) ; Longword at a1 is commands for setting transfer length | |
lea (VDP_control_port).l,a5 | |
move.l (sp)+,(a5) ; Send command to specify DMA transfer length | |
move.l #dmaCommSrcLow(dmaSource(Chunk_Table)),(a5) | |
move.l #(dmaCommSrcHigh(dmaSource(Chunk_Table))<<16)|((vdpComm((dest)|.c,VRAM,DMA)>>16)&$FFFF),(a5) | |
move.w #(vdpComm((dest)|.c,VRAM,DMA)&$FFFF),(DMA_data_thunk).w | |
move.w (DMA_data_thunk).w,(a5) | |
endm |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
BSD 0-clause.