Difference between revisions of "6502 opcodes for hackers"

From 8BitDev.org - Atari 7800 Development Wiki
Jump to: navigation, search
Line 323: Line 323:
 
This section covers the official, documented NMOS 6502 opcodes.
 
This section covers the official, documented NMOS 6502 opcodes.
  
 +
<span id="ADC"></span>
 
=== ADC (ADd with Carry) ===
 
=== ADC (ADd with Carry) ===
 
Adds memory and the Carry flag to the accumulator. To perform an 8-bit addition, a preceding `CLC` is required. The `V` flag detects signed overflow, and the `D` flag enables BCD arithmetic.
 
Adds memory and the Carry flag to the accumulator. To perform an 8-bit addition, a preceding `CLC` is required. The `V` flag detects signed overflow, and the `D` flag enables BCD arithmetic.
Line 347: Line 348:
 
|}
 
|}
  
 +
<span id="AND"></span>
 
=== AND (bitwise AND with accumulator) ===
 
=== AND (bitwise AND with accumulator) ===
 
Performs a bitwise AND between the accumulator and a memory value. Primarily used to mask (clear) bits.
 
Performs a bitwise AND between the accumulator and a memory value. Primarily used to mask (clear) bits.
Line 371: Line 373:
 
|}
 
|}
  
 +
<span id="ASL"></span>
 
=== ASL (Arithmetic Shift Left) ===
 
=== ASL (Arithmetic Shift Left) ===
 
Shifts an operand left by one bit. Bit 0 is cleared to 0, and the old bit 7 is shifted into the Carry flag.
 
Shifts an operand left by one bit. Bit 0 is cleared to 0, and the old bit 7 is shifted into the Carry flag.
Line 413: Line 416:
 
|}
 
|}
  
 +
<span id="BIT"></span>
 
=== BIT (test BITS) ===
 
=== BIT (test BITS) ===
 
Performs a non-destructive `AND` between the accumulator and memory to set the Z flag, without altering any registers. It also copies bit 7 and bit 6 of the memory operand directly to the N and V flags, respectively. This makes it an essential tool for polling I/O registers.
 
Performs a non-destructive `AND` between the accumulator and memory to set the Z flag, without altering any registers. It also copies bit 7 and bit 6 of the memory operand directly to the N and V flags, respectively. This makes it an essential tool for polling I/O registers.
Line 425: Line 429:
 
|}
 
|}
  
 +
<span id="BRK"></span>
 
=== BRK (BReaK) ===
 
=== BRK (BReaK) ===
 
Forces a software interrupt. It pushes PC+2 and the processor status (with the B flag set) to the stack, then jumps via the IRQ vector ($FFFE). An `RTI` returns to the address of `BRK + 2`, allowing it to replace a 2-byte instruction for debugging purposes.
 
Forces a software interrupt. It pushes PC+2 and the processor status (with the B flag set) to the stack, then jumps via the IRQ vector ($FFFE). An `RTI` returns to the address of `BRK + 2`, allowing it to replace a 2-byte instruction for debugging purposes.
Line 441: Line 446:
 
* '''N flag''': Set to bit 7 of the subtraction result.
 
* '''N flag''': Set to bit 7 of the subtraction result.
  
 +
<span id="CMP"></span>
 
==== CMP (CoMPare accumulator) ====
 
==== CMP (CoMPare accumulator) ====
 
'''Affects Flags:''' N, Z, C
 
'''Affects Flags:''' N, Z, C
Line 463: Line 469:
 
|}
 
|}
  
 +
<span id="CPX"></span>
 
==== CPX (ComPare X register) ====
 
==== CPX (ComPare X register) ====
 
'''Affects Flags:''' N, Z, C
 
'''Affects Flags:''' N, Z, C
Line 475: Line 482:
 
|}
 
|}
  
 +
<span id="CPY"></span>
 
==== CPY (ComPare Y register) ====
 
==== CPY (ComPare Y register) ====
 
'''Affects Flags:''' N, Z, C
 
'''Affects Flags:''' N, Z, C
Line 490: Line 498:
 
These modify a register or memory location by one. Register operations are 1-byte, 2-cycle instructions. Memory operations are read-modify-write and take longer.
 
These modify a register or memory location by one. Register operations are 1-byte, 2-cycle instructions. Memory operations are read-modify-write and take longer.
  
 +
<span id="DEC"></span>
 
==== DEC (DECrement memory) ====
 
