Skip to content

Files

Latest commit

368627b · Dec 31, 2024

History

History
1488 lines (1100 loc) · 70.1 KB

ISA.md

File metadata and controls

1488 lines (1100 loc) · 70.1 KB

Table of Contents

  1. Introduction
  2. Registers
    1. Status Register
  3. Programs
    1. Metadata Section
    2. Code Section
    3. Data Section
    4. Symbol Table
    5. Relocation Data Section
    6. Debug Data Section
  4. Directives
    1. %code
    2. %data
    3. %type
    4. %size
    5. %string
    6. %stringz
    7. %8b, %4b, %2b, %1b
    8. %align
    9. %fill
  5. Rings
  6. Interrupts
    1. SYSTEM
    2. TIMER
    3. PROTEC
    4. PFAULT
    5. INEXEC
    6. BWRITE
    7. KEYBRD
  7. Paging
  8. Instruction Format
    1. R-Type Instructions
    2. I-Type Instructions
    3. J-Type Instructions
    4. Linker Flags
    5. Condition Bits
  9. Operations
    1. Math (R-Types)
      1. Add (add)
      2. Subtract (sub)
      3. Multiply (mult)
      4. Multiply Unsigned (multu)
      5. Shift Left Logical (sll)
      6. Shift Right Logical (srl)
      7. Shift Right Arithmetic (sra)
      8. Modulo (mod)
      9. Divide (div)
      10. Divide Unsigned (divu)
      11. Modulo Unsigned (modu)
      12. Sign Extend 32 to 64 (sext32)
      13. Sign Extend 16 to 64 (sext16)
      14. Sign Extend 8 to 64 (sext8)
    2. Logic (R-Types)
      1. Bitwise AND (and)
      2. Bitwise NAND (nand)
      3. Bitwise NOR (nor)
      4. Bitwise NOT (not)
      5. Bitwise OR (or)
      6. Bitwise XNOR (xnor)
      7. Bitwise XOR (xor)
      8. Logical AND (land)
      9. Logical NAND (lnand)
      10. Logical NOR (lnor)
      11. Logical NOT (lnot)
      12. Logical OR (lor)
      13. Logical XNOR (lxnor)
      14. Logical XOR (lxor)
    3. Math (I-Types)
      1. Add Immediate (addi)
      2. Subtract Immediate (subi)
      3. Multiply Immediate (multi)
      4. Multiply Unsigned Immediate (multui)
      5. Shift Left Logical Immediate (slli)
      6. Shift Right Logical Immediate (srli)
      7. Shift Right Arithmetic Immediate (srai)
      8. Shift Left Logical Inverse Immediate (sllii)
      9. Shift Right Logical Inverse Immediate (srlii)
      10. Shift Right Arithmetic Inverse Immediate (sraii)
      11. Modulo Immediate (modi)
      12. Divide Immediate (divi)
      13. Divide Unsigned Immediate (divui)
      14. Divide Inverse Immediate (divii)
      15. Divide Unsigned Inverse Immediate (divuii)
      16. Modulo Unsigned Immediate (modui)
    4. Logic (I-Types)
      1. Bitwise AND Immediate (andi)
      2. Bitwise NAND Immediate (nandi)
      3. Bitwise NOR Immediate (nori)
      4. Bitwise OR Immediate (ori)
      5. Bitwise XNOR Immediate (xnori)
      6. Bitwise XOR Immediate (xori)
    5. Comparisons (R-Types)
      1. Compare (cmp)
      2. Set on Less Than (sl)
      3. Set on Less Than or Equal (sle)
      4. Set on Equal (seq)
      5. Set on Greater Than or Equal (sge)
      6. Set on Greater Than (sg)
      7. Set on Less Than Unsigned (slu)
      8. Set on Less Than or Equal Unsigned (sleu)
      9. Set on Greater Than or Equal Unsigned (sgeu)
      10. Set on Greater Than Unsigned (sgu)
    6. Comparisons (I-Types)
      1. Compare Immediate (cmpi)
      2. Set on Less Than Immediate (sli)
      3. Set on Less Than or Equal Immediate (slei)
      4. Set on Equal Immediate (seqi)
      5. Set on Greater Than or Equal Immediate (sgei)
      6. Set on Greater Than Immediate (sgi)
      7. Set on Less Than Unsigned Immediate (slui)
      8. Set on Less Than or Equal Unsigned Immediate (sleui)
      9. Set on Greater Than or Equal Unsigned Immediate (sgeui)
      10. Set on Greater Than Unsigned Immediate (sgui)
    7. Jumps (J-Types)
      1. Jump (j)
      2. Jump Conditional (jc)
    8. Jumps (R-Types)
      1. Jump to Register (jr)
      2. Jump to Register Conditional (jrc)
      3. Jump to Register and Link (jrl)
      4. Jump to Register and Link Conditional (jrlc)
    9. Memory (R-Types)
      1. Copy (c)
      2. Load (l)
      3. Store (s)
      4. Copy Byte (cb)
      5. Load Byte (lb)
      6. Store Byte (sb)
      7. Copy Halfword (ch)
      8. Load Halfword (lh)
      9. Store Halfword (sh)
      10. Copy Short (cs)
      11. Load Short (ls)
      12. Store Short (ss)
      13. Stack Push (spush)
      14. Stack Pop (spop)
      15. Memset (ms)
      16. Translate Address (trans)
    10. Memory (I-Types)
      1. Load Immediate (li)
      2. Store Immediate (si)
      3. Load Indirect Immediate (lni)
      4. Load Byte Immediate (lbi)
      5. Store Byte Immediate (sbi)
      6. Load Byte Indirect Immediate (lbni)
      7. Set (set)
      8. Load Upper Immediate (lui)
      9. Sized Stack Push (sspush)
      10. Sized Stack Pop (sspop)
      11. Spill Store (sps)
      12. Spill Load (spl)
    11. Special Instructions
      1. External (ext)
      2. Select (sel)
      3. Interrupt (int)
      4. Register Interrupt Table (rit)
      5. Set Timer (time)
      6. Set Timer Immediate (timei)
      7. Save Timer (svtime)
      8. Change Ring (ring)
      9. Save Ring (svring)
      10. Change Ring Immediate (ringi)
      11. Disable Paging (pgoff)
      12. Enable Paging (pgon)
      13. Set Page Table (setpt)
      14. Save Paging (svpg)
      15. Query Memory (qm)
      16. Disable Interrupts (di)
      17. Enable Interrupts (ei)
      18. Push Paging (ppush)
      19. Pop Paging (ppop)
    12. Pseudoinstructions
      1. Move (mv)
      2. Return (ret)
      3. Push (push)
      4. Pop (pop)
      5. Jump if Equal (jeq)
  10. Externals
    1. Print Register (printr)
    2. Halt (halt)
    3. Evaluate String (eval)
    4. Print Character (prc)
    5. Print Decimal (prd)
    6. Print Hexadecimal (prx)
    7. Sleep (sleep)
    8. Print Binary (prb)
    9. Rest (rest)
    10. I/O (io)

