HDMA's 127 scanline limit workaround code

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Post Reply
psycopathicteen
Posts: 3178
Joined: Wed May 19, 2010 6:12 pm

HDMA's 127 scanline limit workaround code

Post by psycopathicteen »

Since the fact that the SNES's HDMA is limited to runs of 127 scanlines which is much smaller than the screen and requires a lot of register juggling in order to compensate for this, I decided to make some general use routines to get around this problem. I'll add comments later on tonight, when I feel like doing it.

Code: Select all

fix_HDMA_length_overload_byte:
ldy #$0000
tyx
-;
lda {HDMA_buffer_1},y
bit #$00ff
beq ++
bit #$0080
beq +
sec
sbc #$007f
sta {HDMA_buffer_2},x
and #$ff00
ora #$007f
inx #2
+;
sta {HDMA_buffer_2},x
inx #2
iny #2
bra -
+;
sta {HDMA_buffer_2},x
rts


fix_HDMA_length_overload_word:
ldy #$0000
tyx
-;
sep #$20
lda {HDMA_buffer_1},y
bpl +
sec
sbc #$7f
sta {HDMA_buffer_2},x
lda #$7f
sta {HDMA_buffer_2}+3,x
rep #$21
lda {HDMA_buffer_1}+1,y
sta {HDMA_buffer_2}+1,x
sta {HDMA_buffer_2}+4,x
iny #3
txa
adc #$0006
tax
bra -
+;
sta {HDMA_buffer_2},x
beq +
rep #$20
lda {HDMA_buffer_1}+1,y
sta {HDMA_buffer_2}+1,x
iny #3
inx #3
bra -
+;
rep #$20
rts


fix_HDMA_length_overload_long:
ldy #$0000
tyx
-;
sep #$20
lda {HDMA_buffer_1},y
bpl +
sec
sbc #$7f
sta {HDMA_buffer_2},x
lda #$7f
sta {HDMA_buffer_2}+5,x
rep #$21
lda {HDMA_buffer_1}+1,y
sta {HDMA_buffer_2}+1,x
sta {HDMA_buffer_2}+6,x
lda {HDMA_buffer_1}+3,y
sta {HDMA_buffer_2}+3,x
sta {HDMA_buffer_2}+8,x
tya
adc #$0005
tay
txa
adc #$000a
tax
bra -
+;
sta {HDMA_buffer_2},x
beq +
rep #$21
lda {HDMA_buffer_1}+1,y
sta {HDMA_buffer_2}+1,x
lda {HDMA_buffer_1}+3,y
sta {HDMA_buffer_2}+3,x
tya
adc #$0005
tay
txa
adc #$0005
tax
bra -
+;
rep #$20
rts

I made another version of this that makes use of block move instructions:

Code: Select all

fix_HDMA_length_overload_byte:
ldx #$0000
sep #$20
-;
lda {HDMA_buffer},x
beq ++
bmi +
inx #2
bra -
+;
rep #$20
stx {temp}
lda {HDMA_buffer_size}
tax
sec
sbc {temp}
txy
iny #2
sty {HDMA_buffer_size}
mvp {dest_bank}={source_bank}		//some assemblers have these reversed
sep #$21
ldx {temp}
lda {HDMA_buffer},x
sbc #$7f
sta {HDMA_buffer},x
lda #$7f
sta {HDMA_buffer}+2,x
+;
rep #$20
rts




fix_HDMA_length_overload_word:
ldx #$0000
sep #$20
-;
lda {HDMA_buffer},x
beq ++
bmi +
inx #3
bra -
+;
rep #$20
stx {temp}
lda {HDMA_buffer_size}
tax
sec
sbc {temp}
txy
iny #3
sty {HDMA_buffer_size}
mvp {dest_bank}={source_bank}		//some assemblers have these reversed
sep #$21
ldx {temp}
lda {HDMA_buffer},x
sbc #$7f
sta {HDMA_buffer},x
lda #$7f
sta {HDMA_buffer}+3,x
+;
rep #$20
rts

fix_HDMA_length_overload_long:
ldx #$0000
sep #$20
-;
lda {HDMA_buffer},x
beq ++
bmi +
inx #5
bra -
+;
rep #$20
stx {temp}
lda {HDMA_buffer_size}
tax
sec
sbc {temp}
txy
iny #5
sty {HDMA_buffer_size}
mvp {dest_bank}={source_bank}		//some assemblers have these reversed
sep #$21
ldx {temp}
lda {HDMA_buffer},x
sbc #$7f
sta {HDMA_buffer},x
lda #$7f
sta {HDMA_buffer}+5,x
+;
rep #$20
rts
I haven't tested either of these sets of routines, so if I made a mistake, you can point it out.
psycopathicteen
Posts: 3178
Joined: Wed May 19, 2010 6:12 pm

Re: HDMA's 127 scanline limit workaround code

Post by psycopathicteen »

Here is the "check as you go" method of doing it:

Code: Select all

write_to_HDMA_layer_byte:
lda {bottom_y}
cmp #$00e0			//#$00f0 for PAL region
bcc +
lda #$00e0
sta {bottom_y}
+;
sep #$21
sbc {top_y}
bmi +
sta {HDMA_buffer},x
lda {temp}
sta {HDMA_buffer}+1,x
inx #2
rep #$20
lda {bottom_y}
sta {top_y}
rts
+;
sec
sbc #$7f
sta {HDMA_buffer},x
lda #$7f
sta {HDMA_buffer}+2,x
lda {temp}
sta {HDMA_buffer}+1,x
sta {HDMA_buffer}+3,x
rep #$21
txa
adc #$0004
tax
lda {bottom_y}
sta {top_y}
rts

