CASE STUDY / 01 / COMPUTER ARCHITECTURE

The processor development archive.

A five-stage RV32I-subset processor with independent instruction/data ports and opt-in fault-stop diagnostics. The latest verification checks instruction-fetch bounds, older-instruction completion and speculative fault suppression at the 4 KiB modeled memory boundary.

RECRUITER BRIEF / WHAT THE EVIDENCE SUPPORTS

My engineering work

Built and iterated on the five-stage RTL, tagged I/D handshakes and fault-ordering behavior, with testbenches and review. AI-assisted development and review were part of this iteration; inspect the linked source rather than assuming unaided authorship of every line.

Inspect first

72/72 fetch-boundary scenarios across six timing setups, with archived output, independent assertions and a reproduction script. Current RTL and testbench are linked directly.

Verification boundary

Educational RV32I subset with modeled 4 KiB fetch bounds. Not full ISA compliance, architectural traps, formal proof, synthesis or FPGA performance.

01 / THE QUESTION

How does an instruction become hardware behavior?

Studying processor architecture in a diagram is one thing. Translating instruction fields into data paths, control decisions and state transitions forces every assumption to become explicit. This project follows the journey from a base RISC-V instruction to the modules that process it.

The earlier integrated core learned to wait for delayed internal data memory. The new question is whether both instruction fetch and data memory can live outside the processor, each with independent request acceptance and response timing. The current external-port mode tests that boundary with separate I/D handshakes while retaining architectural program checks.

The latest milestone addresses an additional pipeline problem: what happens when an instruction is invalid, its taken target is misaligned, or it accesses an unsupported memory address? With FAULT_HALT=1, the core stops precisely at the faulting instruction, exposes a stable diagnosis, and waits for reset. It does not execute a RISC-V machine-mode trap.

The next challenge is a fetch just beyond the modeled instruction memory: does it truly fault, or can an older taken branch prove that fetch was speculative? The new implementation carries an invalid fetch as a squashable token to EX so the pipeline preserves instruction age rather than treating every attempted fetch as an immediate fault.

02 / SYSTEM DESIGN

Five stages, one data path.

Fetch, decode, execute, memory and writeback form one in-order pipeline. In EXTERNAL_PORTS=1 mode, instruction and data memories are supplied by separate ports outside the core. Each channel allows one outstanding request and uses rising-edge valid && ready transfers; the two channels can overlap. The older self-contained mode remains for historical regressions.

Opt-in, architecturally ordered fault-stop

With FAULT_HALT=1, the EX stage recognizes illegal/unsupported encodings, misaligned taken branch/JAL/JALR targets, and misaligned or out-of-range loads/stores. Any older memory operation finishes before the younger fault is reported; older writeback can retire. The faulting instruction never enters memory, and wrong-path or younger instructions cannot modify architectural state. A pending external fetch may still be accepted and drained without execution.

Four outputs retain the first diagnosis until reset: fault_valid (sticky), fault_cause (0 control-target alignment; 1 modeled instruction-fetch range; 2 illegal instruction; 4/6 load/store misalignment; 5/7 modeled load/store range), fault_pc (faulting instruction or fetch PC), and fault_tval (illegal instruction bits, invalid fetch PC, bad target or effective address). The default FAULT_HALT=0 preserves prior behavior.

A bad fetch is not always an architectural fault

When the next fetch PC falls outside 0x00000000–0x00000fff, FAULT_HALT=1 creates one synthetic IF-to-EX fault token instead of reading an aliased internal word or issuing an invalid external I request. If an older taken BEQ, JAL or JALR at 0x00000ffc redirects in range, it flushes the wrong-path token. If the fetch is real, EX reports sticky cause=1 with fault_pc=fault_tval equal to the invalid fetch PC.

An aligned JAL/JALR to 0x00001000 is itself valid: the link register retires, then the *younger fetch* at that address faults. Earlier loads or stores drain first, even with independent I/D delays and held responses. Reset clears the sticky diagnosis. This checks only the fixed local teaching memory; external hardware bus errors and architectural instruction-access trap handling remain unsupported.

TESTED PIPELINE STAGE ORDERSCHEMATIC SUMMARY, NOT RTL PLACEMENT

Fetch buffers a returned instruction until decode can accept it. An older data transaction holds younger pipeline stages until its response handshake; earlier writeback retires once, and redirects cannot overtake an unfinished store.

Conceptual stage order in external-port mode. Instruction and data responses arrive from a separate simulation adapter; the diagram does not imply timing closure or a standardized bus implementation.
01

Match fetched instructions to their PC

Instruction requests carry an address and 8-bit tag; matching responses are buffered until IF/ID can advance. Redirects invalidate the old fetch epoch, drain obsolete replies, and request the new branch target without executing wrong-path instructions.

