Registers { A | Accumulator | Main working register X/Y | Index registers | Generally used for array access S | Stack pointer | 16-bit pointer. Gives the location of the first free byte on the stack. Decrements when pushed to, increments when pulled from DP | Direct page | Points to the start of the direct page area of RAM (typically $0000), used by 8-bit address modes. Must be set by TCD instruction DB | Data bank | The bank used for 16-bit address modes (must be set by PLB instruction) PB/PC | Program bank/counter | The bank/address of the next instruction to execute PSR | Processor status register | Contains some flags concerning the CPU state: { 1 | C: Carry flag | See ADC/SBC/CMP/LSR/ASL/ROR/ROL 2 | Z: Zero flag | Set if the result of an operation is zero 4 | I: IRQ disable | If set, disables IRQ (but not NMI nor BRK) 8 | D: Decimal mode | If set, binary-coded decimal is used for ADC/SBC operations 10h | X: Indices mode | If set, index registers are 8-bit with upper bytes cleared 20h | M: Memory/accumulator mode | If set, memory accesses and accumulator are 8-bit, upper byte of A is preserved 40h | V: Overflow flag | See ADC/SBC/BIT 80h | N: Negative flag | Set if the result of an operation is negative (most significant bit is set) } } LDA/LDX/LDY { Load to A, X or Y from memory Sets PSR.Z and PSR.N according to the value loaded A9xxxx | LDA #xxxx | A = xxxx, if PSR.M (8-bit accumulator) is set, then x is only one byte A2xxxx | LDX #xxxx | X = xxxx, if PSR.X (8-bit indices) is set, then x is only one byte A0xxxx | LDY #xxxx | Y = xxxx, if PSR.X (8-bit indices) is set, then x is only one byte AFxxxxbb | LDA bbxxxx | A = [bb:xxxx] ADxxxx | LDA xxxx | A = [DB:xxxx] AExxxx | LDX xxxx | X = [DB:xxxx] ACxxxx | LDY xxxx | Y = [DB:xxxx] A5xx | LDA xx | A = [00:00xx + DP] A6xx | LDX xx | X = [00:00xx + DP] A4xx | LDY xx | Y = [00:00xx + DP] BFxxxxbb | LDA bbxxxx,X | A = [bb:xxxx + X] BDxxxx | LDA xxxx,X | A = [DB:xxxx + X] BCxxxx | LDY xxxx,X | Y = [DB:xxxx + X] B9xxxx | LDA xxxx,Y | A = [DB:xxxx + Y] BExxxx | LDX xxxx,Y | X = [DB:xxxx + Y] B5xx | LDA xx,X | A = [00:00xx + DP + X] B4xx | LDY xx,X | Y = [00:00xx + DP + X] B6xx | LDX xx,Y | X = [00:00xx + DP + Y] A3xx | LDA xx,S | A = [00:00xx + S] A7xx | LDA [xx] | A = [bb:yyyy] where bb:yyyy = [00:00xx + DP] B2xx | LDA (xx) | A = [DB:yyyy] where yyyy = [00:00xx + DP] B7xx | LDA [xx],Y | A = [bb:yyyy + Y] where bb:yyyy = [00:00xx + DP] B1xx | LDA (xx),Y | A = [DB:yyyy + Y] where yyyy = [00:00xx + DP] A1xx | LDA (xx,X) | A = [DB:yyyy] where yyyy = [00:00xx + DP + X] B3xx | LDA (xx,S),Y | A = [DB:yyyy + Y] where yyyy = [00:00xx + S] } STA/STX/STY/STZ { Store A/X/Y/0 to memory No PSR flags are set STZ uses PSR.M to determine how many zero bytes to write 8Fxxxxbb | STA bbxxxx | bb:xxxx = A 8Dxxxx | STA xxxx | DB:xxxx = A 8Exxxx | STX xxxx | DB:xxxx = X 8Cxxxx | STY xxxx | DB:xxxx = Y 9Cxxxx | STZ xxxx | DB:xxxx = 0 85xx | STA xx | 00:00xx + DP = A 86xx | STX xx | 00:00xx + DP = X 84xx | STY xx | 00:00xx + DP = Y 64xx | STZ xx | 00:00xx + DP = 0 9Fxxxxbb | STA bbxxxx,X | bb:xxxx + X = A 9Dxxxx | STA xxxx,X | DB:xxxx + X = A 9Exxxx | STZ xxxx,X | DB:xxxx + X = 0 99xxxx | STA xxxx,Y | DB:xxxx + Y = A 95xx | STA xx,X | 00:00xx + DP + X = A 94xx | STY xx,X | 00:00xx + DP + X = Y 74xx | STZ xx,X | 00:00xx + DP + X = 0 96xx | STX xx,Y | 00:00xx + DP + Y = X 83xx | STA xx,S | 00:00xx + S = A 87xx | STA [xx] | bb:yyyy = A where bb:yyyy = [00:00xx + DP] 92xx | STA (xx) | DB:yyyy = A where yyyy = [00:00xx + DP] 97xx | STA [xx],Y | bb:yyyy = A where bb:yyyy = [00:00xx + DP] 91xx | STA (xx),Y | DB:yyyy = A where yyyy = [00:00xx + DP] 81xx | STA (xx,X) | DB:yyyy = A where yyyy = [00:00xx + DP + X] 93xx | STA (xx,S),Y | DB:yyyy + Y = A where yyyy = [00:00xx + S] } CMP/CPX/CPY { Compare A, X or Y with memory Sets PSR.Z/PSR.N/PSR.C according to the result of subtracting the value from A/X/Y Unlike SBC, this operation isn't affected by PSR.C and doesn't set PSR.V Let lhs = A/X/Y and rhs = the compared value: PSR.Z is set if lhs - rhs = 0 PSR.N is set if 8000h <= lhs - rhs <= FFFFh PSR.C is set if subtraction doesn't exceed the range of unsigned numbers, i.e. unsigned(lhs) - unsigned(rhs) >= 0 (like ARM and unlike x86/z80) Thus: If lhs = rhs, then PSR.Z = 1 If unsigned(lhs) >= unsigned(rhs), then PSR.C = 1 If signed(lhs) >= signed(rhs), then PSR.N = 0 (assuming no overflow) C9xxxx | CMP #xxxx | A - xxxx, if PSR.M (8-bit accumulator) is set, then x is only one byte E0xxxx | CPX #xxxx | X - xxxx, if PSR.X (8-bit indices) is set, then x is only one byte C0xxxx | CPY #xxxx | Y - xxxx, if PSR.X (8-bit indices) is set, then x is only one byte CFxxxxxx | CMP bbxxxx | A - [bb:xxxx] CDxxxx | CMP xxxx | A - [DB:xxxx] ECxxxx | CPX xxxx | X - [DB:xxxx] CCxxxx | CPY xxxx | Y - [DB:xxxx] C5xx | CMP xx | A - [00:00xx + DP] E4xx | CPX xx | X - [00:00xx + DP] C4xx | CPY xx | Y - [00:00xx + DP] DFxxxxxx | CMP bbxxxx,X | A - [bb:xxxx + X] DDxxxx | CMP xxxx,X | A - [DB:xxxx + X] D9xxxx | CMP xxxx,Y | A - [DB:xxxx + Y] D5xx | CMP xx,X | A - [00:00xx + DP + X] C3xx | CMP xx,S | A - [00:00xx + S] C7xx | CMP [xx] | A - [bb:yyyy] where bb:yyyy = [00:00xx + DP] D2xx | CMP (xx) | A - [DB:yyyy] where yyyy = [00:00xx + DP] D7xx | CMP [xx],Y | A - [bb:yyyy + Y] where bb:yyyy = [00:00xx + DP] D1xx | CMP (xx),Y | A - [DB:yyyy + Y] where yyyy = [00:00xx + DP] C1xx | CMP (xx,X) | A - [DB:yyyy] where yyyy = [00:00xx + DP + X] D3xx | CMP (xx,S),Y | A - [DB:yyyy + Y] where yyyy = [00:00xx + S] } ADC/SBC/AND/ORA/EOR { ADC: Add with carry SBC: Subtract with carry AND: Bitwise AND ORA: Bitwise OR EOR: Bitwise XOR ADC/SBC notes { Let lhs = A and rhs = the memory operand: SBC sets the carry/overflow flags the same way CMP does: PSR.C is set if subtraction doesn't exceed the range of unsigned numbers, i.e. unsigned(lhs) - unsigned(rhs) + PSR.C - 1 >= 0 (like ARM and unlike x86/z80) PSR.V is set if subtraction exceeds the range of signed numbers, i.e. not 8000h <= signed(lhs) - signed(rhs) + PSR.C - 1 <= 7FFFh ADC sets the carry/overflow flags as: PSR.C is set if addition exceeds the range of unsigned numbers, i.e. unsigned(lhs) + unsigned(rhs) + PSR.C > FFFFh PSR.V is set if addition exceeds the range of signed numbers, i.e. not 8000h <= signed(lhs) + signed(rhs) + PSR.C <= 7FFFh The reason ADC/SBC involves the carry is for multiprecision variables. E.g.: Suppose: $02 contains a 16-bit position $00 contains a 16-bit subpixel position (where there are 10000h subpixels per pixel) $12 contains a 16-bit speed $10 contains a 16-bit subpixel speed Then to add the speed to the position, one would do: CLC ; Clear the carry so that the first addition is correct LDA $00 : ADC $10 : STA $00 ; Add the subpixel values, the carry is propagated to the next ADC LDA $02 : ADC $12 : STA $02 ; Add the pixel values along with the carry To subtract the speed, one would do: SEC LDA $00 : SBC $10 : STA $00 LDA $02 : SBC $12 : STA $02 } 69xxxx | ADC #xxxx | A = A + xxxx + PSR.C, if PSR.M (8-bit accumulator) is set, then x is only one byte E9xxxx | SBC #xxxx | A = A - xxxx + PSR.C - 1, if PSR.M (8-bit accumulator) is set, then x is only one byte 29xxxx | AND #xxxx | A = A AND xxxx, if PSR.M (8-bit accumulator) is set, then x is only one byte 09xxxx | ORA #xxxx | A = A OR xxxx, if PSR.M (8-bit accumulator) is set, then x is only one byte 49xxxx | EOR #xxxx | A = A XOR xxxx, if PSR.M (8-bit accumulator) is set, then x is only one byte 6Fxxxxbb | ADC bbxxxx | A = A + [bb:xxxx] + PSR.C EFxxxxbb | SBC bbxxxx | A = A - [bb:xxxx] + PSR.C - 1 2Fxxxxbb | AND bbxxxx | A = A AND [bb:xxxx] 0Fxxxxbb | ORA bbxxxx | A = A OR [bb:xxxx] 4Fxxxxbb | EOR bbxxxx | A = A XOR [bb:xxxx] 6Dxxxx | ADC xxxx | A = A + [DB:xxxx] + PSR.C EDxxxx | SBC xxxx | A = A - [DB:xxxx] + PSR.C - 1 2Dxxxx | AND xxxx | A = A AND [DB:xxxx] 0Dxxxx | ORA xxxx | A = A OR [DB:xxxx] 4Dxxxx | EOR xxxx | A = A XOR [DB:xxxx] 65xx | ADC xx | A = A + [00:00xx + DP] + PSR.C E5xx | SBC xx | A = A - [00:00xx + DP] + PSR.C - 1 25xx | AND xx | A = A AND [00:00xx + DP] 05xx | ORA xx | A = A OR [00:00xx + DP] 45xx | EOR xx | A = A XOR [00:00xx + DP] 7Fxxxxbb | ADC bbxxxx,X | A = A + [bb:xxxx + X] + PSR.C FFxxxxbb | SBC bbxxxx,X | A = A - [bb:xxxx + X] + PSR.C - 1 3Fxxxxbb | AND bbxxxx,X | A = A AND [bb:xxxx + X] 1Fxxxxbb | ORA bbxxxx,X | A = A OR [bb:xxxx + X] 5Fxxxxbb | EOR bbxxxx,X | A = A XOR [bb:xxxx + X] 7Dxxxx | ADC xxxx,X | A = A + [DB:xxxx + X] + PSR.C FDxxxx | SBC xxxx,X | A = A - [DB:xxxx + X] + PSR.C - 1 3Dxxxx | AND xxxx,X | A = A AND [DB:xxxx + X] 1Dxxxx | ORA xxxx,X | A = A OR [DB:xxxx + X] 5Dxxxx | EOR xxxx,X | A = A XOR [DB:xxxx + X] 79xxxx | ADC xxxx,Y | A = A + [DB:xxxx + Y] + PSR.C F9xxxx | SBC xxxx,Y | A = A - [DB:xxxx + Y] + PSR.C - 1 39xxxx | AND xxxx,Y | A = A AND [DB:xxxx + Y] 19xxxx | ORA xxxx,Y | A = A OR [DB:xxxx + Y] 59xxxx | EOR xxxx,Y | A = A XOR [DB:xxxx + Y] 75xx | ADC xx,X | A = A + [00:00xx + DP + X] + PSR.C F5xx | SBC xx,X | A = A - [00:00xx + DP + X] + PSR.C - 1 35xx | AND xx,X | A = A AND [00:00xx + DP + X] 15xx | ORA xx,X | A = A OR [00:00xx + DP + X] 55xx | EOR xx,X | A = A XOR [00:00xx + DP + X] 63xx | ADC xx,S | A = A + [00:00xx + S] + PSR.C E3xx | SBC xx,S | A = A - [00:00xx + S] + PSR.C - 1 23xx | AND xx,S | A = A AND [00:00xx + S] 03xx | ORA xx,S | A = A OR [00:00xx + S] 43xx | EOR xx,S | A = A XOR [00:00xx + S] 67xx | ADC [xx] | A = A + [bb:yyyy] + PSR.C where bb:yyyy = [00:00xx + DP] E7xx | SBC [xx] | A = A - [bb:yyyy] + PSR.C - 1 where bb:yyyy = [00:00xx + DP] 27xx | AND [xx] | A = A AND [bb:yyyy] where bb:yyyy = [00:00xx + DP] 07xx | ORA [xx] | A = A OR [bb:yyyy] where bb:yyyy = [00:00xx + DP] 47xx | EOR [xx] | A = A XOR [bb:yyyy] where bb:yyyy = [00:00xx + DP] 72xx | ADC (xx) | A = A + [DB:yyyy] + PSR.C where yyyy = [00:00xx + DP] F2xx | SBC (xx) | A = A - [DB:yyyy] + PSR.C - 1 where yyyy = [00:00xx + DP] 32xx | AND (xx) | A = A AND [DB:yyyy] where yyyy = [00:00xx + DP] 12xx | ORA (xx) | A = A OR [DB:yyyy] where yyyy = [00:00xx + DP] 52xx | EOR (xx) | A = A XOR [DB:yyyy] where yyyy = [00:00xx + DP] 77xx | ADC [xx],Y | A = A + [bb:yyyy + Y] + PSR.C where bb:yyyy = [00:00xx + DP] F7xx | SBC [xx],Y | A = A - [bb:yyyy + Y] + PSR.C - 1 where bb:yyyy = [00:00xx + DP] 37xx | AND [xx],Y | A = A AND [bb:yyyy + Y] where bb:yyyy = [00:00xx + DP] 17xx | ORA [xx],Y | A = A OR [bb:yyyy + Y] where bb:yyyy = [00:00xx + DP] 57xx | EOR [xx],Y | A = A XOR [bb:yyyy + Y] where bb:yyyy = [00:00xx + DP] 71xx | ADC (xx),Y | A = A + [DB:yyyy + Y] + PSR.C where yyyy = [00:00xx + DP] F1xx | SBC (xx),Y | A = A - [DB:yyyy + Y] + PSR.C - 1 where yyyy = [00:00xx + DP] 31xx | AND (xx),Y | A = A AND [DB:yyyy + Y] where yyyy = [00:00xx + DP] 11xx | ORA (xx),Y | A = A OR [DB:yyyy + Y] where yyyy = [00:00xx + DP] 51xx | EOR (xx),Y | A = A XOR [DB:yyyy + Y] where yyyy = [00:00xx + DP] 61xx | ADC (xx,X) | A = A + [DB:yyyy] + PSR.C where yyyy = [00:00xx + DP + X] E1xx | SBC (xx,X) | A = A - [DB:yyyy] + PSR.C - 1 where yyyy = [00:00xx + DP + X] 21xx | AND (xx,X) | A = A AND [DB:yyyy] where yyyy = [00:00xx + DP + X] 01xx | ORA (xx,X) | A = A OR [DB:yyyy] where yyyy = [00:00xx + DP + X] 41xx | EOR (xx,X) | A = A XOR [DB:yyyy] where yyyy = [00:00xx + DP + X] 73xx | ADC (xx,S),Y | A = A + [DB:yyyy + Y] + PSR.C where yyyy = [00:00xx + S] F3xx | SBC (xx,S),Y | A = A - [DB:yyyy + Y] + PSR.C - 1 where yyyy = [00:00xx + S] 33xx | AND (xx,S),Y | A = A AND [DB:yyyy + Y] where yyyy = [00:00xx + S] 13xx | ORA (xx,S),Y | A = A OR [DB:yyyy + Y] where yyyy = [00:00xx + S] 53xx | EOR (xx,S),Y | A = A XOR [DB:yyyy + Y] where yyyy = [00:00xx + S] } BIT { Bit test A with memory Sets PSR flags according to the result of a bitwise AND with memory Immediate BIT (BIT #xxxx) does not set the negative nor overflow flag (but still sets the zero flag) Otherwise: The negative flag is set to the most significant bit of the memory value The overflow flag is set to the second-most significant bit of the memory value 89xxxx | BIT #xxxx | A AND #xxxx, if PSR.M (8-bit accumulator) is set, then x is only one byte 2Cxxxx | BIT xxxx | A AND [DB:xxxx] 24xx | BIT xx | A AND [00:00xx + DP] 3Cxxxx | BIT xxxx,X | A AND [DB:xxxx + X] 34xx | BIT xx,X | A AND [00:00xx+DP + X] } TSB/TRB { Test and set/reset bits of memory Sets PSR.Z according to A AND the value of the memory address *before* modification PSR.N is *not* affected by these instructions 0Cxxxx | TSB xxxx | DB:xxxx = [DB:xxxx] OR A 1Cxxxx | TRB xxxx | DB:xxxx = [DB:xxxx] AND NOT A 04xx | TSB xx | 00:00xx + DP = [00:00xx + DP] OR A 14xx | TRB xx | 00:00xx + DP = [00:00xx + DP] AND NOT A } INC/INX/INY / DEC/DEX/DEY / ASL/LSR/ROL/ROR { INC/INX/INY: Increment A/memory / X / Y DEC/DEX/DEY: Decrement A/memory / X / Y ASL: (Arithmetic) shift left LSR: Logical shift right ROL: Rotate left with carry ROR: Rotate right with carry INC/INX/INY / DEC/DEX/DEY set PSR.Z and PSR.N according to the result, but don't modify PSR.C nor PSR.V ASL/LSR set PSR.Z and PSR.N according to the result and sets PSR.C to the bit that was shifted out ROL/ROR are like ASL/LSR instructions that operate on the 17-bit / 9-bit concatenation of A with PSR.C, that is, the bit shifted out of A by ROL/ROR is shifted into PSR.C, the old PSR.C bit being shifted in to A The reason ROL/ROR exists is for multiprecision variables. E.g.: Suppose: $02 contains a 16-bit speed $00 contains a 16-bit subpixel speed (where there are 10000h subpixels per pixel) Then to multiply the speed by 2, one would do ASL $00 : ROL $02 1A | INC A | A = A + 1 E8 | INX | X = X + 1 C8 | INY | Y = Y + 1 3A | DEC A | A = A - 1 CA | DEX | X = X - 1 88 | DEY | Y = Y - 1 0A | ASL A | A = A << 1 4A | LSR A | A = A >> 1 2A | ROL A | A = A << 1, A.LSb = PSR.C 6A | ROR A | A = A >> 1, A.MSb = PSR.C EExxxx | INC xxxx | DB:xxxx = [DB:xxxx] + 1 CExxxx | DEC xxxx | DB:xxxx = [DB:xxxx] - 1 0Exxxx | ASL xxxx | DB:xxxx = [DB:xxxx] << 1 4Exxxx | LSR xxxx | DB:xxxx = [DB:xxxx] >> 1 2Exxxx | ROL xxxx | DB:xxxx = [DB:xxxx] << 1, (DB:xxxx).LSb = PSR.C 6Exxxx | ROR xxxx | DB:xxxx = [DB:xxxx] >> 1, (DB:xxxx).MSb = PSR.C E6xx | INC xx | 00:00xx + DP = [00:00xx + DP] + 1 C6xx | DEC xx | 00:00xx + DP = [00:00xx + DP] - 1 06xx | ASL xx | 00:00xx + DP = [00:00xx + DP] << 1 46xx | LSR xx | 00:00xx + DP = [00:00xx + DP] >> 1 26xx | ROL xx | 00:00xx + DP = [00:00xx + DP] << 1, (00:00xx + DP).LSb = PSR.C 66xx | ROR xx | 00:00xx + DP = [00:00xx + DP] >> 1, (00:00xx + DP).MSb = PSR.C FExxxx | INC xxxx,X | DB:xxxx + X = [DB:xxxx + X] + 1 DExxxx | DEC xxxx,X | DB:xxxx + X = [DB:xxxx + X] - 1 1Exxxx | ASL xxxx,X | DB:xxxx + X = [DB:xxxx + X] << 1 5Exxxx | LSR xxxx,X | DB:xxxx + X = [DB:xxxx + X] >> 1 3Exxxx | ROL xxxx,X | DB:xxxx + X = [DB:xxxx + X] << 1, (DB:xxxx + X).LSb = PSR.C 7Exxxx | ROR xxxx,X | DB:xxxx + X = [DB:xxxx + X] >> 1, (DB:xxxx + X).MSb = PSR.C F6xx | INC xx,X | 00:00xx + DP + X = [00:00xx + DP + X] + 1 D6xx | DEC xx,X | 00:00xx + DP + X = [00:00xx + DP + X] - 1 16xx | ASL xx,X | 00:00xx + DP + X = [00:00xx + DP + X] << 1 56xx | LSR xx,X | 00:00xx + DP + X = [00:00xx + DP + X] >> 1 36xx | ROL xx,X | 00:00xx + DP + X = [00:00xx + DP + X] << 1, (00:00xx + DP + X).LSb = PSR.C 76xx | ROR xx,X | 00:00xx + DP + X = [00:00xx + DP + X] >> 1, (00:00xx + DP + X).MSb = PSR.C } BRL/BRA/BCC/BCS/BNE/BEQ/BPL/BMI/BVC/BVS { BRL: Branch long BRA: Branch BCC: Branch if carry clear BCS: Branch if carry set BNE: Branch if not equal BEQ: Branch if equal BPL: Branch if plus BMI: Branch if minus BVC: Branch if overflow clear BVS: Branch if overflow set No PSR flags are set Note that BNE/BEQ can be misleading names, especially after AND/BIT. In practice, they're more like BZC/BZS 82xxxx | BRL xxxx | PC = PC + signed(xxxx) 80xx | BRA xx | PC = PC + signed(xx) 90xx | BCC xx | PC = PC + signed(xx) if PSR.C = 0 B0xx | BCS xx | PC = PC + signed(xx) if PSR.C = 1 D0xx | BNE xx | PC = PC + signed(xx) if PSR.Z = 0 F0xx | BEQ xx | PC = PC + signed(xx) if PSR.Z = 1 10xx | BPL xx | PC = PC + signed(xx) if PSR.N = 0 30xx | BMI xx | PC = PC + signed(xx) if PSR.N = 1 50xx | BVC xx | PC = PC + signed(xx) if PSR.V = 0 70xx | BVS xx | PC = PC + signed(xx) if PSR.V = 1 } JMP/JML/JSR/JSL / COP/BRK / RTS/RTL/RTI { JMP: Jump JML: Jump, long JSR: Jump to subroutine JSL: Jump to subroutine, long COP: Coprocessor interrupt BRK: Breakpoint interrupt RTS: Return from subroutine RTL: Return from subroutine, long RTI: Return from interrupt No PSR flags are set (except RTI/COP/BRK) Reminder that PC refers to the next instruction to execute Bug: JMP (xxFF) fetches the MSB from the same page, i.e. yyyy is fetched as [PB:xxFF] OR ([PB:xx00] << 8) 5Cxxxxbb | JML bbxxxx | PB:PC = bb:xxxx 4Cxxxx | JMP xxxx | PC = xxxx DCxxxx | JML [xxxx] | PB:PC = bb:yyyy where bb:yyyy = [00:xxxx] 6Cxxxx | JMP (xxxx) | PC = yyyy where yyyy = [00:xxxx] 7Cxxxx | JMP (xxxx,X) | PC = yyyy where yyyy = [PB:xxxx + X] 22xxxxbb | JSL bbxxxx | Push PB:PC - 1, PB:PC = bb:xxxx 20xxxx | JSR xxxx | Push PC - 1, PC = xxxx FCxxxx | JSR (xxxx,X) | Push PC - 1, PC = yyyy where yyyy = [PB:xxxx + X] 02xx | COP | Push PB:PC + 1, push PSR, PB:PC = 00:yyyy where yyyy = [00:FFF4], PSR.D = 0, PSR.I = 1 00xx | BRK | Push PB:PC + 1, push PSR, PB:PC = 00:yyyy where yyyy = [00:FFE6], PSR.D = 0, PSR.I = 1 60 | RTS | Pull to PC, PC = PC + 1 6B | RTL | Pull to PB:PC, PC = PC + 1 40 | RTI | Pull to PSR, pull to PB:PC } PEA/PEI/PER / PHA/PHX/PHY/PHP/PHD/PHB/PHK / PLA/PLX/PLY/PLP/PLD/PLB { PEA/PEI/PER: Push effective absolute/indirect/relative PHA/PHX/PHY/PHP/PHD/PHB/PHK: Push A/X/Y/PSR/DP/DB/PB PLA/PLX/PLY/PLP/PLD/PLB: Pull to A/X/Y/PSR/DP/DB All pull instructions set the negative/zero flags (even PLB) Pushing an n-byte register r onto the stack means: S = S - n [S + 1] = r Conversely, pulling to an n-byte register from the stack means: r = [S + 1] S = S + n F4xxxx | PEA xxxx | Push xxxx (does not depend on PSR.M) D4xx | PEI (xx) | Push yyyy where yyyy = [00:00xx + DP] 62xxxx | PER xxxx | Push PC + signed(xxxx) 48 | PHA | Push A DA | PHX | Push X 5A | PHY | Push Y 08 | PHP | Push PSR 0B | PHD | Push DP 8B | PHB | Push DB 4B | PHK | Push PB 68 | PLA | Pull to A FA | PLX | Pull to X 7A | PLY | Pull to Y 28 | PLP | Pull to PSR 2B | PLD | Pull to DP AB | PLB | Pull to DB } TAX/TAY/TCS/TCD/TXA/TXY/TXS/TYA/TYX/TSC/TSX/TDC / XBA { TAX/TAY/TCS/TCD: Transfer A to X/Y/S/DP TXA/TXY: Transfer X to A/Y TYA/TYX: Transfer Y to A/X TSC/TSX: Transfer S to A/X TDC: Transfer DP to A XBA: Exchange bytes of A TXS/TCS do *not* set any PSR flags XBA sets the zero/negative flags according to the new LSB AA | TAX | X = A, PSR.M is ignored 8A | TXA | A = X, PSR.X is ignored A8 | TAY | Y = A, PSR.M is ignored 98 | TYA | A = Y, PSR.X is ignored 9B | TXY | Y = X BB | TYX | X = Y 1B | TCS | S = A, PSR.M is ignored 3B | TSC | A = S, PSR.M is ignored BA | TSX | X = S 9A | TXS | S = X, PSR.X is ignored 5B | TCD | DP = A, PSR.M is ignored 7B | TDC | A = DP, PSR.M is ignored EB | XBA | A = (A AND FFh) << 8 OR (A >> 8) } SEP/REP / CLC/CLD/CLI/CLV / SEC/SED/SEI / XCE { SEP/REP: Set/reset PSR bits CLC/CLD/CLI/CLV: Clear carry/decimal/IRQ/overflow flag SEC/SED/SEI: Set carry/decimal/IRQ flag XCE: Exchange carry and emulation flags E2xx | SEP #xx | PSR = PSR OR xx C2xx | REP #xx | PSR = PSR AND NOT xx 18 | CLC | Clear PSR.C (carry) D8 | CLD | Clear PSR.D (decimal) 58 | CLI | Clear PSR.I (IRQ disable) B8 | CLV | Clear PSR.V (overflow) 38 | SEC | Set PSR.C (carry) F8 | SED | Set PSR.D (decimal) 78 | SEI | Set PSR.I (IRQ disable) FB | XCE | Exchange carry and emulation flags (emulation flag not doc'd here) } MVN/MVP { Move memory in the negative/positive direction Use MVN to move data backwards (to a lower address), use MVP to move data forwards (to a higher address) After MVN/MVP, DB = yy, A = FFFFh After MVN, X += A + 1, Y += A + 1 After MVP, X -= A + 1, Y -= A + 1 54yyxx | MVN xx yy | Copy A + 1 bytes from xx:X to yy:Y starting from the beginning 44yyxx | MVP xx yy | Copy A + 1 bytes from xx:X to yy:Y starting from the end } WAI/STP / NOP/WDM { WAI: Wait for interrupt STP: Stop NOP: No operation WDM: William David Mensch Jr., 65816 designer CB | WAI | Sleep until interrupt occurs (NMI or IRQ), will wake up due to IRQ even if IRQ is disabled via PSR.I = 1 DB | STP | Kill CPU EA | NOP | Nothing 42xx | WDM | Reserved } Opcode table { For even n: 00 20 40 60 80 A0 C0 E0 n0 = ooo BRK RTI RTS n0 = JSR xxxx JSR n0 = BRA xx BRA n0 = ooo #xxxx LDY CPY CPX n1 = ooo (xx,X) ORA AND EOR ADC STA LDA CMP SBC n2 = ooo COP WDM n2 = JSR xxxxxx JSR n2 = ooo xxxx PER BRL n2 = LDX #xxxx LDX n2 = oEP #xx REP SEP n3 = ooo xx,S ORA AND EOR ADC STA LDA CMP SBC n4 = ooo xx TSB BIT STZ STY LDY CPY CPX n4 = MVP xx yy MVP n5 = ooo xx ORA AND EOR ADC STA LDA CMP SBC n6 = ooo xx ASL ROL LSR ROR STX LDX DEC INC n7 = ooo [xx] ORA AND EOR ADC STA LDA CMP SBC n8 = ooo PHP PLP PHA PLA DEY TAY INY INX n9 = ooo #xxxx ORA AND EOR ADC BIT LDA CMP SBC nA = ooo ASL ROL LSR ROR TXA TAX DEX NOP nB = ooo PHD PLD PHK RTL PHB PLB WAI XBA nC = ooo xxxx TSB BIT JMP STY LDY CPY CPX nC = JMP (xxxx) JMP nD = ooo xxxx ORA AND EOR ADC STA LDA CMP SBC nE = ooo xxxx ASL ROL LSR ROR STX LDX DEC INC nF = ooo xxxxxx ORA AND EOR ADC STA LDA CMP SBC -------- For odd n: 10 30 50 70 90 B0 D0 F0 n0 = Boo xx BPL BMI BVC BVS BCC BCS BNE BEQ n1 = ooo (xx),Y ORA AND EOR ADC STA LDA CMP SBC n2 = ooo (xx) ORA AND EOR ADC STA LDA CMP SBC n3 = ooo (xx,S),Y ORA AND EOR ADC STA LDA CMP SBC n4 = ooo xx TRB n4 = ooo xx,X BIT STZ STY LDY n4 = MVN xx yy MVN n4 = PEI (xx) PEI n4 = PEA xxxx PEA n5 = ooo xx,X ORA AND EOR ADC STA LDA CMP SBC n6 = ooo xx,X ASL ROL LSR ROR STX LDX DEC INC n7 = ooo [xx],Y ORA AND EOR ADC STA LDA CMP SBC n8 = ooo CLC SEC CLI SEI TYA CLV CLD SED n9 = ooo xxxx,Y ORA AND EOR ADC STA LDA CMP SBC nA = ooo INC DEC PHY PLY TXS TSX PHX PLX nB = ooo TCS TSC TCD TDC TXY TYX STP XCE nC = ooo xxxx TRB STZ nC = ooo xxxx,X BIT LDY nC = JMP xxxxxx JMP nC = Joo (xxxx,X) JMP JSR nC = JMP [xxxx] JMP nD = ooo xxxx,X ORA AND EOR ADC STA LDA CMP SBC nE = ooo xxxx,X ASL ROL LSR ROR STZ DEC INC nE = ooo xxxx,Y LDX nF = ooo xxxxxx,X ORA AND EOR ADC STA LDA CMP SBC }