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

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) |

Symbol | Description |
---|---|

Z | 4-bit condition code used for JUMP or CALL or port number 0-15 for IN and OUT |

B | 8-bit signed integer |

C1 | 56-bit signed integer |

C2 | 42-bit signed integer |

C | 40-bit signed integer |

K | 64-bit signed integer |

E | 64-bit IEEE float |

P | 64-bit Absolute unsigned address |

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) |

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`

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 |
Y_{1} <- Y_{2}Y <- C A _{1} <- A_{2} + RA _{1} <- A_{2} + CA _{1} <- C + A_{2}if Z, Y <- Q _{1} else Y <- Q_{2} |

`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`

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] |

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] |

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 |

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 ZA ZC ZAC ZCA ZCC ZAR | PC <- A PC <- C 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 |

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 ZA ZC ZAC ZCA ZCC ZAR | PC <- A PC <- C 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 |

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] |

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 | See List of Software Interrupts |

`STOP`

halts execution of the virtual CPU.

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

11 | STOP | N |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

12 | NEG | X | X <- -X |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

13 | ADD | AR FX YC AAR FFX AAC FFC ACA FCF | A_{1} <- A_{1} + RF _{1} <- F_{1} + XY _{1} <- Y_{1} + CA _{1} <- A_{2} + RF _{1} <- F_{2} + XA _{1} <- A_{2} + CF _{1} <- F_{2} + CA _{1} <- C + A_{2}F _{1} <- C + F_{2} |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

14 | SUB | AR FX YC AAR FFX AAC FFC ACA FCF | A_{1} <- A_{1} - RF _{1} <- F_{1} - XY _{1} <- Y_{1} - CA _{1} <- A_{2} - RF _{1} <- F_{2} - XA _{1} <- A_{2} - CF _{1} <- F_{2} - CA _{1} <- C - A_{2}F _{1} <- C - F_{2} |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

15 | MULT | AR FX YC AAR FFX AAC FFC ACA FCF | A_{1} <- A_{1} * RF _{1} <- F_{1} * XY _{1} <- Y_{1} * CA _{1} <- A_{2} * RF _{1} <- F_{2} * XA _{1} <- A_{2} * CF _{1} <- F_{2} * CA _{1} <- C * A_{2}F _{1} <- C * F_{2} |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

16 | DIV | AR FX YC AAR FFX AAC FFC ACA FCF RRRR RRRC | A_{1} <- A_{1} / RF _{1} <- F_{1} / XY _{1} <- Y_{1} / CA _{1} <- A_{2} / RF _{1} <- F_{2} / XA _{1} <- A_{2} / CF _{1} <- F_{2} / CA _{1} <- C / A_{2}F _{1} <- C / F_{2}R _{1} <- R_{3} / R_{4}; R_{2} <- R_{3} % R_{4}R _{1} <- R_{3} / C; R_{2} <- R_{3} % C |

16 | RECIP | F | F <- 1 / F |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

17 | COMPL | R | R <- ~R |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

18 | AND | RR RC RRR RRC | R_{1} <- R_{1} & R_{2}R _{1} <- R_{1} & CR _{1} <- R_{2} & R_{3}R _{1} <- R_{2} & C |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

19 | OR | RR RC RRR RRC | R_{1} <- R_{1} | R_{2}R _{1} <- R_{1} | CR _{1} <- R_{2} | R_{3}R _{1} <- R_{2} | C |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

20 | XOR | RR RC RRR RRC | R_{1} <- R_{1} ^ R_{2}R _{1} <- R_{1} ^ CR _{1} <- R_{2} ^ R_{3}R _{1} <- R_{2} ^ C |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

21 | TEST | X | Sets SR based on X |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

22 | CMP | AA AC FF | Sets SR based on A_{1} - A_{2}Sets SR based on A - C Sets SR based on F _{1} - F_{2} |

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 | R_{1} <- R_{1} << R_{2}R _{1} <- R_{1} << CR _{1} <- R_{2} << R_{3}R _{1} <- R_{2} << C |

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 | R_{1} <- R_{1} >> R_{2}R _{1} <- R_{1} >> CR _{1} <- R_{2} >> R_{3}R _{1} <- R_{2} >> C |

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 | R_{1} <- R_{1} >> R_{2}R _{1} <- R_{1} >> CR _{1} <- R_{2} >> R_{3}R _{1} <- R_{2} >> C |

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 | R_{1} <- R_{1} << R_{2}R _{1} <- R_{1} << CR _{1} <- R_{2} << R_{3}R _{1} <- R_{2} << C |

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 | R_{1} <- R_{1} >> R_{2}R _{1} <- R_{1} >> CR _{1} <- R_{2} >> R_{3}R _{1} <- R_{2} >> C |

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.

Symbol | Size |
---|---|

CHAR | 0 |

BYTE | 1 |

SHORT | 2 |

WORD | 4 |

SINGLE | 4 |

DWORD | 8 |

LONG | 8 |

DOUBLE | 8 |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

28 | IN | XZZ XRR XRZ XZR | X <- Read Z_{1} bytes from port Z_{2}X <- Read R _{1} bytes from port R_{2}X <- Read R bytes from port Z X <- Read Z bytes from port R |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

29 | OUT | ZZQ RRQ RZQ ZRQ | Write Z_{1} bytes to port Z_{2} <- QWrite R _{1} bytes to port R_{2} <- QWrite R bytes to port Z <- Q Write Z bytes to port R <- Q |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

30 | PACK | RR RRR RRRR |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

30 | PACK64 | RR RRR RRRR |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

31 | UNPACK | RR RRR RRRR |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

31 | UNPACK64 | RR RRR RRRR |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

32 | CAS | RRAO CCAO RCAO CRAO | Atomic compare and swap First operand is old value Second operand is new value Remaining arguments are address + offset |

Opcode | Pneumonic | Operands | Operation |
---|---|---|---|

33 | ENDIAN | RR RC CR CC | Sets I/O Port endian mode to big-endian or little-endian First operand is port [0-15] Second operand is mode (TRUE for big-endian, FALSE for little-endian) |