Indirect indexed addressing

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
rizz1010
Posts: 47
Joined: Fri Jan 29, 2010 9:28 pm

Indirect indexed addressing

Post by rizz1010 »

Am I understanding indirect indexed addressing correctly? I am using asm6 by the way.

If I have these variables at $0400 and $0500
$0400
MyBytes .byte 0, 0, 0, 0, 0, 0

$0500
Pointer .byte 0, 0


In my code, I initialize these variables like so:
Pointer = $00
Pointer+1 = $04
MyBytes = $AA
MyBytes+1 = $BB
MyBytes+2 = $CC etc

Now, if I understand indirect indexed addressing on the 6502, I should be able to do this:
LDA (Pointer), Y
If Y = 1, then the accumulator should have $BB in it. However, it turned out that $04 was added to the accumulator, which was taken from Pointer+1 (not MyBytes+1 which I expected).



Thanks
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

Let's not discuss assembler equates and so on -- they just add to the confusion when it comes to understanding a processor. Let's discuss actual 6502 operation. :-) Note the below addresses/code doesn't correlate with anything on the NES -- it's just discussing 6502...

Memory dump:

Code: Select all

$00A0: 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
...
$9980: 01 23 45 67 89 AB CD EF 00 00 00 00 69 77 23 11
Code:

Code: Select all

LDY #4
LDA ($A8),Y
The first thing the CPU does is read the bytes at $A8 and $A9. $A8=88, $A9=99, so the "effective address" at this point is $9988.

The next thing the CPU does is add Y to the effective address. $9988 + 4 = $998C.

Finally, the CPU reads into the accumulator the value stored at the final effective address (that's $998C), which is value $69.

Make sense? Just verifying you truly understand how post-indexed indirect addressing works.

Your description of the problem almost makes sense, except you say "turns out $04 was added to the accumulator", which makes no sense whatsoever.

My advice is to use asm6's -l (that's dash-ELL) flag to generate an assembly listing, which will tell you exactly what the assembler is doing with your code and what it actually assembles into. You might be surprised to see something like, say, LDA (Pointer),Y being turned into LDA ($00),Y depending on whether or not you're actually saying "Pointer = $00" in your code or if you're doing "LDA #$00 ; STA Pointer".

I'm willing to bet you've either got some equates like "Pointer = $00" (same as Pointer EQU $00) which are confusing you, or you've got some labels named the same thing for memory as you do for actual equates (such as in your above example, Pointer could be interpreted as both an equate to $00, AS WELL as label that effectively is at address $0500). It's difficult to tell because of how you chose to word things, rather than just showing code. :-)
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: the universe
Contact:

Post by thefox »

I'm guessing you're using NESASM? :) In NESASM you can't use () for indirect addressing (because of its crappy parser I guess), you have to use [].

Change your code to

Code: Select all

LDA [Pointer], Y
or maybe just scrap NESASM altogether and use ASM6/CA65 or something.
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Post by Banshaku »

Yep, NESASM uses [] for indirect addressing. If you use () by mistake, no error will be thrown. This is what made the FT30 driver fail when I was converting it (forgot to convert some of them to []).
User avatar
tokumaru
Posts: 12645
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

And your pointers must be in zero page. The instruction "LDA ($XXXX), Y" doesn't exist, only "LDA ($XX), Y" does.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

thefox wrote:I'm guessing you're using NESASM?
The start of his post says he's using asm6, so my guess is that he's either using equates in a way that he's not sure of, or asm6 isn't throwing an error when trying to do something like

Code: Select all

.org $0400
mylabel .db 0,0,0,0,0,0

.org $8000
ldy #4
lda (mylabel),y
And instead turning the LDA statement into something like LDA ($00),y or LDA ($04),y. Hard to say -- again, listings generation can answer this. But then again so could we if we could see the code. ;-)
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: the universe
Contact:

Post by thefox »

