A small MIPS-32 instruction emulator in modern C++. Parses MIPS assembly, decodes R/I/J-type instructions, and executes them against a register file and 64KB of byte-addressable memory.
You hand it a program in MIPS assembly, it runs:
# examples/sum_first_10.s
# Sum the integers 1..10 into $v0.
addi $t0, $zero, 0 # i = 0
addi $t1, $zero, 0 # sum = 0
addi $t2, $zero, 10 # limit = 10
loop:
addi $t0, $t0, 1 # i++
add $t1, $t1, $t0 # sum += i
bne $t0, $t2, loop # while i != limit
add $v0, $t1, $zero # return sum in $v0$ ./mips run examples/sum_first_10.s
program halted after 32 cycles
$v0 = 55Built as a self-study of MIPS architecture and single-cycle datapath design.
The instruction set is the textbook MIPS subset most courses cover:
| Type | Instructions |
|---|---|
| R-type | add, sub, and, or, xor, nor, slt, sll, srl, jr |
| I-type | addi, andi, ori, xori, slti, lw, sw, lb, sb, beq, bne, lui |
| J-type | j, jal |
Plus pseudo-instructions:
li $rt, imm→addi $rt, $zero, imm(small) orlui+ori(large)move $rd, $rs→add $rd, $rs, $zeronop→sll $zero, $zero, 0
┌──────────────────────────────┐
│ MIPS assembly text │
└─────────────┬────────────────┘
▼
┌──────────────────────────────┐
│ assembler │ → resolves labels, emits 32-bit instructions
└─────────────┬────────────────┘
▼
┌──────────────────────────────┐
│ CPU + memory │ → 32 registers, 64KB memory, PC, instruction
│ │ register; fetch / decode / execute loop
└──────────────────────────────┘
The emulator is a single-cycle reference implementation — no pipelining, no caching, no MMU. Clean and pedagogical. Easy to extend if you want to add a 5-stage pipeline or branch prediction as a follow-on assignment.
git clone https://github.com/forgehk/mips-emulator
cd mips-emulator
make
./mips run examples/sum_first_10.s
# trace mode: print PC, instruction, and registers each cycle
./mips run --trace examples/sum_first_10.s
# dump memory after running
./mips run examples/memory_demo.s --dump 0x100,0x120Run the test suite:
make test| Name | Number | Convention |
|---|---|---|
$zero |
0 | Always zero |
$at |
1 | Assembler temporary |
$v0-$v1 |
2-3 | Return values |
$a0-$a3 |
4-7 | Arguments |
$t0-$t7 |
8-15 | Temporaries (caller-saved) |
$s0-$s7 |
16-23 | Saved (callee-saved) |
$t8-$t9 |
24-25 | Temporaries |
$k0-$k1 |
26-27 | Kernel reserved |
$gp |
28 | Global pointer |
$sp |
29 | Stack pointer |
$fp |
30 | Frame pointer |
$ra |
31 | Return address |
The examples/ directory has runnable programs covering:
- sum_first_10.s — for-loop summation
- factorial.s — recursive
jal/jr $rafactorial - memory_demo.s —
lw/swto stack and heap regions - branch_demo.s —
beq,bne,sltbased control flow - shift_logic.s —
sll,srl,and,or,xor,nor
Building a working emulator is the best way to internalize what each instruction actually does at the hardware level. This is that emulator, kept minimal and pedagogical.
It's also a useful interview artifact because it demonstrates:
- Real systems-level C++ (memory model, bit manipulation, instruction decoding).
- A small but complete compiler/runtime pipeline (text → assembled binary → executed result).
- Discipline around register conventions and ABI rules.
- R/I/J-type decode and execute
- Label resolution in the assembler
- Trace + memory dump modes
- Test suite covering each instruction
- 5-stage pipeline simulator (separate executable)
- Cache model with hit/miss stats
- Floating-point coprocessor (cop1) —
add.s,mul.s, etc. - Linker for multi-file programs
Built by @forgehk — DarkForge AI