A single-page RISC-V machine you can step one data transfer at a time. Not one instruction at a time — one value moving between two components: the register file lights up as it sends, the ALU lights up as it receives, the wire animates, and the value itself rides across on the bus. Every box on the diagram shows what it is currently holding, and keeps holding it until the next instruction overwrites it.
Why another RISC-V simulator? The existing ones answer “what does this program do”. This one answers where did that value come from, and what happened to it on the way — which is the question you actually have when an instruction's behaviour surprises you.
Everything on screen is architectural: no pipeline, no cache, no arithmetization. Just the machine the manual describes.
The machine implements RV32I plus the M extension — the 32-bit base integer instructions and multiply/divide, 45 opcodes, every one of which the pre-loaded program executes at least once in 119 instructions. The omissions are deliberate.
| Not implemented | Why |
|---|---|
| RV64I widths | This is a 32-bit machine. |
| A — atomics | One hart, no interrupts, no preemption: executing in order already satisfies every atomicity guarantee. |
| C — compressed | Every instruction is four bytes wide, which keeps address arithmetic and the ROM layout uniform. |
ecall, ebreak, fence, CSRs | There is no execution environment or privileged software to talk to. Results are written into RAM, where the memory panel reads them back. |
Memory is byte-addressed and little-endian, split into three regions rather than presented as one anonymous array:
| Region | Range | What it holds |
|---|---|---|
| ROM | 0x00000000–0x000007FF | Instructions and read-only data; a store into it raises a store access fault. |
| RAM | 0x00010000–0x000103FF | Ordinary read-write memory. |
| STACK | 0x00020000–0x000203FF | Drawn separately so call frames are legible. sp starts at 0x00020400 and grows downward. |
Alignment is enforced, and the exceptions carry the architecture's own names, from instruction address misaligned to load/store access fault.
The program in ROM makes one pass through every RV32IM instruction, top to bottom, in phases you can jump between:
- Boot —
lui/addisetting up the stack pointer, andauipc+addicomputing an address from the program counter itself. - Arithmetic — including
addion0x7FFFFFFF, which wraps to the most negative integer: RISC-V has no overflow trap and no flags. - Logic and shifts — a shift by
0x54that turns out to be a shift by 20, because only the low five bits of the amount are used. - Comparison — the same register pair read signed and unsigned.
- Branches and a loop — all six conditions, then a backward branch three times around.
- Call —
jalsaving a return address andret(which is justjalr x0, 0(ra)) going back to it. - Multiply and divide — one 64-bit product read four ways, and both degenerate division cases the ISA defines rather than traps.
- Memory — a stack push and pop,
lbversuslbuon the same byte, and byte and halfword stores assembling one word.
- Datapath — PC, ROM, decode, registers, ALU, memory, writeback and next-PC, each box displaying the values it currently holds. Sender teal, receiver amber, the value on the wire.
- Bit-field decoder — the 32-bit word split into its encoding fields, with a plain-English description of the opcode, so
MULHSUreads as “multiply high, signed × unsigned”. - Operation detail, registers and memory — binary before and after, byte lanes and sign extension, the full 64-bit product; all 32 registers and a dump of each memory region.
- Honest timing — a register write or a stored word stays unchanged until the transfer that actually does it goes through.
- Reversible — step backwards a transfer at a time; registers, memory and the program counter all restore exactly.