==== DEC (DECrement memory) ====
 
'''Affects Flags:''' N, Z
 
'''Affects Flags:''' N, Z
Line 504: Line 513:
 
|}
 
|}
  
 +
<span id="DEX"></span>
 
==== DEX (DEcrement X register) ====
 
==== DEX (DEcrement X register) ====
 
'''Affects Flags:''' N, Z
 
'''Affects Flags:''' N, Z
Line 512: Line 522:
 
|}
 
|}
  
 +
<span id="DEY"></span>
 
==== DEY (DEcrement Y register) ====
 
==== DEY (DEcrement Y register) ====
 
'''Affects Flags:''' N, Z
 
'''Affects Flags:''' N, Z
Line 520: Line 531:
 
|}
 
|}
  
 +
<span id="INC"></span>
 
==== INC (INCrement memory) ====
 
==== INC (INCrement memory) ====
 
'''Affects Flags:''' N, Z
 
'''Affects Flags:''' N, Z
Line 534: Line 546:
 
|}
 
|}
  
 +
<span id="INX"></span>
 
==== INX (INcrement X register) ====
 
==== INX (INcrement X register) ====
 
'''Affects Flags:''' N, Z
 
'''Affects Flags:''' N, Z
Line 542: Line 555:
 
|}
 
|}
  
 +
<span id="INY"></span>
 
==== INY (INcrement Y register) ====
 
==== INY (INcrement Y register) ====
 
'''Affects Flags:''' N, Z
 
'''Affects Flags:''' N, Z
Line 550: Line 564:
 
|}
 
|}
  
 +
<span id="EOR"></span>
 
=== EOR (bitwise Exclusive OR) ===
 
=== EOR (bitwise Exclusive OR) ===
 
Performs a bitwise XOR between the accumulator and memory. Useful for flipping specific bits or for simple checksum calculations.
 
Performs a bitwise XOR between the accumulator and memory. Useful for flipping specific bits or for simple checksum calculations.
Line 574: Line 589:
 
|}
 
|}
  
 +
<span id="CLC"></span><span id="SEC"></span><span id="CLD"></span><span id="SED"></span><span id="CLI"></span><span id="SEI"></span><span id="CLV"></span>
 
=== Flag Instructions ===
 
=== Flag Instructions ===
 
These single-byte, 2-cycle instructions directly manipulate the processor status flags. It is critical to use `CLD` on startup, as the power-on state of the D flag is undefined.
 
These single-byte, 2-cycle instructions directly manipulate the processor status flags. It is critical to use `CLD` on startup, as the power-on state of the D flag is undefined.
Line 596: Line 612:
 
|}
 
|}
  
 +
<span id="JMP"></span>
 
=== JMP (JuMP) ===
 
=== JMP (JuMP) ===
 
Unconditionally transfers program control to a new location. The indirect mode has an infamous hardware bug: if the low byte of the indirect vector is $FF (e.g., `JMP ($30FF)`), the high byte of the jump address is fetched from `$3000`, not `$3100`.
 
Unconditionally transfers program control to a new location. The indirect mode has an infamous hardware bug: if the low byte of the indirect vector is $FF (e.g., `JMP ($30FF)`), the high byte of the jump address is fetched from `$3000`, not `$3100`.

Revision as of 20:18, 29 June 2025

6502 Opcodes for Hackers is a reference guide for experienced programmers. It focuses on the practical application of both standard and stable non-standard NMOS 6502 opcodes, including common tricks and non-obvious behaviors. It intentionally omits highly unstable opcodes to provide a focused, practical resource.

Opcode Matrix

This table provides a complete overview of the NMOS 6502 opcode map. Each mnemonic links to its detailed description below.

Legend:

  • Blue: Standard Opcodes
  • Green: Stable Illegal Opcodes
  • Yellow: Semi-Stable Illegal Opcodes (use with caution)
  • Red: Unstable/Unreliable Opcodes (details not included below)
