Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

MIPS ISA

The Opcode enum organizes MIPS instructions into several functional categories, each serving a specific role in the instruction set:

#![allow(unused)]
fn main() {
pub enum Opcode {
    // ALU
    ADD = 0,         // ADDSUB
    SUB = 1,         // ADDSUB
    MUL = 2,         // MUL
    MULT = 3,        // MUL
    MULTU = 4,       // MUL
    DIV = 5,         // DIVREM
    DIVU = 6,        // DIVREM
    MOD = 7,         // DIVREM
    MODU = 8,        // DIVREM
    SLL = 9,         // SLL
    SRL = 10,        // SR
    SRA = 11,        // SR
    ROR = 12,        // SR
    SLT = 13,        // LT
    SLTU = 14,       // LT
    AND = 15,        // BITWISE
    OR = 16,         // BITWISE
    XOR = 17,        // BITWISE
    NOR = 18,        // BITWISE
    CLZ = 19,        // CLO_CLZ
    CLO = 20,        // CLO_CLZ
    // Control FLow
    BEQ = 21,        // BRANCH
    BGEZ = 22,       // BRANCH
    BGTZ = 23,       // BRANCH
    BLEZ = 24,       // BRANCH
    BLTZ = 25,       // BRANCH
    BNE = 26,        // BRANCH
    Jump = 27,       // JUMP
    Jumpi = 28,      // JUMP
    JumpDirect = 29, // JUMP
    SYSCALL = 30,    // SYSCALL
    // Memory Op
    LB = 31,         // LOAD
    LBU = 32,        // LOAD
    LH = 33,         // LOAD
    LHU = 34,        // LOAD
    LW = 35,         // LOAD
    LWL = 36,        // LOAD
    LWR = 37,        // LOAD
    LL = 38,         // LOAD
    SB = 39,         // STORE
    SH = 40,         // STORE
    SW = 41,         // STORE
    SWL = 42,        // STORE
    SWR = 43,        // STORE
    SC = 44,         // STORE
    // Misc
    INS = 45,        // INS
    MADDU = 46,      // MADDSUB
    MSUBU = 47,      // MADDSUB
    MADD = 48,       // MADDSUB
    MSUB = 49,       // MADDSUB
    MEQ = 50,        // MOVCOND
    MNE = 51,        // MOVCOND
    WSBH = 52,       // WSBH
    EXT = 53,        // EXT
    TEQ = 54,        // TEQ
    SEXT = 55,       // SEXT

    // Syscall
    UNIMPL = 0xff,
}
}

All MIPS instructions can be divided into the following taxonomies:

ALU Operators
This category includes the fundamental arithmetic logical operations and count operations. It covers addition (ADD) and subtraction (SUB), several multiplication, division and remainder variants (MULT, MULTU, MUL, DIV, DIVU, MOD, MODU), as well as bit shifting and rotation operations (SLL, SRL, SRA, ROR), comparison operations like set less than (SLT, SLTU) a range of bitwise logical operations (AND, OR, XOR, NOR) and count operations like CLZ counts the number of leading zeros, while CLO counts the number of leading ones. These operations are useful in bit-level data analysis.

Memory Operations
This category is dedicated to moving data between memory and registers. It contains a comprehensive set of load instructions, such as LH (load halfword), LWL (load word left), LW (load word), LB (load byte), LBU (load byte unsigned), LHU (load halfword unsigned), LWR (load word right), and LL (load linked), as well as corresponding store instructions like SB (store byte), SH (store halfword), SWL (store word left), SW (store word), SWR (store word right), and SC (store conditional). These operations ensure that data is correctly and efficiently read from or written to memory.

Branching Instructions
Instructions BEQ (branch if equal), BGEZ (branch if greater than or equal to zero), BGTZ (branch if greater than zero), BLEZ (branch if less than or equal to zero), BLTZ (branch if less than zero), and BNE (branch if not equal) are used to change the flow of execution based on comparisons. These instructions are vital for implementing loops, conditionals, and other control structures.

Jump Instructions
Jump-related instructions, including Jump, Jumpi, and JumpDirect, are responsible for altering the execution flow by redirecting it to different parts of the program. They are used for implementing function calls, loops, and other control structures that require non-sequential execution, ensuring that the program can navigate its code dynamically.

Syscall Instructions
SYSCALL triggers a system call, allowing the program to request services from the zkvm operating system. The service can be a precompile computation, such as do sha extend operation by SHA_EXTEND precompile. It can also be an input/output operation such as SYSHINTREAD and WRITE, or a Linux system call (see Linux ABI).

