A synthesizable, 32-bit RISC-V processor core implementing the RV32I Base Integer Instruction Set. Designed with a classic 5-stage pipeline, complete with a robust hazard detection and data bypass (forwarding) network, fully implemented and verified on the Digilent ZedBoard (Xilinx Zynq-7000 xc7z020clg484-1).
This repository contains the RTL implementation, simulation testbenches, FPGA synthesis scripts, timing reports, and bitstream.
The core implements a classic RISC 5-stage pipeline: Instruction Fetch (IF) ➔ Instruction Decode (ID) ➔ Execute (EX) ➔ Memory (MEM) ➔ Writeback (WB).
- ISA Support: Full RV32I Base Integer Instruction Set.
- Pipeline Registers: Synchronous isolation between all 5 stages for stable high-frequency scaling.
- Data Hazard Resolution:
- Integrated Forwarding Unit to bypass data from EX/MEM and MEM/WB stages directly to the ALU, resolving Read-After-Write (RAW) hazards without stalling.
- Load-Use Hazard Detection: Hardware stall mechanism to automatically insert pipeline bubbles when a memory read output is immediately required by the next instruction.
- Control Hazards: Dynamic pipeline flushing mechanism for taken branches and jumps.
- Memory Interface: Instruction and Data Memory interfaces mapped to 64KB arrays with Byte, Halfword, and Word access precision.
The design has been completely synthesized, placed, routed, and generated into a ready-to-flash bitstream using AMD/Xilinx Vivado 2023.1 targeting the Digilent ZedBoard (xc7z020clg484-1).
| Resource | Used | Available on ZedBoard | Utilization (%) |
|---|---|---|---|
| Slice LUTs (Total) | 9,567 | 53,200 | 17.98% |
| ↳ LUT as Logic (CPU Core) | 1,375 | 53,200 | 2.58% |
| ↳ LUT as Memory (Distributed RAM) | 8,192 | 17,400 | 47.08% |
| Slice Registers (Flip-Flops / FF) | 517 | 106,400 | 0.49% |
| Slices | 2,667 | 13,300 | 20.05% |
| Block RAM Tile (BRAM) | 0 | 140 | 0.00% |
| DSP48E1 Slices | 0 | 220 | 0.00% |
| F7 Muxes | 4,352 | 26,600 | 16.36% |
| F8 Muxes | 2,176 | 13,300 | 16.36% |
| Bonded IOB (I/O Pins) | 10 | 200 | 5.00% |
| Clock Buffers (BUFG) | 1 | 32 | 3.13% |
Complete post-route utilization details can be found in
vivado_build/util_route.rpt.
Static Timing Analysis (STA) performed post-routing with all multi-corner delay extraction:
-
Target Constraint: 100.000 MHz (
$T_{\text{target}} = 10.000\text{ ns}$ ) -
Worst Negative Slack (WNS):
$-0.286\text{ ns}$ -
Worst Hold Slack (WHS):
$+0.086\text{ ns}$ (Hold timing clean with positive slack) -
Total Negative Slack (TNS):
$-7.813\text{ ns}$ across 74 failing endpoints out of 82,738 total endpoints -
Minimum Achievable Clock Period:
$$T_{\min} = T_{\text{target}} - \text{WNS} = 10.000\text{ ns} - (-0.286\text{ ns}) = \mathbf{10.286\text{ ns}}$$ -
Maximum Clock Frequency (
$F_{\max}$ ):$$F_{\max} = \frac{1}{T_{\min}} = \frac{1}{10.286\text{ ns}} = \mathbf{97.22\text{ MHz}}$$
Complete timing signoff details can be found in
vivado_build/timing_summary.rpt.
In the original simulation testbench model, data_memory.v contained an unrolled synchronous reset loop:
if (reset) begin
for (i = 0; i < 16384; i = i + 1) memory[i] <= 32'b0;
endBecause physical FPGA memory cannot clear 16,384 memory addresses in a single clock cycle, Vivado attempted to synthesize 524,288 discrete Flip-Flops and a 16,384-to-1 32-bit combinational multiplexer, exceeding the chip's total register count (106,400 FFs) by nearly 500% and stalling the logic optimizer. Removing this simulation-only loop allowed standard synthesizable FPGA RAM inference, reducing synthesis elaboration from over an hour to just 10 seconds.
-
Why BRAM is 0%: Xilinx 7-Series Block RAM primitives (
RAMB36E1/RAMB18E1) physically require a synchronous clock edge to read data. The current microarchitecture performs combinational (asynchronous) read access (always @(*) read_data = memory[word_addr]). - Because reads are combinational, Vivado mapped the 64 KB storage to 2,048
$\times$ RAM256X1SDistributed RAM primitives (SLICEM LUTRAM), utilizing 8,192 LUTs. - Clocking the memory read port on
posedge clkenables direct mapping into ~16RAMB36E1Block RAM tiles, freeing up all 8,192 LUTs for logic.
The design uses rtl/zedboard_top.v as the board-level wrapper:
| Signal Name | FPGA Package Pin | I/O Standard | Peripheral Function |
|---|---|---|---|
clk |
Y9 | LVCMOS33 |
100 MHz On-Board Clock Oscillator |
reset_btn |
P16 | LVCMOS25 |
Center Pushbutton (BTNC), Active-High |
led[0] |
T22 | LVCMOS33 |
User LED LD0 (Writeback Data Bit 0) |
led[1] |
T21 | LVCMOS33 |
User LED LD1 (Writeback Data Bit 1) |
led[2] |
U22 | LVCMOS33 |
User LED LD2 (Writeback Data Bit 2) |
led[3] |
U21 | LVCMOS33 |
User LED LD3 (Writeback Data Bit 3) |
led[4] |
V22 | LVCMOS33 |
User LED LD4 (Writeback Data Bit 4) |
led[5] |
W22 | LVCMOS33 |
User LED LD5 (Writeback Data Bit 5) |
led[6] |
U19 | LVCMOS33 |
User LED LD6 (Writeback Data Bit 6) |
led[7] |
U14 | LVCMOS33 |
User LED LD7 (Writeback Data Bit 7) |
-
Hardware Verification Behavior: When running the firmware program in
rtl/code.mem(which computes the arithmetic sum$5 + 4 + 3 + 2 + 1 = 15$ ), the writeback value15(0x0F/00001111) is latched to the LEDs, illuminatingLD3..LD0.
- AMD / Xilinx Vivado (2020.1 or newer, tested on 2023.1)
- Digilent ZedBoard Zynq-7000 Development Board
Run Vivado batch mode using the automated implementation script:
vivado -mode batch -source vivado_build/build_zedboard.tclThis executes synthesis, optimization, placement, routing, timing report generation, and writes the bitstream to vivado_build/riscv_zedboard.bit.
- Connect the ZedBoard PROG USB port to your PC and switch on board power.
- Ensure boot jumpers are set to JTAG mode (
MIO[5:2]set to0000). - Run the automated programming script:
vivado -mode batch -source vivado_build/program_zedboard.tcl(Alternatively, open Vivado Hardware Manager, connect to target xc7z020_1, and select vivado_build/riscv_zedboard.bit).
4. Press BTNC (Center Button) to reset the processor.
├── rtl/ # Core Verilog implementation
│ ├── alu.v # 32-bit Execution Unit
│ ├── alu_control.v # ALU operation decoder
│ ├── code.mem # Preloaded firmware machine code (hex)
│ ├── control_unit.v # Main instruction decoder
│ ├── data_memory.v # 64KB Data Memory (RAM)
│ ├── decode_stage.v # Instruction Decode Stage
│ ├── execute_stage.v # Execute Stage
│ ├── ex_mem_register.v # EX/MEM Pipeline Register
│ ├── forwarding_unit.v # RAW Data Bypass Network
│ ├── hazard_detection_unit.v # Load-Use Stall Logic
│ ├── id_ex_register.v # ID/EX Pipeline Register
│ ├── if_id_register.v # IF/ID Pipeline Register
│ ├── immediate_generator.v # Immediate Sign Extension
│ ├── instruction_memory.v # 64KB Instruction ROM
│ ├── mem_wb_register.v # MEM/WB Pipeline Register
│ ├── PC.v # Program Counter Register
│ ├── register_file.v # 32 x 32-bit General Purpose Registers
│ ├── risc_v_top.v # Top-level core wrapper with writeback bus
│ ├── write_back_stage.v # Write-back Stage
│ └── zedboard_top.v # ZedBoard Physical Top-Level Wrapper
├── zedboard.xdc # ZedBoard Pin Mappings & 100MHz Clock Constraints
├── sim/ # Simulation and verification
│ └── riscv_tb.v # Base testbench with waveform dumping
├── vivado_build/ # Implementation scripts, reports, and bitstream
│ ├── build_zedboard.tcl # Full synthesis & implementation batch script
│ ├── program_zedboard.tcl # JTAG bitstream programming script
│ ├── riscv_zedboard.bit # Generated Bitstream for ZedBoard (4.05 MB)
│ ├── util_route.rpt # Post-Route Resource Utilization Report
│ └── timing_summary.rpt # Post-Route Static Timing Signoff Report
└── docs/ # Architecture diagrams & schematics
