This is an old revision of the document!
ADC | Add with carry to A |
---|---|
SBC | Subtract with borrow from carry from A |
ASL | Shift left by one bit, aka multiply by 2 |
LSR | Shift right by one bit, aka divide by 2 |
INC/INX/INY | Increment, adds 1 |
DEC/DEX/DEY | Decrement, subtracts 1 |
There are no general multiply/divide instructions on the CPU. Super Metroid has a routine at $80:82D6 that (inaccurately–it's missing a carry) multiplies two 16-bit values (from A and Y) and stores a result in $05F1-$05F4.
AND | AND value with A |
---|---|
BIT | Test bits against A and set flags |
EOR | Exclusive-or (xor) value with A |
ORA | OR value with A |
TRB | NAND memory with A, but set Z flag as if it were BIT |
TSB | OR memory with A, but set Z flag as if it were BIT |
ROL | Rotate left, through carry |
ROR | Rotate right, through carry |
The rotate operations can be used like shift operations, for data that's bigger than the size of a register.
TRB/TSB oddly affect memory and not the A register. BIT does not affect the value in A.
BRA | Always branch |
---|---|
BCC / BCS | Branch if carry clear or set |
BVC / BVS | Branch if overflow clear or set |
BPL / BMI | Branch if minus flag clear or set |
BNE / BEQ | Branch if zero clear or set |
CMP/CPX/CPY | Compare value with A/Y/X and set flags |
I'm not sure if BRL (long branch) is useful, since it uses the same space as a JMP but can't always travel as far.
CMP does its work by subtracting the compared value from A, setting the flags, and throwing away the result. When the value and A were equal, the subtraction yields 0, and the Z flag is set. Which is why BEQ branches on Zero.
The Super Metroid engine occasionally returns single bits of information from subroutines via the carry flag. For example, whether a block should be treated as solid (SEC) or not (CLC) during touch/collision.
JSR - RTS | Jump to subroutine in the same bank - return from it |
---|---|
JSL - RTL | Jump to subroutine in any bank - return from it |
JMP | Go to address in the same bank |
JML | Go to address in any bank |
JSL-RTL use one extra instruction byte and one additional byte on the stack, compared to JSR-RTS.
What most other chips call “move,” the 65c816 calls “transfer.”
TAX | Accumulator (A) to X |
---|---|
TXA | X to Accumulator |
TAY | Accumulator to Y |
TYA | Y to Accumulator |
TXY | X to Y |
TYX | Y to X |
There are no memory/memory operations. Everything involving two values happens between memory and a register. Also, see the stack section for moving between registers and the stack.
LDA/LDX/LDY | Load from memory to A/X/Y register |
---|---|
STA/STX/STY | Store to memory from A/X/Y register |
STZ | Store zero to memory |
All of the PH* instructions have a corresponding PL*, except for PHK. The only way to affect the code segment is through JSL or JML.
PHP | Push processor flags (frequently before SEP/REP) |
---|---|
PHK | Push code bank |
PHB | Push data bank |
PHD | Push direct page register |
PHA/PHX/PHY | Push A/X/Y register |
PEA | Push address (may have to write PEA.w in xkas) |
Super Metroid occasionally does things like:
PHB : PHK : PLB : (a section of code) : PLB : RTL
This saves the data bank, then sets the data bank to the current code bank for the section of code. Finally, the original data bank is restored just before returning.
Another common sequence is:
PEA $8200 : PLB : PLB
This sets bank $82 as the data bank. PEA writes the stack so that it says $00 $82, making the first PLB set the data bank to $00, and the second one sets the intended $82.
CLC/CLD/CLI/CLV | Clear carry/decimal/interrupt/overflow |
---|---|
SEC/SED/SEI | Set carry/decimal/interrupt |
REP | Clear (reset) status bits |
SEP | Set status bits |
Interrupts are disabled when SEI is used, and allowed when CLI is used. NMIs, as usual, cannot be disabled.
Overflow can only be set by doing arithmetic that sets it, such as ADC, or using SEP.
80 | Negative (BPL/BMI) |
---|---|
40 | Overflow (BVC/BVS) |
20 | A register size: 0 for 16-bit, 1 for 8-bit |
10 | X/Y register size: 0 for 16-bit, 1 for 8-bit |
08 | Decimal mode, may not be emulated properly |
04 | IRQ Disable: 0 for enabled, 1 for disabled |
02 | Zero (BEQ/BNE) |
01 | Carry (BCC/BCS) |
The most common bits changed with SEP and REP in Super Metroid are $10 and $20 (sometimes combined as $30.) SEP changes the flags to 1, and REP changes them to 0, so REP #$30 sets 16-bit mode for A and X/Y.