Misc Instructions
This category includes other instructions. TEQ is typically used to test equality conditions between registers. MADDU/MSUBU is used for multiply accumulation. SEB/SEH (executor opcode SEXT) sign-extend a byte or halfword. EXT/INS extract and insert bit fields. WSBH swaps the bytes within each halfword. MOVZ/MOVN (executor opcodes MEQ/MNE) are conditional moves.

Supported instructions

The support instructions are as follows:

instructionOp [31:26]rs [25:21]rt [20:16]rd [15:11]shamt [10:6]func [5:0]functionchip
ADD000000rsrtrd00000100000rd = rs + rtAddSub
ADDI001000rsrtimmimmimmrt = rs + sext(imm)AddSubImm
ADDIU001001rsrtimmimmimmrt = rs + sext(imm)AddSubImm
ADDU000000rsrtrd00000100001rd = rs + rtAddSub
AND000000rsrtrd00000100100rd = rs & rtBitwise
ANDI001100rsrtimmimmimmrt = rs & zext(imm)BitwiseImm
BEQ000100rsrtoffsetoffsetoffsetPC = PC + sext(offset<<2), if rs == rtBranch
BGEZ000001rs00001offsetoffsetoffsetPC = PC + sext(offset<<2), if rs >= 0Branch
BGTZ000111rs00000offsetoffsetoffsetPC = PC + sext(offset<<2), if rs > 0Branch
BLEZ000110rs00000offsetoffsetoffsetPC = PC + sext(offset<<2), if rs <= 0Branch
BLTZ000001rs00000offsetoffsetoffsetPC = PC + sext(offset<<2), if rs < 0Branch
BNE000101rsrtoffsetoffsetoffsetPC = PC + sext(offset<<2), if rs != rtBranch
CLO011100rsrtrd00000100001rd = count_leading_ones(rs)CloClz
CLZ011100rsrtrd00000100000rd = count_leading_zeros(rs)CloClz
DIV000000rsrt0000000000011010(hi, lo) = (rs % rt, rs / rt), signed; division by zero is rejectedDivRem
DIVU000000rsrt0000000000011011(hi, lo) = (rs % rt, rs / rt), unsigned; division by zero is rejectedDivRem
MOD000000rsrtrd00011011010rd = rs % rt, signed (MIPS32 Release 6 encoding)DivRem
MODU000000rsrtrd00011011011rd = rs % rt, unsigned (MIPS32 Release 6 encoding)DivRem
J000010instr_indexinstr_indexinstr_indexinstr_indexinstr_indexPC = instr_index || 00 (the PC[31..28] region bits are taken as 0)Jump
JAL000011instr_indexinstr_indexinstr_indexinstr_indexinstr_indexr31 = PC + 8, PC = instr_index || 00 (the PC[31..28] region bits are taken as 0)Jump
JALR000000rs00000rdhint001001rd = PC + 8, PC = rsJump
JR000000rs0000000000hint001000PC = rsJump
LB100000basertoffsetoffsetoffsetrt = sext(mem_byte(base + offset))LoadNarrow
LBU100100basertoffsetoffsetoffsetrt = zext(mem_byte(base + offset))LoadNarrow
LH100001basertoffsetoffsetoffsetrt = sext(mem_halfword(base + offset))LoadNarrow
LHU100101basertoffsetoffsetoffsetrt = zext(mem_halfword(base + offset))LoadNarrow
LL110000basertoffsetoffsetoffsetrt = mem_word(base + offset)LoadWord
LUI00111100000rtimmimmimmrt = imm<<16AddSubImm
LW100011basertoffsetoffsetoffsetrt = mem_word(base + offset)LoadWord
LWL100010basertoffsetoffsetoffsetrt = rt merge most significant part of mem(base+offset)MemoryUnaligned
LWR100110basertoffsetoffsetoffsetrt = rt merge least significant part of mem(base+offset)MemoryUnaligned
MFHI0000000000000000rd00000010000rd = hiAddSubImm
MFLO0000000000000000rd00000010010rd = loAddSubImm
MOVN000000rsrtrd00000001011rd = rs, if rt != 0 (executor opcode MNE)MovCond
MOVZ000000rsrtrd00000001010rd = rs, if rt == 0 (executor opcode MEQ)MovCond
MTHI000000rs000000000000000010001hi = rsAddSubImm
MTLO000000rs000000000000000010011lo = rsAddSubImm
MUL011100rsrtrd00000000010rd = rs * rtMul
MULT000000rsrt0000000000011000(hi, lo) = rs * rtMul
MULTU000000rsrt0000000000011001(hi, lo) = rs * rtMul
NOR000000rsrtrd00000100111rd = !(rs | rt)Bitwise
OR000000rsrtrd00000100101rd = rs | rtBitwise
ORI001101rsrtimmimmimmrt = rs | zext(imm)BitwiseImm
SB101000basertoffsetoffsetoffsetmem_byte(base + offset) = rtStoreNarrow
SC111000basertoffsetoffsetoffsetmem_word(base + offset) = rt, rt = 1, if atomic update, else rt = 0StoreWord
SH101001basertoffsetoffsetoffsetmem_halfword(base + offset) = rtStoreNarrow
SLL00000000000rtrdsa000000rd = rt<<saShiftLeftImm
SLLV000000rsrtrd00000000100rd = rt << rs[4:0]ShiftLeft
SLT000000rsrtrd00000101010rd = rs < rtLt
SLTI001010rsrtimmimmimmrt = rs < sext(imm)LtImm
SLTIU001011rsrtimmimmimmrt = rs < sext(imm)LtImm
SLTU000000rsrtrd00000101011rd = rs < rtLt
SRA00000000000rtrdsa000011rd = rt >> saShiftRightImm
SRAV000000rsrtrd00000000111rd = rt >> rs[4:0]ShiftRight
SYNC000000000000000000000stype001111sync (nop)AddSubImm
SRL00000000000rtrdsa000010rd = rt >> saShiftRightImm
SRLV000000rsrtrd00000000110rd = rt >> rs[4:0]ShiftRight
SUB000000rsrtrd00000100010rd = rs - rtAddSub
SUBU000000rsrtrd00000100011rd = rs - rtAddSub
SW101011basertoffsetoffsetoffsetmem_word(base + offset) = rtStoreWord
SWL101010basertoffsetoffsetoffsetstore most significant part of rtMemoryUnaligned
SWR101110basertoffsetoffsetoffsetstore least significant part of rtMemoryUnaligned
SYSCALL000000codecodecodecode001100syscallSyscallInstrs
XOR000000rsrtrd00000100110rd = rs ^ rtBitwise
XORI001110rsrtimmimmimmrt = rs ^ zext(imm)BitwiseImm
BAL0000010000010001offsetoffsetoffsetRA = PC + 8, PC = PC + sign_extend(offset || 00)Jump
SYNCI000001base11111offsetoffsetoffsetsync (nop)AddSubImm
PREF110011basehintoffsetoffsetoffsetprefetch(nop)AddSubImm
TEQ000000rsrtcodecode110100trap if rs == rt (the execution is rejected)MiscInstrs
ROTR00000000001rtrdsa000010rd = rotate_right(rt, sa)ShiftRightImm
ROTRV000000rsrtrd00001000110rd = rotate_right(rt, rs[4:0])ShiftRight
WSBH01111100000rtrd00010100000rd = swaphalf(rt)MovCond
EXT011111rsrtmsbdlsb000000rt = rs[msbd+lsb..lsb]MiscInstrs
SEH01111100000rtrd11000100000rd = signExtend(rt[15..0])MiscInstrs
SEB01111100000rtrd10000100000rd = signExtend(rt[7..0])MiscInstrs
INS011111rsrtmsblsb000100rt = rt[32:msb+1] || rs[msb+1-lsb : 0] || rt[lsb-1:0]MiscInstrs
MADDU011100rsrt0000000000000001(hi, lo) = rs * rt + (hi,lo)MiscInstrs
MADD011100rsrt0000000000000000(hi, lo) = (hi,lo) + rs * rt (signed)MiscInstrs
MSUBU011100rsrt0000000000000101(hi, lo) = (hi,lo) - rs * rtMiscInstrs
MSUB011100rsrt0000000000000100(hi, lo) = (hi,lo) - rs * rt (signed)MiscInstrs

