【发布时间】:2022-12-11 06:40:24
【问题描述】:
编辑:毕竟不是 DMA 这样做,而是例程破坏了我的其他寄存器。傻我。
所以我试图了解 DMA(直接内存访问)在 Sega Genesis 上的工作原理,并且我已经让 VRAM 填充模式以我期望的方式工作,但是,有一个小问题。这样做似乎会在屏幕上移动我的游戏精灵,我不明白为什么。作为参考,这是我在 Fusion 中运行的游戏的图片:
对于必要的背景信息,小狗是精灵,所有其他图形都是图块,盒子、石灰和红色方块作为前景图块,云和天空是背景图块。窗口层在屏幕外。我正在使用 VRAM 配置,其中前景层位于 VDP 地址 $C000(世嘉代码 $40000003),精灵属性表位于 $D800($58000003),背景位于 $E000($60000003),窗口位于 $F000($7000003)。我已经设置好可以按控制器上的 C 键来启动 DMA。下面是执行 DMA 命令的例程。
dma_fill:
;explanation of macros and defined constants:
;pushRegs = MOVEM.L ___,-(SP)
;popRegs = MOVEM.L (SP)+,____
;DI = MOVE #$2300,SR
;pushf = MOVE SR,-(SP)
;popf = MOVE (SP)+,SR
;CD5 = %10000000
;VDP_CTRL = $00C00004
;VDP_DATA = $00C00000
;input:
;D2.L = what address to write to.
;D1.W = DMA LENGTH
;D0 = WHAT DATA TO USE TO FILL VRAM
pushRegs D3-D7
pushf
DI ;we don't want interrupts during this time.
MOVEQ.L #-109,D3 ;quickly move #$FFFFFF93 into D3
LSL.W #8,D3
OR.B D1,D3
;d3 contains $93xx where xx is the low byte of dma length
;this is the correct command to give the vdp
LSR.W #8,D1 ;shift high byte of dma length down to low byte
MOVEQ.L #-108,D4 ;quickly move #$FFFFFF94 into d4
LSL.W #8,D4 ;D4 = #$FFFF9400
OR.B D1,D4
;d3 contains $94xx where xx is the high byte of dma length
;this is the correct command to give the vdp
OR.L #CD5,D2 ;tells the vdp the next write is a DMA write
.wait:
move.w VDP_ctrl,d7
and.w #%0000000000001000,d7 ;See if vblank is running
bne .wait ;wait until it is
MOVE.W #($8100|%01110100),(VDP_CTRL) ;ENABLE DMA
move.w #$8F01,(vdp_ctrl) ;set auto-inc to 1
MOVE.W #$9780,(vdp_ctrl) ;enable dma vram fill
; HALT
MOVE.W D3,(vdp_ctrl) ;set dma length low byte
MOVE.W D4,(vdp_ctrl) ;set dma length high byte
MOVE.L D2,(vdp_ctrl) ;set destination address
MOVE.W D0,(vdp_data) ;write the data, dma begins here.
;do I need to wait for DMA to finish before continuing?
; .waitDma:
; MOVE.W (vdp_ctrl),d6
; btst #1,d6
; bne .waitDma
move.w #($8100|%01100100),(VDP_CTRL) ;DISABLE DMA
move.w #$8F02,(vdp_ctrl) ;set auto-inc back to 2
popf ;restore flags and interrupt level
popRegs D3-D7
RTS
D0 中的填充值为 0(空 8x8 图块的图块编号)的参数,D1 中的填充长度为 $0400,目的地为 $40000003(前景图块地图),我预计 VRAM 区域为 $C000 -$C400 将用空白瓷砖填充。但这是实际发生的事情。
大约前 4 行元瓷砖被清除(请记住,在我的游戏中,每个“元瓷砖”是四个 8x8 的瓷砖。),就长度而言,这似乎是正确的。但是狗精灵已经改变了位置。鉴于我在 VDP 地址 $D800 处有精灵属性表,这真的没有意义。出于好奇,我尝试了将长度参数更改为 $0200 的相同函数,当我这样做时,没有一个图块被清除,但精灵仍然移动到屏幕上的相同位置。多么奇怪。我能找到的现有文档要么没有很好地翻译成英文,要么没有真正解释内存中实际发生的所有细节(它更侧重于如何使 DMA 发生,这并不难理解) ,但我不明白为什么我的精灵会因此移动。)
【问题讨论】:
-
在将它们写入 VDP 寄存器之前,您不应该将长度和目标地址都右移 1 位吗?
-
@Michael 我为什么要那样做?
-
@Michael 好吧,我应该猜到了,这就是 Genesis 执行 DMA 的方式。所以不,我没有,现在修好了。
标签: assembly dma motorola 68000