How to read the tables
Operands are written in the NEC order, source first: ADD r1,r2 adds r1 to r2. imm5 is a 5-bit immediate (sign-extended for MOV, ADD and CMP,
a plain 0 to 31 for the shifts and TRAP); imm16 is sign-extended for MOVEA and ADDI and zero-extended for the logical instructions; disp16[r1] is the address r1 + disp16 with
the displacement sign-extended. The opcode column gives the 6-bit opcode in hexadecimal and its format (see formats). Flags: Z zero, S sign, OV overflow, CY carry;
“OV = 0” means the flag is cleared. A flag not listed is left alone. Clock counts are not given (no source was read). The operations are written in our words from the sources named on the overview.
Data movement and system registers
| Mnemonic | Operands | Opcode | Operation | Flags |
|---|---|---|---|---|
MOV | r1,r2imm5,r2 | 0x00 (I)0x10 (II) | Copy a register, or a sign-extended 5-bit constant, to r2 | none |
MOVEA | imm16,r1,r2 | 0x28 (V) | r2 = r1 + sign-extended imm16. With r1 = r0 it loads a constant from −32768 to 32767 | none |
MOVHI | imm16,r1,r2 | 0x2F (V) | r2 = r1 + (imm16 << 16). With MOVEA or ORI it builds a 32-bit constant | none |
SETF | cond,r2 | 0x12 (II) | r2 = 1 if the condition holds, else 0 (the condition codes are on the registers page) | none |
LDSR | r2,regID | 0x1C (II) | Load the system register numbered regID (the low 5 bits) from r2 | all, when regID is PSW |
STSR | regID,r2 | 0x1D (II) | Store the system register regID into r2 | none |
Arithmetic
| Mnemonic | Operands | Opcode | Operation | Flags |
|---|---|---|---|---|
ADD | r1,r2imm5,r2 | 0x01 (I)0x11 (II) | r2 = r2 + r1, or + a sign-extended 5-bit constant | Z S OV CY |
ADDI | imm16,r1,r2 | 0x29 (V) | r2 = r1 + sign-extended imm16 | Z S OV CY |
SUB | r1,r2 | 0x02 (I) | r2 = r2 - r1 | Z S OV CY |
CMP | r1,r2imm5,r2 | 0x03 (I)0x13 (II) | Set the flags of r2 - r1 (or minus a 5-bit constant); store nothing | Z S OV CY |
MUL | r1,r2 | 0x08 (I) | Signed 32 x 32 to 64 bits: the low word goes to r2, the high word to r30 (if r2 is r30 the low word wins). OV is set when the product does not fit in 32 bits | Z S OV (on the low word) |
MULU | r1,r2 | 0x0A (I) | Unsigned multiply, same registers. OV is set when the high word is not zero | Z S OV (on the low word) |
DIV | r1,r2 | 0x09 (I) | Signed divide: r2 = r2 / r1, r30 = the remainder. A zero divisor takes the zero-divide exception (0xFFFFFF80). 0x80000000 / -1 gives 0x80000000 with OV set | Z S OV |
DIVU | r1,r2 | 0x0B (I) | Unsigned divide, same registers and exception | Z S, OV = 0 |
Logic
| Mnemonic | Operands | Opcode | Operation | Flags |
|---|---|---|---|---|
OR | r1,r2 | 0x0C (I) | r2 = r2 OR r1 | Z S, OV = 0 |
AND | r1,r2 | 0x0D (I) | r2 = r2 AND r1 | Z S, OV = 0 |
XOR | r1,r2 | 0x0E (I) | r2 = r2 XOR r1 | Z S, OV = 0 |
NOT | r1,r2 | 0x0F (I) | r2 = NOT r1 | Z S, OV = 0 |
ORI | imm16,r1,r2 | 0x2C (V) | r2 = r1 OR zero-extended imm16 | Z S, OV = 0 |
ANDI | imm16,r1,r2 | 0x2D (V) | r2 = r1 AND zero-extended imm16 | Z S, OV = 0 |
XORI | imm16,r1,r2 | 0x2E (V) | r2 = r1 XOR zero-extended imm16 | Z S, OV = 0 |
Shifts
The count is the low 5 bits of r1, or the 5-bit immediate. CY is the last bit shifted out (0 for a count of 0); OV is cleared.
| Mnemonic | Operands | Opcode | Operation | Flags |
|---|---|---|---|---|
SHL | r1,r2imm5,r2 | 0x04 (I)0x14 (II) | Logical shift left | Z S CY, OV = 0 |
SHR | r1,r2imm5,r2 | 0x05 (I)0x15 (II) | Logical shift right | Z S CY, OV = 0 |
SAR | r1,r2imm5,r2 | 0x07 (I)0x17 (II) | Arithmetic shift right: the sign bit is kept | Z S CY, OV = 0 |
Load, store, I/O and compare-and-exchange
The address is r1 + disp16 (the displacement sign-extended). Halfword and word accesses ignore the low address bits (the address is aligned down). All are format VI (four bytes).
IN and OUT behave like loads and stores on the Virtual Boy’s bus; they differ in the bus signals the CPU raises, which are not described here.
| Mnemonic | Operands | Opcode | Operation | Flags |
|---|---|---|---|---|
LD.B | disp16[r1],r2 | 0x30 | Load a byte, sign-extended | none |
LD.H | disp16[r1],r2 | 0x31 | Load a halfword, sign-extended | none |
LD.W | disp16[r1],r2 | 0x33 | Load a word | none |
ST.B | r2,disp16[r1] | 0x34 | Store the low byte of r2 | none |
ST.H | r2,disp16[r1] | 0x35 | Store the low halfword of r2 | none |
ST.W | r2,disp16[r1] | 0x37 | Store r2 | none |
IN.B | disp16[r1],r2 | 0x38 | Read a byte from an I/O address, zero-extended | none |
IN.H | disp16[r1],r2 | 0x39 | Read a halfword from an I/O address, zero-extended | none |
IN.W | disp16[r1],r2 | 0x3B | Read a word from an I/O address | none |
OUT.B | r2,disp16[r1] | 0x3C | Write the low byte of r2 to an I/O address | none |
OUT.H | r2,disp16[r1] | 0x3D | Write the low halfword of r2 to an I/O address | none |
OUT.W | r2,disp16[r1] | 0x3F | Write r2 to an I/O address | none |
CAXI | disp16[r1],r2 | 0x3A | Compare r2 with the word at the address (the flags of r2 - memory); if equal store r30 there, otherwise store the old value back; r2 = the old value. The bus is not locked | Z S OV CY |
Jumps and branches
Targets are relative to the address of the instruction itself. The displacement’s bit 0 is cleared in the target.
| Mnemonic | Operands | Opcode | Operation | Flags |
|---|---|---|---|---|
JMP | [r1] | 0x06 (I) | Jump to the address in r1. JMP [r31] (lp) is the usual return | none |
JR | disp26 | 0x2A (IV) | Jump to PC + the 26-bit signed displacement | none |
JAL | disp26 | 0x2B (IV) | r31 = the address after this 4-byte instruction, then jump to PC + the displacement | none |
Bcond | disp9 | 0x20–0x27 (III) | Branch to PC + the 9-bit signed displacement when the condition (bits 12 to 9) holds. The sixteen names are on the registers page: BV BL BE BNH BN BR BLT BLE BNV BNL BNE BH BP and BGE BGT | none |
NOP | none | 0x20–0x27 with condition 13 | The branch “never”: it does nothing. The displacement bits are ignored | none |
System instructions
| Mnemonic | Operands | Opcode | Operation | Flags |
|---|---|---|---|---|
CLI | none | 0x16 (II) | Clear PSW.ID: maskable interrupts are enabled (the Mednafen core calls it EI) | none |
SEI | none | 0x1E (II) | Set PSW.ID: maskable interrupts are disabled (Mednafen: DI) | none |
TRAP | imm5 | 0x18 (II) | Software exception: PC and PSW are saved in EIPC and EIPSW, ECR gets the code 0xFFA0 + imm5, and the CPU jumps to 0xFFFFFFA0 (imm5 0 to 15) or 0xFFFFFFB0 (16 to 31) | PSW changed |
RETI | none | 0x19 (II) | Return from an exception: if PSW.NP is set, PC and PSW come from FEPC and FEPSW, otherwise from EIPC and EIPSW | all (PSW is loaded) |
HALT | none | 0x1A (II) | Stop the CPU until an interrupt, an exception or a reset | none |
Not described
See the status page.