02

Wait for completion without double commits

EX/MEM holds the data address, write strobes, payload and destination until its tagged response handshakes. An older MEM/WB instruction retires once, and a held decode operand is refreshed if its producer writes back. DATA_RESPONSE_DELAY intentionally withholds d_rsp_ready to test stable responses.

03

Keep branches and stores in order

Younger redirects wait behind pending data accesses; stale instruction replies are discarded after a taken branch. The same little-endian byte-lane logic supports LB/LBU/LH/LHU/LW and SB/SH/SW, with no claim of out-of-order memory or MMIO support.

Two ports, independently stalled

The test adapter varies instruction and data latency independently and can hold either req_ready low. A response remains valid, with the same tag and payload, until the core raises rsp_ready. Fetch checks both the echoed PC and tag; data checks its tag. The adapter commits stores at the response handshake once. This is a bounded, single-outstanding educational protocol on one core clock, not AXI or a physical SRAM timing model.

EXTERNAL I/D TRANSACTIONS / CAPTURED HANDSHAKEREAL RTL SIMULATION · NO HARDWARE TIMING CLAIM
Captured cycle samples of independent instruction and data request and response valid/ready signals and transaction tags, including a held data response.
Captured from the independently timed instruction/data adapter. Download the real interface-signal VCD excerpt ↓ The excerpt preserves 22 original interface signals over the first 180 simulation cycles; rerun the linked regression for the full VCD. No hardware throughput or clock frequency is implied.

Earlier latency-controlled internal memory

Before external I/D ports, the core used an internal behavioral memory adapter. That prior milestone tested base delays of 1, 2 or 4 cycles plus deterministic extra delays of up to three cycles; its trace remains below as historical evidence.

EARLIER INTERNAL DATA-MEMORY HANDSHAKESIMULATOR SIGNALS, NOT HARDWARE TIMING
Captured memory-handshake timing showing the processor PC, request valid and ready, pipeline hold and response completion during variable-latency memory accesses.
Waveform derived from the preceding internal-memory milestone. Download raw memory-handshake VCD ↓ Values reflect the behavioral model and test stimulus, not measured FPGA clock timing.
03 / INSPECT THE SOURCE

Implementation with receipts.

The newest instruction-fetch boundary implementation and independent tests come first. Earlier fault-stop, external I/D bus, internal latency-memory and integration sources remain linked below at their original verified revisions.

Instruction-fetch range and ordered fault token / new milestone

Earlier implementation milestonesPrecise fail-stop, external I/D ports, memory latency and initial pipeline · original revision links

Earlier precise fail-stop diagnostics

Independent instruction/data ports

Earlier memory-latency milestone

Earlier integrated and module evidence

REAL RTL / FORWARDING (EARLIER INTEGRATION)Full file ↗
wire [31:0] forward_a = ex_match1 ? ex_mem_alu_res :
                        wb_match1 ? rf_wd : id_ex_rd1;
wire [31:0] forward_b = ex_match2 ? ex_mem_alu_res :
                        wb_match2 ? rf_wd : id_ex_rd2;

Newer EX/MEM wins over MEM/WB. The hazard detector holds back dependent instructions when a load result is not yet available; this prevents forwarding unready memory data.

04 / VERIFICATION

Fetch faults. In instruction order.

The independent fetch-boundary bench executes 12 distinct scenarios under six internal/external I/D timing configurations. Each run compares 32 registers and 1,024 modeled RAM words, yielding 72 scenario runs and 76,032 final-state comparisons—not 76,032 different instructions or tests. The checks verify that valid instructions finish, speculative fetch faults are squashed, and no invalid external instruction request is offered. The I/D adapter also exercises response backpressure.

MODELED 4 KiB FETCH BOUNDS / FAULT_HALT=1 / OCTOBER 14, 2026

72 scenarios · 76,032 architectural state comparisons

72 / 72

Across six configurations, 48 sticky cause-1 fetch faults and 24 valid or reset scenarios passed. The tests cover sequential crossing after 0xffc, older load/store completion, valid redirects at the final instruction word, JAL/JALR link writes before a younger fetch fault at 0x1000, and reset recovery. Four separate opt-out tests confirmed expected simulator rejections; four original integrated programs also passed their existing 4,224 historical state checks. These compatibility checks are not part of the 76,032 new comparisons.

One boundary. Three different correct outcomes.

Examples from the captured passing simulator log and the checking testbench ↗, not illustrative performance numbers.

Taken BEQ at 0xffc redirects inwardInvalid speculative fetch is discarded; no sticky fault; expected marker 41 observed.
Not-taken BEQ at 0xffcSequential fetch at 0x1000 reports cause 1, with fault PC and tval both 0x1000.
JAL at 0xffc targets 0x1000The older link write retires; the younger invalid fetch produces cause 1 at 0x1000.

