6502 Instruction Set

HILO-NIBBLE
‐0‐1‐2‐3‐4‐5‐6‐7‐8‐9‐A‐B‐C‐D‐E‐F
0‐BRK implORA X,ind---------ORA zpgASL zpg---PHP implORA #ASL A------ORA absASL abs---
1‐BPL relORA ind,Y---------ORA zpg,XASL zpg,X---CLC implORA abs,Y---------ORA abs,XASL abs,X---
2‐JSR absAND X,ind------BIT zpgAND zpgROL zpg---PLP implAND #ROL A---BIT absAND absROL abs---
3‐BMI relAND ind,Y---------AND zpg,XROL zpg,X---SEC implAND abs,Y---------AND abs,XROL abs,X---
4‐RTI implEOR X,ind---------EOR zpgLSR zpg---PHA implEOR #LSR A---JMP absEOR absLSR abs---
5‐BVC relEOR ind,Y---------EOR zpg,XLSR zpg,X---CLI implEOR abs,Y---------EOR abs,XLSR abs,X---
6‐RTS implADC X,ind---------ADC zpgROR zpg---PLA implADC #ROR A---JMP indADC absROR abs---
7‐BVS relADC ind,Y---------ADC zpg,XROR zpg,X---SEI implADC abs,Y---------ADC abs,XROR abs,X---
8‐---STA X,ind------STY zpgSTA zpgSTX zpg---DEY impl---TXA impl---STY absSTA absSTX abs---
9‐BCC relSTA ind,Y------STY zpg,XSTA zpg,XSTX zpg,Y---TYA implSTA abs,YTXS impl------STA abs,X------
A‐LDY #LDA X,indLDX #---LDY zpgLDA zpgLDX zpg---TAY implLDA #TAX impl---LDY absLDA absLDX abs---
B‐BCS relLDA ind,Y------LDY zpg,XLDA zpg,XLDX zpg,Y---CLV implLDA abs,YTSX impl---LDY abs,XLDA abs,XLDX abs,Y---
C‐CPY #CMP X,ind------CPY zpgCMP zpgDEC zpg---INY implCMP #DEX impl---CPY absCMP absDEC abs---
D‐BNE relCMP ind,Y---------CMP zpg,XDEC zpg,X---CLD implCMP abs,Y---------CMP abs,XDEC abs,X---
E‐CPX #SBC X,ind------CPX zpgSBC zpgINC zpg---INX implSBC #NOP impl---CPX absSBC absINC abs---
F‐BEQ relSBC ind,Y---------SBC zpg,XINC zpg,X---SED implSBC abs,Y---------SBC abs,XINC abs,X---

Description

Address Modes

AAccumulatorOPC Aoperand is AC (implied single byte instruction)
absabsoluteOPC $LLHHoperand is address $HHLL *
abs,Xabsolute, X-indexedOPC $LLHH,Xoperand is address; effective address is address incremented by X with carry **
abs,Yabsolute, Y-indexedOPC $LLHH,Yoperand is address; effective address is address incremented by Y with carry **
#immediateOPC #$BBoperand is byte BB
implimpliedOPCoperand implied
indindirectOPC ($LLHH)operand is address; effective address is contents of word at address: C.w($HHLL)
X,indX-indexed, indirectOPC ($LL,X)operand is zeropage address; effective address is word in (LL + X, LL + X + 1), inc. without carry: C.w($00LL + X)
ind,Yindirect, Y-indexedOPC ($LL),Yoperand is zeropage address; effective address is word in (LL, LL + 1) incremented by Y with carry: C.w($00LL) + Y
relrelativeOPC $BBbranch target is PC + signed offset BB ***
zpgzeropageOPC $LLoperand is zeropage address (hi-byte is zero, address = $00LL)
zpg,Xzeropage, X-indexedOPC $LL,Xoperand is zeropage address; effective address is address incremented by X without carry **
zpg,Yzeropage, Y-indexedOPC $LL,Yoperand is zeropage address; effective address is address incremented by Y without carry **
*
16-bit address words are little endian, lo(w)-byte first, followed by the hi(gh)-byte.
(An assembler will use a human readable, big-endian notation as in $HHLL.)
**
The available 16-bit address space is conceived as consisting of pages of 256 bytes each, with
address hi-bytes represententing the page index. An increment with carry may affect the hi-byte
and may thus result in a crossing of page boundaries, adding an extra cycle to the execution.
Increments without carry do not affect the hi-byte of an address and no page transitions do occur.
Generally, increments of 16-bit addresses include a carry, increments of zeropage addresses don't.
Notably this is not related in any way to the state of the carry bit of the accumulator.
***
Branch offsets are signed 8-bit values, -128 ... +127, negative offsets in two's complement.
Page transitions may occur and add an extra cycle to the exucution.

Instructions by Name

ADC
add with carry
AND
and (with accumulator)
ASL
arithmetic shift left
BCC
branch on carry clear
BCS
branch on carry set
BEQ
branch on equal (zero set)
BIT
bit test
BMI
branch on minus (negative set)
BNE
branch on not equal (zero clear)
BPL
branch on plus (negative clear)
BRK
break / interrupt
BVC
branch on overflow clear
BVS
branch on overflow set
CLC
clear carry
CLD
clear decimal
CLI
clear interrupt disable
CLV
clear overflow
CMP
compare (with accumulator)
CPX
compare with X
CPY
compare with Y
DEC
decrement
DEX
decrement X
DEY
decrement Y
EOR
exclusive or (with accumulator)
INC
increment
INX
increment X
INY
increment Y
JMP
jump
JSR
jump subroutine
LDA
load accumulator
LDX
load X
LDY
load Y
LSR
logical shift right
NOP
no operation
ORA
or with accumulator
PHA
push accumulator
PHP
push processor status (SR)
PLA
pull accumulator
PLP
pull processor status (SR)
ROL
rotate left
ROR
rotate right
RTI
return from interrupt
RTS
return from subroutine
SBC
subtract with carry
SEC
set carry
SED
set decimal
SEI
set interrupt disable
STA
store accumulator
STX
store X
STY
store Y
TAX
transfer accumulator to X
TAY
transfer accumulator to Y
TSX
transfer stack pointer to X
TXA
transfer X to accumulator
TXS
transfer X to stack pointer
TYA
transfer Y to accumulator
Block diagram 6502 processor
Block diagram of the NMOS 6502 CPU.
After (6501 specifics omitted):
MCS6502 Microcomputer Family Hardware Manual; Jannuary 1976.
MOS Technology, Inc., Norristown/PA, 1976.

Registers

PCprogram counter(16 bit)
ACaccumulator(8 bit)
XX register(8 bit)
YY register(8 bit)
SRstatus register [NV-BDIZC](8 bit)
SPstack pointer(8 bit)

Note: The status register (SR) is also known as the P register,
the accumulator (AC) as just A, the stack pointer (SP) as S, and
X and Y registers as XR and YR respectively.

Machine language monitors show them typically like,

     PC  IRQ  SR AC XR YR SP
    0401 E62E 32 04 5E 00 F8

("IRQ" is not a register, but the interrupt request vector, see below.)

Status Register Flags (bit 7 to bit 0)

NNegative
VOverflow
-ignored
BBreak
DDecimal (use BCD for arithmetics)
IInterrupt (IRQ disable)
ZZero
CCarry

Processor Stack

LIFO, top-down, 8 bit range, 0x0100 - 0x01FF

Bytes, Words, Addressing

8 bit bytes, 16 bit words in lobyte-hibyte representation (Little-Endian).
16 bit address range, operands follow instruction codes.

Signed values are two's complement, sign in bit 7 (most significant bit).
(%11111111 = $FF = -1, %10000000 = $80 = -128, %01111111 = $7F = +127)
Signed binary and binary coded decimal (BCD) arithmetic modes.

System Vectors

$FFFA, $FFFB ... NMI (Non-Maskable Interrupt) vector, 16-bit (LB, HB)
$FFFC, $FFFD ... RES (Reset) vector, 16-bit (LB, HB)
$FFFE, $FFFF ... IRQ (Interrupt Request) vector, 16-bit (LB, HB)

Start/Reset Operations

An active-low reset line allows to hold the processor in a known disabled
state, while the system is initialized. As the reset line goes high, the
processor performs a start sequence of 7 cycles, at the end of which the
program counter (PC) is read from the address provided in the 16-bit reset
vector at $FFFC (LB-HB). Then, at the eighth cycle, the processor transfers
control by performing a JMP to the provided address.
Any other initializations are left to the thus executed program. (Notably,
instructions exist for the initialization and loading of all registers, but
for the program counter, which is provided by the reset vector at $FFFC.)

Instructions by Type

6502 Address Modes in Detail

(This section, especially the diagrams included, is heavily inspired by the Acorn Atom manual "Atomic Theory and Practice" by David Johnson Davies, Acorn Computers Limited, 2nd ed. 1980, p 118–121.)

Vendor

MOS Technology, 1975

MOS Techology 6502 MPU

Image: Wikimedia Commons.

6502 Instructions in Detail

ADC

Add Memory to Accumulator with Carry

A + M + C -> A, C

NZCIDV
+++--+
addressingassembleropcbytescycles
immediateADC #oper6922
zeropageADC oper6523
zeropage,XADC oper,X7524
absoluteADC oper6D34
absolute,XADC oper,X7D34*
absolute,YADC oper,Y7934*
(indirect,X)ADC (oper,X)6126
(indirect),YADC (oper),Y7125*
AND

AND Memory with Accumulator

A AND M -> A

NZCIDV
++----
addressingassembleropcbytescycles
immediateAND #oper2922
zeropageAND oper2523
zeropage,XAND oper,X3524
absoluteAND oper2D34
absolute,XAND oper,X3D34*
absolute,YAND oper,Y3934*
(indirect,X)AND (oper,X)2126
(indirect),YAND (oper),Y3125*
ASL

Shift Left One Bit (Memory or Accumulator)

C <- [76543210] <- 0

NZCIDV
+++---
addressingassembleropcbytescycles
accumulatorASL A0A12
zeropageASL oper0625
zeropage,XASL oper,X1626
absoluteASL oper0E36
absolute,XASL oper,X1E37
BCC

