So I'm trying to devise a convenient HDMA implementation for a personal game project I'm working on. The idea is to use indirect HDMA mode for the main backdrop color gradient. The entries in the ROM-based HDMA table point to an array in the lower 8K of WRAM.
The table itself is laid out like so:
The HDMA channel used for this (2) is set up like this:
So far, so good. Works great.
Next, I'd like to switch to "continuous" HDMA mode for the sake of making the table more readable (by getting rid of all those .DB 1 directives).
And this is what I get:
The new table looks like this:
As you can see from the screenshot, it does process the first 112 scanlines as intended, only to go haywire then. Geiger's HDMA tracing reveals this:
Not only does the scanline count get messed up but WRAM data addresses as well. But how? And why?
I already tried to change the implementation from indirect mode to absolute mode. Curiously enough, continuous mode with the new table above then worked just as expected!
I've read all there is to read about HDMA, HDMA modes, and the HDMA table format, but couldn't find any clue about potential limits regarding the combination of modes and/or data unit lengths. Could this be a hardware limitation, or even a bug? Or what am I missing? Most importantly, why does it work either in absolute "continuous" (i.e., with the repeat flag set) mode or in indirect "normal" (repeat flag clear) mode, but not in indirect continuous mode? (BTW, it's not an emulator issue either, the same error occurs on Geiger's tracer, higan "performance", and higan "accuracy").
Any helpful suggestions are highly appreciated. Thanks!
Ramsis
The table itself is laid out like so:
Code:
SRC_HDMA_ColorGradient:
.DB 1 ; 176 scanlines for playfield, 48 for text box
.DW ARRAY_HDMA_BackgrPlayfield
.DB 1
.DW ARRAY_HDMA_BackgrPlayfield+4
.DB 1
.DW ARRAY_HDMA_BackgrPlayfield+8
.DB 1
.DW ARRAY_HDMA_BackgrPlayfield+12
.DB 1
.DW ARRAY_HDMA_BackgrPlayfield+16
.
.
.
.DB 1 ; 176 scanlines for playfield, 48 for text box
.DW ARRAY_HDMA_BackgrPlayfield
.DB 1
.DW ARRAY_HDMA_BackgrPlayfield+4
.DB 1
.DW ARRAY_HDMA_BackgrPlayfield+8
.DB 1
.DW ARRAY_HDMA_BackgrPlayfield+12
.DB 1
.DW ARRAY_HDMA_BackgrPlayfield+16
.
.
.
The HDMA channel used for this (2) is set up like this:
Code:
; -------------------------- channel 2: main backdrop color
lda #%01000011 ; transfer mode (4 bytes --> $2121, $2121, $2122, $2122), indirect table mode
sta $4320
lda #$21 ; PPU register $2121 (color index)
sta $4321
ldx #SRC_HDMA_ColorGradient
stx $4322
lda #:SRC_HDMA_ColorGradient
sta $4324
lda #$7E ; indirect HDMA CPU bus data address bank
sta $4327
lda #%01000011 ; transfer mode (4 bytes --> $2121, $2121, $2122, $2122), indirect table mode
sta $4320
lda #$21 ; PPU register $2121 (color index)
sta $4321
ldx #SRC_HDMA_ColorGradient
stx $4322
lda #:SRC_HDMA_ColorGradient
sta $4324
lda #$7E ; indirect HDMA CPU bus data address bank
sta $4327
So far, so good. Works great.
Next, I'd like to switch to "continuous" HDMA mode for the sake of making the table more readable (by getting rid of all those .DB 1 directives).
And this is what I get:
The new table looks like this:
Code:
SRC_HDMA_ColorGradient:
.DB 112|$80 ; = $F0 = upper 112 playfield scanlines with "continuous mode" flag set
.DW ARRAY_HDMA_BackgrPlayfield
.DW ARRAY_HDMA_BackgrPlayfield+4
.DW ARRAY_HDMA_BackgrPlayfield+8
.DW ARRAY_HDMA_BackgrPlayfield+12
.
.
.
.DW ARRAY_HDMA_BackgrPlayfield+444
.DB 64|$80 ; = $C0 = lower 64 playfield scanlines with "continuous mode" flag set
.DW ARRAY_HDMA_BackgrPlayfield+448
.DW ARRAY_HDMA_BackgrPlayfield+452
.DW ARRAY_HDMA_BackgrPlayfield+456
.DW ARRAY_HDMA_BackgrPlayfield+460
.
.
.
.DW ARRAY_HDMA_BackgrPlayfield+700
.DB 48|$80 ; = $B0 = 48 textbox scanlines with "continuous mode" flag set
.DW ARRAY_HDMA_BackgrTextBox
.DW ARRAY_HDMA_BackgrTextBox+4
.DW ARRAY_HDMA_BackgrTextBox+8
.DW ARRAY_HDMA_BackgrTextBox+12
.
.
.
.DW ARRAY_HDMA_BackgrTextBox+188
.DB 0 ; end of HDMA table
.DB 112|$80 ; = $F0 = upper 112 playfield scanlines with "continuous mode" flag set
.DW ARRAY_HDMA_BackgrPlayfield
.DW ARRAY_HDMA_BackgrPlayfield+4
.DW ARRAY_HDMA_BackgrPlayfield+8
.DW ARRAY_HDMA_BackgrPlayfield+12
.
.
.
.DW ARRAY_HDMA_BackgrPlayfield+444
.DB 64|$80 ; = $C0 = lower 64 playfield scanlines with "continuous mode" flag set
.DW ARRAY_HDMA_BackgrPlayfield+448
.DW ARRAY_HDMA_BackgrPlayfield+452
.DW ARRAY_HDMA_BackgrPlayfield+456
.DW ARRAY_HDMA_BackgrPlayfield+460
.
.
.
.DW ARRAY_HDMA_BackgrPlayfield+700
.DB 48|$80 ; = $B0 = 48 textbox scanlines with "continuous mode" flag set
.DW ARRAY_HDMA_BackgrTextBox
.DW ARRAY_HDMA_BackgrTextBox+4
.DW ARRAY_HDMA_BackgrTextBox+8
.DW ARRAY_HDMA_BackgrTextBox+12
.
.
.
.DW ARRAY_HDMA_BackgrTextBox+188
.DB 0 ; end of HDMA table
As you can see from the screenshot, it does process the first 112 scanlines as intended, only to go haywire then. Geiger's HDMA tracing reveals this:
Code:
H-DMA[2] (3) 0x7E1022->0x2121 ind, Count: 112, Rep: no , V-LINE: 0 C19280
H-DMA[2] (3) 0x7E2A10->0x2121 ind, Count: 38, Rep: yes, V-LINE: 112 C19283
H-DMA[2] (3) 0x7E102E->0x2121 ind, Count: 16, Rep: yes, V-LINE: 150 C19286
H-DMA[2] (3) 0x7E3610->0x2121 ind, Count: 50, Rep: yes, V-LINE: 166 C19289
H-DMA[2] (3) 0x7E103A->0x2121 ind, Count: 16, Rep: yes, V-LINE: 216 C1928C
H-DMA[2] (3) 0x7E2A10->0x2121 ind, Count: 38, Rep: yes, V-LINE: 112 C19283
H-DMA[2] (3) 0x7E102E->0x2121 ind, Count: 16, Rep: yes, V-LINE: 150 C19286
H-DMA[2] (3) 0x7E3610->0x2121 ind, Count: 50, Rep: yes, V-LINE: 166 C19289
H-DMA[2] (3) 0x7E103A->0x2121 ind, Count: 16, Rep: yes, V-LINE: 216 C1928C
Not only does the scanline count get messed up but WRAM data addresses as well. But how? And why?
I already tried to change the implementation from indirect mode to absolute mode. Curiously enough, continuous mode with the new table above then worked just as expected!
I've read all there is to read about HDMA, HDMA modes, and the HDMA table format, but couldn't find any clue about potential limits regarding the combination of modes and/or data unit lengths. Could this be a hardware limitation, or even a bug? Or what am I missing? Most importantly, why does it work either in absolute "continuous" (i.e., with the repeat flag set) mode or in indirect "normal" (repeat flag clear) mode, but not in indirect continuous mode? (BTW, it's not an emulator issue either, the same error occurs on Geiger's tracer, higan "performance", and higan "accuracy").
Any helpful suggestions are highly appreciated. Thanks!
Ramsis