Master the fundamental concepts of cpu design through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksModern teaching pipelines use IF (fetch), ID (decode), EX (execute), MEM (memory), and WB (writeback). Each stage advances every cycle, so five instructions can be in flight at once when the pipe is full.
cLoading…
| Stage | Job |
|---|---|
| IF | Read instruction at PC |
| ID | Decode, read registers |
| EX | ALU, address calc |
| MEM | Load/store data |
| WB | Write register result |
Load-use hazards are the classic pain: a LOAD in EX produces data in MEM, but the next instruction needs it in EX one cycle later. You must stall one cycle or forward from MEM/WB.
For this exercise, you will refactor your CPU into five pipeline registers. You will need stage-accurate PC and register updates to match textbook timing diagrams before adding forwarding to remove unnecessary stalls.
Keep the relevant datasheet, ISA manual, or architecture textbook chapter open while you implement. When your output disagrees with the reference trace on the same program, the bug is usually a mis-decoded opcode, a stale register read, or a flag bit left unchanged after arithmetic.
For this exercise, you will use those habits while implementing the requirement in the starter code. Microarchitectural product names change across CPU generations, but the control ideas (fetch, bypass, cache lines, vector lanes) stay stable enough to debug from first principles.
Build the classic 5-stage pipeline: IF (fetch), ID (decode + register read), EX (ALU, branch decision), MEM (load/store) and WB (register write). Up to five instructions are in flight at once. This version has no forwarding: an instruction must wait in ID until the registers it needs have been written back. Simulate it cycle by cycle, count stalls and flushes, and measure the speedup over a single-cycle CPU.
Registers R0: R7 (integers, start at 0) and 16 words of data memory (start at 0; the address is (Rs + off) mod 16). Labels are name: at the start of a line. Programs are well-formed.
| Instruction | Reads | Writes |
|---|---|---|
LI Rd, imm | - | Rd |
ADD Rd, Rs, Rt / SUB Rd, Rs, Rt | Rs, Rt | Rd |
LW Rd, off(Rs) | Rs | Rd = mem[Rs + off] |
SW Rt, off(Rs) | Rt, Rs | mem[Rs + off] = Rt |
BNEZ Rs, label | Rs | branch if Rs ≠ 0 |
HALT | - | - |
Instructions are named I0, I1, … by position (labels and blank lines don't count).
BNEZ is decided in EX. If taken, the instructions in ID and IF are flushed and IF fetches the target next cycle (this beats a stall).HALT is fetched and restarts on a taken branch; past the end it yields nothing.HALT is in WB, or once the pipeline is empty. Give up after 300 cycles.cLoading…
-- is an empty stage or bubble. Append stall Rn (the first conflicting source, in operand order: Rs, Rt for ADD/SUB, Rt, Rs for SW) or flush. Then:
cLoading…
N counts instructions that reached WB, including HALT; CPI = C / N. A single-cycle CPU takes one cycle per instruction, but its clock period is five times longer than this pipeline's, so speedup = 5N / C. On the cycle limit, print cycle limit reached instead of the retired/CPI lines.
Input:
cLoading…
Output:
cLoading…
Hidden tests cover a loop whose BNEZ is taken and then not taken, a store followed by a load from the same address, and a program without HALT.