Branch on Carry Clear

branch on C = 0

NZCIDV
------
addressingassembleropcbytescycles
relativeBCC oper9022**
BCS

Branch on Carry Set

branch on C = 1

NZCIDV
------
addressingassembleropcbytescycles
relativeBCS operB022**
BEQ

Branch on Result Zero

branch on Z = 1

NZCIDV
------
addressingassembleropcbytescycles
relativeBEQ operF022**
BIT

Test Bits in Memory with Accumulator

bits 7 and 6 of operand are transfered to bit 7 and 6 of SR (N,V);
the zero-flag is set according to the result of the operand AND
the accumulator (set, if the result is zero, unset otherwise).
This allows a quick check of a few bits at once without affecting
any of the registers, other than the status register (SR).

A AND M -> Z, M7 -> N, M6 -> V

NZCIDV
M7+---M6
addressingassembleropcbytescycles
zeropageBIT oper2423
absoluteBIT oper2C34
BMI

Branch on Result Minus

branch on N = 1

NZCIDV
------
addressingassembleropcbytescycles
relativeBMI oper3022**
BNE

Branch on Result not Zero

branch on Z = 0

NZCIDV
------
addressingassembleropcbytescycles
relativeBNE operD022**
BPL

Branch on Result Plus

branch on N = 0

NZCIDV
------
addressingassembleropcbytescycles
relativeBPL oper1022**
BRK

Force Break

BRK initiates a software interrupt similar to a hardware
interrupt (IRQ). The return address pushed to the stack is
PC+2, providing an extra byte of spacing for a break mark
(identifying a reason for the break.)
The status register will be pushed to the stack with the break
flag set to 1. However, when retrieved during RTI or by a PLP
instruction, the break flag will be ignored.
The interrupt disable flag is not set automatically.

interrupt,
push PC+2, push SR

NZCIDV
---1--
addressingassembleropcbytescycles
impliedBRK0017
BVC

Branch on Overflow Clear

branch on V = 0

NZCIDV
------
addressingassembleropcbytescycles
relativeBVC oper5022**
BVS

Branch on Overflow Set

branch on V = 1

NZCIDV
------
addressingassembleropcbytescycles
relativeBVS oper7022**
CLC

Clear Carry Flag

0 -> C

NZCIDV
--0---
addressingassembleropcbytescycles
impliedCLC1812
CLD

Clear Decimal Mode

0 -> D

NZCIDV
----0-
addressingassembleropcbytescycles
impliedCLDD812
CLI

Clear Interrupt Disable Bit

0 -> I

NZCIDV
---0--
addressingassembleropcbytescycles
impliedCLI5812
CLV

Clear Overflow Flag

0 -> V

NZCIDV
-----0
addressingassembleropcbytescycles
impliedCLVB812
CMP

Compare Memory with Accumulator

A - M

NZCIDV
+++---
addressingassembleropcbytescycles
immediateCMP #operC922
zeropageCMP operC523
zeropage,XCMP oper,XD524
absoluteCMP operCD34
absolute,XCMP oper,XDD34*
absolute,YCMP oper,YD934*
(indirect,X)CMP (oper,X)C126
(indirect),YCMP (oper),YD125*
CPX

Compare Memory and Index X

X - M

NZCIDV
+++---
addressingassembleropcbytescycles
immediateCPX #operE022
zeropageCPX operE423
absoluteCPX operEC34
CPY

Compare Memory and Index Y

Y - M

NZCIDV
+++---
addressingassembleropcbytescycles
immediateCPY #operC022
zeropageCPY operC423
absoluteCPY operCC34
DEC

Decrement Memory by One

M - 1 -> M

NZCIDV
++----
addressingassembleropcbytescycles
zeropageDEC operC625
zeropage,XDEC oper,XD626
absoluteDEC operCE36
absolute,XDEC oper,XDE37
DEX

Decrement Index X by One

X - 1 -> X

NZCIDV
++----
addressingassembleropcbytescycles
impliedDEXCA12
DEY

Decrement Index Y by One

Y - 1 -> Y

NZCIDV
++----
addressingassembleropcbytescycles
impliedDEY8812
EOR

Exclusive-OR Memory with Accumulator

A EOR M -> A

NZCIDV
++----
addressingassembleropcbytescycles
immediateEOR #oper4922
zeropageEOR oper4523
zeropage,XEOR oper,X5524
absoluteEOR oper4D34
absolute,XEOR oper,X5D34*
absolute,YEOR oper,Y5934*
(indirect,X)EOR (oper,X)4126
(indirect),YEOR (oper),Y5125*
INC

Increment Memory by One

M + 1 -> M

NZCIDV
++----
addressingassembleropcbytescycles
zeropageINC operE625
zeropage,XINC oper,XF626
absoluteINC operEE36
absolute,XINC oper,XFE37
INX

Increment Index X by One

X + 1 -> X

NZCIDV
++----
addressingassembleropcbytescycles
impliedINXE812
INY

Increment Index Y by One

Y + 1 -> Y

NZCIDV
++----
addressingassembleropcbytescycles
impliedINYC812
JMP

Jump to New Location

operand 1st byte -> PCL
operand 2nd byte -> PCH

NZCIDV
------
addressingassembleropcbytescycles
absoluteJMP oper4C33
indirectJMP (oper)6C35
JSR

Jump to New Location Saving Return Address

push (PC+2),
operand 1st byte -> PCL
operand 2nd byte -> PCH

NZCIDV
------
addressingassembleropcbytescycles
absoluteJSR oper2036
LDA

Load Accumulator with Memory

M -> A

NZCIDV
++----
addressingassembleropcbytescycles
immediateLDA #operA922
zeropageLDA operA523
zeropage,XLDA oper,XB524
absoluteLDA operAD34
absolute,XLDA oper,XBD34*
absolute,YLDA oper,YB934*
(indirect,X)LDA (oper,X)A126
(indirect),YLDA (oper),YB125*
LDX

Load Index X with Memory

M -> X

NZCIDV
++----
addressingassembleropcbytescycles
immediateLDX #operA222
zeropageLDX operA623
zeropage,YLDX oper,YB624
absoluteLDX operAE34
absolute,YLDX oper,YBE34*
LDY

Load Index Y with Memory

M -> Y

NZCIDV
++----
addressingassembleropcbytescycles
immediateLDY #operA022
zeropageLDY operA423
zeropage,XLDY oper,XB424
absoluteLDY operAC34
absolute,XLDY oper,XBC34*
LSR

Shift One Bit Right (Memory or Accumulator)

0 -> [76543210] -> C

NZCIDV
0++---
addressingassembleropcbytescycles
accumulatorLSR A4A12
zeropageLSR oper4625
zeropage,XLSR oper,X5626
absoluteLSR oper4E36
absolute,XLSR oper,X5E37
NOP

No Operation

---

NZCIDV
------
addressingassembleropcbytescycles
impliedNOPEA12
ORA

OR Memory with Accumulator

A OR M -> A

NZCIDV
++----
addressingassembleropcbytescycles
immediateORA #oper0922
zeropageORA oper0523
zeropage,XORA oper,X1524
absoluteORA oper0D34
absolute,XORA oper,X1D34*
absolute,YORA oper,Y1934*
(indirect,X)ORA (oper,X)0126
(indirect),YORA (oper),Y1125*
PHA

Push Accumulator on Stack

push A

NZCIDV
------
addressingassembleropcbytescycles
impliedPHA4813
PHP

Push Processor Status on Stack

The status register will be pushed with the break
flag and bit 5 set to 1.

push SR

NZCIDV
------
addressingassembleropcbytescycles
impliedPHP0813
PLA

Pull Accumulator from Stack

pull A

NZCIDV
++----
addressingassembleropcbytescycles
impliedPLA6814
PLP

Pull Processor Status from Stack

The status register will be pulled with the break
flag and bit 5 ignored.

pull SR

NZCIDV
from stack
addressingassembleropcbytescycles
impliedPLP2814
ROL

Rotate One Bit Left (Memory or Accumulator)

C <- [76543210] <- C

NZCIDV
+++---
addressingassembleropcbytescycles
accumulatorROL A2A12
zeropageROL oper2625
zeropage,XROL oper,X3626
absoluteROL oper2E36
absolute,XROL oper,X3E37
ROR

Rotate One Bit Right (Memory or Accumulator)

C -> [76543210] -> C

NZCIDV
+++---
addressingassembleropcbytescycles
accumulatorROR A6A12
zeropageROR oper6625
zeropage,XROR oper,X7626
absoluteROR oper6E36
absolute,XROR oper,X7E37
RTI

Return from Interrupt

The status register is pulled with the break flag
and bit 5 ignored. Then PC is pulled from the stack.

pull SR, pull PC

NZCIDV
from stack
addressingassembleropcbytescycles
impliedRTI4016
RTS

Return from Subroutine

pull PC, PC+1 -> PC

NZCIDV
------
addressingassembleropcbytescycles
impliedRTS6016
SBC

Subtract Memory from Accumulator with Borrow

A - M - C̅ -> A

NZCIDV
+++--+
addressingassembleropcbytescycles
immediateSBC #operE922
zeropageSBC operE523
zeropage,XSBC oper,XF524
absoluteSBC operED34
absolute,XSBC oper,XFD34*
absolute,YSBC oper,YF934*
(indirect,X)SBC (oper,X)E126
(indirect),YSBC (oper),YF125*
SEC

Set Carry Flag

1 -> C

NZCIDV
--1---
addressingassembleropcbytescycles
impliedSEC3812
SED

Set Decimal Flag

1 -> D

NZCIDV
----1-
addressingassembleropcbytescycles
impliedSEDF812
SEI

Set Interrupt Disable Status

1 -> I

NZCIDV
---1--
addressingassembleropcbytescycles
impliedSEI7812
STA

Store Accumulator in Memory

A -> M

NZCIDV
------
addressingassembleropcbytescycles
zeropageSTA oper8523
zeropage,XSTA oper,X9524
absoluteSTA oper8D34
absolute,XSTA oper,X9D35
absolute,YSTA oper,Y9935
(indirect,X)STA (oper,X)8126
(indirect),YSTA (oper),Y9126
STX

Store Index X in Memory

