Storing Addresses as Values

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
Guilty
Posts: 93
Joined: Fri Apr 08, 2016 5:58 pm
Location: California, USA

Storing Addresses as Values

Post by Guilty »

I'm here straight from NerdyNights, Easy6502 by Skilled Rick, useage.txt included with NESASM, Patater, and every other resource I could find (nesdev wiki included) and I'm not sure I've got my terms correct.
That being said:

I'm learning NESASM and attempting to create a general-purpose megasprite drawing routine (function?). My idea for making this work is as follows:
Declare a 2 byte variable in the zero page RAM using .rs 2 (spriteframe)
Declare two 1 byte variables in the zero page RAM using .rs 2 (spriteX, spriteY)
In bank 2, I set a label and use .db to write many bytes describing a single metasprite (numberoftiles, vert1, tile1, attr1, horz1, vert2, tile2, etc...)
The label is, for instance, MetaSprite0. Of course after that I would place a label for MetaSprite1 and use .db again.

And then each frame I jsr to my general purpose metasprite routine. It loops through 'numberoftiles'/4 amount of times, the four bytes of each tile and storing them in place for the automatic sprite dma. (the reason spritex and spritey are involved is so that I can draw all of the tiles of the metasprite positioned relatively to a central drawing point)

Ideally, I would like to set the variable spriteframe to represent the location in my ROM that begins the metasprite. To accomplish this, I'm currently loading LOW(MetaSprite0) and HIGH(MetaSprite0). By my understanding of things, this should place the address value of my label MetaSprite0 into my variable spriteframe, for instance if label MetaSprite0 points to $e020 then spriteframe would be $20, $e0 (reversed because of some weird 'little endian' term I hear thrown around?). BUT when looking through with the hex editor, I've found that LOW(MetaSprite0) evaluates to the value at location MetaSprite0 instead of the low byte of the location itself. What should I do instead?

Let's just pretend that works:
From there I think I should be able to use indirect indexed addressing to load the value at the address stored at the address of my variable spriteframe (spriteframe contains an address pointing to my label that begins the metasprite data, and from there we use the Y offset to pick an individual byte for each tile). That seems to work just fine when I test it in isolation... but of course I am having a hard time reading from the correct location as I have not found a way to store locations.


~~~~
Any and all thoughts are welcome. I'm fresh on the NES scene and new to assembly, so any comments you have about what I'm doing is welcome insight.
~~~~


If I should describe anything differently, say the word and I'll try again. I can post my source code too, but it's not commented and its even more disorganized than this post, plus the general nature of my question probably doesn't need much source...?

tl;dr: Is there a way to store the address of a label as opposed to the value at a label's address?
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Storing Addresses as Values

Post by tokumaru »

Guilty wrote:Ideally, I would like to set the variable spriteframe to represent the location in my ROM that begins the metasprite. To accomplish this, I'm currently loading LOW(MetaSprite0) and HIGH(MetaSprite0). By my understanding of things, this should place the address value of my label MetaSprite0 into my variable spriteframe, for instance if label MetaSprite0 points to $e020 then spriteframe would be $20, $e0 (reversed because of some weird 'little endian' term I hear thrown around?).
Yes, LOW() and HIGH() should return the individual bytes of a 16-bit value/address, but you must use # to specify that the load instruction is to use those bytes as immediate values (e.g. lda #LOW(MetaSprite0)), not addresses. The following code should successfully create a pointer to the meta-sprite data:

Code: Select all

	;set up the pointer
	lda #LOW(Metasprite0)
	sta spriteframe+0
	lda #HIGH(Metasprite0)
	sta spriteframe+1
So you can do this to access the data:

Code: Select all

	;load the first byte of the meta-sprite
	ldy #$00
	lda [spriteframe], y
BUT when looking through with the hex editor, I've found that LOW(MetaSprite0) evaluates to the value at location MetaSprite0 instead of the low byte of the location itself. What should I do instead?
Failing to use # would result in the values at ZP locations $0020 and $00e0 being copied to spriteframe, not the value at location MetaSprite0.

EDIT: This thread might be relevant. Interesting how it also appears to be about meta-sprites (which is not really relevant, as the problem itself is about pointers).
User avatar
Guilty
Posts: 93
Joined: Fri Apr 08, 2016 5:58 pm
Location: California, USA

Re: Storing Addresses as Values

Post by Guilty »

tokumaru wrote:lda #LOW(MetaSprite0)
YOU CAN PUT LITERALS ON THAT SHIT? Assembly language is awesome.

Code: Select all

	;load the first byte of the meta-sprite
	ldy #$00
	lda [spriteframe], y
Okay, I see where we're going. This is fantastically useful. I skimmed through the topic you linked, too, and there was some useful information there. I've got one more question though, instead of using lda [spriteframe],y to load the address stored at spriteframe+y, could I use something similar to lda [spriteframe+1],y to load the address at spriteframe+1+y? Or do I need to simply iny and dey for each instruction in each loop?

my current (incomplete) source code for the drawing routine:

Code: Select all

DrawSprites:
  ldx #$00
  ldy #$00
