This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

What is the practical use of indexed indirect addressing?

What is the practical use of indexed indirect addressing?
by on (#223583)
Hello all,

I was recently working on an NES project, and I realized I really needed some pointers in order to deal with a graphics buffer. As such, I am using indirect indexed addressing with the Y register -- for example,
Code:
lda (zp), y
I can understand very practical uses for this--you load in a ZP address, and it uses that byte and the subsequent byte as a pointer to the address you want to access; from there, it uses the Y register as an index. This seems very useful, as it lets us point to, for example, an array, and access an element from the array using the Y register.

But why would you ever need to use indexed indirect addressing with the X register? What practical purpose does this serve? There has to be some situation where this feature would prove useful, otherwise I'd assume it wouldn't be featured in the processor design. Have you ever used indexed indirect addressing in your programs? Do you think it is particularly useful, or do you think indirect indexed addressing is a better tool?

Thanks in advance for the replies!
Re: What is the practical use of indexed indirect addressing
by on (#223585)
much as lda (zp),y lets you take a pointer and add Y to it, lda (zp, x) lets you load one of multiple different pointers.
Re: What is the practical use of indexed indirect addressing
by on (#223586)
truffly wrote:
But why would you ever need to use indexed indirect addressing with the X register? What practical purpose does this serve?

That is indeed the least used addressing mode in the 6502, but there are a few cases where it may be useful. The intended use is obviously for when you have an array of pointers, so you can use X to select which pointer to use. One common example often mentioned here is sound engines, which have to handle multiple tracks, so it may be convenient to select the track to read using the X register, which you can also use to access other word-sized attributes/states of each track.

It basically allows access to multiple streams that are supposed to be read sequentially, meaning that there's no need to preserve the base address and you can simply increment the pointers themselves in order to move on to the next item.
Re: What is the practical use of indexed indirect addressing
by on (#223589)
With (zp, x) mode, remember that the table of pointers needs to be in the zeropage, because it wraps back into the zeropage. Also, you need to Inx twice to switch between them.

Correct me if I'm wrong, it's been a while since I used it.
Re: What is the practical use of indexed indirect addressing
by on (#223592)
For example, in my Pently audio driver, because audio channels' MMIO ports in $400x are 4 apart, the pointers stored in zero page are also 4 bytes apart.
Code:
; Pently persistent zero page layout
;       +0                +1                +2                +3
;  0  | Sq1 sound effect data ptr           Sq1 music pattern data ptr
;  4  | Sq2 sound effect data ptr           Sq2 music pattern data ptr
;  8  | Tri sound effect data ptr           Tri music pattern data ptr
; 12  | Noise sound effect data ptr         Noise music pattern data ptr
; 16  | Sq1 envelope data ptr               Attack music pattern data ptr
; 20  | Sq2 envelope data ptr               Conductor track position
; 24  | Tri envelope data ptr               Tempo counter
; 28  | Noise envelope data ptr             Play/Pause        Attack channel
Re: What is the practical use of indexed indirect addressing
by on (#223594)
Question better-suited for 6502.org forum, as it's about 6502 and not so much NES.

In general, indirect indexed ((foo),y) is more useful given that it allows you to address the entire 64KByte memory space. That said:

A simple jump table is one of the most common uses of the indexed indirect addressing ((foo,x)) mode. Example routine, where you load the "table index" into the accumulator in advance (ex. lda #4 / jmp doit):

Code:
doit:
  asl
  tax
  jmp (table,x)
  ...

table:
  .dw routine1
  .dw routine2
  .dw routine3
  .dw routine4
  .dw routine5
  .dw routine6
  ...

There are tons of ways you can accomplish the above differently. It all depends on use cases and programmer/developer choice. It is impossible to know each and every one of them. OP asked for one, so there it is. If you want others, just ask, but they're all generally the same -- all use-cases that are table-based, particularly a table of pointers.

"Programming the 6502" by Rodney Zaks, 1983, has several examples of where indexed indirect addressing is useful.
Re: What is the practical use of indexed indirect addressing
by on (#223595)
Just maybe, you could additionally use the addressing mode to prefetch a strip of data (or cherrypick data here and there into a strip) at a time when you have plenty of time to do so, in order to read the resulting strip from zp at another time when you don't have as much time, using indexed indirect. That is, if you have the zp to spare.

Some games use a soubroutine handler that load pointers piecemeal and then go to them based on some return value from a subroutine. Instead, you could maybe rather load a whole strip of them this way. An then, if one of the pointed-to subroutines needs to modify what's next in order, it can do so, either by modifying next pointer, or the simply the x register, before returning. The "what's next" handler will just step on to the next or specified pointer cluelessly. It makes for a simple "what's next routine", i think... I'm clearly not an expert.

Basically: you lay out a preliminary string of pointers that is the basic marching order of a section of the program, and then the subroutines will evaluate something and for example modify the what's next counter or a cell within the strip.


Edit: "Pre-indexed indirect addressing is useful for choosing one of a set of indirect addresses to use" -Lance Leventhal, in 6502 assembly language programming, page 3-10. So yeah, what everyone basically already said. The book also contains atomic examples of using CMP and EOR with indexed indirect, but they seem to be mostly there to explain what is happening if you use it. They aren't part of any explanation why you might want to do that.
Re: What is the practical use of indexed indirect addressing
by on (#223597)
koitsu wrote:
Code:
jmp (table,x)

The original 6502 can't do that, though... That's probably a 65816 thing.
Re: What is the practical use of indexed indirect addressing
by on (#223599)
yeah... the book i just read from confusingly stated that jmp could be seen as indexed indirect, but that x is always 0. That's one weird way to put that it is not indexed indirect, haha. But the rule for jmp stands.

Instructions that can use indexed indirect:
ADC
AND
CMP
EOR
LDA
ORA
SBC
STA
Re: What is the practical use of indexed indirect addressing
by on (#223601)
tokumaru wrote:
koitsu wrote:
Code:
jmp (table,x)

The original 6502 can't do that, though... That's probably a 65816 thing.

My apologies, you're right, the 6502 cannot do this. The indirect indexed addressing mode for jmp was introduced in the 65c02, thus the 65816 has it as well.

It's not the first time I've made this mistake publicly. Those that know me well know I often "screw up" some opcodes when doing 6502 in this way. This is because when I first started doing 6502, I actually started on an Apple IIE, which was a 65c02, which has several additional instructions and opcodes with additional addressing modes (inc a / dec a or just inc / dec, instead of clc / adc #1 or sec / sbc #1 is the most well-known). About 6 months later I started doing work on an Apple II+ (6502), followed by 6-8 months later getting an Apple IIGS (65816). So, my brain tends to have a memory of 65c02/65816 addressing modes and instructions. It's very easy to forget which (of the more basic) aren't available on the 6502.

That said: I can quote some examples from the book I referenced if asked (and that is a pure 6502 book).
Re: What is the practical use of indexed indirect addressing
by on (#223607)
Please do! This stuff is interesting, especially as my book is quite sparse on practical examples.

From MOS technology's own reference manual:
"An attempt to define problems to take advantage of this shorter memory and execution time by defining fields should be investigated first. However, in almost every program, the same operation must be performed several times. In those cases, it is sometimes more useful to define a subroutine and set the values that the subroutine will operate on as fields in memory. Pointers to these fields are placed in the Zero Page of memory and then the indexed indirect operation is used to perform the function. This is the primary use of the indexed indirect operation. "

It also specifically but very briefly mentions "polling I/O" and "string processing".
Re: What is the practical use of indexed indirect addressing
by on (#223608)
If Y is tied up you can set X to zero and use it as a worse way to pointer dereference. That's what I use it for.
Re: What is the practical use of indexed indirect addressing
by on (#223613)
pubby wrote:
If Y is tied up you can set X to zero and use it as a worse way to pointer dereference. That's what I use it for.

Yeah, I've done that too.
Re: What is the practical use of indexed indirect addressing
by on (#223637)
tepples wrote:
For example, in my Pently audio driver, because audio channels' MMIO ports in $400x are 4 apart, the pointers stored in zero page are also 4 bytes apart.
Code:
; Pently persistent zero page layout
;       +0                +1                +2                +3
;  0  | Sq1 sound effect data ptr           Sq1 music pattern data ptr
;  4  | Sq2 sound effect data ptr           Sq2 music pattern data ptr
;  8  | Tri sound effect data ptr           Tri music pattern data ptr
; 12  | Noise sound effect data ptr         Noise music pattern data ptr
; 16  | Sq1 envelope data ptr               Attack music pattern data ptr
; 20  | Sq2 envelope data ptr               Conductor track position
; 24  | Tri envelope data ptr               Tempo counter
; 28  | Noise envelope data ptr             Play/Pause        Attack channel

This is pure genius !! I never tought of doing things like this before.
Re: What is the practical use of indexed indirect addressing
by on (#223642)
pubby wrote:
If Y is tied up you can set X to zero and use it as a worse way to pointer dereference. That's what I use it for.

That's one more thing the later processors fixed, they have jmp (ptr).
Re: What is the practical use of indexed indirect addressing
by on (#223649)
In fact, JMP (indirect) already existed in the stock 6502, what changed in latter models is the fact that the fetch of the indirect address is not buggy and doesn't wrap in a page...
Re: What is the practical use of indexed indirect addressing
by on (#223659)
I'm guessing it's because the inventors of the 6502 didn't predict what opcodes were going to be used the most often. They couldn't have predicted their chips being used in one of the most popular video game systems in history.
Re: What is the practical use of indexed indirect addressing
by on (#223660)
psycopathicteen wrote:
I'm guessing it's because the inventors of the 6502 didn't predict what opcodes were going to be used the most often. They couldn't have predicted their chips being used in one of the most popular video game systems in history.

Would that be the Atari 2600 or the Commodore 64? (Kapp'n)
Re: What is the practical use of indexed indirect addressing
by on (#223661)
Apple ][, more likely.
Karateka on NES/Famicom sucksksksk, so Apple ][ >>> Famicom >>>> NES. :roll:
Re: What is the practical use of indexed indirect addressing
by on (#223662)
WHAT?! Have you forgotten the Atari Lynx and Gamate?!

In all seriousness though, this thread is sort of fascinating. The obvious use is for something like an array of pointers, but some of the suggestions here are pretty brilliant. (ex: A table of streams since you can cheaply increment their pointers, or lining up the indexes with other things you want to access)
Re: What is the practical use of indexed indirect addressing
by on (#223665)
FrankenGraphics wrote:
Please do! This stuff is interesting, especially as my book is quite sparse on practical examples.

I will try to type these up this weekend. They're long -- usually 1-3 pages. They're commented, but if I was to provide "just a snippet" it wouldn't provide enough useful educational context.
Re: What is the practical use of indexed indirect addressing
by on (#223703)
psycopathicteen wrote:
I'm guessing it's because the inventors of the 6502 didn't predict what opcodes were going to be used the most often. They couldn't have predicted their chips being used in one of the most popular video game systems in history.

Chuck wanted it to be $5. So making it more expensive and balanced, well you end up with the 68K ;) So it wasn't meant to be "a really nice thing to program for", it was meant to be "$5". But he did design it to be used in EVERYTHING. Cash registers, pinball machines, medical equipment etc But it was price that mattered not ease of use.
Re: What is the practical use of indexed indirect addressing
by on (#223705)
I find it kind of amusing that cash registers, stage light controllers etc to this day often follows obvious programmer logic, as opposed to user logic.

On a cash register, to enter a specific mode of operations, you enter a one-digit variable, then hit "key mode".
A user would in a high degree of probability intuitively hit key mode, then enter the single digit, if not knowing this from the manual or from someone instructung them first day at work, because that follows a linguistic intuition: "set key mode to #".

Want to remote-set the light intensity manually of, say PARcan #53 over the stage, using a digital controller? That's typically
054 CALL
0-255 SET

Whereas on many digital musical synthesizers from the 80s i've used, if you want to carry out a certain action or jump to a specific page of settings, you'd
CALL nnn
or
PAGE nnn

not always though.
Re: What is the practical use of indexed indirect addressing
by on (#223714)
FrankenGraphics wrote:
054 CALL
0-255 SET


The advantage of that is that it easily distinguishes between commands with different digit lengths without requiring another keystroke.

SET-25 ... The system doesn't know if you are done typing the number, or whether you meant 255. So it would require a final "enter" keypress. Putting the "SET" command at the end saves that keystroke.
Re: What is the practical use of indexed indirect addressing
by on (#223719)
FrankenGraphics wrote:
I find it kind of amusing that cash registers, stage light controllers etc to this day often follows obvious programmer logic, as opposed to user logic.

On a cash register, to enter a specific mode of operations, you enter a one-digit variable, then hit "key mode".

Reminds me of the "monitor" (debugger) of the Apple II ROM. (Who remembers 3D0G)?

FrankenGraphics wrote:
A user would in a high degree of probability intuitively hit key mode, then enter the single digit, if not knowing this from the manual or from someone instructung them first day at work, because that follows a linguistic intuition: "set key mode to #".

That'd depend on whether your native language puts the verb at the end of the sentence. In languages that do, "three switch_mode" sounds more "natural" than "switch_mode three". Consider the programming language var'aq, which uses reverse Polish notation (RPN) syntax in order to match the Klingon language's object-verb order. It'd be even more complicated to provide a word order switch in order for speakers of different languages to use a device.

Aside: In his dissertation Representation, information theory and basic word order (PDF, 200+ pages), Luke Maurits presents experimental evidence that the basic word order matching the order of recall of aspects of an event is subject-object-verb, as in Japanese and Hindi. We see shift over time to other word orders in other languages because verb before object is better at spreading information throughout a sentence.
Re: What is the practical use of indexed indirect addressing
by on (#223720)
good points, both. That's true. And when you're supposed to work with an industrial or commercial console, you're likely to work with it or something similar again over long periods, so training new staff in subject-verb operations is a negligible effort in the grand scheme of things.

The trouble with the cash register case specifically is that there's nothing to differentiate monetary operations from administrative ones. Let's say the clerk was planning on doing a non-fiscal checkup (typically under keymode 2) or program a new commodity group (let's say that's under keymode 4), then got interrupted by some task - for example a customer comes along. that 2 or 4 remains in the soft accumulator and unless the clerk makes a habit of pressing Cl before starting to register goods, it can get hairy. This is only valid for manual price input though. A scanner device will always overwrite the accumulator.
If keymodes were operated so that you press the mode key first, then a single digit, it would be watertight. I don't think i've ever seen a cash register with more modes than can fit a single numerical digit. It is also a better analogy to cash registers with actual turnkeys for operating modes - you grip the key, then turn it to the desired digit/mode. edit: actually the best analogy would be to hold the keymode button and hit a single digit.

In parable to the apple 2 thing; zenith computers used halt operations and break out into a monitor/BIOS if you pressed ctrl+alt+ins.
Re: What is the practical use of indexed indirect addressing
by on (#223733)
koitsu wrote:
I will try to type these up this weekend. They're long -- usually 1-3 pages. They're commented, but if I was to provide "just a snippet" it wouldn't provide enough useful educational context.

As promised, I took a look at these in detail this weekend. The book ("Programming the 6502" by Rodnay Zaks, 1983, 4th edition, ISBN 0-89588-135-7) has an entire chapter on data structures. This includes linked lists, binary trees, sorting algorithms, overall data structure creation/organisation, etc.. They're long and include descriptions as well as flow chart diagrams to help with comprehension. The code is commented, though sparsely (normal for the time, given screen widths).

The code is written for ASM 65 from Rockwell, which was a 6502 assembler written in BASIC for HP 2000F computers. Younger folks unfamiliar with some of the more "arcane" assembler syntaxes of the 80s might not comprehend the syntactical sugar. For example: * refers to the current PC at assemble-time, so something like * = $0 sets the PC to $0000, hence any variables/labels you define there get assembled starting with a base address of $0000 (i.e. zero page) (and, of course, it's still your own responsibility to populate zero page with actual data); .WORD declares an explicit 16-bit value (e.g. .dw $1234 or .db $34, $12 in more common-day assemblers). Furthermore, the code is not intended for the NES, but should work given that RAM in the NES resides from $0000 to $07FF.

I would prefer to scan these pages and put them up somewhere, especially since flow chart diagrams are heavily used, except as is common with most reference books, the content is copyrighted ((C) 1983 SYBEX Inc. 2344 Sixth Street, Berkeley, CA 94710; founded by Dr. Zaks); the code would not OCR well given the font, size, and weight. So what I've typed up below is indeed a copyright violation; I'm hoping SYBEX will allow me a bit of leeway.

Here are the general examples in book, all from Chapter 9, which use indexed indirect ((foo,x)) addressing:

1. A hashing algorithm (8 pages; 2 pages of code; long)
2. Bubble sort (5 pages; 1 page of code; short)
3. A merge algorithm (4 pages; 1 page of code; semi-long)

The short of it: in all 3 cases, indexed indirect addressing is used to reference a 16-bit pointer (or series of pointers) which are used to point to one or more data structures.

I'll include the code from #2 above, since it's the shortest:

Fig. 9-48: Bubble-Sort: Memory Map
Code:
     +-------------+
0000 |             | -----+
     |- TABLE PTR -|      |
0001 |             |      |
     +-------------+      |
     |             |      |
     |             |      |
     |             |      |
     +-------------+      |
0200 |             |      |
     |   PROGRAM   |      |
     |             |      |
     +-------------+      |
     |             |      |
     |             |      |
     |             |      |
     +-------------+      |
     |  NUMBER n   | <----+
     +-------------+
     |  ELEMENT 1  |
     +-------------+
     |  ELEMENT 2  |
     +-------------+
     |             |             Y                       X
     +-------------+      +-------------+         +-------------+
     |             | <----|     PTR     |         | EXCHANGED?  |
     +-------------+      +-------------+         +-------------+
     |             |      CURRENT ELEMENT
     +-------------+
     |             |
     +-------------+
     |  ELEMENT n  |
     +-------------+


What's omitted in the description (which I've also omitted, because it's an entire page) is what the value of $0600 is that TAB contains. This is the actual address in RAM that contains the data structure described (i.e. the actual data to sort). In other words NUMBER n is at $0600, ELEMENT 1 is at $0601, etc.. This data must reside in RAM because the routine actually modifies the RAM area it's reading from. I feel all that's pretty important to know. :-)

Fig. 9-49: Bubble-Sort Program
Code:
* = $0

TAB    .WORD $600

* = $200

SORT   LDX #0           ;SET EXCHANGED TO 0
       LDA (TAB,X)
       TAY              ;NUMBER OF ELEMENTS IS IN Y
LOOP   LDA (TAB),Y      ;READ ELEMENT E(I)
       DEY              ;DECREMENT NUMBER OF ELEMENTS TO READ.
       BEQ FINISH       ;END IF NO MORE ELEMENTS
       CMP (TAB),Y      ;COMPARE TO E'(I)
       BCS LOOP         ;GET NEXT ELEMENT IF E(I)>E'(I)
EXCH   TAX              ;EXCHANGE ELEMENTS
       LDA (TAB),Y
       INY
       STA (TAB),Y
       TXA
       DEY
       STA (TAB),Y
       LDX #1           ;SET EXCHANGED TO 1
       BNE LOOP         ;GET NEXT ELEMENT
FINISH TXA              ;SHIFT 'EXCHANGED' TO A REG. FOR COMPARE...
       BNE SORT         ;IF SOME EXCHANGES MADE, DO ANOTHER PASS.
       RTS


P.S. -- There's actually a checksum routine in this book that looks neat/useful too, but it doesn't use the discussed addressing mode, so it's off-topic.
Re: What is the practical use of indexed indirect addressing
by on (#223735)
koitsu wrote:
something like * = $0 sets the PC to $0000, hence any variables/labels you define there get assembled starting with a base address of $0000

For comparison: ca65 has a .feature pc_assignment that makes * = behave like .org.

koitsu wrote:
.WORD declares an explicit 16-bit value (e.g. .dw $1234 or .db $34, $12 in more common-day assemblers).

For comparison: .word in ca65. I guess the more things change, the more they don't.

This particular bubble sort routine could have been done just as easily with lda (tab),y, seeing as Y doesn't need to be saved (the next instruction overwrites it anyway), and X=$00 isn't used farther down.
Re: What is the practical use of indexed indirect addressing
by on (#223743)
That's interesting. I received this specific book (confirmed with the ISBN) as a Christmas present when I started nes programming and I read the basics but stopped in the middle of it (well, I stopped everything actually, not just the book).

I guess I should take the time to read it since there is maybe a lot of interesting things that may come handy someday. I remember reading it in the Tokyo subway and it was, well, not very convenient since it is always overcrowded in the morning ^^;;

What are the highlight of the books, the part that should be read no matter what? I still think my knowledge of 6502 is quite low so I don't yet grasp what is a good approach or not (like the Tepples explained one). I guess that comes with experience, nothing you can do about it.
Re: What is the practical use of indexed indirect addressing
by on (#223749)
koitsu wrote:
I would prefer to scan these pages and put them up somewhere, especially since flow chart diagrams are heavily used, except as is common with most reference books, the content is copyrighted ((C) 1983 SYBEX Inc. 2344 Sixth Street, Berkeley, CA 94710; founded by Dr. Zaks); the code would not OCR well given the font, size, and weight. So what I've typed up below is indeed a copyright violation; I'm hoping SYBEX will allow me a bit of leeway.


http://www.bombjack.org/commodore/books-generic.htm a fair way down the page.

Although generally Machine Language on the Commodore 64, 128 and other Commodore Computers Revised and Expanded Edition by Jim Butterfield is seen as "the" 6502 book to learn from ;) found here http://www.bombjack.org/commodore/books.htm
Re: What is the practical use of indexed indirect addressing
by on (#223753)
tepples wrote:
This particular bubble sort routine could have been done just as easily with lda (tab),y, seeing as Y doesn't need to be saved (the next instruction overwrites it anyway), and X=$00 isn't used farther down.

I'm glad that addresses what the OP asked. :|

RIP me doing the other examples, especially if this is going to be a point of contention. If you want to see the other examples, buy the book. :D

Signed,
The Guy Who Tries To Stay On Topic and Does What Other People Politely Ask For
Re: What is the practical use of indexed indirect addressing
by on (#223757)
Well i learned a couple of things, so thanks for the insight!

primarily a method to sorting in 6502 (never touched that before - yes i haven't done my homework :oops: ). Sorting is quite expensive in a game context, but i'd think sorting very short lists of say 4 options could be used in ocassionally called pathfinding and action priority sequencing routines for AI for example. That could perhaps allow for less rigid, more context aware priority chains.

Let's say we want to sort 1 such sequence each for a number of actors using a loaddr pointer. Wouldn't that be the perfect occasion to use lda (sequenceTable, x)?
(that also means we can't set x to 0 just yet like in the example).
Re: What is the practical use of indexed indirect addressing
by on (#223869)
truffly wrote:
But why would you ever need to use indexed indirect addressing with the X register? What practical purpose does this serve? There has to be some situation where this feature would prove useful, otherwise I'd assume it wouldn't be featured in the processor design. Have you ever used indexed indirect addressing in your programs? Do you think it is particularly useful, or do you think indirect indexed addressing is a better tool?

(ZP,X) is used all the time in the Forth programming language which uses a data stack in ZP that's separate from the return stack in page 1. Keeping them separate like this solves certain problems in passing stacked data to and from nested subroutines. X is used as the stack pointer. Then suppose you want to read the content of the memory pointed to by the top stack two-byte cell. Regardless of the current depth of the ZP data stack, do LDA (0,X). (We make X point to the top of the stack, not one position past it like the S register does for the hardware stack.) If you want to read the content of memory pointed to by the second-on-stack two-byte cell, it's LDA(2,X), again regardless of the current data-stack depth. You may find benefits in doing things this way in assembly language too. This, and tons more, is discussed in detail in my treatise on 6502 stacks (plural, not just the page-1 hardware stack), at http://wilsonminesco.com/stacks/ .