X -> M

NZCIDV
------
addressingassembleropcbytescycles
zeropageSTX oper8623
zeropage,YSTX oper,Y9624
absoluteSTX oper8E34
STY

Sore Index Y in Memory

Y -> M

NZCIDV
------
addressingassembleropcbytescycles
zeropageSTY oper8423
zeropage,XSTY oper,X9424
absoluteSTY oper8C34
TAX

Transfer Accumulator to Index X

A -> X

NZCIDV
++----
addressingassembleropcbytescycles
impliedTAXAA12
TAY

Transfer Accumulator to Index Y

A -> Y

NZCIDV
++----
addressingassembleropcbytescycles
impliedTAYA812
TSX

Transfer Stack Pointer to Index X

SP -> X

NZCIDV
++----
addressingassembleropcbytescycles
impliedTSXBA12
TXA

Transfer Index X to Accumulator

X -> A

NZCIDV
++----
addressingassembleropcbytescycles
impliedTXA8A12
TXS

Transfer Index X to Stack Register

X -> SP

NZCIDV
------
addressingassembleropcbytescycles
impliedTXS9A12
TYA

Transfer Index Y to Accumulator

Y -> A

NZCIDV
++----
addressingassembleropcbytescycles
impliedTYA9812
*
add 1 to cycles if page boundary is crossed
**
add 1 to cycles if branch occurs on same page
add 2 to cycles if branch occurs to different page

Legend to Flags:

+
modified
-
not modified
1
set
0
cleared
M6
memory bit 6
M7
memory bit 7

Note on assembler syntax:
Some assemblers employ "OPC *oper" or a ".b" extension to the mneomonic for
forced zeropage addressing.

Note on Read-Modify-Write instructions (NMOS 6502 only):
Some instructions like EOR, ASL, ROL, DEC, INC, etc., fetch a value from memory
to modify it and to write the modified value back to the originating address.
The original NMOS 6502 switches immediately into write mode after the read of
the value, resulting in the unmodified value being written back to the address
(while the value is modified in the next cycle), before the modified value is
finally written to the destination. This may cause issues when writing to
devices attached to the address bus that may trigger some action on this
intermediate write operation.
This does not apply to the CMOS variants of the 6502.

"Illegal" Opcodes and Undocumented Instructions

The following instructions are undocumented are not guaranteed to work.
Some are highly unstable, some may even start two asynchronous threads competing in race condition with the winner determined by such miniscule factors as temperature or minor differences in the production series, at other times, the outcome depends on the exact values involved and the chip series.

Use with care and at your own risk.

There are several mnemonics for various opcodes. Here, they are (mostly) the same as those used by the ACME and DASM assemblers with known synonyms provided in parentheses:

"Illegal" Opcodes in Details

Legend to markers used in the instruction details:

*
add 1 to cycles if page boundary is crossed
unstable
††
highly unstable
ALR (ASR)

AND oper + LSR

A AND oper, 0 -> [76543210] -> C

NZCIDV
+++---
addressingassembleropcbytescycles
immediateALR #oper4B22
ANC

AND oper + set C as ASL

A AND oper, bit(7) -> C

NZCIDV
+++---
addressingassembleropcbytescycles
immediateANC #oper0B22
ANC (ANC2)

AND oper + set C as ROL

effectively the same as instr. 0B

A AND oper, bit(7) -> C

NZCIDV
+++---
addressingassembleropcbytescycles
immediateANC #oper2B22
ANE (XAA)

* OR X + AND oper

Highly unstable, do not use.

A base value in A is determined based on the contets of A and a constant, which may be typically $00, $ff, $ee, etc. The value of this constant depends on temerature, the chip series, and maybe other factors, as well.
In order to eliminate these uncertaincies from the equation, use either 0 as the operand or a value of $FF in the accumulator.

(A OR CONST) AND X AND oper -> A

NZCIDV
++----
addressingassembleropcbytescycles
immediateANE #oper8B22 ††
ARR

AND oper + ROR

This operation involves the adder:
V-flag is set according to (A AND oper) + oper
The carry is not set, but bit 7 (sign) is exchanged with the carry

A AND oper, C -> [76543210] -> C

NZCIDV
+++--+
addressingassembleropcbytescycles
immediateARR #oper6B22
DCP (DCM)

DEC oper + CMP oper

M - 1 -> M, A - M

Decrements the operand and then compares the result to the accumulator.

NZCIDV
+++---
addressingassembleropcbytescycles
zeropageDCP operC725
zeropage,XDCP oper,XD726
absoluteDCP operCF36
absolut,XDCP oper,XDF37
absolut,YDCP oper,YDB37
(indirect,X)DCP (oper,X)C328
(indirect),YDCP (oper),YD328
ISC (ISB, INS)

INC oper + SBC oper

M + 1 -> M, A - M - C̅ -> A

NZCIDV
+++--+
addressingassembleropcbytescycles
zeropageISC operE725
zeropage,XISC oper,XF726
absoluteISC operEF36
absolut,XISC oper,XFF37
absolut,YISC oper,YFB37
(indirect,X)ISC (oper,X)E328
(indirect),YISC (oper),YF328
LAS (LAR)

LDA/TSX oper

M AND SP -> A, X, SP

NZCIDV
++----
addressingassembleropcbytescycles
absolut,YLAS oper,YBB34*
LAX

LDA oper + LDX oper

M -> A -> X

NZCIDV
++----
addressingassembleropcbytescycles
zeropageLAX operA723
zeropage,YLAX oper,YB724
absoluteLAX operAF34
absolut,YLAX oper,YBF34*
(indirect,X)LAX (oper,X)A326
(indirect),YLAX (oper),YB325*
LXA (LAX immediate)

Store * AND oper in A and X

Highly unstable, involves a 'magic' constant, see ANE

(A OR CONST) AND oper -> A -> X

NZCIDV
++----
addressingassembleropcbytescycles
immediateLXA #operAB22 ††
RLA

ROL oper + AND oper

M = C <- [76543210] <- C, A AND M -> A

NZCIDV
+++---
addressingassembleropcbytescycles
zeropageRLA oper2725
zeropage,XRLA oper,X3726
absoluteRLA oper2F36
absolut,XRLA oper,X3F37
absolut,YRLA oper,Y3B37
(indirect,X)RLA (oper,X)2328
(indirect),YRLA (oper),Y3328
RRA

ROR oper + ADC oper

M = C -> [76543210] -> C, A + M + C -> A, C

NZCIDV
+++--+
addressingassembleropcbytescycles
zeropageRRA oper6725
zeropage,XRRA oper,X7726
absoluteRRA oper6F36
absolut,XRRA oper,X7F37
absolut,YRRA oper,Y7B37
(indirect,X)RRA (oper,X)6328
(indirect),YRRA (oper),Y7328
SAX (AXS, AAX)

A and X are put on the bus at the same time (resulting effectively in an AND operation) and stored in M

A AND X -> M

NZCIDV
------
addressingassembleropcbytescycles
zeropageSAX oper8723
zeropage,YSAX oper,Y9724
absoluteSAX oper8F34
(indirect,X)SAX (oper,X)8326
SBX (AXS, SAX)

CMP and DEX at once, sets flags like CMP

(A AND X) - oper -> X

NZCIDV
+++---
addressingassembleropcbytescycles
immediateSBX #operCB22
SHA (AHX, AXA)

Stores A AND X AND (high-byte of addr. + 1) at addr.

unstable: sometimes 'AND (H+1)' is dropped, page boundary crossings may not work (with the high-byte of the value used as the high-byte of the address)

A AND X AND (H+1) -> M

NZCIDV
------
addressingassembleropcbytescycles
absolut,YSHA oper,Y9F35
(indirect),YSHA (oper),Y9326
SHX (A11, SXA, XAS)

Stores X AND (high-byte of addr. + 1) at addr.

unstable: sometimes 'AND (H+1)' is dropped, page boundary crossings may not work (with the high-byte of the value used as the high-byte of the address)

X AND (H+1) -> M

NZCIDV
------
addressingassembleropcbytescycles
absolut,YSHX oper,Y9E35
SHY (A11, SYA, SAY)

Stores Y AND (high-byte of addr. + 1) at addr.

unstable: sometimes 'AND (H+1)' is dropped, page boundary crossings may not work (with the high-byte of the value used as the high-byte of the address)

Y AND (H+1) -> M

NZCIDV
------
addressingassembleropcbytescycles
absolut,XSHY oper,X9C35
SLO (ASO)

ASL oper + ORA oper

M = C <- [76543210] <- 0, A OR M -> A

NZCIDV
+++---
addressingassembleropcbytescycles
zeropageSLO oper0725
zeropage,XSLO oper,X1726
absoluteSLO oper0F36
absolut,XSLO oper,X1F37
absolut,YSLO oper,Y1B37
(indirect,X)SLO (oper,X)0328
(indirect),YSLO (oper),Y1328
SRE (LSE)

LSR oper + EOR oper

M = 0 -> [76543210] -> C, A EOR M -> A

NZCIDV
+++---
addressingassembleropcbytescycles
zeropageSRE oper4725
zeropage,XSRE oper,X5726
absoluteSRE oper4F36
absolut,XSRE oper,X5F37
absolut,YSRE oper,Y5B37
(indirect,X)SRE (oper,X)4328
(indirect),YSRE (oper),Y5328
TAS (XAS, SHS)

Puts A AND X in SP and stores A AND X AND (high-byte of addr. + 1) at addr.

unstable: sometimes 'AND (H+1)' is dropped, page boundary crossings may not work (with the high-byte of the value used as the high-byte of the address)

A AND X -> SP, A AND X AND (H+1) -> M

NZCIDV
------
addressingassembleropcbytescycles
absolut,YTAS oper,Y9B35
USBC (SBC)

SBC oper + NOP

effectively same as normal SBC immediate, instr. E9.

A - M - C̅ -> A

NZCIDV
+++--+
addressingassembleropcbytescycles
immediateUSBC #operEB22
NOPs (including DOP, TOP)

Instructions effecting in 'no operations' in various address modes. Operands are ignored.

