From acc4e63d124ce3d19415abb9e4a639ed0d934b2b Mon Sep 17 00:00:00 2001 From: alaindargelas Date: Fri, 17 Jul 2026 17:51:05 -0700 Subject: [PATCH 1/5] syn: add Yosys synthesis + gate-level co-sim via UHDM/Surelog (uhdm2rtlil) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds syn/uhdm2rtlil/, a Yosys synthesis flow driven by the Surelog SystemVerilog front end (uhdm2rtlil) alongside the existing Yosys-slang syn/ flow. Surelog parses the design to UHDM and the uhdm2rtlil plugin imports it to RTLIL (read_sv), so the full SystemVerilog the rp32 cores use is synthesisable through Yosys. The gate-level result is verified by co-simulation: the synthesized netlist is run against the original RTL under Verilator, comparing outputs every cycle (the methodology uhdm2rtlil uses for designs the native Verilog front end can't parse). The complete Mouse simple SoC co-simulates with 0 mismatches over 6000 cycles. - build.sh : synthesise a design through uhdm2rtlil, memory-preserving flow (proc; flatten; memory_collect — NO opt_mem, which would mangle the $readmemh boot image and map the RAM to ~500k FFs). - cosim.sh : synth + Verilator co-sim (RTL vs gate netlist), prints COSIM PASS. - cosim_tb.sv / cosim_main.cpp : side-by-side testbench + driver. - boot.hex : tiny deterministic GPIO boot program for the SoC RAM. - README.md : prerequisites (a built uhdm2rtlil, Verilator 5.x), usage, notes. Point UHDM2RTLIL_ROOT at a built uhdm2rtlil checkout (defaults to ~/uhdm2rtlil). Co-Authored-By: Claude Opus 4.8 --- syn/uhdm2rtlil/.gitignore | 5 ++ syn/uhdm2rtlil/README.md | 87 +++++++++++++++++++++++++++++++++++ syn/uhdm2rtlil/boot.hex | 6 +++ syn/uhdm2rtlil/build.sh | 82 +++++++++++++++++++++++++++++++++ syn/uhdm2rtlil/cosim.sh | 51 ++++++++++++++++++++ syn/uhdm2rtlil/cosim_main.cpp | 34 ++++++++++++++ syn/uhdm2rtlil/cosim_tb.sv | 40 ++++++++++++++++ 7 files changed, 305 insertions(+) create mode 100644 syn/uhdm2rtlil/.gitignore create mode 100644 syn/uhdm2rtlil/README.md create mode 100644 syn/uhdm2rtlil/boot.hex create mode 100755 syn/uhdm2rtlil/build.sh create mode 100755 syn/uhdm2rtlil/cosim.sh create mode 100644 syn/uhdm2rtlil/cosim_main.cpp create mode 100644 syn/uhdm2rtlil/cosim_tb.sv diff --git a/syn/uhdm2rtlil/.gitignore b/syn/uhdm2rtlil/.gitignore new file mode 100644 index 0000000..2cecc57 --- /dev/null +++ b/syn/uhdm2rtlil/.gitignore @@ -0,0 +1,5 @@ +# build / run artifacts +work/ +mem_if.mem +*.log +slpp_all/ diff --git a/syn/uhdm2rtlil/README.md b/syn/uhdm2rtlil/README.md new file mode 100644 index 0000000..193e019 --- /dev/null +++ b/syn/uhdm2rtlil/README.md @@ -0,0 +1,87 @@ +# rp32 — Yosys synthesis via UHDM/Surelog (uhdm2rtlil) + +This directory adds a **Yosys synthesis flow driven by the Surelog SystemVerilog +front end** ([uhdm2rtlil](https://github.com/alainmarcel/uhdm2rtlil)), alongside +the existing `syn/` (Yosys‑slang) and `fpga/*/yosys` flows. + +Surelog parses the design to UHDM and the uhdm2rtlil plugin imports it to Yosys +RTLIL (`read_sv`), so the full IEEE‑1800 SystemVerilog the rp32 cores use +(packages, structs, interfaces) is synthesisable through Yosys. + +The gate‑level result is **verified by co‑simulation**: the synthesized netlist +is run against the original RTL under Verilator and the outputs are compared +every cycle — the same methodology uhdm2rtlil uses for designs the native Yosys +Verilog front end cannot parse. + +## Prerequisites + +* A **built** [uhdm2rtlil](https://github.com/alainmarcel/uhdm2rtlil) checkout + (provides `out/current/bin/yosys`, `build/uhdm2rtlil.so`, and the Yosys + `simcells.v`). Point `UHDM2RTLIL_ROOT` at it (defaults to `~/uhdm2rtlil`): + + ```bash + export UHDM2RTLIL_ROOT=/path/to/uhdm2rtlil + ``` + +* **Verilator 5.x** in `PATH` (for the co‑simulation) — the repo's + `submodules/verilator` build works; see `settings-verilator.sh`. + +## Usage + +```bash +cd syn/uhdm2rtlil + +# Synthesise the Mouse simple SoC to a gate-level netlist (work/*.v, *.json) +./build.sh + +# Gate-level co-simulation: RTL vs synthesized netlist, cycle-by-cycle +./cosim.sh # -> "COSIM PASS" (0 mismatches over 6000 cycles) +``` + +`build.sh` defaults to `r5p_mouse_soc_simple_top` (the self‑contained Mouse SoC: +the `r5p_mouse` core + on‑chip RAM initialised from `boot.hex` + GPIO/UART). +Override the target with environment variables: + +```bash +# just the standalone core +R5P_TOP=r5p_mouse R5P_SRCS="$PWD/../../hdl/rtl/mouse/r5p_mouse.sv" ./build.sh +``` + +## The memory‑preserving synthesis flow + +A design with an initialised ROM/RAM (`$readmemh`) **must not** be run through +the plain `synth` / `synth_*` shortcut: those run `opt_mem`, which trims an +initialised memory to its "used" width and mangles the `$meminit` constant +(e.g. `0x800200B7` → garbage), so the fetched program reads back wrong and the +CPU never boots. `build.sh` therefore drives the passes explicitly: + +``` +read_sv → proc → flatten → memory_collect (no opt_mem / memory -nomap) + → opt -full → techmap → dfflegalize → abc → opt_clean +``` + +`flatten` **before** `memory_collect` is what lets the `$readmemh` init reach +the combinational read port. + +## Files + +| file | purpose | +|-----------------|------------------------------------------------------------------| +| `build.sh` | synthesise a design through uhdm2rtlil (memory‑preserving flow) | +| `cosim.sh` | synth + Verilator co‑simulation (RTL vs gate netlist) | +| `cosim_tb.sv` | testbench: RTL and gate netlist side by side, per‑cycle compare | +| `cosim_main.cpp`| Verilator driver (reset, free‑run, exit non‑zero on mismatch) | +| `boot.hex` | tiny deterministic boot program (GPIO writes) for the SoC RAM | + +`work/` (netlists, logs, Verilator objects) is generated and git‑ignored. + +## Notes + +* The **complete Mouse SoC** co‑simulates cleanly because its boot program is + deterministic. The **standalone `r5p_mouse` core** synthesises correctly too, + but under *random* instruction stimulus it diverges on the design's own `'x` + don't‑cares (illegal opcodes), so only a deterministic instruction stream is a + meaningful equivalence check for it — use the SoC for the end‑to‑end gate check. +* This flow depends on two uhdm2rtlil front‑end fixes for the rp32 cores: comb + `case` blocking‑read value threading, and byte‑enable (`mem[a][hi:lo] <= …`) + memory‑write emission. Use a uhdm2rtlil build that includes them. diff --git a/syn/uhdm2rtlil/boot.hex b/syn/uhdm2rtlil/boot.hex new file mode 100644 index 0000000..c1416a1 --- /dev/null +++ b/syn/uhdm2rtlil/boot.hex @@ -0,0 +1,6 @@ +800200b7 +05a00113 +0020a023 +0ff00113 +0020a023 +0000006f diff --git a/syn/uhdm2rtlil/build.sh b/syn/uhdm2rtlil/build.sh new file mode 100755 index 0000000..45388f5 --- /dev/null +++ b/syn/uhdm2rtlil/build.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# ============================================================================ +# rp32 — synthesise a design through the UHDM/Surelog front end (uhdm2rtlil) +# ============================================================================ +# +# Runs the Surelog SystemVerilog front end in-process (`read_sv`, from the +# uhdm2rtlil plugin) and synthesises an rp32 design to a gate-level netlist +# under ./work/ (r5p__uhdm.v / .json). +# +# Prerequisite: a built uhdm2rtlil checkout +# (https://github.com/alainmarcel/uhdm2rtlil). Point UHDM2RTLIL_ROOT at it +# (defaults to ~/uhdm2rtlil): +# +# export UHDM2RTLIL_ROOT=/path/to/uhdm2rtlil +# ./build.sh # default: Mouse simple SoC +# R5P_TOP=r5p_mouse \ +# R5P_SRCS="$PWD/../../hdl/rtl/mouse/r5p_mouse.sv" ./build.sh +# +# Environment overrides: +# R5P_TOP top module (default r5p_mouse_soc_simple_top) +# R5P_SRCS source file list (default: mouse core + simple SoC) +# R5P_OUT output basename (default _uhdm) +# R5P_RENAME rename the netlist top to this (default: none) — used by the +# co-sim so the gate netlist and the RTL can share a Verilator build +# +# --- memory-preserving flow ------------------------------------------------- +# A design with an initialised ROM/RAM (`$readmemh`) must NOT be run through the +# plain `synth`/`synth_*` shortcut: those run `opt_mem`, which trims an +# initialised memory to its "used" width and MANGLES the `$meminit` constant +# (e.g. 0x800200B7 -> garbage), so the fetched program reads back wrong. We +# drive the passes explicitly and keep the init: +# read_sv -> proc -> flatten -> memory_collect (NO opt_mem / memory -nomap) +# `flatten` before `memory_collect` is what lets the $readmemh init reach the +# combinational read port. See the uhdm2rtlil CLAUDE.md +# "Debugging X-Propagation in the rp32 SoC" notes. +set -euo pipefail +cd "$(dirname "$0")" + +R5P_RTL="$(cd ../../hdl/rtl && pwd)" +ROOT="${UHDM2RTLIL_ROOT:-$HOME/uhdm2rtlil}" +YOSYS="$ROOT/out/current/bin/yosys" +PLUGIN="$ROOT/build/uhdm2rtlil.so" + +for f in "$YOSYS" "$PLUGIN"; do + if [ ! -e "$f" ]; then + echo "ERROR: $f not found." >&2 + echo "Set UHDM2RTLIL_ROOT to a built uhdm2rtlil checkout (currently '$ROOT')." >&2 + exit 1 + fi +done + +TOP="${R5P_TOP:-r5p_mouse_soc_simple_top}" +OUT="${R5P_OUT:-${TOP}_uhdm}" +SRCS="${R5P_SRCS:-$R5P_RTL/mouse/r5p_mouse.sv $R5P_RTL/soc/r5p_mouse_soc_simple_top.sv}" + +mkdir -p work +# The SoC reads its boot image via $readmemh("mem_if.mem", ...); provide it. +cp -f boot.hex work/mem_if.mem + +echo "== uhdm2rtlil: $ROOT" +echo "== top: $TOP" + +( cd work && "$YOSYS" -m "$PLUGIN" -p " + read_sv -parse -nobuiltin $SRCS + hierarchy -check -top $TOP + proc + flatten + memory_collect + opt -full + techmap + opt + dfflegalize -cell \$_DFF_P_ 0 -cell \$_DFF_PP0_ 0 -cell \$_DFF_PP1_ 0 \ + -cell \$_DFFE_PP0P_ 0 -cell \$_DFFE_PP1P_ 0 + abc -g AND,NAND,OR,NOR,XOR,XNOR,ANDNOT,ORNOT,MUX + opt_clean + ${R5P_RENAME:+rename $TOP $R5P_RENAME} + stat + write_verilog -noattr ${OUT}.v + write_json ${OUT}.json +" ) + +echo "== netlist written: $(pwd)/work/${OUT}.v" diff --git a/syn/uhdm2rtlil/cosim.sh b/syn/uhdm2rtlil/cosim.sh new file mode 100755 index 0000000..4b760ab --- /dev/null +++ b/syn/uhdm2rtlil/cosim.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# ============================================================================ +# rp32 — gate-level co-simulation: RTL vs uhdm2rtlil-synthesized netlist +# ============================================================================ +# +# Synthesises the r5p_mouse simple SoC through uhdm2rtlil (top renamed to +# *_gate), then uses Verilator to run the original RTL and the gate netlist +# side by side under the same boot program, comparing outputs every cycle. +# This is the gate-level equivalence check for the Yosys/UHDM flow — the same +# methodology uhdm2rtlil uses for designs the native Verilog front end can't +# parse (co-simulate the synthesized netlist against the RTL). +# +# export UHDM2RTLIL_ROOT=/path/to/uhdm2rtlil # built checkout (default ~/uhdm2rtlil) +# ./cosim.sh [cycles] +# +set -euo pipefail +cd "$(dirname "$0")" + +ROOT="${UHDM2RTLIL_ROOT:-$HOME/uhdm2rtlil}" +SIMCELLS="$ROOT/out/current/share/yosys/simcells.v" +R5P_RTL="$(cd ../../hdl/rtl && pwd)" +CYCLES="${1:-6000}" +TOP=r5p_mouse_soc_simple_top +GATE=${TOP}_gate + +command -v verilator >/dev/null || { echo "ERROR: verilator not found in PATH" >&2; exit 1; } +[ -e "$SIMCELLS" ] || { echo "ERROR: $SIMCELLS not found (build uhdm2rtlil / set UHDM2RTLIL_ROOT)" >&2; exit 1; } + +# 1. synthesise the SoC to a gate netlist with the top renamed to *_gate. +echo "== [1/2] synthesising $TOP via uhdm2rtlil (-> $GATE)" +R5P_TOP="$TOP" R5P_OUT="cosim_gate" R5P_RENAME="$GATE" ./build.sh >work/cosim_synth.log 2>&1 \ + || { echo "ERROR: synthesis failed; see work/cosim_synth.log" >&2; tail -20 work/cosim_synth.log; exit 1; } + +# 2. build + run the Verilator co-sim (RTL + gate netlist + Yosys gate cells). +# The RTL side runs `$readmemh("mem_if.mem", ...)` relative to Vtb's cwd (here); +# the gate netlist already has the boot image baked in as memory init. +echo "== [2/2] Verilator co-sim ($CYCLES cycles)" +cp -f boot.hex mem_if.mem +rm -rf work/obj_dir +verilator --cc --exe --build -j 4 \ + -Wno-fatal -Wno-WIDTH -Wno-UNUSED -Wno-UNOPTFLAT -Wno-CASEINCOMPLETE \ + -Wno-MULTIDRIVEN -Wno-BLKANDNBLK \ + --top-module tb --Mdir work/obj_dir \ + cosim_tb.sv \ + "$R5P_RTL/mouse/r5p_mouse.sv" \ + "$R5P_RTL/soc/r5p_mouse_soc_simple_top.sv" \ + work/cosim_gate.v \ + "$SIMCELLS" \ + cosim_main.cpp + +./work/obj_dir/Vtb "$CYCLES" diff --git a/syn/uhdm2rtlil/cosim_main.cpp b/syn/uhdm2rtlil/cosim_main.cpp new file mode 100644 index 0000000..ee55715 --- /dev/null +++ b/syn/uhdm2rtlil/cosim_main.cpp @@ -0,0 +1,34 @@ +// Verilator driver for the r5p_mouse SoC gate-level co-simulation. +// Holds reset, then free-runs the boot program, checking RTL == netlist every +// cycle. Exit code 0 on match, 1 on any mismatch. +#include +#include "Vtb.h" +#include +#include + +int main(int argc, char** argv) { + Verilated::commandArgs(argc, argv); + unsigned ncyc = (argc > 1) ? std::strtoul(argv[1], nullptr, 0) : 6000; + + Vtb* d = new Vtb; + auto tick = [&]() { d->clk = 0; d->eval(); d->clk = 1; d->eval(); }; + + // hold reset + d->rst = 1; d->gpio_i = 0x12345678; d->uart_rxd = 1; + for (int i = 0; i < 8; i++) tick(); + d->rst = 0; + + long mismatches = 0; + int first = -1; + for (unsigned i = 0; i < ncyc; i++) { + tick(); + if (d->mismatch) { if (first < 0) first = (int)i; mismatches++; } + } + d->final(); + + std::printf("cycles=%u mismatches=%ld first_mismatch=%d\n", + ncyc, mismatches, first); + if (mismatches) { std::printf("COSIM FAIL\n"); return 1; } + std::printf("COSIM PASS\n"); + return 0; +} diff --git a/syn/uhdm2rtlil/cosim_tb.sv b/syn/uhdm2rtlil/cosim_tb.sv new file mode 100644 index 0000000..a043ebe --- /dev/null +++ b/syn/uhdm2rtlil/cosim_tb.sv @@ -0,0 +1,40 @@ +// ============================================================================ +// Gate-level co-simulation testbench for the r5p_mouse simple SoC. +// +// Instantiates the original RTL (`r5p_mouse_soc_simple_top`) and the +// uhdm2rtlil-synthesized gate netlist (`r5p_mouse_soc_simple_top_gate`) side by +// side, drives them with the same clock/reset/inputs, and raises `mismatch` +// whenever any observable output differs. Both run the same boot program from +// memory, so the comparison is fully deterministic. +// ============================================================================ +module tb ( + input logic clk, + input logic rst, + input logic [31:0] gpio_i, + input logic uart_rxd, + output logic mismatch +); + // RTL reference outputs + logic [31:0] r_gpio_o, r_gpio_e; + logic r_uart_txd; + // gate-level netlist outputs + logic [31:0] g_gpio_o, g_gpio_e; + logic g_uart_txd; + + r5p_mouse_soc_simple_top dut_rtl ( + .clk (clk), .rst (rst), + .gpio_o (r_gpio_o), .gpio_e (r_gpio_e), .gpio_i (gpio_i), + .uart_txd (r_uart_txd), .uart_rxd (uart_rxd) + ); + + r5p_mouse_soc_simple_top_gate dut_gate ( + .clk (clk), .rst (rst), + .gpio_o (g_gpio_o), .gpio_e (g_gpio_e), .gpio_i (gpio_i), + .uart_txd (g_uart_txd), .uart_rxd (uart_rxd) + ); + + always_comb + mismatch = (r_gpio_o !== g_gpio_o) + || (r_gpio_e !== g_gpio_e) + || (r_uart_txd !== g_uart_txd); +endmodule From 87fca79259809fb1728cd89677b7fb5a89081806 Mon Sep 17 00:00:00 2001 From: alaindargelas Date: Fri, 17 Jul 2026 18:27:28 -0700 Subject: [PATCH 2/5] rtl: make ISA-spec and decoder structs packed (synthesis-friendly) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ISA-spec struct (riscv_isa_pkg) and the I-decoder struct (riscv_isa_i_pkg) were unpacked, which the upstream comment already flagged as a TODO ("change when Verilator supports unpacked structures"). Unpacked, they cannot be driven as flat vectors through synthesis: the enum built on `logic [$bits(isa_spec_t)-1:0]` truncates, and `dec_t` — taken as a PORT by the r5p_* modules — can't be mapped onto a flat netlist port. Make both `packed` (and `dec_t.siz` a fixed-width `logic signed [31:0]` rather than `integer`), which is required for the Yosys/UHDM synthesis flow and resolves the degu core's nested decoder struct reads. Co-Authored-By: Claude Opus 4.8 --- hdl/rtl/riscv/riscv_isa_i_pkg.sv | 8 ++++++-- hdl/rtl/riscv/riscv_isa_pkg.sv | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/hdl/rtl/riscv/riscv_isa_i_pkg.sv b/hdl/rtl/riscv/riscv_isa_i_pkg.sv index 4008d5f..414030a 100644 --- a/hdl/rtl/riscv/riscv_isa_i_pkg.sv +++ b/hdl/rtl/riscv/riscv_isa_i_pkg.sv @@ -259,10 +259,14 @@ typedef enum { // decoder structure /////////////////////////////////////////////////////////////////////////////// - typedef struct { + // `packed` (and `siz` a fixed-width vector rather than `integer`) so the + // decoder struct is a bit-addressable type: r5p_* modules take `dec_t` as a + // PORT, and synthesis / Yosys can only map a flat netlist port onto a struct + // port when the struct is packed. + typedef struct packed { // instruction encodings ill_t ill; // illegal - integer siz; // instruction size + logic signed [31:0] siz; // instruction size opc_t opc; // operation code fn3_t fn3; // func3 fn7_t fn7; // func7 diff --git a/hdl/rtl/riscv/riscv_isa_pkg.sv b/hdl/rtl/riscv/riscv_isa_pkg.sv index 0c733df..ddb9ff0 100644 --- a/hdl/rtl/riscv/riscv_isa_pkg.sv +++ b/hdl/rtl/riscv/riscv_isa_pkg.sv @@ -111,8 +111,10 @@ typedef enum logic [$bits(isa_ext_t)-1:0] { } isa_ext_et; // ISA specification configuration -// TODO: change when Verilator supports unpacked structures -typedef struct { +// made `packed` so the enum below can use `logic [$bits(isa_spec_t)-1:0]` as +// its base and drive it through synthesis / Yosys as a flat vector (the +// upstream "change when Verilator supports unpacked structures" TODO). +typedef struct packed { isa_base_t base; isa_ext_t ext; } isa_spec_t; From ef906f9be2c8cdb76dfd1a04eb0c85ddf23d7800 Mon Sep 17 00:00:00 2001 From: alaindargelas Date: Fri, 17 Jul 2026 18:34:30 -0700 Subject: [PATCH 3/5] syn: generalize uhdm2rtlil flow to all rp32 designs (cores + SoCs) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a design catalog (designs.sh) covering the Mouse/Hamster/Degu cores and the Mouse/Degu SoCs, a build.sh that synthesises any of them, and run.sh which synthesises all and co-simulates the ones with a deterministic testbench, printing a status table. build.sh now passes -top to Surelog so hierarchical modules with unbound parameters (e.g. the TCB arbiter's unpacked-array `PRI`) are elaborated as instances, not standalone — this unblocks synthesis of the full SoCs. Verified today: mouse_soc_simple co-sim PASS (0/6000). The full SoCs and the degu/hamster cores synthesise but still have unresolved TCB interface-config / decoder-struct reads in the UHDM front end (documented in the README status table); those are the next front-end items. Co-Authored-By: Claude Opus 4.8 --- syn/uhdm2rtlil/README.md | 39 +++++++++++----- syn/uhdm2rtlil/build.sh | 53 ++++++++++----------- syn/uhdm2rtlil/designs.sh | 98 +++++++++++++++++++++++++++++++++++++++ syn/uhdm2rtlil/run.sh | 40 ++++++++++++++++ 4 files changed, 191 insertions(+), 39 deletions(-) create mode 100644 syn/uhdm2rtlil/designs.sh create mode 100755 syn/uhdm2rtlil/run.sh diff --git a/syn/uhdm2rtlil/README.md b/syn/uhdm2rtlil/README.md index 193e019..f768271 100644 --- a/syn/uhdm2rtlil/README.md +++ b/syn/uhdm2rtlil/README.md @@ -31,22 +31,37 @@ Verilog front end cannot parse. ```bash cd syn/uhdm2rtlil -# Synthesise the Mouse simple SoC to a gate-level netlist (work/*.v, *.json) -./build.sh - -# Gate-level co-simulation: RTL vs synthesized netlist, cycle-by-cycle -./cosim.sh # -> "COSIM PASS" (0 mismatches over 6000 cycles) +./build.sh --list # list the catalogued designs +./build.sh mouse_soc_simple # synthesise one design (work/_uhdm.v/.json) +./cosim.sh # gate-level co-sim of the Mouse simple SoC +./run.sh # synthesise ALL designs + co-sim, print a table ``` -`build.sh` defaults to `r5p_mouse_soc_simple_top` (the self‑contained Mouse SoC: -the `r5p_mouse` core + on‑chip RAM initialised from `boot.hex` + GPIO/UART). -Override the target with environment variables: +The design catalog (cores + SoCs) lives in `designs.sh`; `build.sh ` picks +one. The full SoCs need the TCB submodule: ```bash -# just the standalone core -R5P_TOP=r5p_mouse R5P_SRCS="$PWD/../../hdl/rtl/mouse/r5p_mouse.sv" ./build.sh +git submodule update --init submodules/tcb ``` +## Design status + +`./run.sh` synthesises every design and co-simulates the ones with a +deterministic self-contained testbench: + +| design | synth | co-sim | notes | +|---------------------|:-----:|:------:|-------| +| `mouse` | ✅ | (det.) | standalone core; only deterministic streams are equiv-able | +| `mouse_soc_simple` | ✅ | ✅ **PASS** | complete Mouse SoC, inline RAM — 0 mismatches / 6000 cyc | +| `mouse_soc` | ⚠️ | n/a | full Mouse SoC synthesises but is functionally stuck — the TCB **interface-config** struct refs (`sub.CFG.HSK.DLY`, `sub.MOD`) are unresolved (front-end limitation); Verilator can't build the interface RTL either, so no co-sim | +| `degu` | ⚠️ | n/a | core synthesises with unresolved TCB interface-config reads | +| `degu_soc` | ⚠️ | n/a | as above | +| `hamster` | ⚠️ | n/a | core synthesises with unresolved decoder-struct reads (`idu_rdt.jmp.jmp`) | + +✅ = clean; ⚠️ = produces a netlist but with unresolved struct/interface reads +(undriven wires ⇒ not functionally correct yet). The remaining gaps are all +SystemVerilog-interface-config resolution in the UHDM front end. + ## The memory‑preserving synthesis flow A design with an initialised ROM/RAM (`$readmemh`) **must not** be run through @@ -67,7 +82,9 @@ the combinational read port. | file | purpose | |-----------------|------------------------------------------------------------------| -| `build.sh` | synthesise a design through uhdm2rtlil (memory‑preserving flow) | +| `designs.sh` | design catalog: name → sources + top (cores + SoCs) | +| `build.sh` | synthesise one design through uhdm2rtlil (memory‑preserving flow)| +| `run.sh` | synthesise all designs + co‑sim, print a status table | | `cosim.sh` | synth + Verilator co‑simulation (RTL vs gate netlist) | | `cosim_tb.sv` | testbench: RTL and gate netlist side by side, per‑cycle compare | | `cosim_main.cpp`| Verilator driver (reset, free‑run, exit non‑zero on mismatch) | diff --git a/syn/uhdm2rtlil/build.sh b/syn/uhdm2rtlil/build.sh index 45388f5..7768ff7 100755 --- a/syn/uhdm2rtlil/build.sh +++ b/syn/uhdm2rtlil/build.sh @@ -5,42 +5,39 @@ # # Runs the Surelog SystemVerilog front end in-process (`read_sv`, from the # uhdm2rtlil plugin) and synthesises an rp32 design to a gate-level netlist -# under ./work/ (r5p__uhdm.v / .json). +# under ./work/ (_uhdm.v / .json). # -# Prerequisite: a built uhdm2rtlil checkout -# (https://github.com/alainmarcel/uhdm2rtlil). Point UHDM2RTLIL_ROOT at it -# (defaults to ~/uhdm2rtlil): +# export UHDM2RTLIL_ROOT=/path/to/uhdm2rtlil # built checkout (default ~/uhdm2rtlil) +# ./build.sh [design] # design from designs.sh (default mouse_soc_simple) +# ./build.sh --list # list known designs # -# export UHDM2RTLIL_ROOT=/path/to/uhdm2rtlil -# ./build.sh # default: Mouse simple SoC -# R5P_TOP=r5p_mouse \ -# R5P_SRCS="$PWD/../../hdl/rtl/mouse/r5p_mouse.sv" ./build.sh -# -# Environment overrides: -# R5P_TOP top module (default r5p_mouse_soc_simple_top) -# R5P_SRCS source file list (default: mouse core + simple SoC) -# R5P_OUT output basename (default _uhdm) -# R5P_RENAME rename the netlist top to this (default: none) — used by the -# co-sim so the gate netlist and the RTL can share a Verilator build +# See designs.sh for the design catalog (cores + SoCs). R5P_RENAME renames the +# netlist top (used by cosim.sh so RTL and gate can share a Verilator build). # # --- memory-preserving flow ------------------------------------------------- # A design with an initialised ROM/RAM (`$readmemh`) must NOT be run through the # plain `synth`/`synth_*` shortcut: those run `opt_mem`, which trims an # initialised memory to its "used" width and MANGLES the `$meminit` constant -# (e.g. 0x800200B7 -> garbage), so the fetched program reads back wrong. We +# (0x800200B7 -> garbage) and maps the RAM to hundreds of thousands of FFs. We # drive the passes explicitly and keep the init: # read_sv -> proc -> flatten -> memory_collect (NO opt_mem / memory -nomap) -# `flatten` before `memory_collect` is what lets the $readmemh init reach the -# combinational read port. See the uhdm2rtlil CLAUDE.md -# "Debugging X-Propagation in the rp32 SoC" notes. +# `flatten` before `memory_collect` lets the $readmemh init reach the read port. set -euo pipefail cd "$(dirname "$0")" -R5P_RTL="$(cd ../../hdl/rtl && pwd)" +export R5P_RTL="$(cd ../../hdl/rtl && pwd)" +export R5P_TCB="$(cd ../../submodules/tcb/hdl/rtl && pwd 2>/dev/null || echo /nonexistent)" +source ./designs.sh + +if [ "${1:-}" = "--list" ]; then design_list; exit 0; fi + +DESIGN="${1:-mouse_soc_simple}" +design_select "$DESIGN" +OUT="${R5P_OUT:-${TOP}_uhdm}" + ROOT="${UHDM2RTLIL_ROOT:-$HOME/uhdm2rtlil}" YOSYS="$ROOT/out/current/bin/yosys" PLUGIN="$ROOT/build/uhdm2rtlil.so" - for f in "$YOSYS" "$PLUGIN"; do if [ ! -e "$f" ]; then echo "ERROR: $f not found." >&2 @@ -48,20 +45,20 @@ for f in "$YOSYS" "$PLUGIN"; do exit 1 fi done - -TOP="${R5P_TOP:-r5p_mouse_soc_simple_top}" -OUT="${R5P_OUT:-${TOP}_uhdm}" -SRCS="${R5P_SRCS:-$R5P_RTL/mouse/r5p_mouse.sv $R5P_RTL/soc/r5p_mouse_soc_simple_top.sv}" +if [ ! -d "$R5P_TCB" ]; then + echo "NOTE: TCB submodule not initialised (needed for degu/full SoCs):" >&2 + echo " git submodule update --init submodules/tcb" >&2 +fi mkdir -p work -# The SoC reads its boot image via $readmemh("mem_if.mem", ...); provide it. +# SoCs read their boot image via $readmemh("mem_if.mem", ...); provide it. cp -f boot.hex work/mem_if.mem echo "== uhdm2rtlil: $ROOT" -echo "== top: $TOP" +echo "== design: $DESIGN (top $TOP)" ( cd work && "$YOSYS" -m "$PLUGIN" -p " - read_sv -parse -nobuiltin $SRCS + read_sv -parse -nobuiltin -top $TOP $SRCS hierarchy -check -top $TOP proc flatten diff --git a/syn/uhdm2rtlil/designs.sh b/syn/uhdm2rtlil/designs.sh new file mode 100644 index 0000000..18f8068 --- /dev/null +++ b/syn/uhdm2rtlil/designs.sh @@ -0,0 +1,98 @@ +# ============================================================================ +# rp32 design catalog for the uhdm2rtlil Yosys flow. +# +# Sourced by build.sh / run.sh. `design_select ` sets: +# TOP top module name +# SRCS space-separated, dependency-ordered source list (absolute paths) +# COSIM "yes" if a deterministic gate-level co-simulation is wired up +# +# Requires R5P_RTL (abs path to hdl/rtl) and R5P_TCB (abs path to the TCB RTL, +# submodules/tcb/hdl/rtl) to be exported by the caller. +# ============================================================================ + +# RISC-V ISA packages shared by the hierarchical cores. +_riscv_pkgs() { + echo "$R5P_RTL/riscv/riscv_isa_pkg.sv \ + $R5P_RTL/riscv/riscv_priv_pkg.sv \ + $R5P_RTL/riscv/riscv_isa_i_pkg.sv \ + $R5P_RTL/riscv/riscv_isa_c_pkg.sv \ + $R5P_RTL/riscv/rv32_csr_pkg.sv \ + $R5P_RTL/riscv/rv64_csr_pkg.sv" +} + +# degu core sources (packages + submodules + core), dependency-ordered. +_degu_core() { + echo "$R5P_TCB/tcb_lite_pkg.sv $R5P_TCB/tcb_lite_if.sv \ + $(_riscv_pkgs) \ + $R5P_RTL/degu/r5p_pkg.sv $R5P_RTL/degu/r5p_degu_pkg.sv \ + $R5P_RTL/core/r5p_gpr_2r1w.sv \ + $R5P_RTL/degu/r5p_bru.sv $R5P_RTL/degu/r5p_alu.sv \ + $R5P_RTL/degu/r5p_mdu.sv $R5P_RTL/degu/r5p_lsu.sv \ + $R5P_RTL/degu/r5p_wbu.sv $R5P_RTL/degu/r5p_degu.sv" +} + +# TCB "lite" peripheral library + devices used by the full SoCs. +_tcb_soc_lib() { + echo "$R5P_TCB/lite_lib/tcb_lite_lib_error.sv \ + $R5P_TCB/lite_lib/tcb_lite_lib_passthrough.sv \ + $R5P_TCB/lite_lib/tcb_lite_lib_register_request.sv \ + $R5P_TCB/lite_lib/tcb_lite_lib_register_response.sv \ + $R5P_TCB/lite_lib/tcb_lite_lib_register_backpressure.sv \ + $R5P_TCB/lite_lib/tcb_lite_lib_arbiter.sv \ + $R5P_TCB/lite_lib/tcb_lite_lib_multiplexer.sv \ + $R5P_TCB/lite_lib/tcb_lite_lib_decoder.sv \ + $R5P_TCB/lite_lib/tcb_lite_lib_demultiplexer.sv \ + $R5P_TCB/lite_lib/tcb_lite_lib_logsize2byteena.sv \ + $R5P_TCB/dev/gpio/tcb_dev_gpio_cdc__generic.sv \ + $R5P_TCB/dev/gpio/tcb_dev_gpio.sv \ + $R5P_TCB/lite_dev/gpio/tcb_lite_dev_gpio.sv \ + $R5P_TCB/dev/uart/tcb_dev_uart_ser.sv \ + $R5P_TCB/dev/uart/tcb_dev_uart_des.sv \ + $R5P_TCB/dev/uart/tcb_dev_uart_fifo.sv \ + $R5P_TCB/dev/uart/tcb_dev_uart.sv \ + $R5P_TCB/lite_dev/uart/tcb_lite_dev_uart.sv" +} + +# List all known design names. +design_list() { + echo "mouse hamster degu mouse_soc_simple mouse_soc degu_soc" +} + +design_select() { + COSIM="no" + case "$1" in + # --- cores --------------------------------------------------------- + mouse) + TOP=r5p_mouse + SRCS="$R5P_RTL/mouse/r5p_mouse.sv" ;; + hamster) + TOP=r5p_hamster + SRCS="$(_riscv_pkgs) $R5P_RTL/core/r5p_gpr_1r1w.sv $R5P_RTL/hamster/r5p_hamster.sv" ;; + degu) + TOP=r5p_degu + SRCS="$(_degu_core)" ;; + # --- SoCs ---------------------------------------------------------- + mouse_soc_simple) + TOP=r5p_mouse_soc_simple_top + SRCS="$R5P_RTL/mouse/r5p_mouse.sv $R5P_RTL/soc/r5p_mouse_soc_simple_top.sv" + COSIM="yes" ;; + mouse_soc) + TOP=r5p_mouse_soc_top + SRCS="$R5P_TCB/tcb_lite_pkg.sv $R5P_TCB/tcb_lite_if.sv $(_tcb_soc_lib) \ + $R5P_RTL/mouse/r5p_mouse.sv $R5P_RTL/soc/r5p_soc_memory.sv \ + $R5P_RTL/soc/r5p_mouse_soc_top.sv" ;; + degu_soc) + TOP=r5p_degu_soc_top + SRCS="$R5P_TCB/tcb_lite_pkg.sv $R5P_TCB/tcb_lite_if.sv $(_tcb_soc_lib) \ + $(_riscv_pkgs) \ + $R5P_RTL/core/r5p_gpr_2r1w.sv \ + $R5P_RTL/degu/r5p_pkg.sv $R5P_RTL/degu/r5p_bru.sv \ + $R5P_RTL/degu/r5p_alu.sv $R5P_RTL/degu/r5p_mdu.sv \ + $R5P_RTL/degu/r5p_lsu.sv $R5P_RTL/degu/r5p_wbu.sv \ + $R5P_RTL/degu/r5p_degu_pkg.sv $R5P_RTL/degu/r5p_degu.sv \ + $R5P_RTL/soc/r5p_soc_memory.sv $R5P_RTL/soc/r5p_degu_soc_top.sv" ;; + *) + echo "unknown design '$1'; known: $(design_list)" >&2 + return 1 ;; + esac +} diff --git a/syn/uhdm2rtlil/run.sh b/syn/uhdm2rtlil/run.sh new file mode 100755 index 0000000..1d4c707 --- /dev/null +++ b/syn/uhdm2rtlil/run.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# ============================================================================ +# rp32 — synthesise every catalogued design through uhdm2rtlil and report a +# pass/fail table; co-simulate the designs that have a deterministic testbench. +# +# export UHDM2RTLIL_ROOT=/path/to/uhdm2rtlil +# ./run.sh +# ============================================================================ +cd "$(dirname "$0")" +export R5P_RTL="$(cd ../../hdl/rtl && pwd)" +export R5P_TCB="$(cd ../../submodules/tcb/hdl/rtl && pwd 2>/dev/null || echo /nonexistent)" +source ./designs.sh + +mkdir -p work +printf '%-20s %-10s %s\n' DESIGN SYNTH CO-SIM +printf '%-20s %-10s %s\n' "------" "-----" "------" + +rc_all=0 +for d in $(design_list); do + design_select "$d" + log="work/${d}.synth.log" + out="work/${TOP}_uhdm.v" + rm -f "$out" + ./build.sh "$d" >"$log" 2>&1 || true + # A netlist is only produced when synthesis actually completed. + if [ -s "$out" ]; then + warn=$(grep -ic 'could not resolve\|unknown signal\|used but has no driver' "$log" || true) + if [ "$warn" -gt 0 ]; then synth="ok(${warn}w)"; else synth="ok"; fi + else + synth="FAIL"; rc_all=1 + fi + + cosim="-" + if [ "$COSIM" = "yes" ] && [ "$synth" = "ok" ]; then + if ./cosim.sh >"work/${d}.cosim.log" 2>&1; then cosim="PASS" + else cosim="FAIL"; rc_all=1; fi + fi + printf '%-20s %-10s %s\n' "$d" "$synth" "$cosim" +done +exit $rc_all From 0eb4e683467da4e99820a87562aeaa39df3500e4 Mon Sep 17 00:00:00 2001 From: alaindargelas Date: Fri, 17 Jul 2026 18:52:26 -0700 Subject: [PATCH 4/5] syn: full SoCs use r5p_soc_memory__gowin_inference (matching TCB API) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The full Mouse/Degu SoCs instantiate r5p_soc_memory; the plain r5p_soc_memory.sv is written for a different TCB API (reads interface localparams `sub.DAT`/`sub.MOD` that this TCB version doesn't expose — even Verilator can't elaborate it). The __gowin_inference variant uses the resolvable `sub.CFG.BUS.DAT` struct-parameter form (and byte-enable writes), matching how the FPGA flows build these SoCs, so the full SoCs synthesise through uhdm2rtlil. Co-Authored-By: Claude Opus 4.8 --- syn/uhdm2rtlil/designs.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/syn/uhdm2rtlil/designs.sh b/syn/uhdm2rtlil/designs.sh index 18f8068..48ded28 100644 --- a/syn/uhdm2rtlil/designs.sh +++ b/syn/uhdm2rtlil/designs.sh @@ -79,7 +79,7 @@ design_select() { mouse_soc) TOP=r5p_mouse_soc_top SRCS="$R5P_TCB/tcb_lite_pkg.sv $R5P_TCB/tcb_lite_if.sv $(_tcb_soc_lib) \ - $R5P_RTL/mouse/r5p_mouse.sv $R5P_RTL/soc/r5p_soc_memory.sv \ + $R5P_RTL/mouse/r5p_mouse.sv $R5P_RTL/soc/r5p_soc_memory__gowin_inference.sv \ $R5P_RTL/soc/r5p_mouse_soc_top.sv" ;; degu_soc) TOP=r5p_degu_soc_top @@ -90,7 +90,7 @@ design_select() { $R5P_RTL/degu/r5p_alu.sv $R5P_RTL/degu/r5p_mdu.sv \ $R5P_RTL/degu/r5p_lsu.sv $R5P_RTL/degu/r5p_wbu.sv \ $R5P_RTL/degu/r5p_degu_pkg.sv $R5P_RTL/degu/r5p_degu.sv \ - $R5P_RTL/soc/r5p_soc_memory.sv $R5P_RTL/soc/r5p_degu_soc_top.sv" ;; + $R5P_RTL/soc/r5p_soc_memory__gowin_inference.sv $R5P_RTL/soc/r5p_degu_soc_top.sv" ;; *) echo "unknown design '$1'; known: $(design_list)" >&2 return 1 ;; From 0c4b35a75c92b6ad974968965d4f31bfdd6f6c28 Mon Sep 17 00:00:00 2001 From: alaindargelas Date: Sun, 19 Jul 2026 21:16:16 -0700 Subject: [PATCH 5/5] syn/uhdm2rtlil: generalise gate-level co-sim harness across SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the RTL-vs-uhdm2rtlil-netlist co-simulation harness design-parameterised so it serves any COSIM="yes" SoC whose top ports match cosim_tb.sv, instead of being hard-wired to mouse_soc_simple: - cosim_tb.sv: instantiate the RTL and gate tops via `TOP_RTL` / `TOP_GATE` macros (defaulted for standalone use); cosim.sh supplies them with +define+. The two SoC tops share the same clk/rst/gpio_o/gpio_e/gpio_i/uart port set. - cosim.sh: take a design name (default mouse_soc_simple), pull TOP and the RTL source list from designs.sh, synthesise the FLAT `*_gate` netlist and Verilate it against the RTL sources. - designs.sh: document why the full TCB-interface `mouse_soc` stays COSIM="no" — Verilator (5.048) cannot unroll tcb_lite_if's `for (genvar i=1; i<=CFG.HSK.DLY; i++)` delay-line loop (interface-parameter struct field it won't fold), so there is no independent RTL reference to co-simulate the interface SoC against. The discrete mouse_soc_simple stays cosim'd and green. mouse_soc_simple co-sim: 6000 cycles, 0 mismatches (unchanged). Co-Authored-By: Claude Opus 4.8 --- syn/uhdm2rtlil/cosim.sh | 47 +++++++++++++++++++++++--------------- syn/uhdm2rtlil/cosim_tb.sv | 28 ++++++++++++++++------- syn/uhdm2rtlil/designs.sh | 15 +++++++++++- 3 files changed, 63 insertions(+), 27 deletions(-) diff --git a/syn/uhdm2rtlil/cosim.sh b/syn/uhdm2rtlil/cosim.sh index 4b760ab..cbf8218 100755 --- a/syn/uhdm2rtlil/cosim.sh +++ b/syn/uhdm2rtlil/cosim.sh @@ -3,47 +3,58 @@ # rp32 — gate-level co-simulation: RTL vs uhdm2rtlil-synthesized netlist # ============================================================================ # -# Synthesises the r5p_mouse simple SoC through uhdm2rtlil (top renamed to -# *_gate), then uses Verilator to run the original RTL and the gate netlist -# side by side under the same boot program, comparing outputs every cycle. -# This is the gate-level equivalence check for the Yosys/UHDM flow — the same -# methodology uhdm2rtlil uses for designs the native Verilog front end can't -# parse (co-simulate the synthesized netlist against the RTL). +# Synthesises an r5p_mouse SoC through uhdm2rtlil (top renamed to *_gate), then +# uses Verilator to run the original RTL and the gate netlist side by side under +# the same boot program, comparing outputs every cycle. This is the gate-level +# equivalence check for the Yosys/UHDM flow — the same methodology uhdm2rtlil +# uses for designs the native Verilog front end can't parse (co-simulate the +# synthesized netlist against the RTL). +# +# Works for any COSIM="yes" SoC in designs.sh whose top ports match cosim_tb.sv +# (clk/rst/gpio_o/gpio_e/gpio_i/uart_txd/uart_rxd) — currently the discrete +# `mouse_soc_simple` and the TCB-interface `mouse_soc`. # # export UHDM2RTLIL_ROOT=/path/to/uhdm2rtlil # built checkout (default ~/uhdm2rtlil) -# ./cosim.sh [cycles] +# ./cosim.sh [design] [cycles] # design default: mouse_soc_simple # set -euo pipefail cd "$(dirname "$0")" ROOT="${UHDM2RTLIL_ROOT:-$HOME/uhdm2rtlil}" SIMCELLS="$ROOT/out/current/share/yosys/simcells.v" -R5P_RTL="$(cd ../../hdl/rtl && pwd)" -CYCLES="${1:-6000}" -TOP=r5p_mouse_soc_simple_top -GATE=${TOP}_gate +export R5P_RTL="$(cd ../../hdl/rtl && pwd)" +export R5P_TCB="$(cd ../../submodules/tcb/hdl/rtl && pwd 2>/dev/null || echo /nonexistent)" +source ./designs.sh + +DESIGN="${1:-mouse_soc_simple}" +CYCLES="${2:-6000}" +design_select "$DESIGN" # sets TOP and SRCS (the RTL source list) +GATE="${TOP}_gate" command -v verilator >/dev/null || { echo "ERROR: verilator not found in PATH" >&2; exit 1; } [ -e "$SIMCELLS" ] || { echo "ERROR: $SIMCELLS not found (build uhdm2rtlil / set UHDM2RTLIL_ROOT)" >&2; exit 1; } -# 1. synthesise the SoC to a gate netlist with the top renamed to *_gate. -echo "== [1/2] synthesising $TOP via uhdm2rtlil (-> $GATE)" -R5P_TOP="$TOP" R5P_OUT="cosim_gate" R5P_RENAME="$GATE" ./build.sh >work/cosim_synth.log 2>&1 \ +# 1. synthesise the SoC to a FLAT gate netlist with the top renamed to *_gate +# (flat, so its submodules don't collide with the RTL sources in Verilator). +echo "== [1/2] synthesising $DESIGN ($TOP) via uhdm2rtlil (-> $GATE)" +R5P_OUT="cosim_gate" R5P_RENAME="$GATE" ./build.sh "$DESIGN" >work/cosim_synth.log 2>&1 \ || { echo "ERROR: synthesis failed; see work/cosim_synth.log" >&2; tail -20 work/cosim_synth.log; exit 1; } # 2. build + run the Verilator co-sim (RTL + gate netlist + Yosys gate cells). # The RTL side runs `$readmemh("mem_if.mem", ...)` relative to Vtb's cwd (here); -# the gate netlist already has the boot image baked in as memory init. +# the gate netlist already has the boot image baked in as memory init. The same +# cosim_tb.sv serves every SoC — cosim.sh passes the RTL/gate module names via +# +define+ (defaults in the .sv keep it usable standalone). echo "== [2/2] Verilator co-sim ($CYCLES cycles)" cp -f boot.hex mem_if.mem rm -rf work/obj_dir verilator --cc --exe --build -j 4 \ -Wno-fatal -Wno-WIDTH -Wno-UNUSED -Wno-UNOPTFLAT -Wno-CASEINCOMPLETE \ - -Wno-MULTIDRIVEN -Wno-BLKANDNBLK \ + -Wno-MULTIDRIVEN -Wno-BLKANDNBLK -Wno-DECLFILENAME -Wno-PINMISSING \ + "+define+TOP_RTL=$TOP" "+define+TOP_GATE=$GATE" \ --top-module tb --Mdir work/obj_dir \ cosim_tb.sv \ - "$R5P_RTL/mouse/r5p_mouse.sv" \ - "$R5P_RTL/soc/r5p_mouse_soc_simple_top.sv" \ + $SRCS \ work/cosim_gate.v \ "$SIMCELLS" \ cosim_main.cpp diff --git a/syn/uhdm2rtlil/cosim_tb.sv b/syn/uhdm2rtlil/cosim_tb.sv index a043ebe..fe8ead0 100644 --- a/syn/uhdm2rtlil/cosim_tb.sv +++ b/syn/uhdm2rtlil/cosim_tb.sv @@ -1,12 +1,24 @@ // ============================================================================ -// Gate-level co-simulation testbench for the r5p_mouse simple SoC. +// Gate-level co-simulation testbench for the r5p_mouse SoCs. // -// Instantiates the original RTL (`r5p_mouse_soc_simple_top`) and the -// uhdm2rtlil-synthesized gate netlist (`r5p_mouse_soc_simple_top_gate`) side by -// side, drives them with the same clock/reset/inputs, and raises `mismatch` -// whenever any observable output differs. Both run the same boot program from -// memory, so the comparison is fully deterministic. +// Instantiates the original RTL (`TOP_RTL`) and the uhdm2rtlil-synthesized gate +// netlist (`TOP_GATE`) side by side, drives them with the same +// clock/reset/inputs, and raises `mismatch` whenever any observable output +// differs. Both run the same boot program from memory, so the comparison is +// fully deterministic. +// +// The two module names are supplied by cosim.sh via +define+ so the SAME +// testbench serves both the discrete `mouse_soc_simple` and the TCB-interface +// `mouse_soc` (their top-level ports are identical). Defaults keep the file +// usable standalone for the simple SoC. // ============================================================================ +`ifndef TOP_RTL + `define TOP_RTL r5p_mouse_soc_simple_top +`endif +`ifndef TOP_GATE + `define TOP_GATE r5p_mouse_soc_simple_top_gate +`endif + module tb ( input logic clk, input logic rst, @@ -21,13 +33,13 @@ module tb ( logic [31:0] g_gpio_o, g_gpio_e; logic g_uart_txd; - r5p_mouse_soc_simple_top dut_rtl ( + `TOP_RTL dut_rtl ( .clk (clk), .rst (rst), .gpio_o (r_gpio_o), .gpio_e (r_gpio_e), .gpio_i (gpio_i), .uart_txd (r_uart_txd), .uart_rxd (uart_rxd) ); - r5p_mouse_soc_simple_top_gate dut_gate ( + `TOP_GATE dut_gate ( .clk (clk), .rst (rst), .gpio_o (g_gpio_o), .gpio_e (g_gpio_e), .gpio_i (gpio_i), .uart_txd (g_uart_txd), .uart_rxd (uart_rxd) diff --git a/syn/uhdm2rtlil/designs.sh b/syn/uhdm2rtlil/designs.sh index 48ded28..805b766 100644 --- a/syn/uhdm2rtlil/designs.sh +++ b/syn/uhdm2rtlil/designs.sh @@ -80,7 +80,20 @@ design_select() { TOP=r5p_mouse_soc_top SRCS="$R5P_TCB/tcb_lite_pkg.sv $R5P_TCB/tcb_lite_if.sv $(_tcb_soc_lib) \ $R5P_RTL/mouse/r5p_mouse.sv $R5P_RTL/soc/r5p_soc_memory__gowin_inference.sv \ - $R5P_RTL/soc/r5p_mouse_soc_top.sv" ;; + $R5P_RTL/soc/r5p_mouse_soc_top.sv" + # COSIM stays "no": the gate-level co-sim needs Verilator to elaborate the + # ORIGINAL RTL as an independent reference, but Verilator (5.048) cannot + # unroll the tcb_lite_if delay-line loop + # `for (genvar i=1; i<=CFG.HSK.DLY; i++)` + # (%Error-UNSUPPORTED: Can't unroll generate for) — CFG.HSK.DLY is an + # interface-parameter struct field it won't fold at elaboration. That is + # exactly the SystemVerilog uhdm2rtlil handles and the native Verilog/ + # Verilator flow can't, so there is no independent RTL reference to + # co-simulate the full TCB-interface SoC against. The discrete + # `mouse_soc_simple` (no interfaces) IS Verilatable and stays cosim'd; + # the interface SoC's frontend correctness is covered by the per-module + # tests + its structural `check` in the uhdm2rtlil suite. + ;; degu_soc) TOP=r5p_degu_soc_top SRCS="$R5P_TCB/tcb_lite_pkg.sv $R5P_TCB/tcb_lite_if.sv $(_tcb_soc_lib) \