NMOS 6502 Opcode Matrix
HI\LO -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F
0- BRK ORA JAM SLO NOP ORA ASL SLO PHP ORA ASL ANC NOP ORA ASL SLO
1- BPL ORA JAM SLO NOP ORA ASL SLO CLC ORA NOP SLO NOP ORA ASL SLO
2- JSR AND JAM RLA BIT AND ROL RLA PLP AND ROL ANC BIT AND ROL RLA
3- BMI AND JAM RLA NOP AND ROL RLA SEC AND NOP RLA NOP AND ROL RLA
4- RTI EOR JAM SRE NOP EOR LSR SRE PHA EOR LSR ALR JMP EOR LSR SRE
5- BVC EOR JAM SRE NOP EOR LSR SRE CLI EOR NOP SRE NOP EOR LSR SRE
6- RTS ADC JAM RRA NOP ADC ROR RRA PLA ADC ROR ARR JMP ADC ROR RRA
7- BVS ADC JAM RRA NOP ADC ROR RRA SEI ADC NOP RRA NOP ADC ROR RRA
8- NOP STA NOP SAX STY STA STX SAX DEY NOP TXA ANE STY STA STX SAX
9- BCC STA JAM SHA STY STA STX SAX TYA STA TXS TAS SHY STA SHX SHA
A- LDY LDA LDX LAX LDY LDA LDX LAX TAY LDA TAX LAX LDY LDA LDX LAX
B- BCS LDA JAM LAX LDY LDA LDX LAX CLV LDA TSX LAS LDY LDA LDX LAX
C- CPY CMP NOP DCP CPY CMP DEC DCP INY CMP DEX SBX CPY CMP DEC DCP
D- BNE CMP JAM DCP NOP CMP DEC DCP CLD CMP NOP DCP NOP CMP DEC DCP
E- CPX SBC NOP ISC CPX SBC INC ISC INX SBC NOP SBC CPX SBC INC ISC
F- BEQ SBC JAM ISC NOP SBC INC ISC SED SBC NOP ISC NOP SBC INC ISC

Standard Opcodes

This section covers the official, documented NMOS 6502 opcodes.

ADC (ADd with Carry)

Adds memory and the Carry flag to the accumulator. To perform an 8-bit addition, a preceding `CLC` is required. The `V` flag detects signed overflow, and the `D` flag enables BCD arithmetic. Affects Flags: N, V, Z, C

Mode Syntax HEX LEN TIM
Immediate ADC #$44 $69 2 2
Zero Page ADC $44 $65 2 3
Zero Page,X ADC $44,X $75 2 4
Absolute ADC $4400 $6D 3 4
Absolute,X ADC $4400,X $7D 3 4+
Absolute,Y ADC $4400,Y $79 3 4+
Indirect,X ADC ($44,X) $61 2 6
Indirect,Y ADC ($44),Y $71 2 5+

AND (bitwise AND with accumulator)

Performs a bitwise AND between the accumulator and a memory value. Primarily used to mask (clear) bits. Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Immediate AND #$44 $29 2 2
Zero Page AND $44 $25 2 3
Zero Page,X AND $44,X $35 2 4
Absolute AND $4400 $2D 3 4
Absolute,X AND $4400,X $3D 3 4+
Absolute,Y AND $4400,Y $39 3 4+
Indirect,X AND ($44,X) $21 2 6
Indirect,Y AND ($44),Y $31 2 5+

ASL (Arithmetic Shift Left)

Shifts an operand left by one bit. Bit 0 is cleared to 0, and the old bit 7 is shifted into the Carry flag. Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Accumulator ASL A $0A 1 2
Zero Page ASL $44 $06 2 5
Zero Page,X ASL $44,X $16 2 6
Absolute ASL $4400 $0E 3 6
Absolute,X ASL $4400,X $1E 3 7

Branch Instructions

Branch instructions alter program flow based on the state of a specific flag. All use relative addressing, taking a signed 8-bit offset. A branch costs 2 cycles if not taken, 3 if taken within the same page, and 4 if the destination crosses a page boundary. To create an unconditional branch (`BRA`), branch on a flag with a known state. The `V` flag is a good candidate, as it is unaffected by most operations: `CLV` followed by `BVC` will always branch. Affects Flags: none

Mnemonic Name HEX
BCC Branch on Carry Clear (C=0) $90
BCS Branch on Carry Set (C=1) $B0
BEQ Branch on EQual (Z=1) $F0
BNE Branch on Not Equal (Z=0) $D0
BMI Branch on MInus (N=1) $30
BPL Branch on PLus (N=0) $10
BVC Branch on oVerflow Clear (V=0) $50
BVS Branch on oVerflow Set (V=1) $70

BIT (test BITS)

Performs a non-destructive `AND` between the accumulator and memory to set the Z flag, without altering any registers. It also copies bit 7 and bit 6 of the memory operand directly to the N and V flags, respectively. This makes it an essential tool for polling I/O registers. Affects Flags: N, V, Z

