6502 Addressing Modes

When the 6502 refers to addressing modes, it really means "What is the source of the data used in this instruction?" The 6502's data book divides the addressing modes into 2 groups, indexed and non-indexed. That seems to be a logical way to discuss them, so I'll stick with that.

Non-Indexed, non memory

Most of the addressing modes are used to access memory, but 3 do not.

Accumulator

These instructions have register A (the accumulator) as the target. Examples are LSR A and ROL A.

Immediate

These instructions have their data defined as the next byte after the opcode. ORA #$B2 will perform a logical (also called bitwise) of the value B2 with the accumulator. Remember that in assembly when you see a # sign, it indicates an immediate value. If $B2 was written without a #, it would indicate an address or offset.

Implied

In an implied instruction, the data and/or destination is mandatory for the instruction. For example, the CLC instruction is implied, it is going to clear the processor's Carry flag.

Non-Indexed memory ops

Relative

Relative addressing on the 6502 is only used for branch operations. The byte after the opcode is the branch offset. If the branch is taken, the new address will the the current PC plus the offset. The offset is a signed byte, so it can jump a maximum of 127 bytes forward, or 128 bytes backward. (For more info about signed numbers, check here.)

Absolute

Absolute addressing specifies the memory location explicitly in the two bytes following the opcode. So JMP $4032 will set the PC to $4032. The hex for this is 4C 32 40. The 6502 is a little endian machine, so any 16 bit (2 byte) value is stored with the LSB first. All instructions that use absolute addressing are 3 bytes.

Zero-Page

Zero-Page is an addressing mode that is only capable of addressing the first 256 bytes of the CPU's memory map. You can think of it as absolute addressing for the first 256 bytes. The instruction LDA $35 will put the value stored in memory location $35 into A. The advantage of zero-page are two - the instruction takes one less byte to specify, and it executes in less CPU cycles. Most programs are written to store the most frequently used variables in the first 256 memory locations so they can take advantage of zero page addressing.

Indirect

The JMP instruction is the only instruction that uses this addressing mode. It is a 3 byte instruction - the 2nd and 3rd bytes are an absolute address. The set the PC to the address stored at that address. So maybe this would be clearer.

   Memory:    
   1000 52 3a 04 d3 93 00 3f 93 84    

   Instruction:    
   JMP  ($1000)    

When this instruction is executed, the PC will be set to $3a52, which is the address stored at address $1000.

Indexed memory ops

The 6502 has the ability to do indexed addressing, where the X or Y register is used as an extra offset to the address being accessed.

Absolute Indexed

This addressing mode makes the target address by adding the contents of the X or Y register to an absolute address. For example, this 6502 code can be used to fill 10 bytes with $FF starting at address $1009, counting down to address $1000.

   LDA #$FF    
   LDY #$09    
   loop:    
   STA $1000,Y ; absolute indexed addressing    
   DEY    
   BPL loop    

Zero-Page Indexed

This works just like absolute indexed, but the target address is limited to the first 0xFF bytes.

The target address will wrap around and will always be in the zero page. If the instruction is LDA $C0,X, and X is $60, then the target address will be $20. $C0+$60 = $120, but the carry is discarded in the calculation of the target address.

Indexed Indirect

This mode is only used with the X register. Consider a situation where the instruction is LDA ($20,X), X contains $04, and memory at $24 contains 0024: 74 20, First, X is added to $20 to get $24. The target address will be fetched from $24 resulting in a target address of $2074. Register A will be loaded with the contents of memory at $2074.

If X + the immediate byte will wrap around to a zero-page address. So you could code that like targetAddress = (X + opcode[1]) & 0xFF .

Indexed Indirect instructions are 2 bytes - the second byte is the zero-page address - $20 in the example. Obviously the fetched address has to be stored in the zero page.

Indirect Indexed

This mode is only used with the Y register. It differs in the order that Y is applied to the indirectly fetched address. An example instruction that uses indirect index addressing is LDA ($86),Y . To calculate the target address, the CPU will first fetch the address stored at zero page location $86. That address will be added to register Y to get the final target address. For LDA ($86),Y, if the address stored at $86 is $4028 (memory is 0086: 28 40, remember little endian) and register Y contains $10, then the final target address would be $4038. Register A will be loaded with the contents of memory at $4038.

Indirect Indexed instructions are 2 bytes - the second byte is the zero-page address - $86 in the example. (So the fetched address has to be stored in the zero page.)

While indexed indirect addressing will only generate a zero-page address, this mode's target address is not wrapped - it can be anywhere in the 16-bit address space.

← Prev: 6502-emulator   Next: 6502-disassembler →


Post questions or comments on Twitter @realemulator101, or if you find issues in the code, file them on the github repository.