koitsu wrote:
thefox wrote:I'm guessing you're using NESASM?
The start of his post says he's using asm6, so my guess is that he's either using equates in a way that he's not sure of, or asm6 isn't throwing an error when trying to do something like
Oops, missed that. It could indeed by that ASM6 parser is seeing this as LDA $0500,Y because of the non-zeropage address.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
rizz1010
Posts: 47
Joined: Fri Jan 29, 2010 9:28 pm

Post by rizz1010 »

tokumaru wrote:And your pointers must be in zero page. The instruction "LDA ($XXXX), Y" doesn't exist, only "LDA ($XX), Y" does.


The solution has been found (it was the zero page issue).

Sorry for the confusion in my post koitsu (my actual code was assembly friendly, using LDA, STA instructions). When I read your post I was thinking "yes, that is exactly how I understand it" which was bugging me even more that my code wasn't working as was expected.


Regarding the $04 value put into the accumulator, apparently, if you try a 2 byte value with indirect indexed addressing, it ignores the value inside the address, and uses the address itself. So, going back to my example:
LDA (Pointer), Y ;Y = 1
It took the address where Pointer was ($0500), added 1 to that ($0501), and put $04 into the accumulator. $04 was the value held in $0501.


And thanks for the debugger tip with -l. I'd love to here a more detailed explanation of how to use that. Where does the -l get added exactly? As far as debugging goes, any other helpful hints are welcome. The day I discovered the hex editor was so nice.
User avatar
tokumaru
Posts: 12645
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

If you use a value > than $FF the assembler probably just considers the parenthesis as part of a logical expression (which evaluates to the value inside the parenthesis) rather than indirect addressing.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

rizz1010 wrote:And thanks for the debugger tip with -l. I'd love to here a more detailed explanation of how to use that. Where does the -l get added exactly?
It's a command-line flag you pass to asm6. Read the README. :-)

I'd love to classify this as an asm6 bug, however, I still don't understand the way the problem manifests itself. You said:
rizz1010 wrote: Regarding the $04 value put into the accumulator, apparently, if you try a 2 byte value with indirect indexed addressing, it ignores the value inside the address, and uses the address itself. So, going back to my example:
LDA (Pointer), Y ;Y = 1
It took the address where Pointer was ($0500), added 1 to that ($0501), and put $04 into the accumulator. $04 was the value held in $0501.
I don't know how that would even be possible. The CPU doesn't know how to do anything like LDA ($0500),Y -- by this I mean there's no such addressing mode -- and the assembler should not be causing this somehow (the assembler doesn't know/care what Y is set to).

If LDA ($0500),Y is permitted by asm6, then that's a bug in the assembler.

Can you please show the listing generation for the code in question? Let's get to the bottom of this.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

tokumaru wrote:If you use a value > than $FF the assembler probably just considers the parenthesis as part of a logical expression (which evaluates to the value inside the parenthesis) rather than indirect addressing.
I'm not sure that's the case either though, because:

1) What would the "value for Pointer" expand to? It should expand to a 16-bit address (e.g. $0500), which would turn the instruction into something invalid for the 6502 (specifically, LDA ($0500),Y).

2) It doesn't explain how the assembler would somehow generate $0501 for any part of the effective address.

3) He says "it took the address where Pointer was (e.g. $0500, added 1 to that (to make $0501), and loaded the contents from that address, which loaded $04 into the accum" -- that would imply the assembler, somehow, translated his code into either LDA $0500,Y (valid 6502, opcode $B9) or LDA $0501 (valid 6502, opcode $AD).

The generated assembly listing should answer the question.
Last edited by koitsu on Sat Mar 13, 2010 7:16 pm, edited 1 time in total.
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

Post by cpow »

Pointer = $00
Pointer+1 = $04

How is this even valid? What am I missing?
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

NESICIDE wrote:Pointer = $00
Pointer+1 = $04

How is this even valid? What am I missing?
He wrote "pseudocode" in attempt to say this:

Code: Select all

LDA #$00
STA Pointer
LDA #$04
STA Pointer+1
Where Pointer is a label to $0500.
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

Post by cpow »

koitsu wrote:He wrote "pseudocode"
Oh thank goodness!
Post Reply