Mode Syntax HEX LEN TIM
Zero Page BIT $44 $24 2 3
Absolute BIT $4400 $2C 3 4

BRK (BReaK)

Forces a software interrupt. It pushes PC+2 and the processor status (with the B flag set) to the stack, then jumps via the IRQ vector ($FFFE). An `RTI` returns to the address of `BRK + 2`, allowing it to replace a 2-byte instruction for debugging purposes. Affects Flags: B

Mode Syntax HEX LEN TIM
Implied BRK $00 1 7

Compare Instructions

These instructions perform a non-destructive subtraction (`Register - Memory`) to set the N, Z, and C flags. They are fundamental for conditional logic and comparisons.

  • C flag: Set if `Register >= Memory` (no borrow).
  • Z flag: Set if `Register == Memory`.
  • N flag: Set to bit 7 of the subtraction result.

CMP (CoMPare accumulator)

Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Immediate CMP #$44 $C9 2 2
Zero Page CMP $44 $C5 2 3
Zero Page,X CMP $44,X $D5 2 4
Absolute CMP $4400 $CD 3 4
Absolute,X CMP $4400,X $DD 3 4+
Absolute,Y CMP $4400,Y $D9 3 4+
Indirect,X CMP ($44,X) $C1 2 6
Indirect,Y CMP ($44),Y $D1 2 5+

CPX (ComPare X register)

Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Immediate CPX #$44 $E0 2 2
Zero Page CPX $44 $E4 2 3
Absolute CPX $4400 $EC 3 4

CPY (ComPare Y register)

Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Immediate CPY #$44 $C0 2 2
Zero Page CPY $44 $C4 2 3
Absolute CPY $4400 $CC 3 4

Decrement & Increment Instructions

These modify a register or memory location by one. Register operations are 1-byte, 2-cycle instructions. Memory operations are read-modify-write and take longer.

DEC (DECrement memory)

Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Zero Page DEC $44 $C6 2 5
Zero Page,X DEC $44,X $D6 2 6
Absolute DEC $4400 $CE 3 6
Absolute,X DEC $4400,X $DE 3 7

DEX (DEcrement X register)

Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Implied DEX $CA 1 2

DEY (DEcrement Y register)

Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Implied DEY $88 1 2

INC (INCrement memory)

Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Zero Page INC $44 $E6 2 5
Zero Page,X INC $44,X $F6 2 6
Absolute INC $4400 $EE 3 6
Absolute,X INC $4400,X $FE 3 7

INX (INcrement X register)

Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Implied INX $E8 1 2

INY (INcrement Y register)

Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Implied INY $C8 1 2

EOR (bitwise Exclusive OR)

Performs a bitwise XOR between the accumulator and memory. Useful for flipping specific bits or for simple checksum calculations. Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Immediate EOR #$44 $49 2 2
Zero Page EOR $44 $45 2 3
Zero Page,X EOR $44,X $55 2 4
Absolute EOR $4400 $4D 3 4
Absolute,X EOR $4400,X $5D 3 4+
Absolute,Y EOR $4400,Y $59 3 4+
Indirect,X EOR ($44,X) $41 2 6
Indirect,Y EOR ($44),Y $51 2 5+

Flag Instructions

These single-byte, 2-cycle instructions directly manipulate the processor status flags. It is critical to use `CLD` on startup, as the power-on state of the D flag is undefined. Affects Flags: as noted

Mnemonic Function HEX
CLC C = 0 $18
SEC C = 1 $38
CLD D = 0 $D8
SED D = 1 $F8
CLI I = 0 (Enable IRQs) $58
SEI I = 1 (Disable IRQs) $78
CLV V = 0 $B8

JMP (JuMP)

Unconditionally transfers program control to a new location. The indirect mode has an infamous hardware bug: if the low byte of the indirect vector is $FF (e.g., `JMP ($30FF)`), the high byte of the jump address is fetched from `$3000`, not `$3100`. Affects Flags: none

Mode Syntax HEX LEN TIM
Absolute JMP $5597 $4C 3 3
Indirect JMP ($5597) $6C 3 5

JSR (Jump to SubRoutine)

Pushes the return address (the address of the last byte of the `JSR` instruction) onto the stack and jumps to a new location. Paired with `RTS` for standard subroutine calls. Affects Flags: none