NZCIDV
------
opcaddressingbytescycles
1Aimplied12
3Aimplied12
5Aimplied12
7Aimplied12
DAimplied12
FAimplied12
80immediate22
82immediate22
89immediate22
C2immediate22
E2immediate22
04zeropage23
44zeropage23
64zeropage23
14zeropage,X24
34zeropage,X24
54zeropage,X24
74zeropage,X24
D4zeropage,X24
F4zeropage,X24
0Cabsolute34
1Cabsolut,X34*
3Cabsolut,X34*
5Cabsolut,X34*
7Cabsolut,X34*
DCabsolut,X34*
FCabsolut,X34*
JAM (KIL, HLT)

These instructions freeze the CPU.

The processor will be trapped infinitely in T1 phase with $FF on the data bus. — Reset required.

Instruction codes: 02, 12, 22, 32, 42, 52, 62, 72, 92, B2, D2, F2

Have a look at this table of the instruction layout in order to see how most of these
"illegal" instructions are a result of executing both instructions at c=1 and c=2 in
a given slot (same column, rows immediately above) at once.
Where c is the lowest two bits of the instruction code. E.g., "SAX abs", instruction
code $8F, binary 10001111, is "STA abs", 10001101 ($8D) and "STX abs", 10001110 ($8E).

Honorable Mention: Rev. A 6502 ROR, Pre-June 1976

Famously, the Rev. A 6502 as delivered from September 1975 to June 1976 had a
"ROR bug". However, the "ROR" instruction isn't only missing from the original
documentation, as it turns out, the chip is actually missing crucial control lines,
which would have been required to make this instruction work. The instruction is
simply not implemented and it wasn't even part of the design. (This was actually
added on popular demand in Rev. B, as rumor has it, demand by Steve Wozniak. Even,
if not true, this makes for a good story. And how could there be a page on the 6502
without mentioning "Woz" once?) So, for all means, "ROR" is an undocumented or
"illegal" instruction on the Rev. A 6502.

And this is how ROR behaves on these Rev. A chips, much like ASL: it shifts all bits
to the left, shifting in a zero bit at the LSB side, but, unlike ASL, it does not
shift the high-bit into the carry. (So there are no connections to the carry at all.)

ROR  Rev. A (pre-June 1976)

As ASL, but does not update the carry.

N and Z flags are set correctly for the operation performed.

[76543210] <- 0

NZCIDV
++----
addressingassembleropcbytescycles
accumulatorROR A6A12
zeropageROR oper6625
zeropage,XROR oper,X7626
absoluteROR oper6E36
absolute,XROR oper,X7E37

Compare Instructions

The 6502 MPU features three basic compare instructions in various address modes:

InstructionComparison
CMPAccumulator and operand
CPXX register and operand
CPYY register and operand

The various compare instructions subtract the operand from the respective register
(as if the carry was set) without setting the result and adjust the N, Z, and C
flags accordingly to this operation.
Flags will be set as follows:

RelationZCN
register < operand00sign-bit of result
register = operand110
register > operand01sign-bit of result

And for the derivative relations "less/greater than or equal":

RelationZCN
register ≤ operand10sign-bit of result
register ≥ operand11sign-bit of result

Mind that the negative flag is not significant and all conditions may be evaluated
by checking the carry and/or zero flag(s).

The BIT Instruction

The BIT instruction may be the most obscure instruction of the 6502:
While other instruction serve a very clear purpose, like transferring values or
performing basic arithmetic or logical operations, this one serves a rather
specialized purpose, but it does so in a very general way.
This purpose is bit testing.

Generally, testing of a particular bit is achieved by masking (isolating) this
bit (or multiple bits) by an AND operation and then checking the zero flag (Z) by
a BNE or BEQ instruction. This, however, destroys the contents of the accumulator.
This is, where the BIT instruction comes in: much like the comparisons perform a
subtraction without setting the result, the BIT instruction performs a logical AND
without setting the result, but still reflects the result in the state of the zero
flag (Z). Which allows for the same checks using the BNE or BEQ instructions,
without affecting the contents of the accumulator.

Since the sign-bit is often used as a flag, testing this is also covered by the BIT
instruction, which additionally to setting the zero flag also transfers bits 7 and 6
of the operand into the corresponding bits of the status register — which happen to
be the negative (N) and overflow (V) flags. Therefore, bits 7 and 6 of the operand
may be tested independently using the BMI/BPL and BVS/BVC instructions.

accumulator operand [76543210] AND [76543210] == 0? ↓↓ ↓ NV Z

A Primer of 6502 Arithmetic Operations

The 6502 processor features two basic arithmetic instructions, ADC, ADd with Carry,
and SBC, SuBtract with Carry. As the names suggest, these provide addition and
subtraction for single byte operands and results. However, operations are not
limited to a single byte range, which is where the carry flag comes in, providing
the means for a single-bit carry (or borrow), to combine operations over several
bytes.

In order to accomplish this, the carry is included in each of these operations:
for additions, it is added (much like another operand); for subtractions, which are
just an addition using the inverse of the operand (complement value of the operand),
the role of the carry is inverted, as well.
Therefore, it is crucial to set up the carry appropriatly: fo additions, the carry
has to be initially cleared (using CLC), while for subtractions, it must be initally
set (using SEC — more on SBC below).

;ADC: A = A + M + C CLC ;clear carry in preparation LDA #2 ;load 2 into the accumulator ADD #3 ;add 3 -> now 5 in accumulator ;SBC: A = A - M - C̅   ("C̅": "not carry") SEC ;set carry in preparation LDA #15 ;load 15 into the accumulator SBC #8 ;subtract 8 -> now 7 in accumulator

Note: Here, we used immediate mode, indicated by the prefix "#" before the operand,
to directly load a literal value. If there is no such "#" prefix, we generally
mean to use the value stored at the address, which is given by the operand. As
we will see in the next example.)

To combine this for 16-bit values (2 bytes each), we simply chain the instructions
for the next bytes to operate on, but this time without setting or clearing the carry.

Supposing the following locations for storing 16-bit values:

low-byte high-byte first argument .... $1000 $1001 second argument ... $1002 $1003 result ............ $1004 $1005  

we perform a 16-bit addition by:

CLC ;prepare carry for addition LDA $1000 ;load value at address $1000 into A (low byte of first argument) ADC $1002 ;add low byte of second argument at $1002 STA $1004 ;store low byte of result at $1004 LDA $1001 ;load high byte of first argument ADC $1003 ;add high byte of second argument STA $1005 ;store high byte of result (result in $1004 and $1005)

and, conversely, for a 16-bit subtraction:

SEC ;prepare carry for subtraction LDA $1000 ;load value at address $1000 into A (low byte of first argument) SBC $1002 ;subtract low byte of second argument at $1002 STA $1004 ;store low byte of result at $1004 LDA $1001 ;load high byte of first argument SBC $1003 ;subtract high byte of second argument STA $1005 ;store high byte of result (result in $1004 and $1005)

Note: Another, important preparatory step is to set the processor into binary
mode by use of the CLD (CLear Decimal flag) instruction. (Compare the section
on decimal mode below.) This has to be done only once.

Signed Values

Operations for unsigned and signed values are principally the same, the only
difference being in how we interpret the values. Generally, the 6502 uses what
is known as two's complement to represent negative values.

(In earlier computers,something known as ones' complement was used, where we
simply flip all bits to their opposite state to represent a negative value.
While simple, this came with a few drawbacks, like an additional value of
negative zero, which are overcome by two's complement.)

In two's complement representation, we simply flip all the bits in a byte to
their opposite (the same as an XOR by $FF) and then add 1 to this.

E.g., to represent -4:,
(We here use "$" to indicate a hexadecimal number and "%" for binary notation.
A dot is used to separate the high- and low-nibble, i.e. group of 4 bits.)

%0000.0100 4 XOR %1111.1111 255 ------------- %1111.1011 complement (all bits flipped) + 1 ------------- %1111.1100 -4, two's complement

Thus, in a single byte, we may represent values in the range

from -128 (%1000.0000 or $80) to +127 (%0111.1111 or $7F)

A notable feature is that the highest value bit (first bit from the left) will
always be 1 for a negative value and always be 0 for a positive one, for which
it is also known as the sign bit. Whenever we interpret a value as a signed
number, a set sign bit indicates a negative value.
This works just the same for larger values, e.g., for a signed 16-bit value:

-512 = %1111.1110.0000.0000 = $FE $00 -516 = %1111.1101.1111.1100 = $FD $FC (mind how the +1 step carries over)

Notably, the binary operations are still the same as with unsigned values and
provide the expected results:

dec binary hex 100 %0110.0100 $64 + -24 %1110.1000 $E8 ------------------------ 76 %0100.1100 $4C (+ carry)

Note: We may now see how SBC actually works, by adding ones' complement of
the operand to the accumulator. If we add 1 from the carry to the result,
this effectively results in a subtraction in two's complement (the inverse
of the operand + 1). If the carry happens to be zero, the result falls
short by 1 in terms of two's complement, which is equivalent to adding 1
to the operand before the subtraction. Thus, the carry either provides
the correction required for a valid two's complement representation or,
if missing, results in a subtraction including a binary borrow.

FLags with ADC and SBC

Besides the carry flag (C), which allows us to chain multi-byte operations, the
CPU sets the following flags on the result of an arithmetic operation:

zero flag (Z) ........ set if the result is zero, else unset negative flag (N) ... the N flag always reflects the sign bit of the result overflow flag (V) ... indicates overflow in signed operations

The latter may require explanation: how is signed overflow different from
the carry flag? The overflow flag is about a certain ambiguity of the sign bit
and the negative flag in signed context: if operands are of the same sign, the
case may occure, where the sign bit flips (as indicated by a change of the
negative flag), while the result is still of the same sign. This condition is
indicated by the overflow flag. Notably, such an overflow can never occur, when
the operands are of opposite signs.

E.g., adding positive $40 to positive $40:

acc. acc. flags hex binary NVDIZC LDA #$40 $40 %0100.0000 000000 ADC #$40 $80 %1000.0000 110000

Here, the change of the sign bit is unrelated to the actual value in the
accumulator, it is merely a consequence of carry propagation from bit 6 to
bit 7, the sign bit. Since both operands are positive, the result must be
positive, as well.
The overflow flag (V) is of interest in signed context only and has no meaning
in unsigned context.