DrawSpritesLoop:
  lda spritey		;load offy
  sta SPRITEOAM, y	;store vert
  iny
  iny
  lda [spriteframe],y	;load tile
  dey
  sta SPRITEOAM, y	;store tile
  iny
  iny
  lda [spriteframe], y	;load attr
  dey
  sta SPRITEOAM, y;store attr
  iny
  lda spritex		;load offx
  sta SPRITEOAM,y	;store horiz
  iny
  inx
  cpx #$09
  bne DrawSpritesLoop
  rts
As I add more to this, I'll need to jump around more to, for instance, load the current sprite's attribute for comparison and then load the sprite's horizontal offset for addition with spritex. Which involves multiple inys and deys.

Another question, actually. Right now I'm using cpx #$09 to make sure the loop stops after 9 sprites are drawn, but I'd like to just, say, cpx [spriteframe] to terminate the loop after it has iterated the number of times stored at spriteframe ($e020). Obviously that doesn't compile though and I'm having a hard time finding the correct syntax for that. Is it just cpx spriteframe? I feel like that would terminate the loop after $02 iterations but I could be wrong
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Storing Addresses as Values

Post by tepples »

Guilty wrote:instead of using lda [spriteframe],y to load the address stored at spriteframe+y, could I use something similar to lda [spriteframe+1],y to load the address at spriteframe+1+y?

No. lda [spriteframe+1],y will interpret RAM[spriteframe+1], which contains the high byte of the pointer, as a low byte, and RAM[spriteframe+2], which is likely to contain unrelated data, as a high byte. To do what you want, you will have to manipulate Y to access each byte.

Guilty wrote:my current (incomplete) source code for the drawing routine:

Code: Select all

DrawSprites:
  ldx #$00
  ldy #$00
DrawSpritesLoop:
  lda spritey		;load offy
  sta SPRITEOAM, y	;store vert
  iny
  iny
  lda [spriteframe],y	;load tile
  dey
  sta SPRITEOAM, y	;store tile
  iny
  iny
  lda [spriteframe], y	;load attr
  dey
  sta SPRITEOAM, y;store attr
  iny
  lda spritex		;load offx
  sta SPRITEOAM,y	;store horiz
  iny
  inx
  cpx #$09
  bne DrawSpritesLoop
  rts
I recommend that you use Y to read from spriteframe and use X to write to SPRITEOAM. Then use a variable to tell how many sprites are left in the metasprite, and use dec spritesleft / bne DrawSpritesLoop to end the loop. Also, save and restore X to a variable that's cleared to 0 each frame. (Or clear it to 4 if using sprite 0 for raster effects.) This way, as you draw multiple sprites, you can keep track of how far the metasprite routine has written through SPRITEOAM. In my productions, I tend to call this variable oam_used.
Right now I'm using cpx #$09 to make sure the loop stops after 9 sprites are drawn, but I'd like to just, say, cpx [spriteframe] to terminate the loop after it has iterated the number of times stored at spriteframe ($e020). Obviously that doesn't compile though and I'm having a hard time finding the correct syntax for that. Is it just cpx spriteframe? I feel like that would terminate the loop after $02 iterations but I could be wrong
If the value at spriteframe is LOW(Metasprite0), then cpx spriteframe will terminate the loop after LOW(Metasprite0) iterations. This is another reason why I recommend reading the length of the metasprite into a variable.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Storing Addresses as Values

Post by tokumaru »

Guilty wrote:could I use something similar to lda [spriteframe+1],y to load the address at spriteframe+1+y?
Unfortunately, no. The +n trick doesn't work with indirection, because it offsets the address of the pointer (causing the program to use the wrong data as a pointer), not the address the pointer points to. Indirect addressing is quite limited on the 6502, which is why we avoid it whenever possible.
I'd like to just, say, cpx [spriteframe] to terminate the loop after it has iterated the number of times stored at spriteframe ($e020). Obviously that doesn't compile though and I'm having a hard time finding the correct syntax for that.
This is not a matter of syntax, some things are just not possible. Not all addressing modes are available to all instructions and registers. When in doubt, look up the instruction in question on this page to see what addressing modes are available. Like I said before, indirection is very limited on the 6502... It's always indexed by the Y register (if you don't want an index you HAVE to set Y to 0 and use it anyway), and math operations and data transfers must be done with the accumulator, never the X register.

With time you'll get used to what can be done and what can't, but in the mean time, keep a tab in your browser with the page I linked to permanently open.
User avatar
Guilty
Posts: 93
Joined: Fri Apr 08, 2016 5:58 pm
Location: California, USA

Re: Storing Addresses as Values

Post by Guilty »

This is just about the fastest moving and most helpful forum I've ever signed in to. Thanks guys, this is crazy useful information. My megasprite routine is approaching feature complete and I'll save that link.
User avatar
Guilty
Posts: 93
Joined: Fri Apr 08, 2016 5:58 pm
Location: California, USA

Re: Storing Addresses as Values

Post by Guilty »

Also,
tepples wrote:...save and restore X to a variable that's cleared to 0 each frame. (Or clear it to 4 if using sprite 0 for raster effects.) This way, as you draw multiple sprites, you can keep track of how far the metasprite routine has written through SPRITEOAM. In my productions, I tend to call this variable oam_used.
Woah woah woah, I'm a little green for messing with RASTER EFFECTS I think. I'll hold off on that for a bit.
But the oam_used idea is solid gold.
Post Reply