Introduction

The VM emulates Why, a custom RISC instruction set that may or may not actually be theoretically implementable as real hardware. This instruction set has 64-bit word length, and memory addressability is also 64 bits.

Registers

There are 128 registers. Their purposes are pretty much stolen from MIPS:

Number Name Purpose
0 $0 Always contains zero.
1 $g Global area pointer (right after end of program).
2 $sp Stack pointer.
3 $fp Frame pointer.
4 $rt Return address.
5 $lo Stores the lower half of a mult result.
6 $hi Stores the upper half of a mult result.
7–22 $r0$rf Contains return values.
23–38 $a0$af Contains arguments for subroutines.
39–61 $t0$t16 Temporary registers.
62–84 $s0$s16 Saved registers.
85–100 $k0$kf Kernel registers.
101 $st Status register.
102–117 $m0$mf Reserved for use by the assembler.
118–121 $f0$f3 Floating point return values.
122–127 $e0$e5 Contains data about exceptions.

Status Register

The $st register stores flag bits. Currently, this includes the results of arithmetic instructions. In ascending order of significance, these are:

  1. Z (zero): Whether the last arithmetic result was zero (for cmp/cmpi, whether the compared values are equal)
  2. N (negative): Whether the result of the last arithmetic result was negative (for cmp/cmpi, whether the left value was less than the right value)
  3. C (carry): Whether the result of an addition was truncated. (Currently not implemented for subtraction.)
  4. O (overflow): Whether the addition of two positive signed numbers had a negative result due to overflow.

These status numbers are used in conditional branches, but they can also be accessed by programs. Writing to the $st register is possible, but strange behavior may occur as a result.

Programs

Programs are divided into five sections: metadata, code, data, symbol table and debug data. The metadata section contains information about the program. The code section consists of executable code. The data section consists of read/write data. The symbol table contains the names, locations and types of all visible symbols. The debug data section contains data that correlates assembly instructions to locations in source files for higher-level languages like C.

Note that the code section and data section are combined into the #text section in assembly. Code and data sections can be switched between using the %code and %data directives.

Metadata Section

The metadata section is a block of data at the beginning of the program that contains the beginning addresses of the other sections. The first value in this section represents the beginning address of the code section and is therefore equivalent to the size of the metadata section.

  • 0x00: Address of the beginning of the code section.
  • 0x08: Address of the beginning of the data section.
  • 0x10: Address of the beginning of the symbol table.
  • 0x18: Address of the beginning of the debug data section.
  • 0x20: Address of the beginning of the relocation data section.
  • 0x28: Total size of the program.
  • 0x300x38: ORCID of the author (represented in ASCII without hyphens).
  • 0x40...: Program name, version string and author name of the program (represented with null-terminated ASCII).
    • Example: given a program name "Example", version string "4" and author name "Kai Tamkun", this will be 0x4578616d706c6500 0x34004b6169205461 0x6d6b756e00000000.

Assembly syntax

#meta
author: "Kai Tamkun"
orcid: "0000-0001-7405-6654"
name: "Example"
version: "4"

Code Section

The code section consists of executable code. This is the only section of the code that the program counter is expected to point to. Code is represented using the syntax described by entries in the Operations section.

Data Section

The data section contains read/write data. Data is added using directives.

Symbol Table Section

The symbol table contains a list of debug symbols. Each debug symbol is assigned a numeric ID equal to part of the SHA256 hash of its name. (See /wasmc/src/wasm/Assembler.cpp for the precise transformation.) Each symbol is encoded in the table as a variable number of words. The upper half of the first is the numeric ID. The next 16 bits comprise the symbol type, while the lowest 16 bits comprise the length (in words) of the symbol's name. The second word represents the symbol's offset (its position relative to the start of the section containing it). The third word is the length of what the symbol points to (for functions, this will generally be eight times the number of instructions in the function). The remaining words encode the symbol's name. The length of the name in words is equal to the ceiling of 1/8 of the symbol name's length in characters. Any extra bytes in the last word are null.

Debug Data Section

The debug data section contains data mapping instructions to their positions in source files. It's stored as a list of entries whose order is important and must be maintained. The first byte of each entry determines the entry's type. All multibyte items in an entry are encoded as little-endian.

An entry with type 0 is invalid.

An entry with type 1 declares the filename of a source file and can be referenced by other entries. After the first byte in a type 1 entry, the next three bytes indicate the length of the filename. The filename then follows, plus padding until the total length of the entry is divisible by eight bytes.

An entry with type 2 declares a function name. It uses the same format as a type 1 entry, but instead of a filename, a function name is stored instead.

An entry with type 3 references a line on a source file defined by a type 1 entry. After the first byte in a type 3 entry, the next three bytes indicate the index of the referenced type 1 entry. The four bytes after that indicate the line number in the referenced file and the next three bytes indicate the column number. The next byte indicates how many contiguous instructions the entry applies to. The next four bytes indicate the index of the referenced type 2 entry. The final eight bytes indicate the address of an instruction.

The assembly syntax for type 3 entries defines a template. Multiple type 3 entries will be generated per template depending on how many instructions reference the type 3 entry. In the example below, only one entry is generated per template because each template occurs in a single continuous span. If a !2 instruction were added after the last !3 instruction, two type 3 entries would be generated for the template with index 2.