Decimal Mode (BCD)

Besides binary arithmetic, the 6502 processor supports a second mode, binary
coded decimal (BCD), where each byte, rather than representing a range of 0…255,
represents two decimal digits packed into a single byte. For this, a byte is
thought divided into two sections of 4 bits, the high- and the low-nibble. Only
values from 0…9 are used for each nibble and a byte can represent a range of a
2-digit decimal value only, as in 0…99.
E.g.,

dec binary hex 14 %0001.0100 $14 98 %1001.1000 $98

Mind how this intuitively translates to hexadecimal notation, where figures
A…F are never used.

Whether or not the processor is in decimal mode is determined by the decimal
flag (D). If it is set (using SED) the processor will use BCD arithmetic.
If it is cleared (using CLD), the processor is in binary mode.
Decimal mode only affects instructions ADC and SBC (but not INC or DEC.)

Examples:

SED CLC LDA #$12 ADC #$44 ;accumulator now holds $56 SED CLC LDA #$28 ADC #$14 ;accumulator now holds $42

Mind that BCD mode is always unsigned:

acc. NVDIZC SED SEC LDA #0 $00 001011 SBC #1 $99 101000

The carry flag and the zero flag work in decimal mode as expected.
The negative flag is set similar to binary mode (and of questionable value.)
The overflow flag has no meaning in decimal mode.

Multi-byte operations are just as in decimal mode: We first prepare the carry
and then chain operations of the individual bytes in increasing value order,
starting with the lowest value pair.

(It may be important to note that Western Design Center (WDC) version of
the processor, the 65C02, always clears the decimal flag when it enters an
interrupt, while the original NMOS version of the 6502 does not.)

6502 Jump Vectors and Stack Operations

The 256 bytes processor stack of the 6502 is located at $0100 ... $01FF in
memory, growing down from top to bottom.

There are three 2-byte address locations at the very top end of the 64K address
space serving as jump vectors for reset/startup and interrupt operations:

$FFFA, $FFFB ... NMI (Non-Maskable Interrupt) vector
$FFFC, $FFFD ... RES (Reset) vector
$FFFE, $FFFF ... IRQ (Interrupt Request) vector

As an interrupt occurs, any instruction currently processed is completed first.
Only then, the value of the program counter (PC) is put in high-low order onto
the stack, followed by the value currently in the status register, and control
will be transferred to the address location found in the respective interrupt
vector. The registers stored on the stack are recovered at the end of an
interrupt routine, as control is transferred back to the interrupted code by
the RTI instruction.

ADDRESS MEMORY ADH ADL MNEMONIC OP CODE LOW MEMORY HIGH MEMORY 010E 010F 0110 0111 0112 STATUS PC Low-BytePCL02 PC High-BytePCH03 STACK 0300 0301 0302 0405 0406 0407RTI40 FFFAAddress Low-ByteADL FFFBAddress High-ByteADH FFFCAddress Low-ByteADL FFFDAddress High-ByteADH FFFEAddress Low-ByteADL05 FFFFAddress High-ByteADH04 SP AFTER IRQ OR NMIBUT BEFORE RTI SP BEFORE IRQ OR NMIAND AFTER RTI PC AT TIME OF IRQ ORNMI · THIS INSTRUCTIONWILL COMPLETE BEFOREINTERRUPT IS SERVICED PC AFTER RTI INTERRUPT SERVICEMAIN BODY RETURN FROMINTERRUPT NMI VECTOR RES VECTOR IRQ VECTOR PC IRQ, NMI, RTI, BRK OPERATION
(Reset after: MCS6502 Instruction Set Summary, MOS Technology, Inc.)

Similarly, as a JSR instruction is encountered, PC is dumped onto the stack
and recovered by the JSR instruction. (Here, the value stored is actually the
address before the location, the program will eventually return to. Thus, the
effective return address is PC+1.)

010E 010F 0110 0111 PC Low-BytePCL02 PC High-BytePCH03 STACK 0300JSR20 0301Address Low-ByteADL05 0302Address High-ByteADH04 0303 0405 0406 0407 0408RTS60 SP AFTER JSR BUT BEFORERETURN (RTS) SP BEFORE JSR AND AFTERRETURN (RTS) FROMSUBROUTINE JUMP TO SUBROUTINE RETURN FROM SUBROUTINE TOTHIS LOCATION SUBROUTINE MAINBODY RETURN FROM SUBROUTINE PC JSR, RTS OPERATION
(Reset after: MCS6502 Instruction Set Summary, MOS Technology, Inc.)

Curious Interrupt Behavior

The Break Flag and the Stack

Interrupts and stack operations involving the status register (or P register)
are the only instances, the break flag appears (namely on the stack).
It has no representation in the CPU and can't be accessed by any instruction.

Therefore, it's somewhat difficult to inspect the break flag in order to
discern a software interrupt (BRK) from a hardware interrupt (NMI or IRQ) and
the mechanism is seldom used. Accessing a break mark put in the extra byte
following a BRK instruction is even more cumbersome and probably involves
indexed zeropage operations.

Bit 5 (unused) of the status register will be set to 1, whenever the
register is pushed to the stack. Bits 5 and 4 will always be ignored, when
transferred to the status register.

E.g.,

1)

SR: N V - B D I Z C 0 0 - - 0 0 1 1 PHP -> 0 0 1 1 0 0 1 1 = $33 PLP <- 0 0 - - 0 0 1 1 = $03 but: PLA <- 0 0 1 1 0 0 1 1 = $33

2)

LDA #$32 ;00110010 PHA -> 0 0 1 1 0 0 1 0 = $32 PLP <- 0 0 - - 0 0 1 0 = $02

3)

LDA #$C0 PHA -> 1 1 0 0 0 0 0 0 = $C0 LDA #$08 PHA -> 0 0 0 0 1 0 0 0 = $08 LDA #$12 PHA -> 0 0 0 1 0 0 1 0 = $12 RTI SR: 0 0 - - 0 0 1 0 = $02 PC: $C008

Mind that most emulators are displaying the status register (SR or P) in the
state as it would be currently pushed to the stack, with bits 4 and 5 on, adding
a bias of $30 to the register value. Here, we chose to rather omit this virtual
presence of these bits, since there isn't really a slot for them in the hardware.

6502 Instruction Layout

The 6502 instruction table is laid out according to a pattern a-b-c, where
a and b are an octal number each, followed by a group of two binary digits c,
as in the bit-vector "aaabbbcc".

aaabbbcc
bit76543210
(0…7)(0…7)(0…3)

Example:
All ROR instructions share a = 3 and c = 2 (3b2) with the address mode in b.
At the same time, all instructions addressing the zero-page share b = 1 (a1c).
abc = 312  =>  ( 3 << 5 | 1 << 2 | 2 )  =  %011.001.10  =  $66  "ROR zpg".

Notably, there are no legal opcodes defined where c = 3, accounting for the
empty columns in the usual, hexadecimal view of the instruction table.
(For compactness empty rows where c = 3 are omitted from the tables below.)

The following table lists the instruction set, rows sorted by c, then a.

Generally, instructions of a kind are typically found in rows as a combination
of a and c, and address modes are in columns b.
However, there are a few exception to this rule, namely, where bits 0 of both
c and b are low (c = 0, 2; b = 0, 2, 4, 6) and combinations of c and b select
a group of related operations. (E.g., c=0 ∧ b=4: branch, c=0 ∧ b=6: set flag)

cab
01234567
00$00BRK impl$08PHP impl$10BPL rel$18CLC impl
1$20JSR abs$24BIT zpg$28PLP impl$2CBIT abs$30BMI rel$38SEC impl
2$40RTI impl$48PHA impl$4CJMP abs$50BVC rel$58CLI impl
3$60RTS impl$68PLA impl$6CJMP ind$70BVS rel$78SEI impl
4$84STY zpg$88DEY impl$8CSTY abs$90BCC rel$94STY zpg,X$98TYA impl
5$A0LDY #$A4LDY zpg$A8TAY impl$ACLDY abs$B0BCS rel$B4LDY zpg,X$B8CLV impl$BCLDY abs,X
6$C0CPY #$C4CPY zpg$C8INY impl$CCCPY abs$D0BNE rel$D8CLD impl
7$E0CPX #$E4CPX zpg$E8INX impl$ECCPX abs$F0BEQ rel$F8SED impl
10$01ORA X,ind$05ORA zpg$09ORA #$0DORA abs$11ORA ind,Y$15ORA zpg,X$19ORA abs,Y$1DORA abs,X
1$21AND X,ind$25AND zpg$29AND #$2DAND abs$31AND ind,Y$35AND zpg,X$39AND abs,Y$3DAND abs,X
2$41EOR X,ind$45EOR zpg$49EOR #$4DEOR abs$51EOR ind,Y$55EOR zpg,X$59EOR abs,Y$5DEOR abs,X
3$61ADC X,ind$65ADC zpg$69ADC #$6DADC abs$71ADC ind,Y$75ADC zpg,X$79ADC abs,Y$7DADC abs,X
4$81STA X,ind$85STA zpg$8DSTA abs$91STA ind,Y$95STA zpg,X$99STA abs,Y$9DSTA abs,X
5$A1LDA X,ind$A5LDA zpg$A9LDA #$ADLDA abs$B1LDA ind,Y$B5LDA zpg,X$B9LDA abs,Y$BDLDA abs,X
6$C1CMP X,ind$C5CMP zpg$C9CMP #$CDCMP abs$D1CMP ind,Y$D5CMP zpg,X$D9CMP abs,Y$DDCMP abs,X
7$E1SBC X,ind$E5SBC zpg$E9SBC #$EDSBC abs$F1SBC ind,Y$F5SBC zpg,X$F9SBC abs,Y$FDSBC abs,X
20$06ASL zpg$0AASL A$0EASL abs$16ASL zpg,X$1EASL abs,X
1$26ROL zpg$2AROL A$2EROL abs$36ROL zpg,X$3EROL abs,X
2$46LSR zpg$4ALSR A$4ELSR abs$56LSR zpg,X$5ELSR abs,X
3$66ROR zpg$6AROR A$6EROR abs$76ROR zpg,X$7EROR abs,X
4$86STX zpg$8ATXA impl$8ESTX abs$96STX zpg,Y$9ATXS impl
5$A2LDX #$A6LDX zpg$AATAX impl$AELDX abs$B6LDX zpg,Y$BATSX impl$BELDX abs,Y
6$C6DEC zpg$CADEX impl$CEDEC abs$D6DEC zpg,X$DEDEC abs,X
7$E6INC zpg$EANOP impl$EEINC abs$F6INC zpg,X$FEINC abs,X