Mode Syntax HEX LEN TIM
Absolute JSR $5597 $20 3 6

Load Instructions

Load instructions copy a byte from memory into a register, setting the N and Z flags based on the value loaded. Note the addressing mode asymmetries: `LDX` has a `Zero Page,Y` mode while `LDY` has an `Absolute,X` mode, but not vice-versa.

LDA (LoaD Accumulator)

Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Immediate LDA #$44 $A9 2 2
Zero Page LDA $44 $A5 2 3
Zero Page,X LDA $44,X $B5 2 4
Absolute LDA $4400 $AD 3 4
Absolute,X LDA $4400,X $BD 3 4+
Absolute,Y LDA $4400,Y $B9 3 4+
Indirect,X LDA ($44,X) $A1 2 6
Indirect,Y LDA ($44),Y $B1 2 5+

LDX (LoaD X register)

Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Immediate LDX #$44 $A2 2 2
Zero Page LDX $44 $A6 2 3
Zero Page,Y LDX $44,Y $B6 2 4
Absolute LDX $4400 $AE 3 4
Absolute,Y LDX $4400,Y $BE 3 4+

LDY (LoaD Y register)

Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Immediate LDY #$44 $A0 2 2
Zero Page LDY $44 $A4 2 3
Zero Page,X LDY $44,X $B4 2 4
Absolute LDY $4400 $AC 3 4
Absolute,X LDY $4400,X $BC 3 4+

LSR (Logical Shift Right)

Shifts an operand right by one bit. Bit 7 is cleared to 0, and the old bit 0 is shifted into the Carry flag. Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Accumulator LSR A $4A 1 2
Zero Page LSR $44 $46 2 5
Zero Page,X LSR $44,X $56 2 6
Absolute LSR $4400 $4E 3 6
Absolute,X LSR $4400,X $5E 3 7

NOP (No OPeration)

The official NOP wastes 2 cycles and does nothing else. Many illegal opcodes also function as NOPs with different cycle and byte counts; some still perform memory reads, which can be useful for I/O timing or acknowledging interrupts without altering registers. Affects Flags: none

Mode Syntax HEX LEN TIM
Implied NOP $EA 1 2

ORA (bitwise OR with Accumulator)

Performs a bitwise OR between the accumulator and a memory value. Primarily used to set bits. Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Immediate ORA #$44 $09 2 2
Zero Page ORA $44 $05 2 3
Zero Page,X ORA $44,X $15 2 4
Absolute ORA $4400 $0D 3 4
Absolute,X ORA $4400,X $1D 3 4+
Absolute,Y ORA $4400,Y $19 3 4+
Indirect,X ORA ($44,X) $01 2 6
Indirect,Y ORA ($44),Y $11 2 5+

Register Instructions

These 1-byte, 2-cycle instructions transfer data between registers. `TXS` is unique in that it does not affect any flags. Affects Flags: N, Z (except TXS)

Mnemonic Description HEX
TAX Transfer A to X $AA
TAY Transfer A to Y $A8
TXA Transfer X to A $8A
TYA Transfer Y to A $98
TSX Transfer Stack Pointer to X $BA
TXS Transfer X to Stack Pointer $9A

ROL (ROtate Left)

Rotates an operand left by one bit. The old bit 7 is moved to the Carry flag, and the old Carry flag is moved into bit 0. Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Accumulator ROL A $2A 1 2
Zero Page ROL $44 $26 2 5
Zero Page,X ROL $44,X $36 2 6
Absolute ROL $4400 $2E 3 6
Absolute,X ROL $4400,X $3E 3 7

ROR (ROtate Right)

Rotates an operand right by one bit. The old bit 0 is moved to the Carry flag, and the old Carry flag is moved into bit 7. Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Accumulator ROR A $6A 1 2
Zero Page ROR $44 $66 2 5
Zero Page,X ROR $44,X $76 2 6
Absolute ROR $4400 $6E 3 6
Absolute,X ROR $4400,X $7E 3 7

RTI (ReTurn from Interrupt)

Restores the processor state after an interrupt by pulling the processor status register and program counter from the stack. Affects Flags: all

Mode Syntax HEX LEN TIM
Implied RTI $40 1 6

RTS (ReTurn from Subroutine)

Returns from a subroutine by pulling the program counter from the stack and incrementing it. Can be used to implement powerful jump tables by pushing crafted return addresses onto the stack. Affects Flags: none