Supported syscalls

syscall numberfunction
SYSHINTLEN = 0x00_00_00F0,Return length of current input data.
SYSHINTREAD = 0x00_00_00F1,Read current input data.
SYSVERIFY = 0x00_00_00F2,Verify pre-compile program.
HALT = 0x00_00_0000,Halts the program.
WRITE = 0x00_00_0002,Write to the output buffer.
ENTER_UNCONSTRAINED = 0x00_00_0003,Enter unconstrained block.
EXIT_UNCONSTRAINED = 0x00_00_0004,Exit unconstrained block.
SHA_EXTEND = 0x30_01_0005,Executes the SHA_EXTEND precompile.
SHA_COMPRESS = 0x01_01_0006,Executes the SHA_COMPRESS precompile.
ED_ADD = 0x01_01_0007,Executes the ED_ADD precompile.
ED_DECOMPRESS = 0x00_01_0008,Executes the ED_DECOMPRESS precompile.
KECCAK_SPONGE = 0x01_01_0009,Executes the KECCAK_SPONGE precompile.
SECP256K1_ADD = 0x01_01_000A,Executes the SECP256K1_ADD precompile.
SECP256K1_DOUBLE = 0x00_01_000B,Executes the SECP256K1_DOUBLE precompile.
SECP256K1_DECOMPRESS = 0x00_01_000C,Executes the SECP256K1_DECOMPRESS precompile.
BN254_ADD = 0x01_01_000E,Executes the BN254_ADD precompile.
BN254_DOUBLE = 0x00_01_000F,Executes the BN254_DOUBLE precompile.
COMMIT = 0x00_00_0010,Executes the COMMIT precompile.
COMMIT_DEFERRED_PROOFS = 0x00_00_001A,Executes the COMMIT_DEFERRED_PROOFS precompile.
VERIFY_ZKM_PROOF = 0x00_00_001B,Executes the VERIFY_ZKM_PROOF precompile.
BLS12381_DECOMPRESS = 0x00_01_001C,Executes the BLS12381_DECOMPRESS precompile.
UINT256_MUL = 0x01_01_001D,Executes the UINT256_MUL precompile.
U256XU2048_MUL = 0x01_01_002F,Executes the U256XU2048_MUL precompile.
BLS12381_ADD = 0x01_01_001E,Executes the BLS12381_ADD precompile.
BLS12381_DOUBLE = 0x00_01_001F,Executes the BLS12381_DOUBLE precompile.
BLS12381_FP_ADD = 0x01_01_0020,Executes the BLS12381_FP_ADD precompile.
BLS12381_FP_SUB = 0x01_01_0021,Executes the BLS12381_FP_SUB precompile.
BLS12381_FP_MUL = 0x01_01_0022,Executes the BLS12381_FP_MUL precompile.
BLS12381_FP2_ADD = 0x01_01_0023,Executes the BLS12381_FP2_ADD precompile.
BLS12381_FP2_SUB = 0x01_01_0024,Executes the BLS12381_FP2_SUB precompile.
BLS12381_FP2_MUL = 0x01_01_0025,Executes the BLS12381_FP2_MUL precompile.
BN254_FP_ADD = 0x01_01_0026,Executes the BN254_FP_ADD precompile.
BN254_FP_SUB = 0x01_01_0027,Executes the BN254_FP_SUB precompile.
BN254_FP_MUL = 0x01_01_0028,Executes the BN254_FP_MUL precompile.
BN254_FP2_ADD = 0x01_01_0029,Executes the BN254_FP2_ADD precompile.
BN254_FP2_SUB = 0x01_01_002A,Executes the BN254_FP2_SUB precompile.
BN254_FP2_MUL = 0x01_01_002B,Executes the BN254_FP2_MUL precompile.
SECP256R1_ADD = 0x01_01_002C,Executes the SECP256R1_ADD precompile.
SECP256R1_DOUBLE = 0x00_01_002D,Executes the SECP256R1_DOUBLE precompile.
SECP256R1_DECOMPRESS = 0x00_01_002E,Executes the SECP256R1_DECOMPRESS precompile.
POSEIDON2_PERMUTE = 0x00_01_0030,Executes the POSEIDON2_PERMUTE precompile.
SYS_MMAP = 4210,Linux mmap: allocate memory from the heap.
SYS_MMAP2 = 4090,Linux mmap2: same as mmap.
SYS_BRK = 4045,Linux brk: return the program break.
SYS_CLONE = 4120,Linux clone: simulated, returns 1.
SYS_EXT_GROUP = 4246,Linux exit_group: halt with an exit code.
SYS_READ = 4003,Linux read: only stdin, returns 0 bytes.
SYS_WRITE = 4004,Linux write: stdout, stderr, or the public-values (3) and hint (4) descriptors.
SYS_FCNTL = 4055,Linux fcntl: F_GETFD and F_GETFL on fds 0-2.

Linux syscalls not listed above but handled as no-ops (open, close, munmap, rt_sigaction, uname, futex_time64, prctl and others) are listed in Linux ABI. All Linux syscalls are proved by one chip, SysLinux; in the proof they are grouped under the code SYS_LINUX = 4000, which is not itself a syscall. Any other syscall number is rejected by the executor (UnsupportedSyscall).