Note: The operand of instructions like "ASL A" is often depicted as implied, as well.
Mind that, for any practical reasons, the two notations are interchangeable for any
instructions involving the accumulator. — However, there are subtle differences.

A rotated view, rows as combinations of c and b, and columns as a:

cba
01234567
00$00BRK impl$20JSR abs$40RTI impl$60RTS impl$A0LDY #$C0CPY #$E0CPX #
1$24BIT zpg$84STY zpg$A4LDY zpg$C4CPY zpg$E4CPX zpg
2$08PHP impl$28PLP impl$48PHA impl$68PLA impl$88DEY impl$A8TAY impl$C8INY impl$E8INX impl
3$2CBIT abs$4CJMP abs$6CJMP ind$8CSTY abs$ACLDY abs$CCCPY abs$ECCPX abs
4$10BPL rel$30BMI rel$50BVC rel$70BVS rel$90BCC rel$B0BCS rel$D0BNE rel$F0BEQ rel
5$94STY zpg,X$B4LDY zpg,X
6$18CLC impl$38SEC impl$58CLI impl$78SEI impl$98TYA impl$B8CLV impl$D8CLD impl$F8SED impl
7$BCLDY abs,X
10$01ORA X,ind$21AND X,ind$41EOR X,ind$61ADC X,ind$81STA X,ind$A1LDA X,ind$C1CMP X,ind$E1SBC X,ind
1$05ORA zpg$25AND zpg$45EOR zpg$65ADC zpg$85STA zpg$A5LDA zpg$C5CMP zpg$E5SBC zpg
2$09ORA #$29AND #$49EOR #$69ADC #$A9LDA #$C9CMP #$E9SBC #
3$0DORA abs$2DAND abs$4DEOR abs$6DADC abs$8DSTA abs$ADLDA abs$CDCMP abs$EDSBC abs
4$11ORA ind,Y$31AND ind,Y$51EOR ind,Y$71ADC ind,Y$91STA ind,Y$B1LDA ind,Y$D1CMP ind,Y$F1SBC ind,Y
5$15ORA zpg,X$35AND zpg,X$55EOR zpg,X$75ADC zpg,X$95STA zpg,X$B5LDA zpg,X$D5CMP zpg,X$F5SBC zpg,X
6$19ORA abs,Y$39AND abs,Y$59EOR abs,Y$79ADC abs,Y$99STA abs,Y$B9LDA abs,Y$D9CMP abs,Y$F9SBC abs,Y
7$1DORA abs,X$3DAND abs,X$5DEOR abs,X$7DADC abs,X$9DSTA abs,X$BDLDA abs,X$DDCMP abs,X$FDSBC abs,X
20$A2LDX #
1$06ASL zpg$26ROL zpg$46LSR zpg$66ROR zpg$86STX zpg$A6LDX zpg$C6DEC zpg$E6INC zpg
2$0AASL A$2AROL A$4ALSR A$6AROR A$8ATXA impl$AATAX impl$CADEX impl$EANOP impl
3$0EASL abs$2EROL abs$4ELSR abs$6EROR abs$8ESTX abs$AELDX abs$CEDEC abs$EEINC abs
4
5$16ASL zpg,X$36ROL zpg,X$56LSR zpg,X$76ROR zpg,X$96STX zpg,Y$B6LDX zpg,Y$D6DEC zpg,X$F6INC zpg,X
6$9ATXS impl$BATSX impl
7$1EASL abs,X$3EROL abs,X$5ELSR abs,X$7EROR abs,X$BELDX abs,Y$DEDEC abs,X$FEINC abs,X

Finally, a more complex view, the instruction set listed by rows as
combinations of a and c, and b in columns:

Address modes are either a property of b (even columns) or combinations
of b and c (odd columns with aspecific row-index modulus 3; i.e., every
third row in a given column). In those latter columns, first and third
rows (c = 0 and c = 2) refer to the same kind of general operation.

Load, store and transfer instructions as well as comparisons are typically
found in the lower half of the table, while most of the arithmetical and
logical operations as well as stack and jump instructions are found in the
upper half. (However, mind the exception of SBC as a "mirror" of ADC.)

acb
01234567
00$00BRK impl$08PHP impl$10BPL rel$18CLC impl
1$01ORA X,ind$05ORA zpg$09ORA #$0DORA abs$11ORA ind,Y$15ORA zpg,X$19ORA abs,Y$1DORA abs,X
2$06ASL zpg$0AASL A$0EASL abs$16ASL zpg,X$1EASL abs,X
10$20JSR abs$24BIT zpg$28PLP impl$2CBIT abs$30BMI rel$38SEC impl
1$21AND X,ind$25AND zpg$29AND #$2DAND abs$31AND ind,Y$35AND zpg,X$39AND abs,Y$3DAND abs,X
2$26ROL zpg$2AROL A$2EROL abs$36ROL zpg,X$3EROL abs,X
20$40RTI impl$48PHA impl$4CJMP abs$50BVC rel$58CLI impl
1$41EOR X,ind$45EOR zpg$49EOR #$4DEOR abs$51EOR ind,Y$55EOR zpg,X$59EOR abs,Y$5DEOR abs,X
2$46LSR zpg$4ALSR A$4ELSR abs$56LSR zpg,X$5ELSR abs,X
30$60RTS impl$68PLA impl$6CJMP ind$70BVS rel$78SEI impl
1$61ADC X,ind$65ADC zpg$69ADC #$6DADC abs$71ADC ind,Y$75ADC zpg,X$79ADC abs,Y$7DADC abs,X
2$66ROR zpg$6AROR A$6EROR abs$76ROR zpg,X$7EROR abs,X
40$84STY zpg$88DEY impl$8CSTY abs$90BCC rel$94STY zpg,X$98TYA impl
1$81STA X,ind$85STA zpg$8DSTA abs$91STA ind,Y$95STA zpg,X$99STA abs,Y$9DSTA abs,X
2$86STX zpg$8ATXA impl$8ESTX abs$96STX zpg,Y$9ATXS impl
50$A0LDY #$A4LDY zpg$A8TAY impl$ACLDY abs$B0BCS rel$B4LDY zpg,X$B8CLV impl$BCLDY abs,X
1$A1LDA X,ind$A5LDA zpg$A9LDA #$ADLDA abs$B1LDA ind,Y$B5LDA zpg,X$B9LDA abs,Y$BDLDA abs,X
2$A2LDX #$A6LDX zpg$AATAX impl$AELDX abs$B6LDX zpg,Y$BATSX impl$BELDX abs,Y
60$C0CPY #$C4CPY zpg$C8INY impl$CCCPY abs$D0BNE rel$D8CLD impl
1$C1CMP X,ind$C5CMP zpg$C9CMP #$CDCMP abs$D1CMP ind,Y$D5CMP zpg,X$D9CMP abs,Y$DDCMP abs,X
2$C6DEC zpg$CADEX impl$CEDEC abs$D6DEC zpg,X$DEDEC abs,X
70$E0CPX #$E4CPX zpg$E8INX impl$ECCPX abs$F0BEQ rel$F8SED impl
1$E1SBC X,ind$E5SBC zpg$E9SBC #$EDSBC abs$F1SBC ind,Y$F5SBC zpg,X$F9SBC abs,Y$FDSBC abs,X
2$E6INC zpg$EANOP impl$EEINC abs$F6INC zpg,X$FEINC abs,X

"Illegal" Opcodes Revisited

So, how do the "illegal" opcodes fit into this decoding scheme?
Let's have a look — "illegals" are shown on grey background.

The first view — rows by c and a and columns as b — reveals a strict relation
beetween address modes and columns:

