# CPUSim64 Instruction Set

The CPUSim64 instruction set has 32 instructions that operate on the 29 general purpose integer registers, 32 floating point registers, stack frame pointer, stack pointer, program counter and status register. Each instruction can have multiple numbers and types of operands as described in this document.

In the Operation columns below the description of the operation will use the operands in the same order that they appear in the Operands column. The `<-` or `->` symbols show the direction of data movement. For all but the `STORE` instructions the direction is into the first argument. If a register is listed such as `A` it means that the value in the register is used. If a register is listed in square brackets such as `[A]` it means that the value of `A` is taken as an address and the contents in that address are used. This is known as a memory reference. You will only see this in the Register Load/Store Instructions.

Because some instructions operate on integer registers or floating point registers and because some instructions support integer literals of differing sizes, the following table lists the symbols used in the Operands and Operation columns

Register Reference Symbols
Symbol | Description
--- | ---
R | Integer in r0-r28
A | Address in r0-r28, SF, SP or PC
F | Float in f0-f31
X | R or F
Y | A or F
O | R or C
Q | A, F or C
SF | Stack Frame
SP | Stack Pointer
PC | Program Counter
SR | Status Register (PZSO)

Integer Literal Symbols
Symbol | Description
--- | ---
Z | 4-bit condition code used for JUMP or CALL or port number 0-255 for IN and OUT
B | 8-bit signed integer
C0 | 12-bit signed integer
C1 | 56-bit signed integer
C2 | 42-bit signed integer
C3 | 28-bit signed integer
K | 64-bit signed integer
E | 64-bit IEEE float
P | 64-bit Absolute unsigned address

Condition Codes
Symbol | Value | Description | Other Interpretation
--- | --- | --- | ---
u | 0 | Unconditional | Any result
z or eq | 1 | Zero | Compare equivalent
nz or ne | 2 | Not zero | Compare not equivalent
n or lt | 3 | Negative | Compare less than
p or gt | 4 | Positive | Compare greater than
nn or ge | 5 | Not negative | Compare greater or equal
np or le | 6 | Not positive | Compare less or equal
o or inf | 7 | Overflow | Infinite
no or ninf | 8 | No overflow | Finite
pe | 9 | Parity even | None
po | 10 | Parity odd | None

### No-op/Debug

Does nothing but take up a CPU cycle. If debugging is turn on for the virtual CPU, then debugging information is printed.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
0 | NOP | N | Does nothing
0 | DEBUG | Y YY | Prints contents of 1-4 registers if debugging is enabled.
0 | DEBUG | AC CC | Dump memory from starting address for number of words (walk heap if operand 2 is neg)

## Register Load/Store Instructions

### Clear

Used to move zero into registers.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
1 | CLEAR | N X XX XXX XXXX | Clear all registers or 1-4 specific registers.

### Move (Register-to-Register)

`MOVE` is used to move data between registers. Conditional version moves the third operand into the destination register if the condition is met otherwise it moves the fourth operand.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
2 | MOVE | YY YC AAR AAC ACA ZYQQ | Y1 <- Y2 Y <- C A1 <- A2 + R A1 <- A2 + C A1 <- C + A2 if Z, Y <- Q1 else Y <- Q2

### Load (Memory-to-Register)

`LOAD` is used to move data from memory into registers.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
3 | LOAD | YC YA YAC YCA YCC YAR | Y <- [C] Y <- [A] Y <- [A + C] Y <- [C + A] Y <- [C + C] Y <- [A + R]

### Store (Register-to-Memory)

`STORE` is used to move data from registers into memory.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
4 | STORE | QC QA QAC QCA QCC QAR | Q -> [C] Q -> [A] Q -> [A + C] Q -> [C + A] Q -> [C + C] Q -> [A + R]

### Pop

This instruction moves the `SP` register up by one and then pulls the value now pointed to by the `SP`.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
5 | POP | N Y | SP = SP + 1; discard <- [SP] SP = SP + 1; Y <- [SP]

### Push

This instruction pushes the operand onto the stack at the current value of the `SP`. It then moves the `SP` down by one.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
6 | PUSH | Y C | Y -> [SP]; SP = SP - 1 C -> [SP]; SP = SP - 1

## Control Instructions

### Jump

The `JUMP` instruction branches control to the address specified by the operands. The conditional forms only branch if the `SR` condition specified is true.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
7 | JUMP | A C AC AR ZA ZC ZAC ZCA ZCC ZAR | PC <- A PC <- C PC <- A + C PC <- A + R if Z, PC <- A if Z, PC <- C if Z, PC <- A + C if Z, PC <- C + A if Z, PC <- C + C if Z, PC <- A + R

