I was playing a little with x86 assembly when I was a kid and now SUDDENLY decided to try some retrocomputing. The X16 was a pretty obvious reason, so I started learning the 6502 assembly. And that's HARD though I'm having a lot of fun.
The problem is that lots of books and tutorials answer the question 'WHAT' but never 'WHY'. Like they patiently explain how to work with different addressing modes but never when and why to use them. Book after book, tutorial after tutorial - everywhere I get the same info that is almost useless without the practical examples, not just "how to address that stuff".
I'd wanted to share my understanding of the potential usage of different addressing modes and ask for some clarification or better ideas if possible.
As we know, there are 16 addressing modes in total, 3 of them were added in 65c02.
1 - 3: Immediate, Accumulator and Implied modes are not technically 'addressing modes' as they have nothing to do with getting the memory location.
JMP and JSR instructions and their modes are somewhat special. Actually, JMP means Load PC counter (and JSR is the same, but with additional saving of the return address to stack). So technically what we call the Absolute mode for the JMP instruction is Immediate (take the immediate 2-BYTE value and put it to the PC register), what we call Indirect mode is Absolute for JMP (take the address that is stored on that location and put it to PC) and the same stuff for Absolute indirect addressing for JMP added in 65c02, it's just Absolute, X mode (take the address with the offset and put it to the PC register). That's not a critical addition, but quite important for me. And I've seen it only once. Though I'm not going to make exceptions for these instructions further.
4. Relative mode. Used only with different branch instructions so can be used for organizing conditional or unconditional (BRA) short jumps and loops (happens often, but no other uses).
In case the loop body is really big and 127 bytes of the offset is not enough can be combined with the long jump (JMP abs).
5. ZP relative mode is much less popular. Operates with variables in Zero page and used only by BBR/BBS instructions for the same purpose - short or long jumps but now depending on concrete bit values.
6. Absolute mode. The most important one as it's supported by the vast majority of commands. If compared with high level languages, using absolute mode is the same thing as defining simple variables and performing actions on them.
and so on.
Assembler turns labels into absolute values, based on .org definitions. The bad part of such variable declarations - it's static and it increases the code size. We mix code and data and we cannot move beyond the user area ($9EFF).
By using banking we can have several instances of complex structures (up to 256) with instant switching between them and that gives us lots of opportunities. But that requires a kind of 'manual' memory management unlike the definition via labels. On the other hand, memory is not wasted, program size is not increased, going beyond the user area is possible.
JMP makes far jumps, JSR calls subroutines, that's ok.
7. Zero page mode. Mostly the same as absolute mode, but 1 cycle less in speed, 1 byte less in memory. Half of ZP is occupied by the system already, so we have 126 bytes only with 32 bytes given to virtual registers, so even 94 bytes remains.
As CPU works at much higher speed and X16 has much more memory, ZP mode is not so usable now. Probably, we can use virtual registers with all supported commands but all other ZP space should be used for indirect modes with values just loaded and read via move commands.
Just recently I read about Sweet 16, need to investigate more. Just curious if it can share the same space that is used by virtual registers if I want to use it or I need to free some extra ZP memory for it.
8. Absolute,X mode allows working with arrays or strings and working in loops with help of the X register.
A little bit less of available instructions. More problems if we want to use labels - need to allocate more memory that will increase the program size, can go beyond the limit and overwrite the code in a loop.
Working with zero-end strings is even worse - you never know where it ends. And the X register is only 8 bit wide.
9. Absolute,Y mode is similar, but provides even less instructions. Can't invent much use of it. Maybe working in the same loop with moving from the end to the beginning, while X moves from the beginning to the end. Or processing the array with some dynamically adjusted offset.
I don't know a good example of usage of 10. ZP, X (and tiny 11. ZP, Y) modes due to the small size of Zero Page. Like, if it's about arrays why not use absolute addressing instead? I'll spend more time by moving the data to/from ZP.
12. Indirect mode is used only by JMP instruction. And literally everywhere they tell you: Indirect JMP bug and that’s all
The benefit of this mode is that you can calculate the address during the execution. Though that’s achievable via self modified code:
So the good use is calling some OS routines via indirect calls with possible replacements or additions (like custom handlers). The problem is that there is no indirect JSR.
13. Indirect, X - simplifies handling of jump tables or something like complex switch instructions.
14. (ZP), Y indirect mode looks very promising when it comes to arrays or other blocks of memory that need to be dynamically created. Something like copying memory blocks from one destination to another.
And two remaining addressing modes are quite unclear to me.
15. (ZP) indirect introduced in 65c02 is a complement to indirect mode used by JMP instruction (with limitation to ZP only), so we have that orthogonality Absolute addressing (including jump) - Indirect addressing (including jump) but due to ZP size limitations I can hardly imagine the good usage for it.
And finally the most complicated 16. (ZP, X) mode that looks totally unusable.
Sorry if that looks too verbose or primitive to you, but I'm trying to be systematic in my understanding of the CPU and assembly.