Course project for ECE494 — Microprocessor Design at the University of Thessaly, comparing CV32E40P RISC-V forwarding variants on a minimal ZedBoard-style FPGA wrapper. The repository keeps each RTL variant in a separate submodule and uses shared scripts for RTL simulation, Vivado project generation, timing/utilization/power report export, benchmark execution, and comparison plots.
| Area | What is included |
|---|---|
| RISC-V RTL variants | Baseline CV32E40P plus no-multiplier-forwarding, no-ALU-forwarding, and combined no-ALU/no-multiplier-forwarding variants. |
| Correctness testing | Icarus Verilog/sv2v-based RTL regressions with assembly tests, golden memory/register dumps, and focused dependency-stress cases. |
| Benchmarking | Bare-metal RV32IM C benchmarks loaded into simulated instruction/data memories with cycle metrics for each RTL variant. |
| Vivado comparison | Automated ZedBoard-style project generation and post-synthesis/post-implementation timing, utilization, power, and critical-path reports. |
| Result visualization | Python scripts and generated plots for execution time, timing histograms, utilization, power, and presentation summaries. |
The project studies whether removing selected forwarding paths can improve FPGA timing closure without breaking architectural behavior. The best-performing variant removes multiplier forwarding, keeps architectural correctness through existing writeback availability and dependency stalls, and is evaluated with both Vivado implementation reports and benchmark-level cycle measurements.
Useful paths:
cv32e40p_baseline/— baseline CV32E40P submodule.cv32e40p_no_mul_forwarding/— no-multiplier-forwarding RTL variant.cv32e40p_no_alu_forwarding/— no-ALU-forwarding RTL variant.cv32e40p_no_alu_mul_forwarding/— combined forwarding-removal RTL variant.rtl-tests/— assembly regression tests and golden outputs.benchmarks/— bare-metal benchmark sources and runtime support.reports/— generated Vivado reports, summaries, and plots.docs/reports/ece494-cv32e40p-forwarding-report.pdf— final project report.docs/presentations/ece494-cv32e40p-final-presentation.pdf— final presentation.
| Path | Description |
|---|---|
cv32e40p_* |
Variant-specific CV32E40P RTL submodules. |
zedboard-wrapper/ |
Minimal FPGA wrapper, memories, clock gate, testbench, and constraints. |
rtl-tests/ |
RTL correctness tests, testbench files, and golden outputs. |
benchmarks/ |
Bare-metal benchmark sources and runtime support. |
scripts/ |
RTL-test, benchmark, plot, and report helper scripts. |
reports/ |
Generated timing/utilization/power reports, summary CSVs, and comparison plots. |
docs/reports/ |
Final written report. |
docs/presentations/ |
Final presentation PDF. |
docs/images/ |
README architecture diagram and selected result plots. |
The report combines implementation-level timing/utilization/power data with benchmark execution time. The README keeps representative plot exports near the top while the full raw report set remains under reports/.
experiment name RTL submodule directory default clock
baseline cv32e40p_baseline 15.000 ns
no-mul-forwarding cv32e40p_no_mul_forwarding 14.000 ns
no-alu-forwarding cv32e40p_no_alu_forwarding 15.000 ns
no-alu-mul-forwarding cv32e40p_no_alu_mul_forwarding 15.000 ns
The experiment name is the value passed to make EXPERIMENT=..., report.sh --experiment ..., and the Vivado project Tcl --experiment ... option. The RTL-test runner accepts both hyphenated and underscored aliases, for example no-mul-forwarding and no_mul_forwarding.
Initialize the CV32E40P submodules and their nested vendor submodules:
git submodule update --init --recursiveIf Vivado is not on PATH, set VIVADO explicitly:
export VIVADO=/path/to/Vivado/2022.2/bin/vivadoThe project uses different tools depending on the flow:
flow required tools
--------------------------- --------------------------------------------------
Vivado project/reports Vivado 2022.2 or compatible Vivado installation
RTL tests Python 3, make, Icarus Verilog (iverilog + vvp),
RISC-V bare-metal GNU toolchain, sv2v
RTL benchmarks Python 3, make, Icarus Verilog (iverilog + vvp),
RISC-V bare-metal GNU toolchain, sv2v
Plot regeneration Python 3 only for the SVG plot scripts in scripts/
For the RTL tests and RTL benchmarks, the RISC-V toolchain must provide these executables on PATH:
riscv-none-elf-gcc
riscv-none-elf-objcopy
riscv-none-elf-objdump
The benchmark flow specifically compiles freestanding RV32IM C programs with riscv-none-elf-gcc, then uses riscv-none-elf-objcopy to create the IMEM/DMEM images loaded by the benchmark testbench. If these tools are missing, make rtl-tests and make rtl-benchmarks will fail before simulation.
A typical local setup is:
export PATH=/path/to/riscv-toolchain/bin:$PATH
export VIVADO=/path/to/Vivado/2022.2/bin/vivadosv2v is needed because Icarus Verilog cannot parse all CV32E40P SystemVerilog sources directly. If sv2v is not already installed, scripts/run-rtl-tests.py and scripts/run-rtl-benchmarks.py try to use a bundled checkout under ../tools/sv2v-0.0.13/ or download the pinned Linux release into build/tools/.
No extra Python packages are required for the main regression/benchmark/report scripts; they use the Python standard library and generate SVG plots directly. The standalone exploratory scripts scripts/plot-execution-time-change.py and scripts/plot-break-even-frequency.py are optional and require matplotlib/numpy if used.
The RTL tests live under rtl-tests/ and are run by scripts/run-rtl-tests.py. The runner assembles the test program, converts CV32E40P SystemVerilog with sv2v, compiles with iverilog, runs vvp, and compares final DMEM/register-file state against generated golden dumps.
Run the full RTL regression for all variants:
make rtl-testsRun one variant:
make rtl-tests-baseline
make rtl-tests-no-mul-forwarding
make rtl-tests-no-alu-forwarding
make rtl-tests-no-alu-mul-forwardingFocused examples:
python3 scripts/run-rtl-tests.py --version baseline --test alu_load_store
python3 scripts/run-rtl-tests.py --version no-mul-forwarding --test mul_dependency_matrix
python3 scripts/run-rtl-tests.py --version no-alu-forwarding --test alu_dependency_matrix
python3 scripts/run-rtl-tests.py --version no-alu-mul-forwarding --test mixed_dependency_stress
python3 scripts/run-rtl-tests.py --force-rebuildPer-test outputs are written under:
build/rtl-tests/<version>/<test>/
Important files there include program_imem.mem, expected_dmem.mem, expected_regfile.mem, dmem_dump.mem, regfile_dump.mem, and sim.log.
The C benchmarks live under benchmarks/src/ and are run by scripts/run-rtl-benchmarks.py. This flow is separate from the assembly correctness regression: it builds bare-metal RV32IM C workloads, initializes both instruction and data memories, runs a larger benchmark testbench, and records cycle metrics from memory-mapped start/stop/DONE stores.
Available benchmarks:
vvadd multiply median sort rsort mm dhrystone
Run all benchmarks on all RTL variants:
make rtl-benchmarks
# equivalent:
python3 scripts/run-rtl-benchmarks.py --version all --benchmark allRun one RTL variant and one benchmark:
python3 scripts/run-rtl-benchmarks.py --version baseline --benchmark vvadd
python3 scripts/run-rtl-benchmarks.py --version 1 --benchmark multiply # 1 = no-mul-forwarding
python3 scripts/run-rtl-benchmarks.py --version 2 --benchmark sort # 2 = no-alu-forwarding
python3 scripts/run-rtl-benchmarks.py --version 3 --benchmark mm # 3 = no-alu-mul-forwardingMake targets are also provided:
make rtl-benchmarks-baseline RTL_BENCH_ARGS="--benchmark vvadd"
make rtl-benchmarks-no-mul-forwarding RTL_BENCH_ARGS="--benchmark all"
make rtl-benchmarks-no-alu-forwarding RTL_BENCH_ARGS="--benchmark median sort"
make rtl-benchmarks-no-alu-mul-forwarding RTL_BENCH_ARGS="--benchmark mm dhrystone"Per-run artifacts are written under:
build/rtl-benchmarks/<version>/<benchmark>/
Important files there include program_imem.mem, program_dmem.mem, <benchmark>.elf, image_sizes.txt, and sim.log. The benchmark testbench prints a metric line of the form:
[METRIC] total_cycles=<cycles> roi_cycles=<cycles> return_code=<code> signature=0x<hex>
Summary reports are regenerated at:
reports/benchmarks/benchmark_results.csv
reports/benchmarks/benchmark_results.md
The benchmark testbench uses 128 KiB IMEM and 128 KiB DMEM for simulation only. The Vivado wrapper defaults remain unchanged for the FPGA timing/utilization flow, so the benchmark memory-size increase does not affect the existing implementation comparisons.
Create/update a Vivado project for one variant:
make baseline
make no-mul-forwarding
make no-alu-forwarding
make no-alu-mul-forwardingEquivalent explicit form:
make EXPERIMENT=baseline all
make EXPERIMENT=no-mul-forwarding allGenerated projects are placed under:
build/vivado-<experiment>/cv32e40p-zedboard-project.xpr
The project-creation Tcl is:
vivado -mode batch -source cv32e40p-zedboard-project.tcl \
-tclargs --experiment baselineOptional Tcl arguments include:
--experiment <baseline|no-mul-forwarding|no-alu-forwarding|no-alu-mul-forwarding>
--core_dir <path-to-cv32e40p-checkout>
--build_dir <path>
--project_name <name>
--clock_period <period-ns>
Recommended full comparison command:
./report.sh --comparison --report all --create-projects --yes --stage post-implementationEquivalent Make target:
make reportsThis command:
1. creates/updates Vivado projects for all built-in variants;
2. runs the selected post-implementation report flow;
3. writes per-variant raw reports/CSVs/metadata;
4. regenerates summary CSVs and SVG comparison plots.
Single-variant examples:
./report.sh --experiment baseline --report all --create-projects --yes --stage post-implementation
./report.sh --experiment no-mul-forwarding --report timing --yes --stage post-synthesis
./report.sh --experiment no-alu-forwarding --report utilization --yes
./report.sh --experiment no-alu-mul-forwarding --report path-distribution --yesReport type aliases:
all utilization + timing + path CSV + power
timing timing summary + worst paths + path CSV
timing-summary timing_summary_1000_paths.rpt
worst-paths worst_1000_paths.rpt + critical_paths_top10.rpt
path-csv timing_paths.csv
path-distribution path-csv + timing plots
utilization utilization.rpt + utilization_hierarchical.rpt
power power.rpt + power plots
Report stage choices:
auto open impl_1 if available, otherwise synthesize and report post-synthesis
post-synthesis synthesize current sources and report the post-synthesis netlist
post-implementation report an implemented design; with --create-projects the script can run
an in-memory synth/opt/place/route flow before exporting reports
Outputs:
reports/<experiment>/ raw Vivado reports, timing_paths.csv, metadata.txt
reports/summary/*.csv comparison summaries
reports/plots/*.svg comparison plots
Useful generated reports:
reports/<experiment>/timing_summary_1000_paths.rpt
reports/<experiment>/critical_paths_top10.rpt
reports/<experiment>/worst_1000_paths.rpt
reports/<experiment>/utilization.rpt
reports/<experiment>/utilization_hierarchical.rpt
reports/<experiment>/power.rpt
If reports/*/timing_paths.csv, utilization reports, and power reports already exist, regenerate plots without rerunning Vivado:
python3 scripts/plot-timing.py
python3 scripts/plot-utilization.py
python3 scripts/plot-power.py
python3 scripts/plot-presentation-summary.pyThe datapath-delay histogram spacing is controlled in scripts/plot-timing.py by:
HISTOGRAM_BIN_GAP_PX = 8Increase this value for more space between adjacent histogram bins; decrease it for wider grouped bars.
The report flow can generate reports from an in-memory implementation. That is enough for .rpt/.csv output, but it does not necessarily leave a completed GUI impl_1 run inside the .xpr. If Open Implemented Design is disabled after opening the .xpr, run implementation as a normal Vivado project run:
open_project build/vivado-baseline/cv32e40p-zedboard-project.xpr
launch_runs synth_1 -jobs 8
wait_on_run synth_1
launch_runs impl_1 -to_step route_design -jobs 8
wait_on_run impl_1
open_run impl_1
start_guiChange the build/vivado-<experiment>/... path for other variants.
bash -n report.sh
python3 -m py_compile scripts/run-rtl-tests.py scripts/plot-timing.py scripts/plot-utilization.py scripts/plot-power.py scripts/plot-presentation-summary.py
make -n baseline
make -n no-mul-forwarding
make -n no-alu-forwarding
make -n no-alu-mul-forwarding
make -n reports


