vram slot searching routine for wiki.superfamicom.org

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
vram slot searching routine for wiki.superfamicom.org
by on (#162711)
I don't think anybody has updated wiki.superfamicom.org in a while, and so I had an idea. Since animation is something that pulls people's hair out, I decided to take the most important part of my animation engine (the part that calculates where in VRAM to place sprite cells) and modify it to be used as example code for wiki.superfamicom.org.

Before I post it on wiki.superfamicom.org, can anybody find anything else I can simplify for beginners (other than adding notes), or find any mistakes?

Code:
find_32x32_slot:
sep #$20
ldx #$0000
lda {vram_slot_table},x
beq +
-;
inx
lda {vram_slot_table},x
bne -
+;
cpx #$0020
bne +
rep #$20
lda #$0200
rts
+;
lda #$0f
sta {vram_slot_table},x
rep #$20
lda large_slot_vram_location,x
and #$00ff
asl
rts


find_16x16_slot:
ldy #$0000
tyx
lda #$0f0f
cmp {vram_slot_table},x
bne +
-;
inx #2
cmp {vram_slot_table},x
beq -
+;
lda {vram_slot_table},x
sep #$20
cmp #$0f
bne +
inx
xba
+;
cpx #$0020
bne +
rep #$20
lda #$0200
rts
+;
tay
ora vram_slot_table_bit_set,y
sta {vram_slot_table},x
rep #$20
lda large_slot_vram_location,x
ora small_slot_vram_location,y
and #$00ff
asl
rts



large_slot_vram_location:
db $00
db $02
db $04
db $06
db $20
db $22
db $24
db $26
db $40
db $42
db $44
db $46
db $60
db $62
db $64
db $66
db $80
db $82
db $84
db $86
db $a0
db $a2
db $a4
db $a6
db $c0
db $c2
db $c4
db $c6
db $e0
db $e2
db $e4
db $e6

small_slot_vram_location:
db $00
db $01
db $00
db $10
db $00
db $01
db $00
db $11
db $00
db $01
db $00
db $10
db $00
db $01
db $00


vram_slot_table_bit_set:
db $01
db $02
db $01
db $04
db $01
db $02
db $01
db $08
db $01
db $02
db $01
db $04
db $01
db $02
db $01
Re: vram slot searching routine for wiki.superfamicom.org
by on (#162713)
Are you sure I'm not the only one who's pulling their hair out? :lol:

...And I haven't actually looked at the code yet, but I'm less experienced than you so I doubt I'd be able to help.
Re: vram slot searching routine for wiki.superfamicom.org
by on (#162714)
Quote:
Are you sure I'm not the only one who's pulling their hair out? :lol:


Looking at SNES code is a little like staring at the sun. I want to look at it because it's so amazing, but as soon as I do, I feel like my eyes are going to burn out of my head.

I mean you mention 'sprites' but then go on to talk about VRAM. I thought Sprites were located in the OAM, not the VRAM, so the entire conversation is over my head...

Oh, wait ...the actual tiles are in the VRAM. Ok, I get it...

So, the top part is for 32x32 tiles? And the next part is for 16x16 tiles?
Re: vram slot searching routine for wiki.superfamicom.org
by on (#162716)
The actual graphics are still located in VRAM; the OAM just controls appearance, positioning, orientation, etc.

Also, I feel like commenting your code is probably something you should do before asking other people to check it for correctness.
Re: vram slot searching routine for wiki.superfamicom.org
by on (#162717)
The sprite display list is in OAM. The tile numbers in the display list correspond to addresses in VRAM.
Re: vram slot searching routine for wiki.superfamicom.org
by on (#162747)
Revenant wrote:
Also, I feel like commenting your code is probably something you should do before asking other people to check it for correctness.
this ^^
As honestly we don't even know what your code is actually supposed to do (there are many ways of allocating VRAM) ;)
Re: vram slot searching routine for wiki.superfamicom.org
by on (#162755)
Figured out it makes more sense to have index registers in 8-bit mode.

Is this good enough note taking, or is this making it more confusing?

Code:
find_32x32_slot:
sep #$30
ldx #$00
lda {vram_slot_table},x      //check first 32x32 slot
beq +                              //if zero, found open slot
-;
inx
lda {vram_slot_table},x
bne -
+;

cpx #$20                      //slot values of #32 are invalid
bne +
rep #$20
lda #$0200                      //end routine with CHR number = $0200, if slot is invalid
rts

+;
lda #$0f
sta {vram_slot_table},x     //when slot is valid, mark it with #$0f.  Each of the 4 bits corresponds to a specific 16x16 cell inside the 32x32 cell
lda large_slot_vram_location,x       //find the CHR number
rep #$20
and #$00ff
asl
rts                                            //routine ends with CHR number of slot found, in accumulator

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

find_16x16_slot:
rep #$20                                  //uses 16-bit accumulator to read two slot entries at once
sep #$10
ldx #$00
lda #$0f0f                                //everything is compared to #$0f0f, in order to find a pair of 32x32 slots that aren't full
cmp {vram_slot_table},x
bne +
-;
inx #2
cmp {vram_slot_table},x
beq -
+;
lda {vram_slot_table},x             //go back into 8-bit mode to determine which 32x32 slot is the one that's not full
sep #$20
cmp #$0f
bne +
inx
xba                                        //if this 32x32 slot is full, the other one must not be.  Switch sides of the accumulator.
+;

cpx #$20                                //again, slot #32 is invalid
bne +
rep #$20
lda #$0200
rts

+;
tay                                          //find the first blank 16x16 slot, of the 32x32 slot
ora vram_slot_table_bit_set,y
sta {vram_slot_table},x              //mark bit as used
lda large_slot_vram_location,x     //get the CHR number of the 32x32 slot, the 16x16 slot is a part of
ora small_slot_vram_location,y    //get the CHR number of the 16x16 slot, within the 32x32 slot
rep #$20
and #$00ff
asl
rts                                            //routine ends with CHR number of slot found, in accumulator

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

large_slot_vram_location:
db $00,$02,$04,$06            // n = 32x32 slot number
db $20,$22,$24,$26            // CHR number = LUT(n)*2
db $40,$42,$44,$46            // vram address = LUT(n)*32
db $60,$62,$64,$66
db $80,$82,$84,$86
db $a0,$a2,$a4,$a6
db $c0,$c2,$c4,$c6
db $e0,$e2,$e4,$e6

vram_slot_table_bit_set:       //find first empty bit per byte.  Bytes represent 32x32 slots, with the low 4 bits representing the 16x16 slots that make up the 32x32 slot.
db $01                               //0000 => 000x => 0001
db $02                               //0001 => 00x1 => 0010
db $01                               //0010 => 001x => 0001
db $04                               //0011 => 0x11 => 0100
db $01                               //0100 => 010x => 0001
db $02                               //etc
db $01
db $08
db $01
db $02
db $01
db $04
db $01
db $02
db $01

small_slot_vram_location:     //corresponds to table above
db $00                               //0000 => 000x => 0001, top left of 32x32 slot
db $01                               //0001 => 00x1 => 0010, top right
db $00
db $10                               //0011 => 0x11 => 0100, bottom left
db $00
db $01
db $00
db $11                               //0111 => x111 => 1000, bottom right
db $00
db $01
db $00
db $10
db $00
db $01
db $00

Re: vram slot searching routine for wiki.superfamicom.org
by on (#162790)
Far easier to understand now :-)
I guess your vram_slot_table is a 32 bytes table defining vram slot allocation ? Shouldn't you test the 32 bytes limit inside the loop ? Or you always have a null byte after the end of vram_slot_table (by allocating 33 bytes table and setting the last entry to 0).
I was wondering why are you loading A in 16 bit from large_slot, can't you just move rep #$20 right after loading A ?

Not sure to understand what you are doing in the 16x16 allocation part but I read it quickly :-p
Re: vram slot searching routine for wiki.superfamicom.org
by on (#162793)
Stef wrote:
I was wondering why are you loading A in 16 bit from large_slot, can't you just move rep #$20 right after loading A ?

Thanks for pointing that out.
Re: vram slot searching routine for wiki.superfamicom.org
by on (#162855)
Ok, i think i understand now your algorithm for 16x16 blocks search, neat use of LUT :)
Re: vram slot searching routine for wiki.superfamicom.org
by on (#162882)
Stef wrote:
Ok, i think i understand now your algorithm for 16x16 blocks search, neat use of LUT :)


Sik actually thought of that trick about a year ago, in a thread that got seriously derailed.
Re: vram slot searching routine for wiki.superfamicom.org
by on (#162891)
Well, if you want to help make it easier... add proper indentation (no idea if the forum ate those) so it's easier to tell apart the labels. Also may want to put several entries of each look-up table in the same line so they don't look like a huge DB column (i.e. make all LUTs look like large_slot_vram_location in the second example). This is all to do exclusively with readability.

Didn't really go around reading exactly what it does, but why are those last two LUTs missing an entry each? Is it implicitly handled or what? (may want to explicitly add a comment for this)
Re: vram slot searching routine for wiki.superfamicom.org
by on (#163706)
Code:
find_32x32_slot:
sep #$30
ldx #$00
lda {vram_slot_table},x      //check first 32x32 slot
beq +                              //if zero, found open slot
-;
inx
lda {vram_slot_table},x
bne -
+;

cpx #$20                      //slot values of #32 are invalid
bne +
rep #$20
lda #$0200                      //end routine with CHR number = $0200, if slot is invalid
rts

+;
lda #$0f
sta {vram_slot_table},x     //when slot is valid, mark it with #$0f.  Each of the 4 bits corresponds to a specific 16x16 cell inside the 32x32 cell
lda large_slot_vram_location,x       //find the CHR number
rep #$20
and #$00ff
asl
rts                                            //routine ends with CHR number of slot found, in accumulator

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

find_16x16_slot:
rep #$20                                  //uses 16-bit accumulator to read two slot entries at once
sep #$10
ldx #$00
lda #$0f0f                                //everything is compared to #$0f0f, in order to find a pair of 32x32 slots that aren't full
cmp {vram_slot_table},x
bne +
-;
inx #2
cmp {vram_slot_table},x
beq -
+;
lda {vram_slot_table},x             //go back into 8-bit mode to determine which 32x32 slot is the one that's not full
sep #$20
cmp #$0f
bne +
inx
xba                                        //if this 32x32 slot is full, the other one must not be.  Switch sides of the accumulator.
+;

cpx #$20                                //again, slot #32 is invalid
bne +
rep #$20
lda #$0200
rts

+;
tay                                          //find the first blank 16x16 slot, of the 32x32 slot
ora vram_slot_table_bit_set,y
sta {vram_slot_table},x              //mark bit as used
lda large_slot_vram_location,x     //get the CHR number of the 32x32 slot, the 16x16 slot is a part of
ora small_slot_vram_location,y    //get the CHR number of the 16x16 slot, within the 32x32 slot
rep #$20
and #$00ff
asl
rts                                            //routine ends with CHR number of slot found, in accumulator

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

large_slot_vram_location:
db $00,$02,$04,$06            // n = 32x32 slot number
db $20,$22,$24,$26            // CHR number = LUT(n)*2
db $40,$42,$44,$46            // vram address = LUT(n)*32
db $60,$62,$64,$66
db $80,$82,$84,$86
db $a0,$a2,$a4,$a6
db $c0,$c2,$c4,$c6
db $e0,$e2,$e4,$e6

//find first empty bit per byte.  Bytes represent 32x32 slots, with the low 4 bits representing the 16x16 slots that make up the 32x32 slot.
//0000 => 000x => 0001
//0001 => 00x1 => 0010
//0010 => 001x => 0001
//0011 => 0x11 => 0100
//0100 => 010x => 0001
//etc

vram_slot_table_bit_set:
db $01,$02,$01,$04,$01,$02,$01,$08,$01,$02,$01,$04,$01,$02,$01


//corresponds to table above
//0000 => 000x => 0001, top left of 32x32 slot
//0001 => 00x1 => 0010, top right
//0011 => 0x11 => 0100, bottom left
//0111 => x111 => 1000, bottom right

small_slot_vram_location:     
db $00,$01,$00,$10,$00,$01,$00,$11,$00,$01,$00,$10,$00,$01,$00