Ordering under load: a separate SW→LW case must finish two older data transactions before the invalid fetch stops the core. The captured external-memory runs report D=2, cause=1 and pc=tval=0x1000. The exact test sequence ↗ and runner output ↗ let a reviewer check the causal claim; these are modeled, not physical bus faults.

Earlier illegal instruction and data fault-stop checks

The preceding opt-in fail-stop milestone established EX-stage illegal-instruction, misaligned control target, and invalid data-access diagnostics. Its 90 scenarios and 95,040 architectural comparisons remain separate from the new instruction-fetch boundary regression.

The fault-halt suite runs 12 invalid-instruction or access scenarios and three non-fault cases under each of six configurations: three internal-memory and three independently timed external I/D combinations. Every run checks 32 registers and 1,024 data-memory words, including whether younger instructions were suppressed, valid older work survived and the diagnosis remains stable until reset.

OPT-IN FAULT-STOP / ICARUS VERILOG / OCTOBER 14, 2026

90 scenarios · 95,040 architectural state comparisons

90 / 90

Across the six timing configurations, 72 fault cases and 18 no-fault cases passed. Checks cover illegal encodings, misaligned or out-of-range memory accesses, misaligned taken control targets, wrong-path suppression, sticky fault outputs, and the absence of faulting data requests. Four additional expected simulator-fatal cases confirm FAULT_HALT=0 preserves the earlier behavior. These checks do not implement or verify RISC-V privilege, machine-mode traps or recovery.

Earlier external I/D bus verification

The preceding port-level regression separately passed 42 directed runs and 12 interpreter-reference runs, totaling 57,024 state comparisons, plus two expected corrupted-tag rejections. Its independently timed instruction/data traces and source remain linked below. None of those checks are counted as part of the new 95,040 fault-stop comparisons.

The external regression uses a separate adapter with independently varied instruction and data timing. Six configurations run seven self-checking programs each: mixed load/store hazards, branch redirects and wrong-path suppression, backward branches with delayed fetch, signed subword loads and masked stores, reset cancellation of an outstanding store, a 300-redirect loop that wraps fetch tags, and a 301-instruction straight-line test. Every completed case checks all 32 registers and 1,024 modeled memory words against explicit expected state.

EXTERNAL I/D BUS / DIRECTED REGRESSION / OCTOBER 14, 2026

42 scenario runs · 44,352 state comparisons

42 / 42

Request and response counters catch duplicate or missing data transactions and repeated stores. The testbench also asserts that instruction and data request/response payloads remain stable while ready is low. Timed configurations exercise independent ready stalls, fetch redirects and held data responses. Two negative tests deliberately corrupt I/D response tags and must terminate with identity errors.

INDEPENDENT SEQUENTIAL ORACLE / EXTERNAL I/D PORTS

12 program runs · 12,672 additional state comparisons

12 / 12

Three seeded instruction programs are independently decoded and interpreted by Python to calculate architectural register and byte-addressed memory results. Each executes under four independent instruction/data timing combinations, then checks every register and all 1,024 modeled memory words. These are self-checking simulation results, not formal ISA conformance or unique instruction-count measurements.

REPRODUCE EXTERNAL PORT TESTS / ICARUS VERILOGInterface contract ↗
bash scripts/run_external_regression.sh /tmp/rv32i-external

The runner prints per-case instruction/data request and response counts, store counts, ready-stall cycles and held-response cycles, and captures the complete raw VCD. The site provides a compact, unmodified signal-value excerpt from it for quick inspection. These are finite simulation scenarios, not a formal proof of all protocol interleavings.

Earlier internal memory-latency verification

The previous internal-memory adapter was checked across six delay configurations and against a separate Python sequential interpreter. Those 50,688 architectural comparisons and four expected-fault tests are earlier, distinct evidence; they are not included in the external-port totals above.

EARLIER INTERNAL MEMORY-LATENCY REGRESSION / OCTOBER 14, 2026

36 directed runs · 38,016 state comparisons

36 / 36

Cases cover back-to-back loads and stores, load-use and store-data dependencies, branches and wrong-path suppression, reset cancellation, and little-endian LB/LBU/LH/LHU/LW and SB/SH/SW. Checks fail if data, control flow, memory contents or transaction counts are wrong.

EARLIER INTERNAL-MEMORY SEQUENTIAL REFERENCE

12 interpreter-based runs · 12,672 comparisons

12 / 12

Three deterministic seeds generate programs and expected results with a separate Python instruction interpreter, then run each program at four memory configurations. A byte-addressed reference memory and all 32 expected registers are compared with RTL final state. Four additional expected-failure tests confirm the simulator rejects unsupported addresses and alignments; they do not establish an architectural trap handler.