Mode Syntax HEX LEN TIM
Implied RTS $60 1 6

SBC (SuBtract with Carry)

Subtracts memory and an inverted Carry flag (borrow) from the accumulator. To perform an 8-bit subtraction, a preceding `SEC` (to indicate "no borrow") is required. The `D` flag enables BCD arithmetic. Affects Flags: N, V, Z, C

Mode Syntax HEX LEN TIM
Immediate SBC #$44 $E9 2 2
Zero Page SBC $44 $E5 2 3
Zero Page,X SBC $44,X $F5 2 4
Absolute SBC $4400 $ED 3 4
Absolute,X SBC $4400,X $FD 3 4+
Absolute,Y SBC $4400,Y $F9 3 4+
Indirect,X SBC ($44,X) $E1 2 6
Indirect,Y SBC ($44),Y $F1 2 5+

Stack Instructions

These instructions interact with the hardware stack located at page one ($0100-$01FF). The 6502 stack pointer grows downwards. Affects Flags: all (for PLP) or none

Mnemonic Description HEX TIM
PHA PusH Accumulator $48 3
PLA PuLl Accumulator $68 4
PHP PusH Processor status $08 3
PLP PuLl Processor status $28 4

Store Instructions

Store instructions copy the content of a register to memory. They do not affect any flags. Note the addressing mode asymmetries, particularly the absence of accumulator-relative addressing and the presence of `STX zp,Y` and `STY zp,X`.

STA (STore Accumulator)

Affects Flags: none

Mode Syntax HEX LEN TIM
Zero Page STA $44 $85 2 3
Zero Page,X STA $44,X $95 2 4
Absolute STA $4400 $8D 3 4
Absolute,X STA $4400,X $9D 3 5
Absolute,Y STA $4400,Y $99 3 5
Indirect,X STA ($44,X) $81 2 6
Indirect,Y STA ($44),Y $91 2 6

STX (STore X register)

Affects Flags: none

Mode Syntax HEX LEN TIM
Zero Page STX $44 $86 2 3
Zero Page,Y STX $44,Y $96 2 4
Absolute STX $4400 $8E 3 4

STY (STore Y register)

Affects Flags: none

Mode Syntax HEX LEN TIM
Zero Page STY $44 $84 2 3
Zero Page,X STY $44,X $94 2 4
Absolute STY $4400 $8C 3 4

Stable & Semi-Stable Illegal Opcodes

This section details non-standard opcodes that are generally stable on NMOS 6502 and its direct variants. They often combine two standard operations into one, saving bytes and/or cycles. "Semi-stable" opcodes are marked and should be used with an understanding of their specific quirks, which are detailed in their descriptions.

SLO (ASO)

Function: ` {addr} = {addr} * 2`, then `A = A OR {addr}` (ASL followed by ORA)
Performs an `ASL` on a memory location, then `ORA`s the new value with the accumulator. Useful for multi-byte shifts where the result must be combined into a register. Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Zero Page SLO $44 $07 2 5
Zero Page,X SLO $44,X $17 2 6
Absolute SLO $4400 $0F 3 6
Absolute,X SLO $4400,X $1F 3 7
Absolute,Y SLO $4400,Y $1B 3 7
Indirect,X SLO ($44,X) $03 2 8
Indirect,Y SLO ($44),Y $13 2 8

Example: A 24-bit shift where the high byte is also needed in A.

; Assuming A is zero before this sequence:
  SLO data+2    ; Shifts data+2, A now holds the result
  ROL data+1
  ROL data+0
; This saves an LDA instruction compared to the standard ASL/ROL sequence.

RLA

Function: `{addr} = ROL {addr}`, then `A = A AND {addr}` (ROL followed by AND)
Performs a `ROL` on memory, then `AND`s the new value with the accumulator. Excellent for scrolling effects where a rotated tile needs to be masked by a background. Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Zero Page RLA $44 $27 2 5
Zero Page,X RLA $44,X $37 2 6
Absolute RLA $4400 $2F 3 6
Absolute,X RLA $4400,X $3F 3 7
Absolute,Y RLA $4400,Y $3B 3 7
Indirect,X RLA ($44,X) $23 2 8
Indirect,Y RLA ($44),Y $33 2 8

Example: Combining a sliding sprite with a background mask.

; Standard method (16 bytes, 18 cycles):
  ROL scroll_gfx
  LDA scroll_gfx
  AND background_mask
  STA screen_ram