Assembly syntax

#debug
1 "src/printf.cpp" // 0
2 "_vsnprintf"     // 1
3 0 541 10 1       // 2 (File 0, line 541, column 10, function 1)
3 0 551 12 1       // 3 (File 0, line 551, column 12, function 1)

#code
// ...
	$t6 -> [$ta]     !2
	[$t3] -> $t4 /b  !3
	1 -> $m0         !3
	$m0 << 7  -> $m0 !3
	$t4 x $m0 -> $t5 !3
	$t5 - $m0 -> $t5 !3
	$t5 & -1  -> $t5 !3
// ...

Relocation Data Section

Relocation data allows the linker to combine multiple binaries. Some instructions have immediate values that contain not an absolute value but instead an address or an address plus a constant offset. Jumps to labels are the most common example.

The upper 61 bits of the first word of a relocation data entry represent the index of the symbol in the symbol table, while the next two bits are 0 if the value to relocate is 8 bytes wide, 2 if it's the lower 4 bytes of the symbol's address or 3 if it's the upper 4 bytes of the symbol's address. A value of 1 is invalid. The lowest bit of the first word is 1 if the value to be relocated is in the data section or 0 if it's in the code section. The second word is the signed offset to be applied to the symbol's location. The third and final word is the address of the value relative to the start of the code section.

Directives

Directives are instructions to the assembler. They control the assembly process.

%code

Switches the current section to the code section. After using this, anything emitted using %8b, %string and other such directives will be placed in the code section. (Note that inserting 8-byte values directly in the code section is discouraged and that inserting strings is absolutely pointless.)

%data

Switches the current section to the data section. After using this, anything emitted using %8b, %string and other such directives will be placed in the data section. (Note that putting instructions in the data section causes unspecified behavior.)

%type

Tells the assembler the type of a symbol. The type can be either object (for data) or function (for code).

Example

%type data_value object
%type strprint function

@data_value
%8b 42

@strprint
	// ...
	: $rt

%size

Tells the assembler the size (in bytes) of a symbol. The value supports expressions. Expressions are mathematical expressions whose operands are numeric constants, symbol names or ., which represents the value of the location counter. An expression is valid if any of the following is true:

  • None of its children contain any label references (that is, all leaves are numeric or .)
  • It's the difference of two labels
  • It's the difference of . and a label
  • It's the difference of a label and a number
  • It's the sum of a label and a number

These restrictions are in place because relocation data supports constant offsets only. All other information has to be known at compile time.

Example

@some_8b
%8b 42

%size some_8b 8

@function_one
	// ...
	: $rt

@function_two
	// ...
	: $ rt

%size function_one function_two-function_one
%size function_two .-function_two

%string

Emits a string (not terminated with a null byte).

Example

@some_string
%string "Hello, world!\n"

%stringz

Emits a string (terminated with a null byte).

Example

@some_string
%stringz "Hello, world!\n"

%8b, %4b, %2b, %1b

Emits a value of the specified width (1 byte for %1b, 2 bytes for %2b and so on). The values can be expressions (see %size).

Example

%8b some_function+32 // 4 instructions past the start of some_function
%8b some_label-10
%8b .
%4b data_value // Valid if data_value is within the first 4 GiB
%2b 65535
%1b 255

%align

Inserts zero until the location counter reaches a given alignment (in bytes).

Example

%align 65536
@p0
// ...

%fill

Adds a given number of bytes with a given value. The number of bytes is the first operand and the value is the second operand.

Example

@ten_ones
%fill 10 0x01

Rings

Why has support for four protection rings, just like x86. Ring 0 is called kernel mode and ring 3 is called user mode; rings 1 and 2 are currently unused.

Interrupts

Interrupts can be triggered by software or by the VM itself. Whenever an interrupt is triggered, $e0 is set to the program counter right before the interrupt was raised and $e1 is set to the current ring at the time the interrupt occurred. Interrupt handlers are expected to deal with properly resuming normal program execution after finishing up. The VM stores an address to a table containing pointers to interrupt handlers. The table is 32 words long.

1: SYSTEM

The SYSTEM interrupt is a software-triggered interrupt handled by the operating system. It can be called from any ring and causes a switch to kernel mode.

2: TIMER

The TIMER interrupt is a hardware-triggered interrupt caused when the hardware timer expires. Usable by ring zero only. This is to prevent unprivileged code from interfering with schedulers; operating systems can implement their own mechanisms to expose timer functionality to lower-privileged code. This interrupt causes a switch to kernel mode.

3: PROTEC

The PROTEC interrupt is a hardware-triggered interrupt caused when a called instruction attempts to do something not possible within the current ring. This causes a switch to kernel mode.

4: PFAULT

The PFAULT interrupt is raised if paging is enabled and an access to a non-present page is attempted. This causes a switch to kernel mode.

5: INEXEC

The INEXEC interrupt is raised if program control flows to an address whose page is not marked as executable. This causes a switch to kernel mode.

6: BWRITE

The BWRITE (bad write) interrupt is raised if paging is enabled and an instruction attempts to write to a nonwritable page.

7: KEYBRD

The KEYBRD interrupt is raised when a key is pressed. The value of the key will be stored in $e2 according to the format below. If this interrupt isn't set in the interrupt table, key presses will be ignored. This interrupt causes a switch to kernel mode.

Range 63–35 (29) 34 33 32 31–0 (32)
Purpose Unused Ctrl Alt Shift Key value (UTF-8)

Instruction Format

Like much of this instruction set, the formatting for instructions is copied from MIPS with a few modifications (for example, instructions are 64 bits long in this instruction set, as opposed to 32 for MIPS64).

R-Type Instructions

R-type instructions perform computations with multiple registers.

Range 63–52 (12) 51–45 (7) 44–38 (7) 37–31 (7) 30–18 (13) 17–14 (4) 13-12 (2) 11–0 (12)
Purpose Opcode rt rs rd Unused Conditions Linker flags Function

I-Type Instructions

I-type instructions perform computations with registers and an immediate value.

Range 63–52 (12) 51–48 (4) 47–46 (2) 45–39 (7) 38–32 (7) 31–0 (32)
Purpose Opcode Conditions Linker flags rs rd Immediate Value