REPRODUCE / PYTHON 3 + ICARUS VERILOGMemory contract ↗
bash scripts/run_memory_regression.sh /tmp/rv32i-memory-regression

The runner writes directed logs, interpreter expectations, four expected rejection logs and the raw handshake VCD. These are simulation comparisons, not proof of complete RV32I compliance, formal exhaustiveness or physical performance.

Earlier one-cycle integrated milestone

Before the delayed-memory design, the first integrated regression passed four programs with 4,224 state checks, plus a separate jump/control-flow test. Its captured trace is retained as historical evidence of how the processor developed.

EARLIER INTEGRATED ARCHITECTURAL REGRESSION / OCTOBER 14, 2026

4 programs, 4,224 state checks passed

4 / 4

The run observed 7 load-use stalls and 11 taken redirects across arithmetic, load/store, branch and load-to-branch scenarios. An additional JAL/JALR control-flow program and all three standalone module benches passed. These are simulation observations, not silicon performance or proof of exhaustive correctness.

EARLIER INTEGRATED SIMULATION / LOAD-TO-BRANCH PROGRAMVCD SAMPLES · NOT PHYSICAL TIMING
Cycle-sampled Icarus Verilog trace with fetch PC, decoded instruction, load stall, branch redirect, writeback enable and destination, including actual stall and redirect events.
A real waveform-derived table of the final directed program, sampled after successive rising clock edges. Highlighted stall and redirect events are simulation signals, not invented CPU timing measurements. Download the original integrated VCD ↓
REPRODUCE EARLIER INTEGRATION / ICARUS VERILOG 12+Build notes ↗
bash scripts/run_regression.sh /tmp/rv32i-evidence

The runner executes standalone and integrated testbenches, captures simulator logs, and writes the raw VCD into the selected output directory.

The earlier module-level foundation

Standalone self-checking tests for the ALU, register file and control unit still pass. The original captured ALU waveform remains below as a separate, narrower piece of evidence.

STANDALONE MODULE VERIFICATION

ALU, register file and control unit passed

3 / 3

These three benches test their respective modules in isolation, with direct assertions. They complement the new integrated instruction programs rather than substituting for them.

REAL SIMULATION DATA / ALURUN ID: 2026-10-14
Waveform from an Icarus Verilog ALU simulation: directed operation controls ADD, SUB, XOR, SLL, AND, OR, SRL, SRA, SLT, SLTU and a zero-result case, with 32-bit results and zero-flag states.
Rendered from a real VCD generated by the standalone ALU testbench against alu.sv. Every value comes from the captured simulation. The VCD can be inspected independently.
01 / ALU

Arithmetic and edge cases

The bench checks arithmetic, logical operations, shifts, signed/unsigned comparisons and zero-flag behavior.

Read the ALU checks ↗
02 / REGISTERS

Architectural state

Checks cover reset behavior, read/write paths, disabled writes and the special behavior of x0.

Inspect the register testbench ↗
03 / CONTROL

Instruction decoding

Directed cases exercise instruction decode and control outputs, including an illegal/default opcode path.

Inspect control tests ↗

Verification boundary. FAULT_HALT=1 checks only the modeled local 4 KiB instruction/data ranges and reports sticky fail-stop diagnostics, including modeled fetch cause 1. It does not save machine-mode CSR state, jump to mtvec, execute a trap handler or MRET, or resume without reset. There is no physical/external bus-error response, memory protection, MMIO, AXI/AHB, interrupts, privilege, cache coherence, full ISA compliance, formal proof, synthesis or FPGA evidence. FAULT_HALT=0 retains prior legacy simulation behavior, including $fatal for invalid accepted data requests. External-memory and core reset must still cancel outstanding transactions together.

Development provenance. AI-assisted development and review were used in this iteration. The listed results describe actual, reproducible simulator runs, not a claim that every RTL and test line was independently handwritten. The linked source and verification procedures are provided for direct inspection.

05 / THE WORK AHEAD

The interesting problems aren't finished.

  1. From modeled fail-stop to architectural traps.

    Add true externally reported instruction access faults, machine-mode CSRs, mtvec, exception entry and MRET recovery, followed by broader ISA compliance work. The current fetch fault is only a local modeled bounds check.

  2. Build an actual memory system.

    Define MMIO, address mapping and bus-error responses, then integrate a real AXI or cache bridge as appropriate. The current external ready/valid ports remain a bounded educational protocol.

  3. Build hardware evidence.

    Measure synthesis and static timing, integrate a synthesizable memory system, and test on an FPGA before making frequency, area or physical performance claims.

The objective is to understand processor design deeply enough to explain the choices, show the RTL, and demonstrate behavior with evidence.

Discuss the verification work