; Faster method (12 bytes, 14 cycles):
  LDA background_mask
  RLA scroll_gfx       ; shift left and combine in one go
  STA screen_ram

SRE (LSE)

Function: `{addr} = LSR {addr}`, then `A = A EOR {addr}` (LSR followed by EOR)
Performs an `LSR` on memory, then `EOR`s the new value with the accumulator. Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Zero Page SRE $44 $47 2 5
Zero Page,X SRE $44,X $57 2 6
Absolute SRE $4400 $4F 3 6
Absolute,X SRE $4400,X $5F 3 7
Absolute,Y SRE $4400,Y $5B 3 7
Indirect,X SRE ($44,X) $43 2 8
Indirect,Y SRE ($44),Y $53 2 8

RRA

Function: `{addr} = ROR {addr}`, then `A = A ADC {addr}` (ROR followed by ADC)
Performs a `ROR` on memory, then adds the new value with carry to the accumulator. Inherits the decimal mode dependency from `ADC`. Affects Flags: N, V, Z, C

Mode Syntax HEX LEN TIM
Zero Page RRA $44 $67 2 5
Zero Page,X RRA $44,X $77 2 6
Absolute RRA $4400 $6F 3 6
Absolute,X RRA $4400,X $7F 3 7
Absolute,Y RRA $4400,Y $7B 3 7
Indirect,X RRA ($44,X) $63 2 8
Indirect,Y RRA ($44),Y $73 2 8

SAX (AXS)

Function: `{addr} = A & X`
Stores the result of a bitwise `AND` between the A and X registers into memory. The A and X registers themselves are not modified, and no flags are affected. Affects Flags: none

Mode Syntax HEX LEN TIM
Zero Page SAX $44 $87 2 3
Zero Page,Y SAX $44,X $97 2 4
Absolute SAX $4400 $8F 3 4
Indirect,X SAX ($44,X) $83 2 6

LAX

Function: `A, X = {addr}`
Loads both the A and X registers with the same value from memory. Saves a byte and cycles over a standard `LDA`/`TAX` pair. Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Zero Page LAX $44 $A7 2 3
Zero Page,Y LAX $44,Y $B7 2 4
Absolute LAX $4400 $AF 3 4
Absolute,Y LAX $4400,Y $BF 3 4+
Indirect,X LAX ($44,X) $A3 2 6
Indirect,Y LAX ($44),Y $B3 2 5+

DCP (DCM)

Function: `{addr} = {addr} - 1`, then `A CMP {addr}` (DEC followed by CMP)
Decrements a memory location, then compares the new value with the accumulator. Excellent for loop counters. Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Zero Page DCP $44 $C7 2 5
Zero Page,X DCP $44,X $D7 2 6
Absolute DCP $4400 $CF 3 6
Absolute,X DCP $4400,X $DF 3 7
Absolute,Y DCP $4400,Y $DB 3 7
Indirect,X DCP ($44,X) $C3 2 8
Indirect,Y DCP ($44),Y $D3 2 8


ISC (ISB, INS)

Function: `{addr} = {addr} + 1`, then `A = A SBC {addr}` (INC followed by SBC)
Increments a memory location, then subtracts the new value from the accumulator. Inherits decimal mode dependency from `SBC`. Affects Flags: N, V, Z, C

Mode Syntax HEX LEN TIM
Zero Page ISC $44 $E7 2 5
Zero Page,X ISC $44,X $F7 2 6
Absolute ISC $4400 $EF 3 6
Absolute,X ISC $4400,X $FF 3 7
Absolute,Y ISC $4400,Y $FB 3 7
Indirect,X ISC ($44,X) $E3 2 8
Indirect,Y ISC ($44),Y $F3 2 8

Example: A loop that counts up to a value in A.

; Instead of INC counter / LDA counter / CMP #END_VALUE
  LDA #END_VALUE
  SEC
loop:
  ISC counter   ; INC counter, then SBC counter. Z will be set when they match.
  BNE loop

ANC

Function: `A = A & #{imm}`, then `C = N`
Performs a standard `AND` immediate, but also copies the resulting N flag (bit 7 of A) into the C flag. This is an excellent way to perform a mask and a bit test in a single, 2-cycle instruction. Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Immediate ANC #$44 $0B 2 2
Immediate ANC #$44 $2B 2 2

Example: Test bit 7 and branch, without needing to preserve the Carry flag.

