The Sparsr Processor is a 5-stage pipelined core built on the 32-bit MIPS I instruction set, extended with custom 4096-bit Wide Instructions for parallel bitwise execution and Co-processor Memory (CMem) transfers.
This page lists every instruction that is either part of standard MIPS I or defined by Sparsr, and tracks — instruction by instruction — whether it is implemented in the Software Emulator backend (softemu) and/or in real Hardware (the Verilog Controller.v). The two don't always match: some instructions exist only for the software emulator, some hardware opcodes are reserved but not yet wired up, and most of classic MIPS I (branches, jumps, shifts, multiply/divide) isn't implemented by either.
Sources of truth used to build this table:
Controller.v) and its case statement.softemu backend of the Sparsr host runtime.spasm, which must be able to encode an instruction before it can run anywhere.| Register Type | Registers | Width | Description |
|---|---|---|---|
| Scalar Registers | $0 – $31 |
32-bit | Standard MIPS general-purpose registers ($zero, $t0–$t9, $s0–$s7, $a0–$a3, $v0–$v1, $gp, $sp, $ra). |
| Wide Registers | $wA – $wB |
4096-bit | Ultra-wide registers used for 4096-bit bitwise operations and CMem payloads. |
| Data Memory (DMem) | Standard RAM | 32-bit | Accessed via standard MIPS scalar loads/stores. |
| Compressed Memory (CMem) | Block RAM (BRAM) | 4096-bit | High-speed storage accessed via wide instructions (WL, WS, WLR, WSR). Compression/decompression happens automatically inside these instructions — there is no separate compress/decompress opcode. |
All instructions are encoded into 32-bit words. opcode is always the top 6 bits.
| Format | Layout | Used by |
|---|---|---|
| R-Type | opcode(6) · rs(5) · rt(5) · rd(5) · shamt(5) · funct(6) |
Register-register ALU ops |
| I-Type | opcode(6) · rs(5) · rt(5) · immediate(16) |
Register-immediate ALU ops, LW/SW |
| J-Type | opcode(6) · address(26) |
Jumps (reserved by MIPS I; unused by Sparsr) |
| WR-Type (Wide Register) | opcode(6) · reserved(2) · wrs(8) · wrt(8) · wrd(8) |
WAND, WOR, WXOR, WADD, WSUB |
| WI-Type (Wide Immediate) | opcode(6) · reserved(2) · wrd(8) · addr(16, BRAM offset) |
WL, WS, WLR, WSR |
| Halt | All 1s (0xFFFFFFFF) |
Program terminator — both the assembler and softemu recognize this exact word as "stop execution". |
31 26 25 21 20 16 15 11 10 6 5 0
+----------+----------+----------+----------+----------+----------+
| opcode | rs | rt | rd | shamt | funct | R-Type
+----------+----------+----------+----------+----------+----------+
| opcode | rs | rt | immediate (16) | I-Type
+----------+----------+----------+----------+----------+----------+
| opcode | address (26) | J-Type
+----------+----------+------------------------------------------------------+
31 26 25 24 23 16 15 8 7 0
+----------+----------+------------------+------------------+------------------+
| opcode | reserved | wrs (8) | wrt (8) | wrd (8) | WR-Type
+----------+----------+------------------+------------------+------------------+
| opcode | reserved | wrd (8) | addr / BRAM offset (16) | WI-Type
+----------+----------+------------------+------------------+------------------+
| 1111111111111111111111111111111111111111111111111111111111111111111111 | Halt
+----------+----------+------------------+------------------+------------------+
The assembler automatically appends a
NOP(0x00000000) followed by aHaltword (0xFFFFFFFF) to the end of every assembled program — you don't write these yourself.
✅ supported · ⚠️ opcode reserved/decoded but not fully wired · ❌ not implemented · — not applicable
CMem)| Mnemonic | Name | Format | Opcode | Softemu | Hardware | Notes |
|---|---|---|---|---|---|---|
WAND |
Wide AND | WR | 18 | ✅ | ✅ | Bitwise AND of $wrs/$wrt → $wrd. |
WOR |
Wide OR | WR | 19 | ✅ | ✅ | Bitwise OR of $wrs/$wrt → $wrd. |
WXOR |
Wide XOR | WR | 20 | ✅ | ✅ | Bitwise XOR of $wrs/$wrt → $wrd. |
WL |
Wide Load | WI | 21 | ✅ | ✅ | Loads 4096 bits from CMem[addr] into $wrd, decompressing automatically. |
WS |
Wide Store | WI | 22 | ✅ | ✅ | Stores $wrd to CMem[addr], compressing automatically. |
WADD |
Wide Add | WR | 23 | ❌ | ⚠️ | Decoded but does not compute — see note below. Not encodable by the assembler, not executed by softemu. |
WSUB |
Wide Subtract | WR | 24 | ❌ | ⚠️ | Decoded but does not compute — see note below. Not encodable by the assembler, not executed by softemu. |
WLR |
Wide Load, Register-indirect | WI | 23 | ✅ | ❌ | Softemu-only extension (not in Controller.v); see note below. Not implemented in hardware yet. |
WSR |
Wide Store, Register-indirect | WI | 24 | ✅ | ❌ | Softemu-only extension (not in Controller.v); see note below. Not implemented in hardware yet. |
Opcode 23/24 overlap:
WADD/WSUB(hardware wide register-register add/subtract) andWLR/WSR(softemu register-indirect wide load/store) both use opcodes 23 and 24, but they're mutually exclusive extensions of the base ISA — hardware never implementsWLR/WSR, and softemu never implementsWADD/WSUB. Don't assume opcode 23/24 means the same thing on both backends.
WLR/WSRuse the same$d,offset($t)shape asLW/SW, except$tholds a runtimeCMembase address instead of the address coming from a fixed instruction immediate — mirroring the register-indirect addressing regularLW/SWalready have. They exist purely to givetorchhd-sparsrruntime-selectable CMem addressing.
WADD/WSUBare incomplete in hardware.Controller.vdecodes both opcodes and enables wide write-back, but the corresponding cases in the wide ALU (Wide_ALU.v) are commented out, so execution falls through to thedefaultbranch and writes all zeros into the destination wide register — silently, with no trap. Treat them as unimplemented.This is not simply a matter of uncommenting those lines. The wide unit is built as 128 independent 32-bit lanes with no signal crossing lane boundaries — which is exactly what makes the 4096-bit logical operations cheap — so the commented code would produce 128 separate 32-bit adds rather than one 4096-bit add. Wide arithmetic needs a carry chain the current design does not have.
| Mnemonic | Name | Format | Opcode | Funct | Softemu | Hardware | Notes |
|---|---|---|---|---|---|---|---|
ADD |
Add | R | 0 | 32 | ✅ | ✅ | |
ADDU |
Add Unsigned | R | 0 | 33 | ✅ | ✅ | Softemu/hardware treat identically to ADD (no trap on overflow). |
SUB |
Subtract | R | 0 | 34 | ✅ | ✅ | |
SUBU |
Subtract Unsigned | R | 0 | 35 | ✅ | ✅ | Softemu/hardware treat identically to SUB. |
AND |
Bitwise AND | R | 0 | 36 | ✅ | ✅ | |
OR |
Bitwise OR | R | 0 | 37 | ✅ | ✅ | |
XOR |
Bitwise XOR | R | 0 | 38 | ✅ | ✅ | |
NOR |
Bitwise NOR | R | 0 | 39 | ✅ | ✅ | |
SLT |
Set on Less Than | R | 0 | 42 | ❌ | ❌ | Opcode/funct not referenced by Controller.v's decode case. |
SLTU |
Set on Less Than Unsigned | R | 0 | 43 | ❌ | ❌ | Same as above. |
LW |
Load Word | I | 35 | — | ✅ | ✅ | |
SW |
Store Word | I | 43 | — | ✅ | ✅ | |
ADDI |
Add Immediate | I | 8 | — | ❌ | ⚠️ | Decoded by Controller.v; assembler has no mnemonic for it, so it's unreachable in practice. |
ADDIU |
Add Immediate Unsigned | I | 9 | — | ❌ | ⚠️ | Same as ADDI. |
SUBI |
Subtract Immediate | I | 16 | — | ❌ | ⚠️ | Non-standard MIPS I opcode added locally; same gap as ADDI. |
ANDI |
AND Immediate | I | 12 | — | ❌ | ⚠️ | Same as ADDI. |
ORI |
OR Immediate | I | 13 | — | ❌ | ⚠️ | Same as ADDI. |
XORI |
XOR Immediate | I | 14 | — | ❌ | ⚠️ | Same as ADDI. |
SLTI |
Set Less Than Immediate | I | 10 | — | ❌ | ❌ | Opcode constant exists but is not referenced by Controller.v's decode case. |
SLTIU |
Set Less Than Immediate Unsigned | I | 11 | — | ❌ | ❌ | Same as above. |
LUI |
Load Upper Immediate | I | 15 | — | ❌ | ❌ | Same as above. |
LB |
Load Byte | I | 32 | — | ❌ | ❌ | |
LBU |
Load Byte Unsigned | I | 36 | — | ❌ | ❌ | |
LH |
Load Halfword | I | 33 | — | ❌ | ❌ | |
LHU |
Load Halfword Unsigned | I | 37 | — | ❌ | ❌ | |
LWL |
Load Word Left | I | 34 | — | ❌ | ❌ | |
LWR |
Load Word Right | I | 38 | — | ❌ | ❌ | |
SB |
Store Byte | I | 40 | — | ❌ | ❌ | |
SH |
Store Halfword | I | 41 | — | ❌ | ❌ | |
SWL |
Store Word Left | I | 42 | — | ❌ | ❌ | |
SWR |
Store Word Right | I | 46 | — | ❌ | ❌ | |
SLL |
Shift Left Logical | R | 0 | 0 | ❌ | ❌ | |
SRL |
Shift Right Logical | R | 0 | 2 | ❌ | ❌ | |
SRA |
Shift Right Arithmetic | R | 0 | 3 | ❌ | ❌ | |
SLLV |
Shift Left Logical Variable | R | 0 | 4 | ❌ | ❌ | |
SRLV |
Shift Right Logical Variable | R | 0 | 6 | ❌ | ❌ | |
SRAV |
Shift Right Arithmetic Variable | R | 0 | 7 | ❌ | ❌ | |
MULT |
Multiply | R | 0 | 24 | ❌ | ❌ | |
MULTU |
Multiply Unsigned | R | 0 | 25 | ❌ | ❌ | |
DIV |
Divide | R | 0 | 26 | ❌ | ❌ | |
DIVU |
Divide Unsigned | R | 0 | 27 | ❌ | ❌ | |
MFHI |
Move From HI | R | 0 | 16 | ❌ | ❌ | |
MTHI |
Move To HI | R | 0 | 17 | ❌ | ❌ | |
MFLO |
Move From LO | R | 0 | 18 | ❌ | ❌ | |
MTLO |
Move To LO | R | 0 | 19 | ❌ | ❌ | |
J |
Jump | J | 2 | — | ❌ | ❌ | |
JAL |
Jump and Link | J | 3 | — | ❌ | ❌ | |
JR |
Jump Register | R | 0 | 8 | ⚠️ | ❌ | Softemu special-cases the literal word for jr $ra only, as an end-of-program halt marker — not a general jump. |
JALR |
Jump and Link Register | R | 0 | 9 | ❌ | ❌ | |
BEQ |
Branch on Equal | I | 4 | — | ❌ | ❌ | |
BNE |
Branch on Not Equal | I | 5 | — | ❌ | ❌ | |
BLEZ |
Branch on ≤ Zero | I | 6 | — | ❌ | ❌ | |
BGTZ |
Branch on > Zero | I | 7 | — | ❌ | ❌ | |
BLTZ |
Branch on < Zero | I (rt=0) |
1 | — | ❌ | ❌ | |
BGEZ |
Branch on ≥ Zero | I (rt=1) |
1 | — | ❌ | ❌ | |
BLTZAL |
Branch on < Zero and Link | I (rt=16) |
1 | — | ❌ | ❌ | |
BGEZAL |
Branch on ≥ Zero and Link | I (rt=17) |
1 | — | ❌ | ❌ | |
SYSCALL |
System Call | R | 0 | 12 | ❌ | ❌ | |
BREAK |
Breakpoint | R | 0 | 13 | ❌ | ❌ | |
NOP |
No Operation | — | — | — | ✅ | ✅ | All-zero instruction word; softemu treats it as a no-op rather than dispatching it as an opcode. |
Coprocessor instructions (
LWC*,SWC*,MFC*,MTC*,CFC*,CTC*) are part of MIPS I but aren't listed here — Sparsr's wide unit is a fixed-function extension, not a MIPS coprocessor interface, so these encodings don't apply to it.
WL $t1,1
WL $t2,2
WAND $t3,$t1,$t2
WOR $t4,$t1,$t2
WXOR $t5,$t1,$t2
WS $t3,3
WS $t4,4
WS $t5,5