J-Type Instructions

J-type instructions point the program counter to a given address under certain circumstances.

Range 63–52 (12) 51–45 (7) 44 43–38 (6) 37–34 (4) 33–32 (2) 31–0 (32)
Purpose Opcode rs Link Unused Conditions Linker flags Address

If the link bit is set, the current value of the program counter will be stored in $rt, the return address register.

Linker Flags

Before the relocation overhaul, linker flags were used to give the linker clues about relocation. There were four possible values. Back then, as now, linker flag values other than 0 are valid for I-type and J-type instructions only.

Now, the linker flags have three possible values. 0 indicates that the immediate value of the instruction isn't affected by relocation, whereas 1 indicates that the symbol needs to be relocated at link time. 2 is the same as 1, but indicates that the current immediate value is invalid because the symbol is currently unknown. Executing an instruction whose linker flag is 2 will cause an error. Other values are invalid.

Condition Bits

For operations that support conditions, the condition bits indicate what combination of ALU flags are required for the operation to occur.

  • 0xxx: Conditions disabled
  • 1000: Positive (!N & !Z)
  • 1001: Negative
  • 1010: Zero
  • 1011: Nonzero

Paging

Why.js supports paging. It's disabled by default and must be enabled with the pgon instruction. It uses a six-level system with a similar philosophy to x86_64's four-level system, but page sizes are 65,536 bytes large. The tables are named P0 through and P5 and each table contains 256 entries. To translate a virtual address to a physical one, P0 is inspected at the address set with setpt. The most significant eight bits in the virtual address are used as an offset into P0 to find the address of P1. If the P0 entry isn't present, a PFAULT interrupt is raised. Otherwise, the P1 entry is inspected to find the P2 address, and so on, until the address for the P5 table is found and the entry specified by bits 23–16 in the virtual address is read. If the present bit isn't set, PFAULT is raised as usual. Otherwise, the low 16 bits of the virtual address are added to the page table entry with the low 16 bits set to zero and this result is used as the physical address.

Address Format

63–56 (8) 55–48 (8) 47–40 (8) 39–32 (8) 31–24 (8) 23–16 (8) 15–0 (16)
P0 offset P1 offset P2 offset P3 offset P4 offset P5 offset Offset in page

Page Table Entry Format

P0 through P4

63–11 (53) 10–1 (10) 0
Address of next table Unused Present

P5

63–16 (48) 15–6 (10) 5 4 3 2 1 0
Address of page start Unused Modified Accessed User Page Executable Writable Present

User Page: Whether the page can be accessed in Ring 3. If zero, only rings 2 and lower can access it.

Operations

Math (R-Types)

Add (add)

$rs + $rt -> $rd or $rd += $rt
000000000001 ttttttt sssssss ddddddd 0000000000000 ...... 000000000000

Adds the values in rs and rt and stores the result in rd.

Subtract (sub)

$rs - $rt -> $rd or $rd -= $rt
000000000001 ttttttt sssssss ddddddd 0000000000000 ...... 000000000001

Subtracts the value in rt from the value in rs and stores the result in rd.

Multiply (mult)

$rs * $rt
000000000001 ttttttt sssssss 0000000 0000000000000 ...... 000000000010

Multiplies the value in rs by the value in rt and stores the upper half in $hi and the lower half in $lo.

Multiply Unsigned (multu)

$rs * $rt /u
000000000001 ttttttt sssssss 0000000 0000000000000 ...... 000000000101

Multiplies the value in rs by the value in rt (treating both as unsigned values) and stores the upper half in $hi and the lower half in $lo.

Shift Left Logical (sll)

$rs << $rt -> $rd or $rd <<= $rt
000000000001 ttttttt sssssss ddddddd 0000000000000 ...... 000000000110

Logically shifts the value in rs to the left by a number of bits equal to the value in rt and stores the result in rd.

Shift Right Logical (srl)

$rs >>> $rt -> $rd or $rd >>>= $rt
000000000001 ttttttt sssssss ddddddd 0000000000000 ...... 000000000111

Logically shifts the value in rs to the right by a number of bits equal to the value in rt and stores the result in rd.

Shift Right Arithmetic (sra)

$rs >> $rt -> $rd or $rd >>= $rt
000000000001 ttttttt sssssss ddddddd 0000000000000 ...... 000000001000

Arithmetically shifts the value in rs to the left by a number of bits equal to the value in rt and stores the result in rd.

Modulo (mod)

$rs % $rt -> $rd or $rs %= $rt
000000000001 ttttttt sssssss ddddddd 0000000000000 ...... 000000001001

Computes the signed rt-modulo of rs and stores the result in rd.

Divide (div)

$rs / $rt -> $rd
000000000001 ttttttt sssssss ddddddd 0000000000000 ...... 000000001010

Divides the value in rs by the value in rt and stores the result in rd, discarding the remainder.

Divide Unsigned (divu)

$rs / $rt -> $rd /u
000000000001 ttttttt sssssss ddddddd 0000000000000 ...... 000000001011

Divides the value in rs by the value in rt (treating both as unsigned values) and stores the result in rd, discarding the remainder.

Modulo Unsigned (modu)

$rs % $rt -> $rd /u or $rs %= $rt /u
000000000001 ttttttt sssssss ddddddd 0000000000000 ...... 000000001100

Computes the unsigned rt-modulo of rs and stores the result in rd.

Sign Extend 32 to 64 (sext32)

sext32 $rs -> $rd
000000000001 0000000 sssssss ddddddd 0000000000000 ...... 000000001101

If bit 31 (zero-indexed) of rs is 1, this instruction copies rs into rd and sets all upper 32 bits of rd to 1. Otherwise, it just copies rs into rd with the upper 32 bits set to zero.

Sign Extend 16 to 64 (sext16)

sext16 $rs -> $rd
000000000001 0000000 sssssss ddddddd 0000000000000 ...... 000000001110

If bit 15 (zero-indexed) of rs is 1, this instruction copies rs into rd and sets all upper 48 bits of rd to 1. Otherwise, it just copies rs into rd with the upper 48 bits set to zero.