cab
01234567
00$00BRK impl$04NOP zpg$08PHP impl$0CNOP abs$10BPL rel$14NOP zpg,X$18CLC impl$1CNOP abs,X
1$20JSR abs$24BIT zpg$28PLP impl$2CBIT abs$30BMI rel$34NOP zpg,X$38SEC impl$3CNOP abs,X
2$40RTI impl$44NOP zpg$48PHA impl$4CJMP abs$50BVC rel$54NOP zpg,X$58CLI impl$5CNOP abs,X
3$60RTS impl$64NOP zpg$68PLA impl$6CJMP ind$70BVS rel$74NOP zpg,X$78SEI impl$7CNOP abs,X
4$80NOP #$84STY zpg$88DEY impl$8CSTY abs$90BCC rel$94STY zpg,X$98TYA impl$9CSHY abs,X
5$A0LDY #$A4LDY zpg$A8TAY impl$ACLDY abs$B0BCS rel$B4LDY zpg,X$B8CLV impl$BCLDY abs,X
6$C0CPY #$C4CPY zpg$C8INY impl$CCCPY abs$D0BNE rel$D4NOP zpg,X$D8CLD impl$DCNOP abs,X
7$E0CPX #$E4CPX zpg$E8INX impl$ECCPX abs$F0BEQ rel$F4NOP zpg,X$F8SED impl$FCNOP abs,X
10$01ORA X,ind$05ORA zpg$09ORA #$0DORA abs$11ORA ind,Y$15ORA zpg,X$19ORA abs,Y$1DORA abs,X
1$21AND X,ind$25AND zpg$29AND #$2DAND abs$31AND ind,Y$35AND zpg,X$39AND abs,Y$3DAND abs,X
2$41EOR X,ind$45EOR zpg$49EOR #$4DEOR abs$51EOR ind,Y$55EOR zpg,X$59EOR abs,Y$5DEOR abs,X
3$61ADC X,ind$65ADC zpg$69ADC #$6DADC abs$71ADC ind,Y$75ADC zpg,X$79ADC abs,Y$7DADC abs,X
4$81STA X,ind$85STA zpg$89NOP #$8DSTA abs$91STA ind,Y$95STA zpg,X$99STA abs,Y$9DSTA abs,X
5$A1LDA X,ind$A5LDA zpg$A9LDA #$ADLDA abs$B1LDA ind,Y$B5LDA zpg,X$B9LDA abs,Y$BDLDA abs,X
6$C1CMP X,ind$C5CMP zpg$C9CMP #$CDCMP abs$D1CMP ind,Y$D5CMP zpg,X$D9CMP abs,Y$DDCMP abs,X
7$E1SBC X,ind$E5SBC zpg$E9SBC #$EDSBC abs$F1SBC ind,Y$F5SBC zpg,X$F9SBC abs,Y$FDSBC abs,X
20$02JAM $06ASL zpg$0AASL A$0EASL abs$12JAM $16ASL zpg,X$1ANOP impl$1EASL abs,X
1$22JAM $26ROL zpg$2AROL A$2EROL abs$32JAM $36ROL zpg,X$3ANOP impl$3EROL abs,X
2$42JAM $46LSR zpg$4ALSR A$4ELSR abs$52JAM $56LSR zpg,X$5ANOP impl$5ELSR abs,X
3$62JAM $66ROR zpg$6AROR A$6EROR abs$72JAM $76ROR zpg,X$7ANOP impl$7EROR abs,X
4$82NOP #$86STX zpg$8ATXA impl$8ESTX abs$92JAM $96STX zpg,Y$9ATXS impl$9ESHX abs,Y
5$A2LDX #$A6LDX zpg$AATAX impl$AELDX abs$B2JAM $B6LDX zpg,Y$BATSX impl$BELDX abs,Y
6$C2NOP #$C6DEC zpg$CADEX impl$CEDEC abs$D2JAM $D6DEC zpg,X$DANOP impl$DEDEC abs,X
7$E2NOP #$E6INC zpg$EANOP impl$EEINC abs$F2JAM $F6INC zpg,X$FANOP impl$FEINC abs,X
30$03SLO X,ind$07SLO zpg$0BANC #$0FSLO abs$13SLO ind,Y$17SLO zpg,X$1BSLO abs,Y$1FSLO abs,X
1$23RLA X,ind$27RLA zpg$2BANC #$2FRLA abs$33RLA ind,Y$37RLA zpg,X$3BRLA abs,Y$3FRLA abs,X
2$43SRE X,ind$47SRE zpg$4BALR #$4FSRE abs$53SRE ind,Y$57SRE zpg,X$5BSRE abs,Y$5FSRE abs,X
3$63RRA X,ind$67RRA zpg$6BARR #$6FRRA abs$73RRA ind,Y$77RRA zpg,X$7BRRA abs,Y$7FRRA abs,X
4$83SAX X,ind$87SAX zpg$8BANE #$8FSAX abs$93SHA ind,Y$97SAX zpg,Y$9BTAS abs,Y$9FSHA abs,Y
5$A3LAX X,ind$A7LAX zpg$ABLXA #$AFLAX abs$B3LAX ind,Y$B7LAX zpg,Y$BBLAS abs,Y$BFLAX abs,Y
6$C3DCP X,ind$C7DCP zpg$CBSBX #$CFDCP abs$D3DCP ind,Y$D7DCP zpg,X$DBDCP abs,Y$DFDCP abs,X
7$E3ISC X,ind$E7ISC zpg$EBUSBC #$EFISC abs$F3ISC ind,Y$F7ISC zpg,X$FBISC abs,Y$FFISC abs,X

And, again, as a rotated view, rows as combinations of c and b, and columns as a.
We may observe a close relationship between the legal and the undocumented
instructions in the vertical (quarter-)segements of each column.

cba
01234567
00$00BRK impl$20JSR abs$40RTI impl$60RTS impl$80NOP #$A0LDY #$C0CPY #$E0CPX #
1$04NOP zpg$24BIT zpg$44NOP zpg$64NOP zpg$84STY zpg$A4LDY zpg$C4CPY zpg$E4CPX zpg
2$08PHP impl$28PLP impl$48PHA impl$68PLA impl$88DEY impl$A8TAY impl$C8INY impl$E8INX impl
3$0CNOP abs$2CBIT abs$4CJMP abs$6CJMP ind$8CSTY abs$ACLDY abs$CCCPY abs$ECCPX abs
4$10BPL rel$30BMI rel$50BVC rel$70BVS rel$90BCC rel$B0BCS rel$D0BNE rel$F0BEQ rel
5$14NOP zpg,X$34NOP zpg,X$54NOP zpg,X$74NOP zpg,X$94STY zpg,X$B4LDY zpg,X$D4NOP zpg,X$F4NOP zpg,X
6$18CLC impl$38SEC impl$58CLI impl$78SEI impl$98TYA impl$B8CLV impl$D8CLD impl$F8SED impl
7$1CNOP abs,X$3CNOP abs,X$5CNOP abs,X$7CNOP abs,X$9CSHY abs,X$BCLDY abs,X$DCNOP abs,X$FCNOP abs,X
10$01ORA X,ind$21AND X,ind$41EOR X,ind$61ADC X,ind$81STA X,ind$A1LDA X,ind$C1CMP X,ind$E1SBC X,ind
1$05ORA zpg$25AND zpg$45EOR zpg$65ADC zpg$85STA zpg$A5LDA zpg$C5CMP zpg$E5SBC zpg
2$09ORA #$29AND #$49EOR #$69ADC #$89NOP #$A9LDA #$C9CMP #$E9SBC #
3$0DORA abs$2DAND abs$4DEOR abs$6DADC abs$8DSTA abs$ADLDA abs$CDCMP abs$EDSBC abs
4$11ORA ind,Y$31AND ind,Y$51EOR ind,Y$71ADC ind,Y$91STA ind,Y$B1LDA ind,Y$D1CMP ind,Y$F1SBC ind,Y
5$15ORA zpg,X$35AND zpg,X$55EOR zpg,X$75ADC zpg,X$95STA zpg,X$B5LDA zpg,X$D5CMP zpg,X$F5SBC zpg,X
6$19ORA abs,Y$39AND abs,Y$59EOR abs,Y$79ADC abs,Y$99STA abs,Y$B9LDA abs,Y$D9CMP abs,Y$F9SBC abs,Y
7$1DORA abs,X$3DAND abs,X$5DEOR abs,X$7DADC abs,X$9DSTA abs,X$BDLDA abs,X$DDCMP abs,X$FDSBC abs,X
20$02JAM $22JAM $42JAM $62JAM $82NOP #$A2LDX #$C2NOP #$E2NOP #
1$06ASL zpg$26ROL zpg$46LSR zpg$66ROR zpg$86STX zpg$A6LDX zpg$C6DEC zpg$E6INC zpg
2$0AASL A$2AROL A$4ALSR A$6AROR A$8ATXA impl$AATAX impl$CADEX impl$EANOP impl
3$0EASL abs$2EROL abs$4ELSR abs$6EROR abs$8ESTX abs$AELDX abs$CEDEC abs$EEINC abs
4$12JAM $32JAM $52JAM $72JAM $92JAM $B2JAM $D2JAM $F2JAM
5$16ASL zpg,X$36ROL zpg,X$56LSR zpg,X$76ROR zpg,X$96STX zpg,Y$B6LDX zpg,Y$D6DEC zpg,X$F6INC zpg,X
6$1ANOP impl$3ANOP impl$5ANOP impl$7ANOP impl$9ATXS impl$BATSX impl$DANOP impl$FANOP impl
7$1EASL abs,X$3EROL abs,X$5ELSR abs,X$7EROR abs,X$9ESHX abs,Y$BELDX abs,Y$DEDEC abs,X$FEINC abs,X
30$03SLO X,ind$23RLA X,ind$43SRE X,ind$63RRA X,ind$83SAX X,ind$A3LAX X,ind$C3DCP X,ind$E3ISC X,ind
1$07SLO zpg$27RLA zpg$47SRE zpg$67RRA zpg$87SAX zpg$A7LAX zpg$C7DCP zpg$E7ISC zpg
2$0BANC #$2BANC #$4BALR #$6BARR #$8BANE #$ABLXA #$CBSBX #$EBUSBC #
3$0FSLO abs$2FRLA abs$4FSRE abs$6FRRA abs$8FSAX abs$AFLAX abs$CFDCP abs$EFISC abs
4$13SLO ind,Y$33RLA ind,Y$53SRE ind,Y$73RRA ind,Y$93SHA ind,Y$B3LAX ind,Y$D3DCP ind,Y$F3ISC ind,Y
5$17SLO zpg,X$37RLA zpg,X$57SRE zpg,X$77RRA zpg,X$97SAX zpg,Y$B7LAX zpg,Y$D7DCP zpg,X$F7ISC zpg,X
6$1BSLO abs,Y$3BRLA abs,Y$5BSRE abs,Y$7BRRA abs,Y$9BTAS abs,Y$BBLAS abs,Y$DBDCP abs,Y$FBISC abs,Y
7$1FSLO abs,X$3FRLA abs,X$5FSRE abs,X$7FRRA abs,X$9FSHA abs,Y$BFLAX abs,Y$DFDCP abs,X$FFISC abs,X

And, finally, in a third view, we may observe how each of the rows of "illegal"
instructions at c = 3 inherits behavior from the two rows with c = 1 and c = 2
immediately above, combining the operations of these instructions with the
address mode of the respective instruction at c = 1.
(Mind that in binary 3 is the combination of 2 and 1, bits 0 and 1 both set.)

We may further observe that additional NOPs result from non-effective or non-
sensical combinations of operations and address modes, e.g., instr. $89, which
would be "STA #", storing the contents of the accumulator in the operand.
Some other instructions, typically combinations involving indirect indexed
addressing, fail over unresolved timing issues entirely, resulting in a "JAM".

(We me also observe that there is indeed a difference in accumulator mode
— as in "OPC A" — and immediate addressing. E.g., $6A, "ROR A", is a valid
instruction, while instruction $7A, "ROR implied", is a NOP.
We may also note how "ROR X,ind" at $62 and "ROR ind,Y" at $72 fail entirely
and result in a JAM.)