### Call

Before the operation listed in the table, all `CALL` instructions first perform the following actions: Push SP + 1 (Return Address), Push SF (Old Stack Frame) then set SF to SP.

    PC + 1 -> [SP]; SP = SP - 1
    SF -> [SP]; SP = SP - 1
    SF <- SP

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
8 | CALL | A C AC AR ZA ZC ZAC ZCA ZCC ZAR | PC <- A PC <- C PC <- A + C PC <- A + R if Z, PC <- A if Z, PC <- C if Z, PC <- A + C if Z, PC <- C + A if Z, PC <- C + C if Z, PC <- A + R

### Return

Returns from a `CALL`. `RETURN` resets the SP back to the SF which is where the SP was when the `CALL` started. Then pops the `SF` off the stack. Then pops the return address off the stack.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
9 | RETURN | N | SP <- SF SP = SP + 1; SF <- [SP] SP = SP + 1; PC <- [SP]

### Interrupt

The `INTERRUPT` instruction invokes the software interrupt specified by its integer argument. This effectively calls the operating system function associated with the interrupt and then returns.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
10 | INTERRUPT | R C ZR ZC | See List of Software Interrupts

### Stop

`STOP` halts execution of the virtual CPU.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
11 | STOP | N |

## Arithmetic Instructions

### Negate

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
12 | NEG | X | X <- -X

### Addition

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
13 | ADD | AR FX YC AAR FFX AAC FFC ACA FCF | A1 <- A1 + R F1 <- F1 + X Y1 <- Y1 + C A1 <- A2 + R F1 <- F2 + X A1 <- A2 + C F1 <- F2 + C A1 <- C + A2 F1 <- C + F2

### Subtraction

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
14 | SUB | AR FX YC AAR FFX AAC FFC ACA FCF | A1 <- A1 - R F1 <- F1 - X Y1 <- Y1 - C A1 <- A2 - R F1 <- F2 - X A1 <- A2 - C F1 <- F2 - C A1 <- C - A2 F1 <- C - F2

### Multiplication

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
15 | MULT | RR FX XC RRR FFX RRC FFC RCR FCF | R1 <- R1 * R2 F1 <- F1 * X X1 <- X1 * C R1 <- R2 * R3 F1 <- F2 * X R1 <- R2 * C F1 <- F2 * C R1 <- C * R2 F1 <- C * F2

### Division

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
16 | DIV | RR FX XC RRR FFX RRC FFC RCR FCF RRRR RRRC | R1 <- R1 / R F1 <- F1 / X X1 <- X1 / C R1 <- R2 / R F1 <- F2 / X R1 <- R2 / C F1 <- F2 / C R1 <- C / R2 F1 <- C / F2 R1 <- R3 / R4; R2 <- R3 % R4 R1 <- R3 / C; R2 <- R3 % C
16 | RECIP | F | F <- 1 / F

## Logical and Conditional Instructions

### Complement

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
17 | COMPL | R | R <- ~R

### Bitwise AND

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
18 | AND | RR RC RRR RRC | R1 <- R1 & R2 R1 <- R1 & C R1 <- R2 & R3 R1 <- R2 & C

### Bitwise OR

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
19 | OR | RR RC RRR RRC | R1 <- R1 | R2 R1 <- R1 | C R1 <- R2 | R3 R1 <- R2 | C

### Bitwise XOR

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
20 | XOR | RR RC RRR RRC | R1 <- R1 ^ R2 R1 <- R1 ^ C R1 <- R2 ^ R3 R1 <- R2 ^ C

### Test

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
21 | TEST | X | Sets SR based on X

### Compare

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
22 | CMP | AA AC FF | Sets SR based on A1 - A2 Sets SR based on A - C Sets SR based on F1 - F2

## Shift Instructions

### Logical & Arithmetic Left Shift

Shifts the bits in the integer register to the left. Zero bit(s) is always shifted in on the right. These can be used for either logical or arithmetic left shift. Arithmetic left shift is equivalent to multiplying by powers of 2, i.e x << 1 is equivalent to x * 2, x << 2 is equivalent to x * 4, x << 3 is equivalent to x * 8, etc.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
23 | LSHIFT | RR RC RRR RRC | R1 <- R1 << R2 R1 <- R1 << C R1 <- R2 << R3 R1 <- R2 << C

### Logical Right Shift

Shifts the bits in the integer register to the right. Zero bit(s) is always shifted in on the left.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
24 | RSHIFT | RR RC RRR RRC | R1 <- R1 >> R2 R1 <- R1 >> C R1 <- R2 >> R3 R1 <- R2 >> C