Sign Extend 8 to 64 (sext8)

sext8 $rs -> $rd
000000000001 0000000 sssssss ddddddd 0000000000000 ...... 000000001111

If bit 7 (zero-indexed) of rs is 1, this instruction copies rs into rd and sets all upper 56 bits of rd to 1. Otherwise, it just copies rs into rd with the upper 56 bits set to zero.

Logic (R-Types)

Bitwise AND (and)

$rs & $rt -> $rd or $rd &= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000000000

Computes the bitwise AND of rs and rt and stores the result in rd.

Bitwise NAND (nand)

$rs ~& $rt -> $rd or $rd ~&= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000000001

Computes the bitwise NAND of rs and rt and stores the result in rd.

Bitwise NOR (nor)

$rs ~| $rt -> $rd or $rd ~|= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000000010

Computes the bitwise NOR of rs and rt and stores the result in rd.

Bitwise NOT (not)

~$rs -> $rd or ~$rs.
000000000010 0000000 sssssss ddddddd 0000000000000 ...... 000000000011

Computes the bitwise NOT of rs and stores the result in rd.

Bitwise OR (or)

$rs | $rt -> $rd or $rd |= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000000100

Computes the bitwise OR of rs and rt and stores the result in rd.

Bitwise XNOR (xnor)

$rs ~x $rt -> $rd or $rd ~x= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000000101

Computes the bitwise XNOR of rs and rt and stores the result in rd.

Bitwise XOR (xor)

$rs x $rt -> $rd or $rd x= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000000110

Computes the bitwise XOR of rs and rt and stores the result in rd.

Logical AND (land)

$rs && $rt -> $rd or $rd &&= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000001000

Computes the logical AND of rs and rt and stores the result in rd.

Logical NAND (lnand)

$rs !&& $rt -> $rd or $rd !&&= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000001001

Computes the logical NAND of rs and rt and stores the result in rd.

Logical NOR (lnor)

$rs !|| $rt -> $rd or $rd !||= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000001010

Computes the logical NOR of rs and rt and stores the result in rd.

Logical NOT (lnot)

!$rs -> $rd or !$rs.
000000000010 0000000 sssssss ddddddd 0000000000000 ...... 000000001011

Computes the logical NOT of rs and stores the result in rd.

Logical OR (lor)

$rs || $rt -> $rd or $rd ||= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000001100

Computes the logical OR of rs and rt and stores the result in rd.

Logical XNOR (lxnor)

$rs !xx $rt -> $rd or $rd !xx= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000001101

Computes the logical XNOR of rs and rt and stores the result in rd.

Logical XOR (lxor)

$rs xx $rt -> $rd or $rd xx= $rt
000000000010 ttttttt sssssss ddddddd 0000000000000 ...... 000000001110

Computes the logical XOR of rs and rt and stores the result in rd.

Math (I-Types)

Add Immediate (addi)

$rs + imm -> $rd or $rd += imm
000000000011 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Adds the value in rs and a constant and stores the result in rd.

Subtract Immediate (subi)

$rs - imm -> $rd or $rd -= imm
000000000100 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Subtracts a constant from the value in rs and stores the result in rd.

Multiply Immediate (multi)

$rs * imm
000000000101 ...... sssssss 0000000 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Multiplies the value in rs by a constant and stores the upper half in $hi and the lower half in $lo.

Multiply Unsigned Immediate (multui)

$rs * imm /u
000000011000 ...... sssssss 0000000 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Multiplies the value in rs by a constant (treating both as unsigned values) and stores the upper half in $hi and the lower half in $lo.

Shift Left Logical Immediate (slli)

$rs << imm -> $rd or $rd <<= imm
000000100010 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Logically shifts the value in rs to the left by a number of bits equal to imm and stores the result in rd.

Shift Right Logical Immediate (srli)

$rs >>> imm -> $rd or $rd >>>= imm
000000100011 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Logically shifts the value in rs to the right by a number of bits equal to imm and stores the result in rd.

Shift Right Arithmetic Immediate (srai)

$rs >> imm -> $rd or $rd >>= imm
000000100100 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Arithmetically shifts the value in rs to the right by a number of bits equal to imm and stores the result in rd.

Shift Left Logical Inverse Immediate (sllii)

imm << $rs -> $rd
000000111110 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Logically shifts imm to the left by a number of bits equal to the value in rs and stores the result in rd.

Shift Right Logical Inverse Immediate (srlii)

imm >>> $rs -> $rd
000000111111 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Logically shifts imm to the right by a number of bits equal to the value in rs and stores the result in rd.

Shift Right Arithmetic Inverse Immediate (sraii)

imm >> $rs -> $rd
000001000000 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Arithmetically shifts imm to the right by a number of bits equal to the value in rs and stores the result in rd.

Modulo Immediate (modi)

$rs % imm -> $rd or $rd %= imm
000000011110 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Computes the signed imm-modulo of rs and stores the result in rd.

Divide Immediate (divi)

$rs / imm -> $rd
000000110100 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Divides the value in rs by a constant and stores the result in rd, discarding the remainder.

Divide Unsigned Immediate (divui)

$rs / imm -> $rd /u
000000110101 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Divide Inverse Immediate (divii)

imm / $rs -> $rd
000000110110 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Divides a constant by the value in rs and stores the result in rd, discarding the remainder.

Modulo Unsigned Immediate (modui)

$rs % imm -> $rd /u or $rd %= imm /u
000001000011 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Computes the unsigned imm-modulo of rs and stores the result in rd.

Divide Unsigned Inverse Immediate (divuii)

imm / $rs -> $rd /u
000000110111 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Divides a constant by the value in rs (treating both as unsigned values) and stores the result in rd, discarding the remainder.

Logic (I-Types)

Bitwise AND Immediate (andi)

$rs & imm -> $rd or $rd &= imm
000000000110 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Computes the bitwise AND of rs and a constant and stores the result in rd.

Bitwise NAND Immediate (nandi)

$rs ~& imm -> $rd or $rd ~&= imm
000000000111 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Computes the bitwise NAND of rs and a constant and stores the result in rd.

Bitwise NOR Immediate (nori)