acb
01234567
00$00BRK impl$04NOP zpg$08PHP impl$0CNOP abs$10BPL rel$14NOP zpg,X$18CLC impl$1CNOP abs,X
1$01ORA X,ind$05ORA zpg$09ORA #$0DORA abs$11ORA ind,Y$15ORA zpg,X$19ORA abs,Y$1DORA abs,X
2$02JAM $06ASL zpg$0AASL A$0EASL abs$12JAM $16ASL zpg,X$1ANOP impl$1EASL abs,X
3$03SLO X,ind$07SLO zpg$0BANC #$0FSLO abs$13SLO ind,Y$17SLO zpg,X$1BSLO abs,Y$1FSLO abs,X
10$20JSR abs$24BIT zpg$28PLP impl$2CBIT abs$30BMI rel$34NOP zpg,X$38SEC impl$3CNOP abs,X
1$21AND X,ind$25AND zpg$29AND #$2DAND abs$31AND ind,Y$35AND zpg,X$39AND abs,Y$3DAND abs,X
2$22JAM $26ROL zpg$2AROL A$2EROL abs$32JAM $36ROL zpg,X$3ANOP impl$3EROL abs,X
3$23RLA X,ind$27RLA zpg$2BANC #$2FRLA abs$33RLA ind,Y$37RLA zpg,X$3BRLA abs,Y$3FRLA abs,X
20$40RTI impl$44NOP zpg$48PHA impl$4CJMP abs$50BVC rel$54NOP zpg,X$58CLI impl$5CNOP abs,X
1$41EOR X,ind$45EOR zpg$49EOR #$4DEOR abs$51EOR ind,Y$55EOR zpg,X$59EOR abs,Y$5DEOR abs,X
2$42JAM $46LSR zpg$4ALSR A$4ELSR abs$52JAM $56LSR zpg,X$5ANOP impl$5ELSR abs,X
3$43SRE X,ind$47SRE zpg$4BALR #$4FSRE abs$53SRE ind,Y$57SRE zpg,X$5BSRE abs,Y$5FSRE abs,X
30$60RTS impl$64NOP zpg$68PLA impl$6CJMP ind$70BVS rel$74NOP zpg,X$78SEI impl$7CNOP abs,X
1$61ADC X,ind$65ADC zpg$69ADC #$6DADC abs$71ADC ind,Y$75ADC zpg,X$79ADC abs,Y$7DADC abs,X
2$62JAM $66ROR zpg$6AROR A$6EROR abs$72JAM $76ROR zpg,X$7ANOP impl$7EROR abs,X
3$63RRA X,ind$67RRA zpg$6BARR #$6FRRA abs$73RRA ind,Y$77RRA zpg,X$7BRRA abs,Y$7FRRA abs,X
40$80NOP #$84STY zpg$88DEY impl$8CSTY abs$90BCC rel$94STY zpg,X$98TYA impl$9CSHY abs,X
1$81STA X,ind$85STA zpg$89NOP #$8DSTA abs$91STA ind,Y$95STA zpg,X$99STA abs,Y$9DSTA abs,X
2$82NOP #$86STX zpg$8ATXA impl$8ESTX abs$92JAM $96STX zpg,Y$9ATXS impl$9ESHX abs,Y
3$83SAX X,ind$87SAX zpg$8BANE #$8FSAX abs$93SHA ind,Y$97SAX zpg,Y$9BTAS abs,Y$9FSHA abs,Y
50$A0LDY #$A4LDY zpg$A8TAY impl$ACLDY abs$B0BCS rel$B4LDY zpg,X$B8CLV impl$BCLDY abs,X
1$A1LDA X,ind$A5LDA zpg$A9LDA #$ADLDA abs$B1LDA ind,Y$B5LDA zpg,X$B9LDA abs,Y$BDLDA abs,X
2$A2LDX #$A6LDX zpg$AATAX impl$AELDX abs$B2JAM $B6LDX zpg,Y$BATSX impl$BELDX abs,Y
3$A3LAX X,ind$A7LAX zpg$ABLXA #$AFLAX abs$B3LAX ind,Y$B7LAX zpg,Y$BBLAS abs,Y$BFLAX abs,Y
60$C0CPY #$C4CPY zpg$C8INY impl$CCCPY abs$D0BNE rel$D4NOP zpg,X$D8CLD impl$DCNOP abs,X
1$C1CMP X,ind$C5CMP zpg$C9CMP #$CDCMP abs$D1CMP ind,Y$D5CMP zpg,X$D9CMP abs,Y$DDCMP abs,X
2$C2NOP #$C6DEC zpg$CADEX impl$CEDEC abs$D2JAM $D6DEC zpg,X$DANOP impl$DEDEC abs,X
3$C3DCP X,ind$C7DCP zpg$CBSBX #$CFDCP abs$D3DCP ind,Y$D7DCP zpg,X$DBDCP abs,Y$DFDCP abs,X
70$E0CPX #$E4CPX zpg$E8INX impl$ECCPX abs$F0BEQ rel$F4NOP zpg,X$F8SED impl$FCNOP abs,X
1$E1SBC X,ind$E5SBC zpg$E9SBC #$EDSBC abs$F1SBC ind,Y$F5SBC zpg,X$F9SBC abs,Y$FDSBC abs,X
2$E2NOP #$E6INC zpg$EANOP impl$EEINC abs$F2JAM $F6INC zpg,X$FANOP impl$FEINC abs,X
3$E3ISC X,ind$E7ISC zpg$EBUSBC #$EFISC abs$F3ISC ind,Y$F7ISC zpg,X$FBISC abs,Y$FFISC abs,X

As a final observation, the two highly unstable instructions "ANE" (XAA) and
"LXA" (LAX immediate) involving a "magic constant" are both combinations of
an accumulator operation and an inter-register transfer between the
accumulator and the X register:

$8B (a=5, c=3, b=2): ANE # = STA # (NOP) + TXA
(A OR CONST) AND X AND oper -> A

$AB (a=4, c=3, b=2): LXA # = LDA # + TAX
(A OR CONST) AND oper -> A -> X

In the case of ANE, the contents of the accumulator is put on the internal
data lines at the same time as the contents of the X-register, while there's
also the operand read for the immediate operation, with the result
transferred to the accumulator.

In the case of LXA, the immediate operand and the contents of the accumulator
are competing for the imput lines, while the result will be transferred to
both the accumulator and the X register.

The outcome of these competing, noisy conditions depends on the production
series of the chip, and maybe even on environmental conditions. This effects
in an OR-ing of the accumulator with the "magic constant" combined with an
AND-ing of the competing inputs. The final transfer to the target register(s)
then seems to work as may be expected.

(This AND-ing of competing values susggests that the 6502 is working internally
in active negative logic, where all data lines are first set to high and then
cleared for any zero bits. This also suggests that the "magic constant" stands
merely for a partial transfer of the contents of the accumulator.)

Much of this also applies to "TAS" (XAS, SHS), $9B, but here the extra cycles
for indexed addressing seem to contribute to the conflict being resolved
without this "magic constant". However, TAS is still unstable.

Simlarly the peculiar group involving the high-byte of the provided address + 1
(as in "H+1") — SHA (AHX, AXA), SHX (A11, SXA, XAS), SHY (A11, SYA, SAY) —
involves a conflict of an attempt to store the accumulator and another register
being put on the data lines at the same time, and the operations required to
determine the target address for for indexed addressing. Again, the competing
values are AND-ed and the instructions are unstable.

We may also observe that SHY is really the unimplemented instruction "STY abs,X"
and SHX is "STX abs,Y" with SHA being the combination of "LDA abs,X" and SHX.

We may conclude that these "illegal opcodes" or "undocumented instructions" are
really a text-book example of undefined behavior for undefined input patterns.
Generally speaking, for any instructions xxxxxx11 (c=3) both instructions at
xxxxxx01 (c=1) and xxxxxx10 (c=2) are started in a thread, with competing ouput
values on the internal data lines AND-ed. For some combinations, this results
in a fragile race condition, while others are showing mostly stable behavior.
The addressing mode is generally determined by that of the instruction at c=1.

(It may be interesting that is doesn't matter, if any of the two threads jams,
as long as the timing for the other thread resolves. So there is no "JAM"
instruction at c=3.)

Pinout (NMOS 6502)

NMOS 6502 Pinout
Vcc, Vsssupply voltage (Vcc: +5 V DC ± 5%, Vss: max. +7 V DC)
Φ0…2clock
AB0–AB15address bus
DB0–DB7data bus
R/Wread/write
RDYready
S.O.set overflow (future I/O interface)
SYNCsync (goes high on opcode fetch phase)
I̅R̅Q̅interrupt request (active low)
N̅M̅I̅non maskable interrupt (active low)
R̅E̅S̅reset (active low)
N.C.no connection

Source: MCS6500 Microcomputer Family Hardware Manual. MOS Technology, Inc., 1976.

The 65xx-Family:

TypeFeatures, Comments
6502NMOS, 16 bit address bus, 8 bit data bus
6502Aaccelerated version of 6502
6502Caccelerated version of 6502, additional halt pin, CMOS
65C02WDC version, additional instructions and address modes, up to 14MHz
6503, 6505, 650612 bit address bus [4 KiB]
650413 bit address bus [8 KiB], no NMI
650713 bit address bus [8 KiB], no interrupt lines
650920 bit address bus [1 MiB] by bankswitching
6510as 6502 with additional 6 bit I/O-port
6511integrated micro controler with I/O-port, serial interface, and RAM (Rockwell)
65F11as 6511, integrated FORTH interpreter
7501as 6502, HMOS
8500as 6510, CMOS
8502as 6510 with switchable 2 MHz option, 7 bit I/O-port
65816 (65C816)16 bit registers and ALU, 24 bit address bus [16 MiB], up to 24 MHz (Western Design Center)
65802 (65C802)as 65816, pin compatible to 6502, 64 KiB address bus, up to 16 MHz

Site Notes

Disclaimer

Errors excepted. The information is provided for free and AS IS, therefore without any warranty;
without even the implied warranty of merchantability or fitness for a particular purpose.

See also the “Virtual 6502” suite of online-programs

External Links

Presented by mass:werk.