write_to_HDMA_layer_word:
lda {bottom_y}
cmp #$00e0			//#$00f0 for PAL region
bcc +
lda #$00e0
sta {bottom_y}
+;
sep #$21
sbc {top_y}
bmi +
sta {HDMA_buffer},x
rep #$20
lda {temp}
sta {HDMA_buffer}+1,x
inx #3
lda {bottom_y}
sta {top_y}
rts
+;
sec
sbc #$7f
sta {HDMA_buffer},x
lda #$7f
sta {HDMA_buffer}+3,x
rep #$21
lda {temp}
sta {HDMA_buffer}+1,x
sta {HDMA_buffer}+4,x
txa
adc #$0006
tax
lda {bottom_y}
sta {top_y}
rts

write_to_HDMA_layer_long:
lda {bottom_y}
cmp #$00e0			//#$00f0 for PAL region
bcc +
lda #$00e0
sta {bottom_y}
+;
sep #$21
sbc {top_y}
bmi +
sta {HDMA_buffer},x
rep #$21
lda {temp}
sta {HDMA_buffer}+1,x
lda {temp2}
sta {HDMA_buffer}+3,x
txa
adc #$0005
tax
lda {bottom_y}
sta {top_y}
rts
+;
sec
sbc #$7f
sta {HDMA_buffer},x
lda #$7f
sta {HDMA_buffer}+5,x
rep #$21
lda {temp}
sta {HDMA_buffer}+1,x
sta {HDMA_buffer}+6,x
lda {temp2}
sta {HDMA_buffer}+3,x
sta {HDMA_buffer}+8,x
txa
adc #$000a
tax
lda {bottom_y}
sta {top_y}
rts
Oziphantom
Posts: 1740
Joined: Tue Feb 07, 2017 2:03 am

Re: HDMA's 127 scanline limit workaround code

Post by Oziphantom »

lets ask the obvious question first
Why can't you just run something for 127 and then set the exact same data again for the next however many?
psycopathicteen
Posts: 3178
Joined: Wed May 19, 2010 6:12 pm

Re: HDMA's 127 scanline limit workaround code

Post by psycopathicteen »

That's what the routines do.
Señor Ventura
Posts: 266
Joined: Sat Aug 20, 2016 3:58 am

Re: HDMA's 127 scanline limit workaround code

Post by Señor Ventura »

c
Last edited by Señor Ventura on Thu Dec 05, 2024 12:26 pm, edited 1 time in total.
SNES AYE
Posts: 281
Joined: Mon Nov 07, 2022 11:28 am

Re: HDMA's 127 scanline limit workaround code

Post by SNES AYE »

psycopathicteen wrote: Fri Nov 29, 2024 3:30 pm Since the fact that the SNES's HDMA is limited to runs of 127 scanlines
What does that mean in actual use?

Does it mean it wouldn't be possible to change the backdrop colour every scanline for example, but rather every second scanline or something like that?

This HDMA restriction is something I wasn't aware of before.
User avatar
Dwedit
Posts: 5069
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: HDMA's 127 scanline limit workaround code

Post by Dwedit »

If there's a limit for HDMA, you could trigger an interrupt and set new parameters.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
psycopathicteen
Posts: 3178
Joined: Wed May 19, 2010 6:12 pm

Re: HDMA's 127 scanline limit workaround code

Post by psycopathicteen »

SNES AYE wrote: Wed Dec 04, 2024 1:26 pm
psycopathicteen wrote: Fri Nov 29, 2024 3:30 pm Since the fact that the SNES's HDMA is limited to runs of 127 scanlines
What does that mean in actual use?

Does it mean it wouldn't be possible to change the backdrop colour every scanline for example, but rather every second scanline or something like that?

This HDMA restriction is something I wasn't aware of before.
No, it's just makes it slightly harder to program. The HDMA format is:

byte 0: scanline count
byte 1: data to be written to

The scanline count byte is formatted like this:

MLLLLLLL

L = number of scanline

M = HDMA block mode
0: write data once then wait L number of lines before next HDMA chunk
1: write data every scanline for L number of scanline

$00 and $80 are special cases. $00 means end HDMA. $80 means write once wait 128 lines.
Last edited by psycopathicteen on Fri Dec 06, 2024 3:46 am, edited 1 time in total.
User avatar
Dwedit
Posts: 5069
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: HDMA's 127 scanline limit workaround code

Post by Dwedit »

Not really a limit if you can just throw in a dummy entry to get to the next part.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
SNES AYE
Posts: 281
Joined: Mon Nov 07, 2022 11:28 am

Re: HDMA's 127 scanline limit workaround code

Post by SNES AYE »

psycopathicteen wrote: Wed Dec 04, 2024 4:47 pm
SNES AYE wrote: Wed Dec 04, 2024 1:26 pm
psycopathicteen wrote: Fri Nov 29, 2024 3:30 pm Since the fact that the SNES's HDMA is limited to runs of 127 scanlines
What does that mean in actual use?

Does it mean it wouldn't be possible to change the backdrop colour every scanline for example, but rather every second scanline or something like that?

This HDMA restriction is something I wasn't aware of before.
No, it's just makes it slightly harder to program. The HDMA format is:

byte 0: scanline count
byte 1: data to be written to

The scanline count byte is formatted like this:

MLLLLLLL

L = number of scanline

M = HDMA block mode
0: write data once then wait L number of lines before next HDMA chunk
1: write data every scanline for L number of scanline

$00 and $80 are special cases. $00 means end HDMA. $80 means write once wait 128 lines.
OK. Thanks for the clarification.
Post Reply