Appendix F: The 65C816 Processor
Table Of Contents
- Overview
- Compatibility with the 65C02
- Registers
- Status Flags
- 16 bit mode
- Address Modes
- Vectors
- Instruction Tables
Overview
This document is a brief introduction and quick reference for the 65C816 Microprocessor. For more details, see the 65C816 data sheet or Programming the 65816: Including the 6502, 65C02, and 65802.
The WDC65C816 CPU is an 8/16 bit CPU and a follow-up to the 65C02 processor. The familiar 65C02 instructions and address modes are retained, and some new ones are added.
The CPU can optionally operate in 16-bit mode, extending the utility of math instruction (16-bit adds!) and the coverage of .X and .Y indexed modes to 64KB.
Zero Page has been renamed to Direct Page, and Direct Page can now be relocated anywhere in the first 64K of RAM. As a result, all of the Zero Page instructions are now "Direct" instructions and can operate anywhere in the X16's address range.
Likewise, the Stack can also be relocated, and the stack pointer is now 16 bits. This allows for a much larger stack, and the combination of stack and DP relocation offer interesting multitasking opportunities.
Compatibility with the 65C02
The 65C916 CPU is generally compatible with the 65C02 instruction set, with the
exception of the BBRx
, BBSx
, RMBx
, and SMBx
instructions. We recommend
programmers avoid these instructions when writing X16 softwware, using the more
conventional Boolean logic instructions, instead.
Registers
Notation | Name | Description |
---|---|---|
A | Accumulator | The accumulator. It stores the result of moth math and logical operations. |
X | X Index | .X is mostly used as a counter and to offset addresses with X indexed modes |
Y | Y Index | .Y is mostly used as a counter and to offset addresses with Y indexed modes |
S | Stack Pointer | SP points to the next open position on the stack. |
DB or DBR | Data Bank | Data bank is the default bank for operations that use a 16 bit address. |
K or PBR | Program Bank | The default address for 16 bit JMP and JSR oprerations. Can only be set with a 24 bit JMP or JSR. |
P | Processor Status | The flags. |
PC | Program Counter | The address of the current CPU instruction |
.A, .X, and .Y can be 8 or 16 bits wide, based on the flag settings (see below).
The Stack Pointer (.S) is 16 bits wide in Native mode and 8 bits wide (and fixed to the $100-1FF range) in Emulation mode.
.DB and .K are the bank registers, allowing programs and data to occupy separate 64K banks on computers with more than 64K of RAM. (The X16 does not use the bank registers, instead using addresses $00 and $01 for banking.)
Status Flags
The native mode flags are as follows:
nvmx dizc e
n = Negative
v = oVerflow
m = Memory width (0=16 bit, 1=8 bit)
x = Index register width (0=16 bit, 1=8 bit)
d = Decimal Mode
i = Interupts Disabled
z = Zero
c = Carry
e = Emulation Mode (0=65C02 mode, 1=65C816 mode)
In emulation mode, the m and x flags are always set to 1.
Here are the 6502 and 65C02 registers, for comparison:
nv1b dizc
n = Negative
v = oVerflow
1 = this bit is always 1
b = brk: set during a BRK instruction interrupt
d = Decimal Mode
i = Interupts Disabled
z = Zero
c = Carry
Note the missing b flag on the 65C816. This is no longer needed in native mode, since the BRK instruction now has its own vector.
The e flag can only accessed via the XCE instruction, which swaps Carry and the Emulation flag.
The other flags can all be manipulated with SEP and REP, and the various branch instructions (BEQ, BCS, etc) test some of the flags. The rest can only be tested indirectly through the stack.
When a BRK or IRQ is triggered in emulation mode, a ghost b flag will be pushed to the stack instead of the x flag. This can be used to test for a BRK vs IRQ in the Interrupt handler.
16 bit mode
The 65C816 CPU boots up in emulation mode. This locks the register width to 8 bits and locks out certain operations.
If you want to use the '816 features, including 16-bit operation, you will need to enable native mode. Clearing e switches the CPU to native mode. However, it's not as simple as just setting a flag. The e flag can only be accessed through the XCE instruction, which swaps the Carry and Emulation flags.
To switch to native mode, use the following steps:
To switch back to emulation mode, set the Carry flag and perform an XCE again.
Once e is cleared, the m and x flags can be set to 1 or 0 to control the register width.
When the m flag is clear, Accumulator operations and memory reads and writes will be 16-bit operations. The CPU reads two bytes at a time with LDA, writes two bytes at a time with STA, and all math involving .A is 16 bits wide.
Likewise, whenn x is clear, the .X and .Y index registers are 16 bits wide.
INX and INY will now count up to 65535, and indexed instructions like LDA addr,X
can now cover 64K.
You can use REP #$10
to enable 16-bit index registers, and REP #$20
to
enable 16-bit memory and Accumulator. SEP #$10
or SEP #$20
will switch back
to 8-bit operation. You can also combine the operand and use SEP #$30
or
REP #$30
to flip both bits at once.
And now we reach the 16-bit assembly trap: the actual assembly opcodes are the same, regardless of the x and m flags. This means the assembler needs to track the state of these flags internally, so it can correctly write one or two bytes when assembling immediate mode instructions like LDA #$01.
You can help the assembler out by using hints. Different assemblers have different hinting systems, so we will focus on 64TASS and cc65.
64TASS accepts .as
(.A short) and
.al
(.A long) to tell the assembler to store 8 bits or 16 bits in an immediate
mode operand. For LDX and LDY, use the .xs
and .xl
hints.
The hints for ca65 are .a8
, .a16
, .i8
, and .i16
Note that this has no effect on absolute or indirect addressing modes, such
as LDA $1234
and LDA ($1000)
, since the operand for these modes is always
16 bits.
To make it easy to remember the modes, just remember that e, m, and x all emulate 65C02 behavior when set.
Address Modes
The 65C816 now has 24 discinct address modes, although most are veriations on a theme. Make note of the new syntax for Stack relative instructions (,S), the use of brackets for [24 bit indirect] addressing, and the fact that Zero Page has been renamed to Direct Page. This means that $0001 and $01 are now two different addresses (although they would be the same if .DP is set to $00.
Mode | Syntax | Description |
---|---|---|
Immediate | #$12 | Value is supplied in the program stream |
Absolute | $1234 | Data is at this address. |
Absolute X Indexed | $1234,X | Address is offset by X. If X=2 this is $1236. |
Absolute Y Indexed | $1234,Y | Address is offset by X. If Y=2 this is $1236. |
Direct | $12 | Direct Page address. Operand is 1 byte. |
Direct X Indexed | $12,X | Address on Direct Page is offset by .X |
Direct Y Indexed | $12,Y | Address on Direct Page is offset by .Y |
Direct Indirect | ($12) | Value at $12 is a 16-bit address. |
Direct Indirect Y Indexed | ($12),Y | Resolve pointer at $12 then offset by Y. |
Direct X Indexed Indirect | ($12,X) | Start at $12, offset by X, then read that address. |
Direct Indirect Long | [$12] | 24 bit pointer on Direct Page. |
Direct Indrect Long Y Indexed | [$12],Y | Resolve address at $12, then offset by Y. |
Indirect | ($1234) | Read pointer at $1234 and get data from the resultant address |
Indirect X Indexed | ($1234,X) | Read pointer at $1234 offset by X, get data from resultant address |
Indirect Long | [$1234] | Pointer is a 24-bit address. |
Absolute Long | $123456 | 24 bit address. |
Absolute Indexed Long | $123456,X | 24 bit address, offset by X. |
Stack Relative Indexed | $12,S | Stack relative. |
Stack Relative Indirect Indexed | ($12,S),Y | Resolve Pointer at $12, then offset by Y. |
Accumulator (implied) | Operation acts on .A | |
Implied | Target is part of the opcode name. | |
Relative Address (8 bit signed) | $1234 | Branches can only jump by -128 to 127 bytes. |
16 bit relative address | $1234 | BRL can jump by 32K bytes. |
Block Move | #$12,#$34 | Operands are the bank numbers for block move/copy. |
Vectors
The 65816 has two different sets of interrupt vectors. In emulation mode, the vectors are the same as the 65C02. In native mode (.e = 0), the native vectors are used. This allows you to switch to the desired operation mode, based on the operating mode of your interrupt handlers.
The Commander X16 operates mostly in emulation mode, so native mode interrupts on the X16 will switch to emulation mode, then simply call the 8-bit interrupt handlers.
The vectors are:
Name | Emu | Native |
---|---|---|
COP | FFF4 | 00FFE4 |
BRK | FFFE | 00FFE6 |
ABORT | FFF8 | 00FFE8 |
NMI | FFFA | 00FFEA |
RESET | FFFC | |
IRQ | FFFE | 00FFEE |
The 65C02 shares the same interrupt for BRK and IRQ, and the b flag tells the interrupt handler whether to execute a break or interrupt.
In emulation mode, the 65C816 pushes a modified version of the flags to the stack. The BRK instruction actually pushes a 1 in bit 4, which can then be tested in the Interrupt Service Routine. In native mode, however, the flags are pushed verbatim, since BRK has its own handler.
There is also no native RESET vector, since the CPU always boots to emulation mode. The CPU always starts at the address stored in $FFFC.
Decimal Mode
When the d flag is set, the CPU operates in Decimal mode. In this mode, a byte is treated as two decimal digits, rather than a binary number. As a result, you can easily add, subtract, and display decimal numbers.
While in Decimal mode, the lower nibble of a byte contains the 1s digit, and the upper nibble contains the 10s digit. Each nibble can only contain value from 0-9, and addition will wrap from 9 to 0. Subtraction works similarly, wrapping down from 0 to 9.
SED enables Decimal mode. At that point, ADC and SBC will perform base-10 addition and subtraction. CLD clears Decimal mode and returns to binary mode.
When adding, the Carry bit will be set if the result is 100 or greater. The total result can never exceed 199, so two digits plus Carry is all that is needed to represent values from 0 to 199.
If you perform an ADC with the Carry bit set, this will add an extra 1 to the result.
Examples
Operation | .A | Result | Notes |
---|---|---|---|
ADC #$01 | $09 | $10 | |
ADC #$01 | $99 | $00 | Carry is set, indicating 100. |
When subtracting, the Carry bit operates as a borrow bit, and the sense is inverted: 0 indicates a borrow took place, and 1 means it did not.
Operation | .A | Result | Notes |
---|---|---|---|
SBC #$01 | $10 | $09 | Carry is set, indicating no borrow. |
SBC #$01 | $00 | $99 | Carry is clear, indicating a borrow. |
In the second example ($00 - $01), the final result was $99 with a borrow.
Note that the n flag tracks the high bit, but two's complement doesn't work as expected in Decimal mode. Instead, we have to use Ten's complement.
Simply put, $00 - $01 gives you $99. So when working in signed BCD, any value where the high digit is 5-9 is actually a negative value. To convert negative values to positive values for printing, you would subtract from 99 and add 1.
For example: the integer -49 is $51 in BCD. 99 - 51 + 1 = 49
. You'd print that
as -49
.
Instruction Tables
Instructions By Opcode
Instructions By Name
ADC | AND | ASL | BCC | BCS | BEQ | BIT | BMI | BNE | BPL |
BRA | BRK | BRL | BVC | BVS | CLC | CLD | CLI | CLV | CMP |
COP | CPX | CPY | DEC | DEX | DEY | EOR | INC | INX | INY |
JMP | JML | JSL | JSR | LDA | LDX | LDY | LSR | MVN | MVP |
NOP | ORA | PEA | PEI | PER | PHA | PHB | PHD | PHK | PHP |
PHX | PHY | PLA | PLB | PLD | PLP | PLX | PLY | REP | ROL |
ROR | RTI | RTL | RTS | SBC | SEC | SED | SEI | SEP | STA |
STP | STX | STY | STZ | TAX | TAY | TCD | TCS | TDC | TRB |
TSB | TSC | TSX | TXA | TXS | TXY | TYA | TYX | WAI | WDM |
XBA | XCE |
Instructions By Category
Category | Instructions |
---|---|
Arithmetic | ADC , SBC |
Boolean | AND , EOR , ORA |
Shift | ASL , LSR , ROL , ROR |
Branch | BCC , BCS , BEQ , BMI , BNE , BPL , BRA , BRK , BRL , BVC , BVS |
Test | BIT , TRB , TSB |
Flags | CLC , CLD , CLI , CLV , REP , SEC , SED , SEI , SEP |
Compare | CMP , CPX , CPY |
Interrupt | COP , WAI |
Inc/Dec | DEC , DEX , DEY , INC , INX , INY |
Flow | JMP , JML , JSL , JSR , NOP , RTI , RTL , RTS , WDM |
Load | LDA , LDX , LDY |
Block Move | MVN , MVP |
Stack | PEA , PEI , PER , PHA , PHB , PHD , PHK , PHP , PHX , PHY , PLA , PLB , PLD , PLP , PLX , PLY |
Store | STA , STP , STX , STY , STZ |
Register Swap | TAX , TAY , TCD , TCS , TDC , TSC , TSX , TXA , TXS , TXY , TYA , TYX , XBA , XCE |
ADC
Add with Carry
SYNTAX MODE HEX LEN CYCLES FLAGS
ADC #$20/#$1234 imm 69 3-m 3-m nv....zc .
ADC $20 dir 65 2 4-m+w nv....zc .
ADC $20,X dir,X 75 2 5-m+w nv....zc .
ADC $20,S stk,S 63 2 5-m nv....zc .
ADC $1234 abs 6D 3 5-m nv....zc .
ADC $1234,X abs,X 7D 3 6-m-x+x*p nv....zc .
ADC $1234,Y abs,Y 79 3 6-m-x+x*p nv....zc .
ADC $FEDBCA long 6F 4 6-m nv....zc .
ADC $FEDCBA,X long,X 7F 4 6-m nv....zc .
ADC ($20) (dir) 72 2 6-m+w nv....zc .
ADC ($20),Y (dir),Y 71 2 7-m+w-x+x*p nv....zc .
ADC ($20,X) (dir,X) 61 2 7-m+w nv....zc .
ADC ($20,S),Y (stk,S),Y 73 2 8-m nv....zc .
ADC [$20] [dir] 67 2 7-m+w nv....zc .
ADC [$20],Y [dir],Y 77 2 7-m+w nv....zc .
ADC adds the accumulator (.A), the supplied operand, and the Carry bit (0 or 1). The result is stored in .A.
Since Carry is always added in, you should always remember to use CLC (Clear Carry) before performing an addition operation. When adding larger numbers (16, 24, 32, or more bits), you can use the Carry flag to chain additions.
Here is an example of a 16-bit add, when in 8 bit mode:
CLC
LDA Addend1
ADC Addend2
STA Result1
LDA Addend1+1 ; Reads the high byte of the addend
ADC Addend2+1 ; (the +1 refers to the *address* of Addend, not the value)
STA Result1+1 ;
done:
; the final result is at Result1
Flags:
- n is set when the high bit of .A is set. This indicates a negative number when using Two's Complement signed values.
- v (overflow) is set when the sum exceeds the maximum signed value for .A. (More on that below). * n is set when the high bit is 1.
- z is set when the result is zero. This is useful for loop counters and can be tested with BEQ and BNE. (BEQ and BNE test the Zero bit, which is also the "equal" bit when performing subtraction or Compare operations.)
- c is set when the unsigned result exceeds the register's capacity (255 or 65535).
Overflow vs Carry
The CPU detects addition that goes past the 7 or 15 bit boundary of a signed number, as well as the 8 bit boundary of an unsigned number.
In 8-bit mode, when you add two positive numbers that result in a sum higher than 127 or add two negative numbers that result in a sum below -128, you will get a signed overflow, and the v flag will be set.
When the sum of the two numbers exceeeds 255 or 65535, then the Carry flag will be set. This bit can be added to the next higher byte with ADC #0.
[Opcodes] [By Name] [By Category]
AND
Boolean AND
SYNTAX MODE HEX LEN CYCLES FLAGS
AND #$20/#$1234 imm 29 3-m 3-m n.....z. .
AND $20 dir 25 2 4-m+w n.....z. .
AND $20,X dir,X 35 2 5-m+w n.....z. .
AND $20,S stk,S 23 2 5-m n.....z. .
AND $1234 abs 2D 3 5-m n.....z. .
AND $1234,X abs,X 3D 3 6-m-x+x*p n.....z. .
AND $1234,Y abs,Y 39 3 6-m-x+x*p n.....z. .
AND $FEDBCA long 2F 4 6-m n.....z. .
AND $FEDCBA,X long,X 3F 4 6-m n.....z. .
AND ($20) (dir) 32 2 6-m+w n.....z. .
AND ($20),Y (dir),Y 31 2 7-m+w-x+x*p n.....z. .
AND ($20,X) (dir,X) 21 2 7-m+w n.....z. .
AND ($20,S),Y (stk,S),Y 33 2 8-m n.....z. .
AND [$20] [dir] 27 2 7-m+w n.....z. .
AND [$20],Y [dir],Y 37 2 7-m+w n.....z. .
Perform a logical AND operation with the operand and .A
AND compares each bit of the operands and sets the result bit to 1 only when the matching bit of each operand is 1.
AND is useful for reading a group of bits from a byte. For example, AND #$0F
will clear the top nibble of .A, returning the bits from the lower nibble.
Truth table for AND:
Flags:
- n is set when the high bit of the result is 1
- z is set when the result is Zero
[Opcodes] [By Name] [By Category]
ASL
Arithmetic Shift Left
SYNTAX MODE HEX LEN CYCLES FLAGS
ASL acc 0A 1 2 n.....zc .
ASL $20 dir 06 2 7-2*m+w n.....zc .
ASL $20,X dir,X 16 2 8-2*m+w n.....zc .
ASL $1234 abs 0E 3 8-2*m n.....zc .
ASL $1234,X abs,X 1E 3 9-2*m n.....zc .
ASL shifts the target left one place. It shifts the high bit of the operand into the Carry flag and a zero into the low bit.
[Opcodes] [By Name] [By Category]
BCC
Branch on Carry Clear
Jumps to the target address when the Carry flag (c) is Zero.
BCC can be used after add, subtract, or compare operations. After a compare, c is as follows:
- When A < Operand, c is clear.
- When A >= Operand, c is set.
A branch operation uses an 8 bit signed value internally, starting from the instruction after the branch. So the branch destination can be 126 bytes before or 128 bytes after the branch instruction.
[Opcodes] [By Name] [By Category]
BCS
Branch on Carry Set
Jumps to the target address when the Carry flag is 1.
BCC can be used after add, subtract, or compare operations. After a compare, c is as follows:
- When A < Operand, c is clear.
- When A >= Operand, c is set.
A branch operation uses an 8 bit signed value internally, starting from the instruction after the branch. So the branch destination can be 126 bytes before or 128 bytes after the branch instruction.
[Opcodes] [By Name] [By Category]
BEQ
Branch on Equal.
Jumps to the target address when the Zero flag is 1. While this is most commonly used after a compare (see CMP ) operation, it's also useful to test if a number is zero after a Load operation, or to test if a loop is complete after a DEC operation.
A branch operation uses an 8 bit signed value internally, starting from the instruction after the branch. So the branch destination can be 126 bytes before or 128 bytes after the branch instruction.
[Opcodes] [By Name] [By Category]
BIT
Bit Test
SYNTAX MODE HEX LEN CYCLES FLAGS
BIT #$20/#$1234 imm 89 3-m 3-m ......z. .
BIT $20 dir 24 2 4-m+w nv....z. .
BIT $20,X dir,X 34 2 5-m+w nv....z. .
BIT $1234 abs 2C 3 5-m nv....z. .
BIT $1234,X abs,X 3C 3 6-m-x+x*p nv....z. .
Tests the operand against the Accumulator. The ALU does an AND operation internally, setting z if the result is 0.
When m=1, n and v are set based on the value of bits 7 and 6 in memory.
When m=0, n and v are set based on the value of bits 15 and 14 in memory.
[Opcodes] [By Name] [By Category]
BMI
Branch on Minus
Jumps to the specified address when the Negative flag (n) is set.
n is set when ALU operations result in a negative number, or when the high bit of an ALU operation is 1.
A branch operation uses an 8 bit signed value internally, starting from the instruction after the branch. So the branch destination can be 126 bytes before or 128 bytes after the branch instruction.
[Opcodes] [By Name] [By Category]
BNE
Branch on Not Equal.
Jumps to the target address when the Zero flag is 0. While this is most commonly used after a compare (CMP) operation, it's also useful to test if a number is zero after a Load operation, or to test if a loop is complete after a DEC operation.
A branch operation uses an 8 bit signed value internally, starting from the instruction after the branch. So the branch destination can be 126 bytes before or 128 bytes after the branch instruction.
[Opcodes] [By Name] [By Category]
BPL
Branch on Plus
Jumps to the specified address when the Negative flag (n) is clear.
n is clear when ALU operations result in a positive number, or when the high bit of an ALU operation is 0.
A branch operation uses an 8 bit signed value internally, starting from the instruction after the branch. So the branch destination can be 126 bytes before or 128 bytes after the branch instruction.
[Opcodes] [By Name] [By Category]
BRA
Branch Always
Jumps to the specified address.
A branch operation uses an 8 bit signed value internally, starting from the instruction after the branch. So the branch destination can be 126 bytes before or 128 bytes after the branch instruction.
[Opcodes] [By Name] [By Category]
BRK
Break
Perform a break interrupt. The exact behavior changes slightly, based on whether the CPU is in native or emulation mode. (e is 1 in emulation mode.)
Since the Program Counter is incremented
In emulation mode:
- .PC (Program Counter) is incremented by 1 byte.
- If the CPU is in Native mode, the Program Bank is pushed to the stack.
- .PC is pushed onto the stack.
- .P (flags) is pushed to the stack. (the b bit, bit 4, is set to 1.)
- The d (Decimal) flag is cleared, forcing the CPU into binary mode.
- The CPU reads the address from the IRQ vector at $FFFE and jumps there.
An IRQ is similar, except that IRQ clears bit 4 (b) during the push to the stack. So an Interrupt Service Routine can read the last byte on the stack to determine whether an emulation-mode interrupt is a BRK or IRQ.
On the X16, the IRQ services the keyboard, mouse, game pads, updates the clock, blinks the cursor, and updates the LEDs.
In native mode:
- .PC is incremented by 1 byte.
- .X (Program Bank) is pushed the stack
- .PC is pushed to the stack
- .P (flags) is pushed to the stack
- The d (Decimal) flag is cleared, forcing the CPU into binary mode.
- The CPU reads the address from the BRK vector at $00FFE6 and jumps there.
Since the Native Mode has a distinct BRK vector, you do not need to query the stack to dispatch a BRK vs IRQ interrupt. You can just handle each immediately.
The RTI instruction is used to return from an interrupt. It pulls the values back off the stack (this varies, depending on the CPU mode) and returns to the pushed PC address.
RTI
See the Vectors section for the break vector.
[Opcodes] [By Name] [By Category]
BRL
Branch Long
BRL is a 16 bit branch instruction, meaning assembly creates a relative address. Unlike BRA and the other branch instructions, BRL uses a 16-bit address, which allows for an offset of -32768 to 32767 bytes away from the instruction following The BRL.
Of course, due to wrapping of the 64K bank, this means that the entire 64K region is accessible. Values below 0 will simply wrap around and start from $FFFF, and values above $FFFF will wrap around to 0.
Since this is a relatve branch, that means code assembled with BRL, instead of JMP, can be moved around in memory without the need for re-assembly.
[Opcodes] [By Name] [By Category]
BVC
Branch on Overflow Clear
Branches to the specified address when the Overflow bit is 0.
A branch operation uses an 8 bit signed value internally, starting from the instruction after the branch. So the branch destination can be 126 bytes before or 128 bytes after the branch instruction.
[Opcodes] [By Name] [By Category]
BVS
Branch on Overflow Set
Branches to the specified address when the Overflow bit is 1.
A branch operation uses an 8 bit signed value internally, starting from the instruction after the branch. So the branch destination can be 126 bytes before or 128 bytes after the branch instruction.
[Opcodes] [By Name] [By Category]
CLC
Clear Carry
Clears the Carry bit in the flags. You'll usually use CLC before addition and SEC before subtraction. You'll also want to use CLC or SEC appropriately before calling certain KERNAL routines that use the c bit as an input value.
[Opcodes] [By Name] [By Category]
CLD
Clear Decimal
Clears the Decimal flag, returning the CPU to 8-bit or 16-bit binary operation.
When Decimal is set, the CPU will store numbers in Binary Coded Decimal format. Clearing this flag restores the CPU to binary operation. See Decimal Mode for more information.
[Opcodes] [By Name] [By Category]
CLI
Clear Interrupt Flag
Clears the i flag, allowing interrupts to be handled.
The i flag operates somewhat non-intuitively: when i is set (1), IRQ is suppressed. When i is clear (0), interrupts are handled. So CLI allows interrupts to be handled.
See [BRK}(#brk) for more information on interrupt handling.
[Opcodes] [By Name] [By Category]
CLV
Clear Overflow
Overflow is set when the result of an addition operation goes up through $80 or subtraction goes down through $80.
CLV clears the overflow flag. There is no "SEV" instruction, but overflow can be set with SEP #$40.
[Opcodes] [By Name] [By Category]
CMP
Compare
SYNTAX MODE HEX LEN CYCLES FLAGS
CMP #$20/#$1234 imm C9 3-m 3-m n.....zc .
CMP $20 dir C5 2 4-m+w n.....zc .
CMP $20,X dir,X D5 2 5-m+w n.....zc .
CMP $20,S stk,S C3 2 5-m n.....zc .
CMP $1234 abs CD 3 5-m n.....zc .
CMP $1234,X abs,X DD 3 6-m-x+x*p n.....zc .
CMP $1234,Y abs,Y D9 3 6-m-x+x*p n.....zc .
CMP $FEDBCA long CF 4 6-m n.....zc .
CMP $FEDCBA,X long,X DF 4 6-m n.....zc .
CMP ($20) (dir) D2 2 6-m+w n.....zc .
CMP ($20),Y (dir),Y D1 2 7-m+w-x+x*p n.....zc .
CMP ($20,X) (dir,X) C1 2 7-m+w n.....zc .
CMP ($20,S),Y (stk,S),Y D3 2 8-m n.....zc .
CMP [$20] [dir] C7 2 7-m+w n.....zc .
CMP [$20],Y [dir],Y D7 2 7-m+w n.....zc .
Compares the Accumulator with memory. This performs a subtract operation between .A and the operand and sets the n, z, and c flags based on the result. The Accumulator is not altered.
- WHen A = Operand, z is set.
- When A < Operand, c is clear.
- When A <> Operand, z is clear.
- When A >= Operand, c is set.
You can use the Branch instructions (BEQ, BNE, BPL, BMI, BCC, BCS) to jump to different parts of your program based on the results of CMP. Here are some BASIC comparisons and the equivalent assembly language steps.
; IF A = N THEN 1000
CMP N
BEQ $1000
; IF A <> N THEN 1000
CMP N
BNE $1000
; IF A < N THEN 1000
CMP N
BCC $1000
; IF A >= N THEN 1000
CMP N
BCS $1000
; IF A > N THEN 1000
CMP N
BEQ skip
BCS $1000
skip:
; IF A <= N THEN 1000
CMP N
BEQ $1000
BCC $1000
As you can see, some comparisons will require two distinct branch instructions.
Also, note that the Branch instructions (except BRL) require that the target address be within 128 bytes of the instruciton after the branch. If you need to branch further, the usual method is to invert the branch instruction and use a JMP to take the branch.
For example, the following two branches behave the same, but the second one can jump to any address on the computer, whereas the first can only jump -128/+127 bytes away:
[Opcodes] [By Name] [By Category]
COP
COP interrupt.
COP is similar to BRK, but uses the FFE4 or FFF4 vectors. The intent is to COP is to switch to a Co-Processor, but this can be used for any purpose on the X16 (including triggering a DMA controller, if that's what you want to do.)
[Opcodes] [By Name] [By Category]
CPX
Compare X Register
SYNTAX MODE HEX LEN CYCLES FLAGS
CPX #$20/#$1234 imm E0 3-x 3-x n.....zc .
CPX $20 dir E4 2 4-x+w n.....zc .
CPX $1234 abs EC 3 5-x n.....zc .
This compares the X register to an operand and sets the flags accordingly.
See CMP for more information.
[Opcodes] [By Name] [By Category]
CPY
Compare Y Register
SYNTAX MODE HEX LEN CYCLES FLAGS
CPY #$20/#$1234 imm C0 3-x 3-x n.....zc .
CPY $20 dir C4 2 4-x+w n.....zc .
CPY $1234 abs CC 3 5-x n.....zc .
This compares the Y register to an operand and sets the flags accordingly.
See CMP for more information.
[Opcodes] [By Name] [By Category]
DEC
Decrement
SYNTAX MODE HEX LEN CYCLES FLAGS
DEC acc 3A 1 2 n.....z. .
DEC $20 dir C6 2 7-2*m+w n.....z. .
DEC $20,X dir,X D6 2 8-2*m+w n.....z. .
DEC $1234 abs CE 3 8-2*m n.....z. .
DEC $1234,X abs,X DE 3 9-2*m n.....z. .
Decrement .A or memory. The z flag is set when the value reaches zero. This makes DEC, DEX, and DEY useful as a loop counter, by setting the number of iterations, the repeated operation, then DEX followed by BNE.
z is set when the counter reaches zero. n is set when the high bit gets set.
[Opcodes] [By Name] [By Category]
DEX
Decrement .X
Decrement .X The z flag is set when the value reaches zero. This makes DEC, DEX, and DEY useful as a loop counter, by setting the number of iterations, the repeated operation, then DEX followed by BNE.
z is set when the counter reaches zero. n is set when the high bit gets set.
[Opcodes] [By Name] [By Category]
DEY
Decrement .Y
Decrement .X The z flag is set when the value reaches zero. This makes DEC, DEX, and DEY useful as a loop counter, by setting the number of iterations, the repeated operation, then DEX followed by BNE.
z is set when the counter reaches zero. n is set when the high bit gets set.
[Opcodes] [By Name] [By Category]
EOR
Exclusive OR
SYNTAX MODE HEX LEN CYCLES FLAGS
EOR #$20/#$1234 imm 49 3-m 3-m n.....z. .
EOR $20 dir 45 2 4-m+w n.....z. .
EOR $20,X dir,X 55 2 5-m+w n.....z. .
EOR $20,S stk,S 43 2 5-m n.....z. .
EOR $1234 abs 4D 3 5-m n.....z. .
EOR $1234,X abs,X 5D 3 6-m-x+x*p n.....z. .
EOR $1234,Y abs,Y 59 3 6-m-x+x*p n.....z. .
EOR $FEDBCA long 4F 4 6-m n.....z. .
EOR $FEDCBA,X long,X 5F 4 6-m n.....z. .
EOR ($20) (dir) 52 2 6-m+w n.....z. .
EOR ($20),Y (dir),Y 51 2 7-m+w-x+x*p n.....z. .
EOR ($20,X) (dir,X) 41 2 7-m+w n.....z. .
EOR ($20,S),Y (stk,S),Y 53 2 8-m n.....z. .
EOR [$20] [dir] 47 2 7-m+w n.....z. .
EOR [$20],Y [dir],Y 57 2 7-m+w n.....z. .
Perform an Exclusive OR operation with the operand and .A
EOR compares each bit of the operands and sets the result bit to 1 if one of the two bits is 1. If both bits are 1, the result is 0. If both bits are 0, the result is 0.
EOR is useful for inverting the bits in a byte. EOR #$FF
will flip an entire
byte. (This will always flip the low byte in .A. To flip both bytes when m
is 0, you would use EOR #$FFFF
.)
Truth table for EOR:
[Opcodes] [By Name] [By Category]
INC
Increment
SYNTAX MODE HEX LEN CYCLES FLAGS
INC acc 1A 1 2 n.....z. .
INC $20 dir E6 2 7-2*m+w n.....z. .
INC $20,X dir,X F6 2 8-2*m+w n.....z. .
INC $1234 abs EE 3 8-2*m n.....z. .
INC $1234,X abs,X FE 3 9-2*m n.....z. .
Increment .A or memory
Adds 1 to the value in .A or the specified memory address. The n and z flags are set, based on the resultant value.
INC is useful for reading strings and operating on large areas of memory, especially with indirect and indexed addressing modes.
[Opcodes] [By Name] [By Category]
INX
Increment .X
Increment the X register.
The following routine prints a null-terminated string (a should be 1.)
See [INC}(#inc)
[Opcodes] [By Name] [By Category]
INY
Increment .Y
Increment the Y register.
See [INC}(#inc)
[Opcodes] [By Name] [By Category]
JMP
Jump
SYNTAX MODE HEX LEN CYCLES FLAGS
JMP $2034 abs 4C 3 3 ........ .
JMP ($2034) (abs) 6C 3 5 ........ .
JMP ($2034,X) (abs,X) 7C 3 6 ........ .
Jump to a differnent address in memory, continuing program execution at the specified address.
Instructions like JMP ($1234,X)
make it possible to branch to a selectable
subroutine by setting X to the indesx into the vector table.
[Opcodes] [By Name] [By Category]
JML
Jump Long
SYNTAX MODE HEX LEN CYCLES FLAGS
JML $FEDCBA long 5C 4 4 ........ .
JMP [$2034] [abs] DC 3 6 ........ .
Jump to a differnent address in memory, continuing program execution at the specified address. JML accepts a 24-bit address, allowing the program to change program banks.
[Opcodes] [By Name] [By Category]
JSL
Jmp to Subroutine Long
This is a 24-bit instruction, which can jump to a subroutine located in another program bank.
Use the RTL instruction to return to the instruction following the JSL.
[Opcodes] [By Name] [By Category]
JSR
Jump to Subroutine
SYNTAX MODE HEX LEN CYCLES FLAGS
JSR $2034 abs 20 3 6 ........ .
JSR ($2034,X) (abs,X) FC 3 8 ........ .
Jumps to a new operating address in memory. Also pushes the return address to the stack, allowing an RTS insruction to pick up at the address following the JSR.
The RTS instruction returns to the instruction following JSR.
The actual address pushed to the stack is the before the next instruction. This means that the CPU still needs to increment the PC by 1 step during the RTS.
[Opcodes] [By Name] [By Category]
LDA
Load Accumulator
SYNTAX MODE HEX LEN CYCLES FLAGS
LDA #$20/#$1234 imm A9 3-m 3-m n.....z. .
LDA $20 dir A5 2 4-m+w n.....z. .
LDA $20,X dir,X B5 2 5-m+w n.....z. .
LDA $20,S stk,S A3 2 5-m n.....z. .
LDA $1234 abs AD 3 5-m n.....z. .
LDA $1234,X abs,X BD 3 6-m-x+x*p n.....z. .
LDA $1234,Y abs,Y B9 3 6-m-x+x*p n.....z. .
LDA $FEDBCA long AF 4 6-m n.....z. .
LDA $FEDCBA,X long,X BF 4 6-m n.....z. .
LDA ($20) (dir) B2 2 6-m+w n.....z. .
LDA ($20),Y (dir),Y B1 2 7-m+w-x+x*p n.....z. .
LDA ($20,X) (dir,X) A1 2 7-m+w n.....z. .
LDA ($20,S),Y (stk,S),Y B3 2 8-m n.....z. .
LDA [$20] [dir] A7 2 7-m+w n.....z. .
LDA [$20],Y [dir],Y B7 2 7-m+w n.....z. .
Reads a value from memory into .A. This sets n and z appropriately, allowing you to use BMI, BPL, BEQ, and BNE to act based on the value being read.
[Opcodes] [By Name] [By Category]
LDX
Load X Register
SYNTAX MODE HEX LEN CYCLES FLAGS
LDX #$20/#$1234 imm A2 3-x 3-x n.....z. .
LDX $20 dir A6 2 4-x+w n.....z. .
LDX $20,Y dir,Y B6 2 5-x+w n.....z. .
LDX $1234 abs AE 3 5-x n.....z. .
LDX $1234,Y abs,Y BE 3 6-2*x+x*p n.....z. .
Read a value into .X. This sets n and z appropriately, allowing you to use BMI, BPL, BEQ, and BNE to act based on the value being read.
[Opcodes] [By Name] [By Category]
LDY
Load X Register
SYNTAX MODE HEX LEN CYCLES FLAGS
LDY #$20/#$1234 imm A0 3-x 3-x n.....z. .
LDY $20 dir A4 2 4-x+w n.....z. .
LDY $20,X dir,X B4 2 5-x+w n.....z. .
LDY $1234 abs AC 3 5-x n.....z. .
LDY $1234,X abs,X BC 3 6-2*x+x*p n.....z. .
Read a value into .Y. This sets n and z appropriately, allowing you to use BMI, BPL, BEQ, and BNE to act based on the value being read.
[Opcodes] [By Name] [By Category]
LSR
Logical Shift Right
SYNTAX MODE HEX LEN CYCLES FLAGS
LSR acc 4A 1 2 n.....zc .
LSR $20 dir 46 2 7-2*m+w n.....zc .
LSR $20,X dir,X 56 2 8-2*m+w n.....zc .
LSR $1234 abs 4E 3 8-2*m n.....zc .
LSR $1234,X abs,X 5E 3 9-2*m n.....zc .
Shifts all bits to the right by one position.
Bit 0 is shifted into Carry.; 0 shifted into the high bit (7 or 15, depending on the m flag.)
Similar instructions:; ASL is the opposite instruction, shifting to the left.; ROR rotates bit 0 through Carry to bit 7.;
+p Adds a cycle if ,X crosses a page boundary.; +c New for the 65C02;
[Opcodes] [By Name] [By Category]
MVN
Block Copy/Move Negative
This performs a block copy. Use MVN when the source and destination ranges overlap and dest < source.
Copying anything other than page zero requires 16-bit index registers, so it's
wise to clear m and x with REP #$30
.
- Set .X to the source address
- Set .Y to the destination address
- Set .A to size-1
- MVN #source_bank, #dest_bank
[Opcodes] [By Name] [By Category]
MVP
Block Copy/Move Positive
This performs a block copy. Use MVP when the source and destination ranges overlap and dest > source.
Copying anything other than page zero requires 16-bit index registers, so it's
wise to clear m and x with REP #$30
.
- Set .X to the source_address + size - 1
- Set .Y to the destination_address
- Set .A to size-1
- MVP #source_bank, #dest_bank
[Opcodes] [By Name] [By Category]
NOP
No Operation
The CPU performs no operation. This is useful when blocking out instructions, or reserving space for later use.
[Opcodes] [By Name] [By Category]
ORA
Boolean OR
SYNTAX MODE HEX LEN CYCLES FLAGS
ORA #$20/#$1234 imm 09 3-m 3-m n.....z. .
ORA $20 dir 05 2 4-m+w n.....z. .
ORA $20,X dir,X 15 2 5-m+w n.....z. .
ORA $20,S stk,S 03 2 5-m n.....z. .
ORA $1234 abs 0D 3 5-m n.....z. .
ORA $1234,X abs,X 1D 3 6-m-x+x*p n.....z. .
ORA $1234,Y abs,Y 19 3 6-m-x+x*p n.....z. .
ORA $FEDBCA long 0F 4 6-m n.....z. .
ORA $FEDCBA,X long,X 1F 4 6-m n.....z. .
ORA ($20) (dir) 12 2 6-m+w n.....z. .
ORA ($20),Y (dir),Y 11 2 7-m+w-x+x*p n.....z. .
ORA ($20,X) (dir,X) 01 2 7-m+w n.....z. .
ORA ($20,S),Y (stk,S),Y 13 2 8-m n.....z. .
ORA [$20] [dir] 07 2 7-m+w n.....z. .
ORA [$20],Y [dir],Y 17 2 7-m+w n.....z. .
Perform a Boolean OR operation with the operand and .A
ORA compares each bit of the operands and sets the result bit to 1 if either or both of the two bits is 1. If both bits are 0, the result is 0.
ORA is useful for setting a specific bit in a byte.
Truth table for ORA:
[Opcodes] [By Name] [By Category]
PEA
Push Absolute
PEA, PEI, and PER push values to the stack without affecting registers.
PEA pushes the operand value onto the stack. The literal operand is used, rather than an address.
This seems inconsistent with the absolute address syntax, as PEA and PEI follow their own syntax rules.
[Opcodes] [By Name] [By Category]
PEI
Push Effecive Indirect Address
PEI takes a pointer as an operand. The value written to the stack is the two bytes at the supplied address.
Example:
The written form of PEI is inconsistent with the usual indirect mode syntax, as PEI and PEA follow their own syntax rules.
[Opcodes] [By Name] [By Category]
PER
Push Effective PC Relative Indirect Address
PER pushes the address relative to the program counter. This allows you to mark the current executing location and push that to the stack.
When used in conjunctin with BRL, PER can form a reloatable JSR instruction.
Consider the following ca65 macro:
This gets the address following the BRL instruction and pushes that to the stack. See JSR to understand why the -1 is required.
[Opcodes] [By Name] [By Category]
PHA
Push Accumulator
Pushes the Accumulator to the stack. This will push 1 byte when m is 1 and two bytes when m is 0 (16-bit memory/.A mode.)
An 8-bit stack push writes data at the Stack Pointer address, then moves SP down by 1 byte.
A 16-bit push writes the high byte first, decrements the PC, then writes the low byte, and decrements the PC again.
In Emulation mode, the Stack Pointer will always be an address in the $100-$1FF range, so there is only room for 256 bytes on the stack. In native mode, the stack can be anywhere in the first 64KB of RAM.
[Opcodes] [By Name] [By Category]
PHB
Push Data Bank register.
The data bank register sets the top 8 bits used when reading data with LDA, LDX, and LDY.
This is always an 8-bit operation.
[Opcodes] [By Name] [By Category]
PHD
Push Direct Page
Pushes the 16-bit Direct Page register to the stack. This is useful for preserving the location of .D before relocating Direct Page for another use (such as an operating system routine.)
[Opcodes] [By Name] [By Category]
PHK
Push Program Bank
Pushes the Program Bank register to the stack. The Program Bank is the top 8 bits of the 24-bit Program Counter address.
[Opcodes] [By Name] [By Category]
PHP
Push Program Status (Flags)
The CPU writes the flags in the order nvmx dizc
. (e does
not get written to the stack.)
Note: the 6502 and 65C02 use bit 4 (x on the '816) for the Break flag. While b does get written to the stack in a BRK operation, bit 4 in .P always reflects the state of the 8-bit-index flag. Since the flags differ slightly in behavior, make sure your Interrupt handler code reads from the stack, not the .P bits, when dispatching a IRQ/BRK interrupt.
[Opcodes] [By Name] [By Category]
PHX
Push X Register
Pushes the X register to the stack. This will push 1 byte when x is 1 and two bytes when x is 0 (16-bit index mode.)
An 8-bit stack push writes data at the Stack Pointer address, then moves SP down by 1 byte. A 16-bit stack push moves the stack pointer down 2 bytes.
[Opcodes] [By Name] [By Category]
PHY
Push Y Register
Pushes the Y register to the stack. This will push 1 byte when y is 1 and two bytes when y is 0 (16-bit index mode.)
An 8-bit stack push writes data at the Stack Pointer address, then moves SP down by 1 byte. A 16-bit stack push moves the stack pointer down 2 bytes.
[Opcodes] [By Name] [By Category]
PLA
Pull Accumulator
Pulls the Accumulator from the stack.
In the opposite of PHA, the PLA instruction reads the current value from the stack and increments the stack pointer by 1 or 2 bytes.
The number of bytes read is based on the value of the m flag.
[Opcodes] [By Name] [By Category]
PLB
Pull Data Bank Register
Pull the Data Bank register from the stack.
In the opposite of PHB, the PLB instruction reads the current value from the stack and increments the stack pointer by 1 byte.
[Opcodes] [By Name] [By Category]
PLD
Pull Direct Page Register
This pulls a word from the stack and loads it into the Direct Page register.
That value can be placed on the stack in several ways, such as PHA, PHX, or PEA.
[Opcodes] [By Name] [By Category]
PLP
Pull Prgram Status Byte (flags)
This reads the flags back from the stack. Since the flags affect the state of the m and x register-width flags, this should be performed before a PLA, PLX, or PLY operation.
[Opcodes] [By Name] [By Category]
PLX
Pull X Register
Pulls the X Register from the stack.
In the opposite of PHX, the PLX instruction reads the current value from the stack and increments the stack pointer by 1 or 2 bytes.
The number of bytes read is based on the value of the x flag.
[Opcodes] [By Name] [By Category]
PLY
Pull Y Register
Pulls the Y Register from the stack.
In the opposite of PHY, the PLY instruction reads the current value from the stack and increments the stack pointer by 1 or 2 bytes.
The number of bytes read is based on the value of the x flag.
[Opcodes] [By Name] [By Category]
REP
Reset Program Status Bit
This clears (to 0) flags in the Program Status Byte. The 1 bits in the will be cleared in the flags, so REP #$30 will set the a and x bits low.
[Opcodes] [By Name] [By Category]
ROL
Rotate Left
SYNTAX MODE HEX LEN CYCLES FLAGS
ROL acc 2A 1 2 n.....zc .
ROL $20 dir 26 2 7-2*m+w n.....zc .
ROL $20,X dir,X 36 2 8-2*m+w n.....zc .
ROL $1234 abs 2E 3 8-2*m n.....zc .
ROL $1234,X abs,X 3E 3 9-2*m n.....zc .
Shifts bits in the accumulator or memory left one bit. The Carry bit (c) is shifted into bit 0. The high bit (7 or 15) is shifted into c.
[Opcodes] [By Name] [By Category]
ROR
Rotate Right
SYNTAX MODE HEX LEN CYCLES FLAGS
ROR acc 6A 1 2 n.....zc .
ROR $20 dir 66 2 7-2*m+w n.....zc .
ROR $20,X dir,X 76 2 8-2*m+w n.....zc .
ROR $1234 abs 6E 3 8-2*m n.....zc .
ROR $1234,X abs,X 7E 3 9-2*m n.....zc .
Shifts bits in the accumulator or memory right one bit. The Carry bit (c) is shifted into the high bit (15 or 7). The low bit (0) is shifted into c.
[Opcodes] [By Name] [By Category]
RTI
Return From Interrupt
This returns control to the executing program. The following steps happen, in order:
- The CPU pulls the flags from the stack (including m and x, which switch to 8/16 bit mode, as appropriate.
- The CPU pulls the Program Counter from the stack.
- If the CPU is in native mode, the CPU pulls the Program Bank register.
[Opcodes] [By Name] [By Category]
RTL
Return From Subroutine Long
This returns to the caller at the end of a subroutine. This should be used to return to the instruction following a JSL instruction.
This reads 3 bytes from the stack and loads them into the Program Counter and Program Bank register. The next instruction executed will then be the instruction after the JSL that jumped to the subroutine.
[Opcodes] [By Name] [By Category]
RTS
Return From Subroutine
Return to to a calling routine after a JSR.
RTS reads a 2 byte address from the stack and loads that address into the Program Counter. The next instruction executed will then be the instruction after the JSR that jumped to the subroutine.
[Opcodes] [By Name] [By Category]
SBC
Subtract With Carry
SYNTAX MODE HEX LEN CYCLES FLAGS
SBC #$20/#$1234 imm E9 3-m 3-m nv....zc .
SBC $20 dir E5 2 4-m+w nv....zc .
SBC $20,X dir,X F5 2 5-m+w nv....zc .
SBC $20,S stk,S E3 2 5-m nv....zc .
SBC $1234 abs ED 3 5-m nv....zc .
SBC $1234,X abs,X FD 3 6-m-x+x*p nv....zc .
SBC $1234,Y abs,Y F9 3 6-m-x+x*p nv....zc .
SBC $FEDBCA long EF 4 6-m nv....zc .
SBC $FEDCBA,X long,X FF 4 6-m nv....zc .
SBC ($20) (dir) F2 2 6-m+w nv....zc .
SBC ($20),Y (dir),Y F1 2 7-m+w-x+x*p nv....zc .
SBC ($20,X) (dir,X) E1 2 7-m+w nv....zc .
SBC ($20,S),Y (stk,S),Y F3 2 8-m nv....zc .
SBC [$20] [dir] E7 2 7-m+w nv....zc .
SBC [$20],Y [dir],Y F7 2 7-m+w nv....zc .
Subtract a value from .A. The result is left in .A.
When performing subtraction, the Carry bit indicates a Borrow and operates in reverse from addition: when c is 0, SBC subtracts one from the final result, to account for the borrow.
After the operation, c will be set to 0 if a borrow took place and 1 if it did not.
When m is 0, this will be a 16 bit add, and the CPU will read two bytes from memory.
Since there is no "subtract with no carry", you should always use SEC before the first SBC in a sequence, to ensure that the Carry bit is set, going into a subtraction.
[Opcodes] [By Name] [By Category]
SEC
Set Carry
Sets the Carry bit to 1
[Opcodes] [By Name] [By Category]
SED
Set Decimal
Sets the Decimal bit to 1, setting the CPU to BCD mode.
When Decimal is set, the CPU will store numbers in Binary Coded Decimal format. Clearing this flag restores the CPU to binary operation. See Decimal Mode for more information.
In binary mode, adding 1 to $09 will set the Accumulator to $0A. In BCD mode, adding 1 to $09 will set the Accumulator to $10.
Using BCD allows for easier conversion of binary numbers to decimal. BCD also allows for storing decimal numbers without loss of precision due to power-of-2 rounding.
An add or subtract (ADC or SBC) is required to actually trigger BCD conversion.
So if you have a number like $1A on the accumulator and you SED, you can convert
.A to $20 with the instruction ADC #$00
.
[Opcodes] [By Name] [By Category]
SEI
Set IRQ Disable
Sets i, which inhibits IRQ handling. When i is set, the CPU will not respond to the IRQ pin. When i is clear, the CPU will perform an interrupt when the IRQ pin is asserted.
The i flag operates somewhat non-intuitively: when i is set (1), IRQ is suppressed. When i is clear (0), interrupts are handled. So CLI allows interrupts to be handled and SEI blocks interrupt handling.
See BRK for a brief description of interrupts.
[Opcodes] [By Name] [By Category]
SEP
Set Processor Status Bit
Reset Program Status Bit
This sets (to 1) a flag in the Program Status Byte. The operand value will be loaded into the flags, so SEP #$30 will set the a and x bits high.
[Opcodes] [By Name] [By Category]
STA
Store Accumulator to Memory
SYNTAX MODE HEX LEN CYCLES FLAGS
STA $20 dir 85 2 4-m+w ........ .
STA $20,X dir,X 95 2 5-m+w ........ .
STA $20,S stk,S 83 2 5-m ........ .
STA $1234 abs 8D 3 5-m ........ .
STA $1234,X abs,X 9D 3 6-m ........ .
STA $1234,Y abs,Y 99 3 6-m ........ .
STA $FEDBCA long 8F 4 6-m ........ .
STA $FEDCBA,X long,X 9F 4 6-m ........ .
STA ($20) (dir) 92 2 6-m+w ........ .
STA ($20),Y (dir),Y 91 2 7-m+w ........ .
STA ($20,X) (dir,X) 81 2 7-m+w ........ .
STA ($20,S),Y (stk,S),Y 93 2 8-m ........ .
STA [$20] [dir] 87 2 7-m+w ........ .
STA [$20],Y [dir],Y 97 2 7-m+w ........ .
Stores the value in .A to a memory address.
When m is 0, the value saved will be a 16-bit number, using two bytes of memory. When m is 1, the value will be an 8-bit number, using one byte of RAM.
[Opcodes] [By Name] [By Category]
STP
Stop the Clock
Halts the CPU. The CPU will no longer process instructions until the Reset pin is asserted.
[Opcodes] [By Name] [By Category]
STX
Store Index X to Memory
SYNTAX MODE HEX LEN CYCLES FLAGS
STX $20 dir 86 2 4-x+w ........ .
STX $20,Y dir,Y 96 2 5-x+w ........ .
STX $1234 abs 8E 3 5-x ........ .
Stores the value in .X to a memory address.
When the flag x is 0, the value saved will be a 16-bit number, using two bytes of memory. When x is 1, the value will be an 8-bit number, using one byte of RAM.
[Opcodes] [By Name] [By Category]
STY
Store Index Y to Memory
SYNTAX MODE HEX LEN CYCLES FLAGS
STY $20 dir 84 2 4-x+w ........ .
STY $20,X dir,X 94 2 5-x+w ........ .
STY $1234 abs 8C 3 5-x ........ .
Stores the value in .Y to a memory address.
When the flag x is 0, the value saved will be a 16-bit number, using two bytes of memory. When x is 1, the value will be an 8-bit number, using one byte of RAM.
[Opcodes] [By Name] [By Category]
STZ
Store Sero to Memory
SYNTAX MODE HEX LEN CYCLES FLAGS
STZ $20 dir 64 2 4-m+w ........ .
STZ $20,X dir,X 74 2 5-m+w ........ .
STZ $1234 abs 9C 3 5-m ........ .
STZ $1234,X abs,X 9E 3 6-m ........ .
Stores a zero to a memory address.
When m is 0, the value saved will be a 16-bit number, using two bytes of memory. When m is 1, the value will be an 8-bit number, using one byte of RAM.
[Opcodes] [By Name] [By Category]
TAX
Transfer Accumulator to Index X
Copies the contents of .A to .X.
[Opcodes] [By Name] [By Category]
TAY
Transfer Accumulator to Index Y
Copies the contents of .A to .Y.
[Opcodes] [By Name] [By Category]
TCD
Transfer C Accumulator to Direct Register
This copies the 16-bit value from the 16-bit Accumulator to the Direct Register, allowing you to relocate Direct Page anywhere in the first 64K of RAM.
This is one of the times that the 16-bit Accumulator is called .C, as it always operates on a 16-bit value, regardless of the state of the m flag.
[Opcodes] [By Name] [By Category]
TCS
Transfer C Accumulator to Stack Pointer
This copies the 16-bit value from the 16-bit Accumulator to the Stack Pointer, allowing you to relocate the stack anywhere in the first 64K of RAM.
This is one of the times that the 16-bit Accumulator is called .C, as it always operates on a 16-bit value, regardless of the state of the m flag.
[Opcodes] [By Name] [By Category]
TDC
Transfer Direct Register to C Accumulator
Copies the value of the Direct Register to the Accumulator.
This is one of the times that the 16-bit Accumulator is called .C, as it always operates on a 16-bit value, regardless of the state of the m flag.
[Opcodes] [By Name] [By Category]
TRB
Test and Reset Bit
SYNTAX MODE HEX LEN CYCLES FLAGS
TRB $20 dir 14 2 7-2*m+w ......z. .
TRB $1234 abs 1C 3 8-2*m ......z. .
TRB does two things with one operation: it tests specified bits in a memory location, and it clears (resets) those bits after the test.
First, TRB performs a logical AND between the memory address specified and the Accmulator. If the result of the AND is zero, the z flag will be set.
Second, TRB clears bits in the memory value based on the bit mask in the accmulator. Any bit that is 1 in .A will be changed to 0 in memory.
So to clear a bit in a memory value, set that value to 1 in .A, like this:
; memory at $2000 contains $84
LDA #$80
TRB $2000
; memory at $2000 now contains $04, and z flag is clear
; memory at $1234 contains $20
LDA #$01
TRB $1234
; memory at $1234 contains $20 and z flag is set
; because $20 AND $01 == 0.
[Opcodes] [By Name] [By Category]
TSB
Test and Set Bit
SYNTAX MODE HEX LEN CYCLES FLAGS
TSB $20 dir 04 2 7-2*m+w ......z. .
TSB $1234 abs 0C 3 8-2*m ......z. .
TSB does two things with one operation: it tests specified bits in a memory location, and it clears (resets) those bits after the test.
First, TSB performs a logical AND between the memory address specified and the Accmulator. If the result of the AND is zero, the z flag will be set.
TSB also sets the bits that are 1 in the accumulator, similar to an OR operation.
[Opcodes] [By Name] [By Category]
TSC
Transfer Stack Pointer to C accumulator
Copies the Stack Pointer to the 16-bit Accumulator.
This is one of the times that the 16-bit Accumulator is called .C, as it always operates on a 16-bit value, regardless of the state of the m flag.
[Opcodes] [By Name] [By Category]
TSX
Transfer Stack Pointer X Register
Copies the Stack Pointer to the X register.
[Opcodes] [By Name] [By Category]
TXA
Transfer X Register to Accumulator
Copies the value in .X to .A
[Opcodes] [By Name] [By Category]
TXS
Transfer X Register to Stack Pointer
Copies the X register to the Stack Pointer. This is used to reset the stack to a known location, usually at boot or when context-switching.
[Opcodes] [By Name] [By Category]
TXY
Transfer X Register to Accumulator
Copies the value in .X to .Y
[Opcodes] [By Name] [By Category]
TYA
Transfer Y Register to Accumulator
Copies the value in .Y to .A
[Opcodes] [By Name] [By Category]
TYX
Transfer Y Register to X Register
Copies the value in .Y to .X
[Opcodes] [By Name] [By Category]
WAI
Wait For Interrupt
Stops the CPU until the next interrupt is triggered. This allows the CPU to respond to an interrupt immediately, rather than waiting for an instruction to complete.
[Opcodes] [By Name] [By Category]
WDM
WDM
WDM is a 2 byte NOP: the WDM opcode and the operand byte following are both read, but not executed.
The WDM opcode is reserved for future use and should be avoided in 65C816 programs.
[Opcodes] [By Name] [By Category]
XBA
Exchange B and A Accumulator
Swaps the values in .A and .B. This exchanges the high and low bytes of the Accumulator. XBA functions the same in both 8 and 16 bit modes.
[Opcodes] [By Name] [By Category]
XCE
Exchange Carry and Emulation Flags
This allows the CPU to switch between Native and Emulation modes.
To switch into native mode:
To switch to 65C02 emulation mode:
[Opcodes] [By Name] [By Category]