### Arithmetic Right Shift

Shifts the bits in the integer register to the right. Sign bit(s) is always shifted in on the right. This results in the equivalent of dividing a signed integer by powers of 2.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
25 | ARSHIFT | RR RC RRR RRC | R1 <- R1 >> R2 R1 <- R1 >> C R1 <- R2 >> R3 R1 <- R2 >> C

### Left Rotate

Shifts the bits in the integer register to the left. The high bit that is shifted off is shifted in on the right.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
26 | LROTATE | RR RC RRR RRC | R1 <- R1 << R2 R1 <- R1 << C R1 <- R2 << R3 R1 <- R2 << C

### Right Rotate

Shifts the bits in the integer register to the right. The low bit that is shifted off is shifted in on the left.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
27 | RROTATE | RR RC RRR RRC | R1 <- R1 >> R2 R1 <- R1 >> C R1 <- R2 >> R3 R1 <- R2 >> C

## I/O Instructions

Input and output instructions read/write a specified number of bytes to a port which can be a stream to the console if `STDIN`, `STDOUT` or `STDERR` are used for the port or to a file that has been opened.

I/O sizes are specified in `<system/io.def>` using the following symbols. The `CHAR` size is unique in that it refers to a UTF-8 sequence that encodes a single codepoint and is therefore a variable number of bytes.

Symbol | Size
--- | ---
CHAR | 0
BYTE | 1
SHORT | 2
WORD | 4
SINGLE | 4
DWORD | 8
LONG | 8
DOUBLE | 8

### Input

If the number of bytes requested can not be read, then status register bit for Overflow will be set.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
28 | IN | XZZ XRR XRZ XZR | X <- Read Z1 bytes from port Z2 X <- Read R1 bytes from port R2 X <- Read R bytes from port Z X <- Read Z bytes from port R

### Output

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
29 | OUT | QZZ QRR QRZ QZR | Write Z1 bytes to port Z2 <- Q Write R1 bytes to port R2 <- Q Write R bytes to port Z <- Q Write Z bytes to port R <- Q

### Pack

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
30 | PACK | RR RRRR | Combines two 16-bit values and stores the resulting low 32-bits into R1. Most significant bits are in R1. R1 <- R1R2 Combines four 8-bit values and stores the resulting low 32-bits into R1. Most significant bits are in R1. R1 <- R1R2R3R4

### Pack64

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
31 | PACK64 | RR RRRR | Combines two 32-bit values and stores the resulting 64-bits into R1. Most significant bits are in R1. R1 <- R1R2 Combines four 16-bit values and stores the resulting 64-bits into R1. Most significant bits are in R1. R1 <- R1R2R3R4

### Unpack

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
32 | UNPACK | RR RRRR | Breaks low 32-bits of R1 into two 16-bit values and stores the results across both registers. Most significant bits are in R1. R1 -> R1R2 Breaks low 32-bits of R1 into four 8-bit values and stores the results across all four registers. Most significant bits are in R1. R1 -> R1R2R3R4

### Unpack64

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
33 | UNPACK64 | RR RRRR | Breaks R1 into two 32-bit values and stores the results across both registers. Most significant bits are in R1. R1 -> R1R2 Breaks R1 into four 16-bit values and stores the results across all four registers. Most significant bits are in R1. R1 -> R1R2R3R4

### Endian Mode

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
35 | ENDIAN | RR RZ ZR ZZ | Sets I/O Port endian mode to big-endian or little-endian First operand is port [0-255] Second operand is mode (TRUE for little-endian, FALSE for big-endian)

## Protect Registers/Memory

### Save Registers

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
36 | Save | RR FF | Saves registers R1 through R2 to the stack. Saves registers F1 through F2 to the stack.

### Restore Registers

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
37 | Restore | RR FF | Restores registers R1 through R2 from the stack. Restores registers F1 through F2 from the stack.

### Compare and Set

Performs atomic set of a memory location. Only if the current value of the memory location matches the old value does it then set it to the new value. Sets status register bit Overflow if successful.

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
34 | CAS | RRAO CCAO RCAO CRAO | Atomic compare and set First operand is old value Second operand is new value Remaining arguments are address + offset. Sets overflow flag if successful.

### Protect Read-Only Memory

Opcode | Pneumonic | Operands | Operation
--- | --- | --- | ---
38 | ReadOnly | C1 | Protects memory addressed from SP through C1 as read-only memory. The Assembler will add a ReadOnly instruction at the beginning of your program that protects memory from 0 through `__DATA__`. Define label `__DATA__` at the beginning of your read-write data directives.