For our Computer Organization and Design (CIS 4710) class we designed a 6-stage pipelined RISC-V processor in SystemVerilog implementing the RV32IM instruction set. The processor handles data and control hazards and communicates with memory through the AXI4-Lite bus protocol.
Special thanks to my teammate Mudit for their collaboration on this project.
Building Up the Processor
The processor was built incrementally over the semester, with each stage adding a layer on top of the last:
Arithmetic building blocks: A 32-bit carry lookahead adder, which computes carries in a tree instead of rippling them through 32 stages, and a 32-bit unsigned divider built from a chain of restoring division iterations.
A single-cycle processor: The first complete CPU, executing one instruction per clock cycle.
A multi-cycle divider: The combinational divider was rebuilt as an 8-stage pipeline running 4 division iterations per stage. This let the rest of the design run at a much higher clock speed.
A 5-stage pipeline: Implemented the Fetch–Decode–Execute–Memory–Writeback pipeline, where five instructions are in flight at once.
An AXI4-Lite memory interface: The final version replaces the single-cycle memory with a realistic bus interface, which required adding a sixth pipeline stage.
Pipeline Architecture
The final design has six stages: Fetch–Go to memory-Decode–Execute–Memory–Writeback. The extra "Go to memory" stage exists because AXI4-Lite transactions only happen on clock edges, so a read request sent on one rising edge does not return data until the next one. That one cycle of instruction-fetch latency needs its own stage in the pipeline.
Every stage is separated by pipeline registers, and control logic decides each cycle whether each stage should advance normally, hold its current instruction, or be flushed and replaced with a “no-op”.
Hazards and Bypassing
To keep the pipeline running efficiently, we implemented hazard detection and data forwarding to minimize unnecessary stalls. Memory-to-Execute and Writeback-to-Execute bypasses forward results directly to dependent instructions, while a Writeback-to-Decode bypass handles register reads occurring in the same cycle as a write. When forwarding cannot resolve a dependency, such as a load-use hazard, the pipeline inserts a one-cycle stall. Taken branches are resolved in Execute and flush the three instructions behind them, while divide tracking allows independent divisions to overlap through the 8-stage divider and stalls only dependent instructions until their results are available.
AXI4-Lite Memory Interface
Connected the pipeline to AXI4-Lite memory, handling variable response timing, backpressure, and instruction requests. Implemented load/store support with sign/zero extension and byte-level writes.
Testing
The processor was synthesized and deployed to an FPGA board, validating its functionality on real hardware beyond simulation.