How do I access data like this with pointers?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
How do I access data like this with pointers?
by on (#76030)
Hi,

I"m a little new to 6502 stuff...I was trying to access data with pointers and I saw how some source was doing it, so I tried testing stuff in a simulator, but I can't seem to get it to work.

the pointer is always at $0000, and the STA tileset_ptr results in nothing
being stored from the accumulator to the pointer.

I'm probably doing something very stupid... the code is below.
I'm trying to get a tile from the tbank0x sections by referring to them with
tilesetbanks...
tileset_ptr is not holding the address of what I want, though...

I may be doing this all wrong as well...
Could someone tell me how to do this sorta thing properly in NESASM?


Code:
 ; set tileset bank to $01 (tbank01)
 LDA #$01
 TAY
 LDA tilesetbanks,y
 STA tileset_ptr
 LDA tilesetbanks+1,y
 STA tileset_ptr+1
 
 ;load tile $02 from bank $01 to $6000
 LDA #$02 ; this number is recieved from map data
 ASL
 ASL
 TAY
 LDA (tileset_ptr),y
 STA $6000
 INY
 LDA (tileset_ptr),y
 STA $6001
 INY
 LDA (tileset_ptr),y
 INY
 STA $6002
 LDA (tileset_ptr),y
 INY
 STA $6003


tbank00:
 .DB $00,$01,$02,$03    ;tile $00
 .DB $04,$05,$06,$07    ;tile $01
 .DB $08,$09,$0A,$0B    ;tile $02
 .DB $0C,$0D,$0E,$0F    ;tile $03

tbank01:
 .DB $10,$11,$12,$13    ;tile $00
 .DB $14,$15,$16,$17    ;tile $01
 .DB $18,$19,$1A,$1B    ;tile $02
 .DB $1C,$1D,$1E,$1F    ;tile $03

tilesetbanks:
 .DW tbank00,tbank01
 

by on (#76034)
Quote:
Code:
 ; set tileset bank to $01 (tbank01)
 LDA #$01
 TAY
 LDA tilesetbanks,y
 STA tileset_ptr
 LDA tilesetbanks+1,y
 STA tileset_ptr+1

You need to multiply Y by 2 at the beginning there. Otherwise, you are reading the high byte of tbank00 as the low byte, and the low byte of tbank01 as the high byte.
To easily multiply by 2, use the ASL A (Arithmetic Shift Left) instruction.
This will limit your range to 0-127.
Alternatively, use two separate tables, one for the high byte and one for the low byte. The ASM6 assembler has a nice feature to easily declare low and high bytes, DL and DH. Otherwise, you can use '& $FF' and '>> 8' to isolate the high and low bytes of a label.

by on (#76037)
Ahh, I see....i think....XD This stuff is really hard for me.

so I do it like this?

Code:
 LDA #$01
 ASL
 TAY
 LDA tilesetbanks,y
 STA tileset_ptr
 LDA tilesetbanks+1,y
 STA tileset_ptr+1


That was all that was wrong??
I was surprised...I thought when I posted this, my code was totally wrong.

127 per tileset is ok. I only use 0-63. 64-127 are used in RLE for making the metatile + the one next to it as to make up for situations like tile 1, tile 2, tile 1, tile 2 type thing.

I always wondered why one would want more than that, because with all 256 BKG 8x8 tiles, you can only make 64 unique ones anyway (256/4 = 64), and you mean 127 per tbank0x entry?

I would just use those for the few tiles you can make up from 8x8 parts over 64 and then bankswitch CHR ROM for diff pattern table sets.
I think 64 BKG metatiles per map is ok for me.

EDIT:
I figured out a better way as well!
I see what you mean by the lo/hi byte. without the ASL it's backwards!
So I tried this too:
Code:
 LDA #$01
 TAY
 LDA tilesetbanks+1,y
 STA tileset_ptr
 LDA tilesetbanks,y
 STA tileset_ptr+1
 


and it now works just the same without the ASL

Thanks very much for pointing that out!

by on (#76042)
Quote:
EDIT:
I figured out a better way as well!
I see what you mean by the lo/hi byte. without the ASL it's backwards!
So I tried this too:
Code:

LDA #$01
TAY
LDA tilesetbanks+1,y
STA tileset_ptr
LDA tilesetbanks,y
STA tileset_ptr+1



and it now works just the same without the ASL


Danger Will Robinson! That code is dead wrong. It happens to produce the same results, but it is dead wrong. Go back to your other code, it's exactly correct. This code will break when you add more tiles.

by on (#76068)
qbradq wrote:
Quote:
EDIT:
I figured out a better way as well!
I see what you mean by the lo/hi byte. without the ASL it's backwards!
So I tried this too:
Code:

LDA #$01
TAY
LDA tilesetbanks+1,y
STA tileset_ptr
LDA tilesetbanks,y
STA tileset_ptr+1



and it now works just the same without the ASL


Danger Will Robinson! That code is dead wrong. It happens to produce the same results, but it is dead wrong. Go back to your other code, it's exactly correct. This code will break when you add more tiles.



ooops! really? do you mean with the ASL? or what I originally had?
I kinda had a feeling about that, that something would go wrong that way.

by on (#76075)
iggydrake wrote:
ooops! really? do you mean with the ASL? or what I originally had?
I kinda had a feeling about that, that something would go wrong that way.


You can LDY #$01 (rather than LDA #$01, TAY)

the LDA xxxx,y instruction doesn't know your trying to deal with two
byte words it just does bytes, so tilesetbanks is tbank00 lo,
tilesetbanks+1 is tbank00 hi, tilesetbanks+2 is tbank01 lo,
tilesetbanks+3 is tbank01 hi etc
so you either mutiply by 2 (ie ASL) 'cause you're entries are two bytes
or split the entires in to two tables one for lo bytes and one for hi bytes.

Or you could just load the index directly if that's feasible and do the
multiply by 2 before hand ie LDY #$00 for the first entry, LDY #$02
for the second LDY #$04 for the third etc

And if that's feasible you could just eg
LDA tilesetbanks+4
STA tileset_ptr
LDA tilesetbanks+5
STA tileset_ptr+1
(for the third entry)

by on (#76077)
hmmm...im not sure how i split into 2 tables...

I can't load the tile indexes directly because i need the 'tilebanks' setup because I switch between sets when I CHR bankswitch. I need to have a way to just point to any given tbankxx set at a time.

I'm not sure if im understanding this pointer stuff properly. funny thing is for me thats harder than anything else NES @_@

by on (#76081)
The reason you have to multiply the index by 2 is because each pointer is 2 bytes long. You can sometimes even get away with not performing the multiplication (like using only even indexes and always incrementing/decrementing them by 2), but that increases your chances of mixing things up and reading parts of 2 different pointers.

To split pointers into 2 tables you have to do this:
Code:
tilesetbanksLO:
   .db <tileset0, <tileset1, <tileset2, (...)

tilesetbanksHI:
   .db >tileset0, >tileset1, >tileset2, (...)

   (...)

   ldy #$00
   lda tilesetbanksLO, y
   sta tileset_ptr
   lda tilesetbanksHI, y
   sta tileset_ptr+1

This way there is no need to multiply, because instead of using a list where each element is two bytes, you are using 2 lists where each element is 1 byte. When writing 6502 code, it's often easier/faster to handle data stored this way.

by on (#76087)
ahh I see! so U can use < and > to access lo and hi bytes of something! Handy, that. I think I'll do it that way.
Thanks very much, I'll try that. :D