Multi-project sandbox for prototyping RTL designs. The flow (Verilator simulation, Yosys synthesis, OpenSTA timing & dynamic power) is project-agnostic and lives at the repository root; each design sits under projects/<name>/.
Projects:
ai-core— fixed-point multiply-accumulate Processing Elements (PEs) for AI/ML inference. The reference project.sc-demo— minimal SystemC co-simulation example (make sim-sc): a Verilated SV multiplier driving a native SystemC accumulator.tdm— time-division multiplexing designs.
This README documents the shared EDA flow: the make targets, their parameters, and the typical pipeline. For a project's designs, top-levels, RTL parameters, and experiments, see that project's own README.
.
├── .claude/
│ └── skills/ # Claude Code skills (add-project)
├── scripts/ # Project-agnostic EDA flow scripts
│ ├── sim/ # Pre-synthesis simulation flow
│ │ └── run.sh # Verilator compile and run script
│ ├── sim-sc/ # SystemC simulation flow (Verilator --sc)
│ │ └── run.sh # Verilator --sc compile and run script
│ ├── unit-test/ # SystemC Unit Tests (Supports internal SystemVerilog)
│ │ └── run.sh # Verilator --sc compile and run script for unit tests
│ ├── syn/ # Logic synthesis flow
│ │ ├── run.tcl # Yosys top-level synthesis script (ASAP7)
│ │ ├── compile.tcl # RTL read and elaboration script
│ │ └── abc.tcl # ABC technology mapping script
│ ├── post-syn-sta/ # Post-synthesis static timing analysis flow
│ │ └── run.tcl # OpenSTA timing analysis script
│ ├── post-syn-sim/ # Post-synthesis gate-level simulation flow
│ │ ├── run.sh # Verilator compile and run script
│ │ └── filelist.f # Gate-level netlist and cell library filelist
│ └── post-syn-dpa/ # Post-synthesis dynamic power analysis flow
│ └── run.tcl # OpenSTA power analysis script
├── projects/ # One subfolder per RTL project
│ └── <name>/ # An RTL project (see its README.md)
│ ├── README.md # Project-specific documentation
│ ├── rtl/ # SystemVerilog source modules (searched recursively)
│ │ └── vendor/ # vendored third-party RTL + import manifests (make vendor)
│ ├── tb/ # Verilator SV testbenches
│ ├── scripts/ # Project-specific scripts
│ │ └── flow/ # End-to-end automation (one subfolder per experiment)
│ ├── doc/ # Documentation and results
│ │ ├── diagrams/ # Block diagrams
│ │ ├── formulas/ # Mathematical formulas
│ │ ├── charts/ # Comparison charts (<exp>/<chart>.png, generated)
│ │ └── data/ # Extracted results (<exp>/results.xlsx, generated)
│ ├── sim/ # Simulation outputs (generated)
│ └── imp/ # Synthesis/STA/DPA outputs (generated)
├── Makefile # Build system entry point (PROJECT=<name> selects project)
├── sourceme.sh # Environment setup (sources ~/.bashrc, derives RTL_LAB_HOME)
└── CLAUDE.md # AI assistant guidance for this repository
All make targets require PROJECT=<name> to select the project they operate on (there is no default). The flow scripts in scripts/ resolve project-specific paths through the SEL_PROJECT env var exported by the Makefile.
This is a multi-project repo, but you don't have to download every project. A partial clone (--filter=blob:none) skips file contents until you check them out, and sparse-checkout controls which projects/<name>/ directories land in your working tree. The shared tooling — the top-level files — is always included. Pick one of the options below; consult the Projects: list above for the <name> of each project.
Your git host must support partial clone (
uploadpack.allowFilter=true). GitHub and GitLab enable it by default.
git clone --filter=blob:none --no-checkout <repo-url> rtl-lab
cd rtl-lab
git sparse-checkout init --cone
git sparse-checkout set scripts projects/<name>
git checkout mainList every project you want after scripts (space-separated):
git clone --filter=blob:none --no-checkout <repo-url> rtl-lab
cd rtl-lab
git sparse-checkout init --cone
git sparse-checkout set scripts projects/<name-1> projects/<name-2>
git checkout mainUse this to start a brand-new project, or when you only need the flow scripts. projects/ stays empty until you create or add one.
git clone --filter=blob:none --no-checkout <repo-url> rtl-lab
cd rtl-lab
git sparse-checkout init --cone
git sparse-checkout set scripts
git checkout mainA normal full clone gives you everything:
git clone <repo-url> rtl-lab
cd rtl-labNo re-clone needed — adjust the working set at any time (files are fetched on demand):
git sparse-checkout add projects/<name> # add another project to the current set
git sparse-checkout set scripts projects/<name> # replace the whole selection
git sparse-checkout list # show what is currently checked out
git sparse-checkout disable # materialize all projects (switch to full)The Projects: list at the top of this README is the catalog of everything that exists — including projects you have not checked out — and is the one shared file every new project edits, so it is where collaborators coordinate.
Tool and PDK install locations are per-user: you declare them in your ~/.bashrc, and sourceme.sh sources that file and derives everything else. Run this once per shell before any make command:
source sourceme.shsourceme.sh sets RTL_LAB_HOME from its own location, sources ~/.bashrc, and then derives SYSTEMC_INCLUDE, SYSTEMC_LIBDIR (from SYSTEMC_HOME) and ASAP7_HOME (from PDK_HOME). You therefore export only the install roots in your ~/.bashrc:
| Variable | Purpose |
|---|---|
EDA_HOME |
Root holding the EDA tool installs. |
VERILATOR_HOME, YOSYS_HOME, YOSYS_SLANG_HOME, OPENSTA_HOME, SYSTEMC_HOME |
Per-tool install dirs (conventionally $EDA_HOME/<tool>); each tool's bin/ must be on PATH. |
PDK_HOME |
Root holding the PDK trees — the ASAP7 standard-cell liberty (.lib) and verilog (.v) consumed by synthesis, STA, DPA and post-synthesis simulation. |
A minimal ~/.bashrc block (adjust the two roots to your machine):
# --- EDA tool binaries ---
export EDA_HOME=/opt/eda
export VERILATOR_HOME=$EDA_HOME/verilator
export YOSYS_HOME=$EDA_HOME/yosys
export YOSYS_SLANG_HOME=$EDA_HOME/yosys-slang
export OPENSTA_HOME=$EDA_HOME/opensta
export SYSTEMC_HOME=$EDA_HOME/systemc
export PATH=$VERILATOR_HOME/bin:$YOSYS_HOME/bin:$YOSYS_SLANG_HOME/bin:$OPENSTA_HOME/bin:$PATH
# --- PDK ---
export PDK_HOME=/opt/pdksNotes:
- Do not set
RTL_LAB_HOME—sourceme.shderives it from its own location, before sourcing~/.bashrc. SYSTEMC_INCLUDEandSYSTEMC_LIBDIRare derived fromSYSTEMC_HOME(thelib64/libvariant is auto-detected); export them yourself to override.ASAP7_HOMEdefaults to$PDK_HOME/OpenROAD-flow-scripts/flow/platforms/asap7; export it in~/.bashrcto target a different platform/technology.
The SystemC simulation mode (make sim-sc) additionally requires the Accellera SystemC library installed at $SYSTEMC_HOME, built with the same C++ standard Verilator compiles the model with (C++17). The other flows do not depend on it.
source sourceme.sh
# Pre-synthesis simulation
make sim PROJECT=<project> TOP_LEVEL=<top_level> CLK_PERIOD_NS=1.0 OUT_DIR=<name>
# Logic synthesis
make syn PROJECT=<project> TOP_LEVEL=<top_level> OUT_DIR=<name>
# Post-synthesis gate-level simulation
make post-syn-sim PROJECT=<project> TOP_LEVEL=<top_level> CLK_PERIOD_NS=1.0 OUT_DIR=<name> NETLIST_DIR=<name>
# Post-synthesis static timing analysis
make post-syn-sta PROJECT=<project> TOP_LEVEL=<top_level> CLK_PERIOD_NS=1.0 OUT_DIR=<name> NETLIST_DIR=<name>
# Post-synthesis dynamic power analysis
make post-syn-dpa PROJECT=<project> TOP_LEVEL=<top_level> CLK_PERIOD_NS=1.0 OUT_DIR=<name> NETLIST_DIR=<name> VCD_DIR=<name>
# Unit Testing you can specify TOP_LEVEL=<test_name> to run a single test called tb_<test_name>.cpp
make unit-test PROJECT=<project>PROJECT and TOP_LEVEL are required on every command — there is no default. See projects/<project>/README.md for the available TOP_LEVEL values and runnable examples.
The make targets form a pipeline where earlier steps produce artifacts consumed by later ones:
make sim— functional verification; producesactivity.vcd.make syn— logic synthesis; produces the netlist consumed by all post-synthesis flows.make post-syn-sim— gate-level functional verification; producesactivity.vcdconsumed bymake post-syn-dpa.make post-syn-sta— static timing analysis from the synthesized netlist.make post-syn-dpa— power estimation using the synthesized netlist and theactivity.vcdfrommake post-syn-sim.
This repository ships Claude Code skills under .claude/skills/. They automate the repetitive parts of working in this sandbox — scaffolding a project so it plugs into the full EDA flow. Invoke a skill by name (e.g. /add-project my-accel) in a Claude Code session.
| Skill | Purpose |
|---|---|
add-project |
Scaffold a new empty project under projects/<name>/: creates the rtl/, tb/, scripts/flow/, and doc/ skeleton, runs make init, writes a stub project README, and registers the project in this README's Projects: list. |
A typical greenfield flow is /add-project to create the skeleton, then populate rtl/ and tb/ to verify, characterize, and document the design.
The TOP_LEVEL values and PARAMS keys are project-specific; the syntax below is the shared interface. See the project README for the available top-levels and elaboration parameters.
make sim TOP_LEVEL=<top_level> CLK_PERIOD_NS=<val> OUT_DIR=<name> [PARAMS="KEY=VAL ..."]| Parameter | Required | Description |
|---|---|---|
TOP_LEVEL |
yes | RTL module to simulate |
CLK_PERIOD_NS |
yes | Clock period in nanoseconds |
OUT_DIR |
yes | Output subdirectory under sim/ |
PARAMS |
no | Project-specific RTL elaboration parameters |
Outputs go to projects/<PROJECT>/sim/<OUT_DIR>/, including an activity.vcd waveform.
A second, parallel simulation mode for designs that involve SystemC. The top is C++ sc_main (not an SV testbench), so it can instantiate both Verilated SV modules and native SystemC modules and simulate them together under the SystemC kernel. Simulation only — SystemC is never synthesized, and the make sim/syn/post-syn flows are unaffected.
make sim-sc TOP_LEVEL=<top_level> CLK_PERIOD_NS=<val> OUT_DIR=<name> [PARAMS="KEY=VAL ..."] [TB_DEFS="KEY=VAL ..."] [IN_DIR=<dir>]| Parameter | Required | Description |
|---|---|---|
TOP_LEVEL |
yes | SystemC design top the harness instantiates (rtl/systemc/<top_level>.hpp); the SV DUT(s) it wraps are verilated from the SV sources under rtl/ (searched recursively, so vendored cells under rtl/vendor/ are included) |
CLK_PERIOD_NS |
yes | Clock period in nanoseconds (drives the harness sc_clock) |
OUT_DIR |
yes | Output subdirectory under sim/ |
PARAMS |
no | RTL elaboration parameters; passed to the verilated SV DUT(s) as -G and mirrored to the harness as -D (kept in sync) |
TB_DEFS |
no | Harness-only compile-time defines (e.g. N_TESTS, SEED), passed as -D |
IN_DIR |
no | Input stimuli directory, exported as SEL_IN_DIR for the harness to read at run time. A bare name is a subfolder of the project's tb/stimuli/; a value containing / is a filesystem path. Unset → the harness's built-in default. Interpreted by the testbench, so the mapping is project-specific. |
TOP_LEVEL names the SystemC design top (rtl/systemc/<top_level>.hpp); its harness is tb/systemc/tb_<top_level>.cpp, which defines sc_main and instantiates it. Any SV under rtl/ is Verilated and linked in (the design top wraps it); a project with no SV is built directly with g++. Both rtl/systemc/ and tb/systemc/ are on the include path. Requires the SystemC library (see Environment setup). Outputs go to projects/<PROJECT>/sim/<OUT_DIR>/, including an activity.vcd.
make syn TOP_LEVEL=<top_level> OUT_DIR=<name> [PARAMS="KEY=VAL ..."] [KEEP_HIERARCHY=1]| Parameter | Required | Description |
|---|---|---|
TOP_LEVEL |
yes | RTL module to synthesize; can be any module in the hierarchy |
OUT_DIR |
yes | Output subdirectory under imp/ |
PARAMS |
no | Project-specific RTL elaboration parameters |
KEEP_HIERARCHY |
no (default: 0) | Preserve module boundaries in the netlist (skips flatten) |
Outputs go to projects/<PROJECT>/imp/<OUT_DIR>/.
make post-syn-sta TOP_LEVEL=<top_level> CLK_PERIOD_NS=<val> OUT_DIR=<name> NETLIST_DIR=<netlist_dir>| Parameter | Required | Description |
|---|---|---|
TOP_LEVEL |
yes | RTL module name |
CLK_PERIOD_NS |
yes | Clock period in nanoseconds |
OUT_DIR |
yes | Output subdirectory under imp/ |
NETLIST_DIR |
yes | Directory containing the synthesized netlist from make syn |
Outputs go to projects/<PROJECT>/imp/<OUT_DIR>/.
make post-syn-sim TOP_LEVEL=<top_level> CLK_PERIOD_NS=<val> OUT_DIR=<name> NETLIST_DIR=<netlist_dir> [PARAMS="KEY=VAL ..."]| Parameter | Required | Description |
|---|---|---|
TOP_LEVEL |
yes | RTL module to simulate |
CLK_PERIOD_NS |
yes | Clock period in nanoseconds |
OUT_DIR |
yes | Output subdirectory under sim/ |
NETLIST_DIR |
yes | Directory containing the synthesized netlist from make syn |
PARAMS |
no | Project-specific RTL elaboration parameters |
Outputs go to projects/<PROJECT>/sim/<OUT_DIR>/. Compiles the testbench with the POST_SYNTH compile-time flag to instantiate the flattened gate-level netlist instead of the RTL.
make post-syn-dpa TOP_LEVEL=<top_level> CLK_PERIOD_NS=<val> OUT_DIR=<name> NETLIST_DIR=<netlist_dir> VCD_DIR=<vcd_dir> [KEEP_HIERARCHY=1]| Parameter | Required | Description |
|---|---|---|
TOP_LEVEL |
yes | RTL module name |
CLK_PERIOD_NS |
yes | Clock period in nanoseconds |
OUT_DIR |
yes | Output subdirectory under imp/ |
NETLIST_DIR |
yes | Directory containing the synthesized netlist from make syn |
VCD_DIR |
yes | Directory containing activity.vcd from make post-syn-sim |
KEEP_HIERARCHY |
no (default: 0) | Also generate power_hierarchy.rpt with per-instance breakdown (requires hierarchical netlist) |
Outputs go to projects/<PROJECT>/imp/<OUT_DIR>/.
Each project keeps its end-to-end automation under projects/<PROJECT>/scripts/flow/, with one subfolder per experiment. By convention every experiment folder provides the same trio of scripts, which the generic flow-* targets drive:
| Script | Target | Purpose |
|---|---|---|
run.py |
make flow-run |
Run the experiment (drives the make flow) |
ext.py |
make flow-ext |
Extract results from the run outputs |
gen.py |
make flow-gen |
Generate charts/tables from the extracted data |
Select the experiment with EXP=<experiment> (required — there is no default):
make flow-list # list the experiments available in the project
make flow-run EXP=<experiment> # then flow-ext / flow-genExperiments are project-specific; see the project's own README for what each one does.
A project may carry third-party RTL under projects/<PROJECT>/rtl/vendor/, imported with the lowRISC vendor.py tool (committed there). Each dependency has a <name>.vendor.hjson manifest pinning an upstream repository and commit, plus optional local patches under patches/<name>/. Re-import every dependency for a project with:
make vendor PROJECT=<project> [VENDOR_ARGS="--update"]This runs vendor.py on every *.vendor.hjson in the project's rtl/vendor/ folder, refreshing each vendored source from its pinned commit and re-applying its patches. Pass extra vendor.py flags via VENDOR_ARGS (e.g. --update to move to the manifest's revision, -c to commit the result). The vendored .sv files are committed, so the simulation/synthesis flows find them through the recursive rtl/ search without re-running vendor.py.
make clean-sim OUT_DIR=<name> # remove one simulation run
make clean-imp OUT_DIR=<name> # remove one synthesis/STA/DPA run
make clean-all # remove all sim/ and imp/ directories| Parameter | Make targets | Values | Description |
|---|---|---|---|
PROJECT |
all | project name | Required. Project under projects/ to operate on (no default) |
TOP_LEVEL |
sim, syn, post-syn-sta, post-syn-sim, post-syn-dpa | module name | RTL module to build/simulate; can be any module in the hierarchy |
CLK_PERIOD_NS |
sim, post-syn-sta, post-syn-sim, post-syn-dpa | e.g. 1.0 |
Clock period in nanoseconds |
OUT_DIR |
all except clean-all | directory name | Output subdirectory under sim/ or imp/ |
NETLIST_DIR |
post-syn-sta, post-syn-sim, post-syn-dpa | e.g. top_bas_4x8_syn |
Directory containing the synthesized netlist from make syn |
VCD_DIR |
post-syn-dpa | e.g. top_bas_4x8_post-syn-sim |
Directory containing activity.vcd from make post-syn-sim |
PARAMS |
sim, syn, post-syn-sim | "KEY=VAL ..." |
Project-specific RTL elaboration parameters |
IN_DIR |
sim-sc | dir name or path | Input stimuli dir, exported as SEL_IN_DIR. Bare name → subfolder of tb/stimuli/; value with / → filesystem path; unset → testbench default |
KEEP_HIERARCHY |
syn, post-syn-dpa | 0 (default), 1 |
Preserve module boundaries in the netlist |
EXP |
flow-run, flow-ext, flow-gen | experiment name | Required. Experiment subfolder under scripts/flow/ (no default) |
VENDOR_ARGS |
vendor | vendor.py flags |
Extra flags forwarded to vendor.py (e.g. --update, -c); default none |