【问题标题】:Sega Genesis DMA moves my sprite around the screenSega Genesis DMA 在屏幕上移动我的精灵
【发布时间】: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


【解决方案1】:

真正的问题是我没有显示的代码,我的寄存器被破坏导致精灵移动。问题不在于 DMA。

【讨论】:

    猜你喜欢
    • 2012-07-07
    • 1970-01-01
    • 2015-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多