$rs ~| imm -> $rd or $rd ~|= imm
000000001000 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Computes the bitwise NOR of rs and a constant and stores the result in rd.

Bitwise OR Immediate (ori)

$rs | imm -> $rd or $rd |= imm
000000001001 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Computes the bitwise OR of rs and a constant and stores the result in rd.

Bitwise XNOR Immediate (xnori)

$rs ~x imm -> $rd or $rd ~x= imm
000000001010 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Computes the bitwise XNOR of rs and a constant and stores the result in rd.

Bitwise XOR Immediate (xori)

$rs x imm -> $rd or $rd x= imm
000000001011 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Computes the bitwise XOR of rs and a constant and stores the result in rd.

Comparisons (R-Types)

Compare (cmp)

$rs ~ $rt
000000001110 ttttttt sssssss ....... 0000000000000 ...... 000000000101

Compares the value in rs to the value in rt (treating both as signed values) and updates the status register.

Set on Less Than (sl)

$rs < $rt -> $rd
000000001110 ttttttt sssssss ddddddd 0000000000000 ...... 000000000000

If the value in rs is less than the value in rt, rd is set to 1; otherwise, rd is set to 0.

Set on Less Than or Equal (sle)

$rs <= $rt -> $rd
000000001110 ttttttt sssssss ddddddd 0000000000000 ...... 000000000001

If the value in rs is less than or equal to the value in rt, rd is set to 1; otherwise, rd is set to 0.

Set on Equal (seq)

$rs == $rt -> $rd
000000001110 ttttttt sssssss ddddddd 0000000000000 ...... 000000000010

If the value in rs is equal to the value in rt, rd is set to 1; otherwise, rd is set to 0.

Set on Less Than Unsigned (slu)

$rs < $rt -> $rd /u
000000001110 ttttttt sssssss ddddddd 0000000000000 ...... 000000000011

If the value in rs is less than the value in rt (treating both as unsigned values), rd is set to 1; otherwise, rd is set to 0.

Set on Less Than or Equal Unsigned (sleu)

$rs <= $rt -> $rd /u
000000001110 ttttttt sssssss ddddddd 0000000000000 ...... 000000000100

If the value in rs is less than or equal to the value in rt (treating both as unsigned values), rd is set to 1; otherwise, rd is set to 0.

Comparisons (I-Types)

Compare Immediate (cmpi)

$rs ~ imm
000000101011 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Compares the value in rs to imm and updates the status register.

Set on Less Than Immediate (sli)

$rs < imm -> $rd
000000011001 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

If the value in rs is less than imm, rd is set to 1; otherwise, rd is set to 0.

Set on Less Than or Equal Immediate (slei)

$rs <= imm -> $rd
000000011010 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

If the value in rs is less than or equal to imm, rd is set to 1; otherwise, rd is set to 0.

Set on Equal Immediate (seqi)

$rs == imm -> $rd
000000011011 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

If the value in rs is equal to imm, rd is set to 1; otherwise, rd is set to 0.

Set on Greater Than Immediate (sgi)

$rs > imm -> $rd
000000101001 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

If the value in rs is greater than imm, rd is set to 1; otherwise, rd is set to 0.

Set on Greater Than or Equal Immediate (sgei)

$rs >= imm -> $rd
000000101010 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

If the value in rs is greater than or equal to imm, rd is set to 1; otherwise, rd is set to 0.

Set on Less Than Unsigned Immediate (slui)

$rs < imm -> $rd /u
000000011100 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

If the value in rs is less than imm (treating both as unsigned values), rd is set to 1; otherwise, rd is set to 0.

Set on Less Than or Equal Unsigned Immediate (sleui)

$rs <= imm -> $rd /u
000000011101 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

If the value in rs is less than or equal to imm (treating both as unsigned values), rd is set to 1; otherwise, rd is set to 0.

Set on Greater Than or Equal Unsigned Immediate (sgeui)

$rs >= imm -> $rd /u
000000111011 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

If the value in rs is greater than or equal to imm (treating both as unsigned values), rd is set to 1; otherwise, rd is set to 0.

Set on Greater Than Unsigned Immediate (sgui)

$rs > imm -> $rd /u
000000111100 ...... sssssss ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

If the value in rs is greater than imm (treating both as unsigned values), rd is set to 1; otherwise, rd is set to 0.

Jumps (J-Types)

Jump (j)

: label or : imm
:: label or :: imm (linking variant)
000000001111 0000000 0000000 cccc .. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Supports conditions:

+:/+::: jump if positive
-:/-::: jump if negative
0:/0::: jump if zero
*:/*::: jump if nonzero

Jumps to the address of a given label or directly to a given address.

Jump Conditional (jc)

: label if $rs or : imm if $rs
:: label if $rs or :: imm if $rs (linking variant)
000000010000 sssssss 0000000 0000 .. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Jumps to the address of a given label or directly to a given address, provided the value in rs is nonzero.

Jumps (R-Types)

Jump to Register (jr)

: $rd
000000010001 0000000 0000000 ddddddd 0000000000000 cccc .. 000000000000
Supports conditions

Jumps to the address stored in rd.

Jump to Register Conditional (jrc)

: $rd if $rs
000000010001 0000000 sssssss ddddddd 0000000000000 ...... 000000000001

Jumps to the address stored in rd, provided the value in rs is nonzero.

Jump to Register and Link (jrl)

:: $rd
000000010001 0000000 0000000 ddddddd 0000000000000 cccc .. 000000000010
Supports conditions

Stores the address of the next instruction in $rt and jumps to the address stored in rd.

Jump to Register and Link Conditional (jrlc)

:: $rd if $rs
000000010001 0000000 sssssss ddddddd 0000000000000 ...... 000000000011

Stores the address of the next instruction in $rt and jumps to the address stored in rd, provided the value in rs is nonzero.

Memory (R-Types)

Copy (c)

[$rs] -> [$rd]
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000000000

Copies the word beginning at the memory address pointed to by rs into memory beginning at the address pointed to by rd.

Load (l)

[$rs] -> $rd
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000000001

Loads the word beginning at the memory address pointed to by rs into rd.

Store (s)

$rs -> [$rd]
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000000010

Stores the value of rs into memory beginning at the address pointed to by rd.

Copy Byte (cb)

[$rs] -> [$rd] /b
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000000011

Copies the byte stored at the memory address pointed to by rs into the memory address pointed to by rd.

Load Byte (lb)

[$rs] -> $rd /b
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000000100

Loads the byte stored at the memory address pointed to by rs into rd.

Store Byte (sb)

$rs -> [$rd] /b
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000000101

Stores the lowest 8 bits of rs into the memory address pointed to by rd.

Copy Halfword (ch)

[$rs] -> [$rd] /h
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000001000

Copies the halfword stored at the memory address pointed to by rs into the memory address pointed to by rd.

Load Halfword (lh)

[$rs] -> $rd /h
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000001001

Loads the halfword stored at the memory address pointed to by rs into rd.

Store Halfword (sh)

$rs -> [$rd] /h
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000001010

Stores the lowest 32 bits of rs into the memory address pointed to by rd.

Copy Short (cs)

[$rs] -> [$rd] /s
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000001100

Copies the short stored at the memory address pointed to by rs into the memory address pointed to by rd.

Load Short (ls)

[$rs] -> $rd /s
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000001101

Loads the short stored at the memory address pointed to by rs into rd.

Store Short (ss)

$rs -> [$rd] /s
000000010010 0000000 sssssss ddddddd 0000000000000 ...... 000000001110

Stores the lowest 16 bits of rs into the memory address pointed to by rd.

Stack Push (spush)

[ $rs
000000010010 0000000 sssssss 0000000 0000000000000 ...... 000000000110

Copies the word at rs into the stack and adjusts the stack pointer.
See also: push pseudoinstruction

Stack Pop (spop)

] $rd
000000010010 0000000 ddddddd 0000000 0000000000000 ...... 000000000111

Adjusts the stack pointer and copies the word at the stack pointer into rd.
See also: pop pseudoinstruction

Memset (ms)

memset $rs x $rt -> $rd
000000010010 ttttttt ddddddd sssssss 0000000000000 ...... 000000001011

Sets rs bytes to rt starting at address rd. The value in rt will be truncated to 8 bits.

Translate Address (trans)

translate $rs -> $rd
000001000100 0000000 ddddddd sssssss 0000000000000 ...... 000000000000

Translates the virtual address stored in rs and stores the resulting physical address in rd.
If paging is disabled, this instruction simply copies rs into rd.
A page fault will occur if paging is enabled and the virtual address has no corresponding physical address.

Memory (I-Types)

Load Immediate (li)

[imm] -> $rd
000000010011 ...... 0000000 ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Loads the word beginning at address imm into rd.

Store Immediate (si)

$rs -> [imm]
000000010100 ...... sssssss 0000000 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Stores the value of rs into memory beginning at address imm.

Load Byte Immediate (lbi)

[imm] -> $rd /b
000000100101 ...... 0000000 ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Loads the byte at address imm into rd.

Store Byte Immediate (sbi)

$rs -> [imm] /b
000000100110 ...... sssssss 0000000 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Stores the lowest 8 bits of rs into memory at address imm.

Load Indirect Immediate (lni)

[imm] -> [$rd]
000000100111 ...... sssssss 0000000 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Copies the word stored in memory at address imm into the memory beginning at the address pointed to by rd.

Load Byte Indirect Immediate (lbni)

[imm] -> [$rd] /b
000000101000 ...... sssssss 0000000 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Copies the byte stored in memory at address imm into the memory address pointed to by rd.

Set (set)

imm -> $rd
000000010101 ...... 0000000 ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Sets a register to the given immediate value.

Load Upper Immediate (lui)

lui: imm -> $rd
000000001101 ...... 0000000 ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Loads an immediate value into the upper half of the word at rd. The lower half is not affected.

Sized Stack Push (sspush)

[:imm $rs
000000111001 ...... sssssss 0000000 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Writes rs to the stack and decrements the stack pointer by imm bytes.

Sized Stack Pop (sspop)

]:imm $rd
000000111010 ...... 0000000 ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Increments the stack pointer by imm bytes and reads into rd from the stack.

Spill Store (sps)

$rs -> [$fp - imm]
000000010110 ...... sssssss 0000000 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Stores rs at the address derived by subtracting imm from the current value of $fp.

Spill Load (spl)

[$fp - imm] -> $rd
000000010111 ...... 0000000 ddddddd iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Loads rd from the address derived by subtracting imm from the current value of $fp.

Special Instructions

External (ext)

(varies; see Externals)
000000011111 ttttttt sssssss ddddddd 0000000000000 ...... xxxxxxxxxxxx

Performs a special instruction, typically for interaction with the world outside the VM.

Select (sel)

[$rs = $rt] -> $rd
[$rs < $rt] -> $rd
[$rs > $rt] -> $rd
[$rs != $rt] -> $rd
000000111000 ttttttt sssssss ddddddd 0000000000000 cond .. xxxxxxxxxxxx

Checks the status register and the condition bits. If the condition matches the status register, rd is set to rs; otherwise, it's set to rt.

Interrupt (int)

%int imm
000000100000 ...... ....... ....... iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Performs an interrupt. If no interrupt table has been registered, nothing interesting happens.

Register Interrupt Table (rit)

%rit imm
000000100001 ...... ....... ....... iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Registers the interrupt table. Takes a pointer to a table in the data section. Valid only in kernel mode; will cause the machine to halt if called in user mode.

Set Timer (time)

%time $rs
000000110000 ....... sssssss ....... 0000000000000 ...... 000000000000

Sets the hardware timer to the number stored in rs (in microseconds), canceling any previous timer. Requires kernel mode. Sub-millisecond precision may be unsupported or inaccurate. Once the timer expires, a timer interrupt occurs.

Set Timer Immediate (timei)

%time imm
000000110001 ...... ....... ....... iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Sets the hardware timer to the number stored in imm (in microseconds), canceling any previous timer. Requires kernel mode. Sub-millisecond precision may be unsupported or inaccurate. Once the timer expires, a timer interrupt occurs.

Save Timer (svtime)

%time -> $rd
000000110000 ....... sssssss ....... 0000000000000 ...... 000000000001

Saves the number of microseconds until the hardware timer expires in rd. If no hardware timer is active, this instruction sets rd to 0.

Change Ring (ring)

%ring $rs
000000110010 ....... sssssss ....... 0000000000000 ...... 000000000000

Sets the protection ring to the value stored in rs. A protection interrupt will occur if the indicated ring is lower than the current ring to prevent privilege escalation.

Save Ring (svring)

%ring -> $rd
000000110010 ....... ....... ddddddd 0000000000000 ...... 000000000001

Stores the current protection ring in rd.

Change Ring Immediate (ringi)

%ring imm
000000110011 ...... ....... ....... iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

Sets the protection ring to imm. A protection interrupt will occur if the indicated ring is lower than the current ring to prevent privilege escalation.

Disable Paging (pgoff)

%page off
000000111101 ....... ....... ....... 0000000000000 ...... 000000000000

Disables virtual memory. Raises PROTEC if used in a ring other than ring zero.

Enable Paging (pgon)

%page on
000000111101 ....... ....... ....... 0000000000000 ...... 000000000001

Enables virtual memory. Raises PROTEC if used in a ring other than ring zero.

Set Page Table (setpt)

%setpt $rs
: %setpt $rs $rt
000000111101 ttttttt sssssss ....... 0000000000000 ...... 000000000010

Sets the address of P0. Raises PROTEC if used in a ring other than ring zero. If rt is specified (i.e., if it's any register other than $0), it will be jumped to.

Save Paging (svpg)

%page -> $rd
000000111101 ....... ....... ddddddd 0000000000000 ...... 000000000011

Sets rd to 1 if paging is enabled or 0 if paging is disabled.

Query Memory (qm)

? mem -> $rd
000001000001 ....... ....... ddddddd 0000000000000 ...... 000000000000

Sets rd to the size of the main memory in bytes.

Disable Interrupts (di)

%di
000001000010 ....... ....... ....... 0000000000000 ...... 000000000000

Disables hardware interrupts. This currently includes TIMER and KEYBRD.

Enable Interrupts (ei)

%ei
000001000010 ....... ....... ....... 0000000000000 ...... 000000000001

Enables hardware interrupts. This currently includes TIMER and KEYBRD.

Push Paging (ppush)

[ %page
[ %page
000000111101 ....... ....... ....... 0000000000000 ...... 000000000100

Pushes the current paging state (whether paging is enabled, plus the physical address of P0) to a special stack that's not part of the accessible memory. If the implementation's stack size is limited and the stack is full, the bottom of the stack will be removed before the current paging state is pushed. Requires ring zero.

Pop Paging (ppop)

] %page
: ] %page $rs
000000111101 ....... sssssss ....... 0000000000000 ...... 000000000101

Pops a paging state (whether paging is enabled, plus the physical address of P0) from a special stack that's not part of the accessible memory. Does nothing if the stack is empty. If rs is specified (i.e., if it's any register other than $0), it will be jumped to, even if the paging stack was empty. Requires ring zero.

Pseudoinstructions

Move (mv)

$rs -> $rd

Copies the value of rs into rd.

Translation:
$rs | $0 -> $rd

Return (ret) (deprecated in wasmc++)

ret

Jumps to the return address.

Translation:
: $r

Push (push) (deprecated in wasmc++)

[ $x $y $z ...

Pushes the value of the specified register(s) to the stack. Acts as a shorthand for calling spush on multiple registers.

Translation for each register in order:
[ $rs

Pop (pop) (deprecated in wasmc++)

] $x $y $z

Pops the value(s) at the top of the stack and stores the value(s) in the specified register(s). Acts as a shorthand for calling spop on multiple registers.

Translation for each register in order: ] $rs

Jump if Equal (jeq)

: $rd if $rs == $rt

If the value in rs is equal to the value in rt, jumps to the address stored in rd. (Modifies m7.)

Translation:
$rs == $rt -> $m7
: $rd if $m7

: label if $rs == $rt

If the value in rs is equal to the value in rt, jumps to label. (Modifies m7.)

Set on Greater Than or Equal (sge)

$rs >= $rt -> $rd

If the value in rs is greater than or equal to the value in rt, rd is set to 1; otherwise, rd is set to 0.

Translation:
$rt <= $rs -> $rd

Set on Greater Than (sg)

$rs > $rt -> $rd

If the value in rs is greater than the value in rt, rd is set to 1; otherwise, rd is set to 0.

Translation:
$rt < $rs -> $rd

Set on Greater Than or Equal Unsigned (sgeu)

$rs >= $rt -> $rd /u

If the value in rs is greater than or equal to the value in rt (treating both as unsigned values), rd is set to 1; otherwise, rd is set to 0.

Translation:
$rt <= $rs -> $rd

Set on Greater Than Unsigned (sgu)

$rs > $rt -> $rd /u

If the value in rs is greater than the value in rt (treating both as unsigned values), rd is set to 1; otherwise, rd is set to 0.

Translation:
$rt < $rs -> $rd /u

Externals

Print Register

Syntax: <print $rs>
Function value: 000000000001

Prints the value stored in rs to the console.

Halt

Syntax: <halt>
Function value: 000000000010

Halts the VM.

Evaluate String

Syntax: <eval $rs>
Function value: 000000000011

Evaluates the string beginning at the address stored in rs. Unimplemented.

Print Character

Syntax: <prc $rs>
Function value: 000000000100

Prints the character stored in rs to the console.

Print Decimal

Syntax: <prd $rs>
Function value: 000000000101

Prints the number stored in rs to the console as a decimal number.

Print Hexadecimal

Syntax: <prx $rs>
Function value: 000000000110

Prints the number stored in rs to the console as a hexadecimal number.

Sleep

Syntax: <sleep $rs>
Function value: 000000000111

Sleeps for the number of microseconds stored in rs.

Print Binary

Syntax: <prb $rs>
Function value: 000000001000

Prints the number stored in rs to the console as a binary number.

Rest

Syntax: <rest>
Function value: 000000001001

Pauses execution until an interrupt occurs.

I/O

Syntax: <io operation_name>
Function value: 000000001010

Interacts with storage devices. See the I/O document for details.