; Instead of PHP / AND #$80 / BEQ ... PLP
  ANC #$80      ; Sets C=1 if bit 7 is set, N=1 if bit 7 is set, Z=0 if bit 7 is set.
  BCC bit_is_clear

ALR (ASR)

Function: `A = (A & #{imm}) / 2` (AND immediate followed by LSR A)
Performs an `AND` immediate, then performs a logical shift right on the accumulator. Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Immediate ALR #$44 $4B 2 2

ARR

Function: `A = (A & #{imm})`, then a complex `ROR`-like operation.
Performs an `AND` immediate, then rotates the accumulator right. Warning: Flag calculation is unusual and decimal mode dependent. After the `AND`, V is set by `(A bit 6) EOR (A bit 7)`. During the rotate, C is set from the original A bit 6, and the new bit 7 is set from the original C flag. Bit 0 is lost. Due to its complexity, it is rarely used. Affects Flags: N, V, Z, C

Mode Syntax HEX LEN TIM
Immediate ARR #$44 $6B 2 2

SBX (AXS)

Function: `X = (A & X) - #{imm}`
Calculates `A & X`, then subtracts an immediate value from this temporary result, storing the final value in X. Flags are set as if from a `CMP` instruction (`(A & X) >= imm` sets the Carry). Does not respect decimal mode and is not affected by the initial state of the Carry flag. Affects Flags: N, Z, C

Mode Syntax HEX LEN TIM
Immediate SBX #$44 $CB 2 2

Example: A faster decrement of X by a constant value.

; Standard method (8 cycles, 5 bytes):
  TXA
  SEC
  SBC #$10
  TAX
; Faster method (4 cycles, 3 bytes):
  TXA         ; A and X are now equal, so (A & X) = X.
  SBX #$10    ; C flag state before this instruction is irrelevant.

'Unstable High Byte' Opcodes

The following opcodes are semi-stable. They combine a load or store operation with a bitwise `AND`, but their behavior can be unreliable under specific hardware conditions. Warning:

  1. Page Boundary Crossing: If the effective address calculation (`address + index`) crosses a page boundary, the result can be unpredictable. Avoid crossing page boundaries with these instructions.
  2. Hardware Dependency: The `AND` operation part of the instruction may fail if the CPU's RDY line is pulled low during a specific cycle (e.g., by sprite DMA). This makes the instruction behave like a standard store (`STA`/`STX`/`STY`). To mitigate this, one can use a target address where the high byte is `$FE`, so the `AND` with `(HighByte+1)` becomes an `AND` with `$FF`, which has no effect.

SHA (AXA, AHX)

(Semi-Stable) Function: `{addr} = A & X & (HighByte({addr}) + 1)`
Stores the result of `A AND X AND (High Byte of target address + 1)` into memory. See warnings above. Affects Flags: none

Mode Syntax HEX LEN TIM
Absolute,Y SHA $4400,Y $9F 3 5
Indirect,Y SHA ($44),Y $93 2 6

SHX (SXA)

(Semi-Stable) Function: `{addr} = X & (HighByte({addr}) + 1)`
Stores the result of `X AND (High Byte of target address + 1)` into memory. See warnings above. Affects Flags: none

Mode Syntax HEX LEN TIM
Absolute,Y SHX $4400,Y $9E 3 5

SHY (SYA)

(Semi-Stable) Function: `{addr} = Y & (HighByte({addr}) + 1)`
Stores the result of `Y AND (High Byte of target address + 1)` into memory. See warnings above. Affects Flags: none

Mode Syntax HEX LEN TIM
Absolute,X SHY $4400,X $9C 3 5

LAS

(Semi-Stable) Function: `A, X, S = {addr} & S`
Loads memory, `AND`s it with the Stack Pointer, and loads the result into A, X, and the Stack Pointer. See warnings above. Affects Flags: N, Z

Mode Syntax HEX LEN TIM
Absolute,Y LAS $4400,Y $BB 3 4+

TAS (SHS)

(Semi-Stable) Function: `S = A & X`, then `{addr} = S & (HighByte({addr}) + 1)`
Calculates `A & X` and puts the result in the Stack Pointer. Then it `AND`s this new S value with `(High Byte of target address + 1)` and stores the result in memory. See warnings above. Affects Flags: none

Mode Syntax HEX LEN TIM
Absolute,Y TAS $4400,Y $9B 3 5


Attribution

This document was derived by combining information from the following sources: