Example Designs#
Every directory below is a working, tested design in the examples folder of the repository. They run in CI, so they compile against the current release rather than the one they were written for.
This page is generated from those directories, so a new example appears here automatically and the folder listing and this page cannot drift out of sync.
Running one#
examples/ is not shipped inside the installed package, so clone the
repository (or open the source link on any entry below) and run the script named
as the entry point:
git clone https://github.com/siliconcompiler/siliconcompiler.git
cd siliconcompiler/examples/gcd
python gcd.py
Where the entry point is make.py, it holds several targets rather than one
script body, and smake runs them by name:
cd siliconcompiler/examples/heartbeat
smake --help # what this example can do
smake lint # run one of them
Read “Requires” before starting a run. Most examples need EDA tools installed locally – see External Tools, or use Docker to run them without installing anything. The ones marked no PDK are the cheapest place to start.
Where to start#
If you want to |
Start with |
|---|---|
Run something in seconds, with no PDK |
adder_cocotb (simulation), sva_sby (formal), blinky (FPGA) |
See a plain RTL-to-GDSII build |
|
Compile from something other than Verilog |
fibone (Bluespec), ghdl_fsynopsys (VHDL), heartbeat_migen (Migen), mlir_hls (LLVM IR) |
Build a design out of other designs |
|
Sweep, parallelise, or analyse a build |
|
See every project type in one place |
All examples#
adder_cocotb#
Example demonstrating cocotb integration with SiliconCompiler.
This example shows how to use the dvflow_cocotb helper to run Python-based
cocotb testbenches against a design, using either the Icarus Verilog or
Verilator simulation flow.
- Requires:
cocotb (pip), plus icarus or verilator – no PDK needed
- Source:
examples/adder_cocotb (entry point
make.py)
adder_lec#
Checks the synthesized ‘adder’ netlist against the RTL it came from.
This script sets up an ASIC project for a small adder, synthesizes it into a Nangate45 netlist, and checks that netlist against the RTL with Kepler-formal.
- Requires:
yosys, kepler-formal; freepdk45 (via lambdapdk)
- Source:
examples/adder_lec (entry point
lec.py)
aes#
This script demonstrates a standard RTL-to-GDSII compilation flow
for an AES (Advanced Encryption Standard) core. It takes Verilog source code and timing constraints as input and produces a final GDSII layout file.
- Requires:
yosys, openroad, opensta, klayout; freepdk45 (via lambdapdk)
- Source:
examples/aes (entry point
aes.py)
blinky#
This script demonstrates a standard RTL-to-bitstream flow for an FPGA.
It takes a Verilog design for a simple “blinky” circuit, compiles it for a specific iCE40 FPGA part, and generates a bitstream file that
can be programmed onto the hardware.
- Requires:
yosys, nextpnr, icepack – no PDK; targets a Lattice iCE40 UP5K
- Source:
examples/blinky (entry point
blinky.py)
fibone#
This script demonstrates a Bluespec SystemVerilog (BSV) to GDSII flow.
It shows how to create a custom compilation flow in SiliconCompiler to handle high-level synthesis from BSV before proceeding with the standard synthesis, place, and route steps.
- Requires:
bsc (Bluespec), yosys, openroad, opensta, klayout; freepdk45 (via lambdapdk)
- Source:
examples/fibone (entry point
fibone.py)
gcd#
Builds the ‘gcd’ (Greatest Common Divisor) design using the FreePDK45 PDK.
This script sets up a basic ASIC project, configures the design with its RTL and SDC files, loads the FreePDK45 demo target, runs the compilation flow, and displays a summary and the final layout.
The other scripts in this directory build the same design against gf180, ihp130 and skywater130.
- Requires:
yosys, openroad, opensta, klayout; freepdk45 (via lambdapdk)
- Source:
examples/gcd (entry point
gcd.py)
ghdl_fsynopsys#
This script demonstrates a VHDL to GDSII flow.
It shows how SiliconCompiler uses a specialized flow to automatically convert VHDL source code into Verilog before running the standard synthesis, place, and route steps.
- Requires:
ghdl, yosys, openroad, opensta, klayout; freepdk45 (via lambdapdk)
- Source:
examples/ghdl_fsynopsys (entry point
build.py)
heartbeat#
One small design, taken through nearly everything SiliconCompiler does.
heartbeat is the design the Quickstart builds. This
script drives it through every project type in the tool, each exposed as an
smake target:
smake lint # Lint: slang, bundled -- no tools to install
smake syn # ASIC: synthesis only
smake asic # ASIC: RTL to GDSII
smake fpga # FPGA: bitstream for a Xilinx Artix-7
smake sim # Sim: RTL simulation, opens the waveform
smake sim_postpnr # Sim: gate-level, against Skywater130 cell models
smake power # three chained jobs: VCD-driven power signoff
smake screenshot # render the finished layout
smake check # verify every referenced file resolves
It is therefore the best single place to see how the project types differ, and
what smake is for.
- Requires:
nothing for lint; verilator or icarus (sim); yosys, openroad, opensta, klayout (syn/asic); vivado (fpga); freepdk45 and skywater130 (via lambdapdk)
- Source:
examples/heartbeat (entry point
make.py)
heartbeat_migen#
Generates Verilog from a Migen module and runs it through a full
ASIC compilation flow using SiliconCompiler.
- Requires:
migen (pip), yosys, openroad, opensta, klayout; freepdk45 (via lambdapdk)
- Source:
examples/heartbeat_migen (entry point
heartbeat_migen.py)
interposer#
A simple example demonstrating how to build a silicon interposer flow.
An interposer is a silicon die that acts as a bridge, providing connections between other dies (chiplets) and a package substrate. This design flow focuses on the physical routing of these connections (Redistribution Layers or RDL) rather than logic synthesis.
- Requires:
openroad, klayout; interposer (via lambdapdk)
- Source:
examples/interposer (entry point
interposer.py)
macro_reuse#
Design Reuse of a Hardened Macro.
This script demonstrates a hierarchical ASIC design flow using SiliconCompiler. It performs the following steps: 1. Defines a child module ‘And’. 2. Hardens ‘And’ into a macro (Synthesize -> Place -> Route -> GDS/LEF/LIB). 3. Packages the results of ‘And’ into a reusable StdCellLibrary object. 4. Defines a top-level module ‘Top’ that instantiates ‘And’ three times. 5. Builds ‘Top’ using the hardened ‘And’ macro.
- Usage:
docker run –rm -v “$(pwd):/sc_work” ghcr.io/siliconcompiler/sc_runner:latest python3 make.py
- Requires:
yosys, openroad, opensta, klayout; skywater130 (via lambdapdk)
- Source:
examples/macro_reuse (entry point
make.py)
mlir_hls#
High-level synthesis from LLVM IR to GDSII.
The design’s rtl fileset holds a .ll file rather than Verilog.
HLSASICFlow runs the HLS tool over it to produce RTL, then hands that to the
usual synthesis, place and route steps.
- Requires:
bambu, yosys, openroad, opensta, klayout; freepdk45 (via lambdapdk)
- Source:
examples/mlir_hls (entry point
mlir_hls.py)
oh_experiments#
Sweep an adder’s datawidth and plot area against it.
Synthesizes oh_add from the oh library
at four datawidths – sources fetched from GitHub at a pinned commit – and
plots cell area per width with matplotlib, falling back to printing if it is not
installed. check_area.py alongside it reads the same metric back out of a
finished build.
- Requires:
yosys, opensta; freepdk45 (via lambdapdk). matplotlib is optional – without it the results are printed instead of plotted.
- Source:
examples/oh_experiments (entry point
adder_sweep.py)
padring#
Wrapping a design in an IO pad ring.
Takes a RISC-V processor and its SRAM to GDSII inside a full sky130 pad ring: 40 bidirectional signal pads, 16 supply pads, corners, IO fill, bond pads, and a core power grid tied out to the ring. The pad ring is generated by lambdalib, so no sky130 cell is named in the RTL.
The processor is picorv32, fetched from its own repository at a pinned commit rather than copied into this one.
- Requires:
yosys, openroad, opensta, klayout; skywater130 (via lambdapdk)
- Source:
examples/padring (entry point
padring.py)
parallel#
Three ways to get parallelism out of the same sweep: synthesizing adder.v
at several datawidths.
serial and processes do identical work and differ only in scheduling, so
their times compare directly. indexed deliberately does more – four
synthesis variants per datawidth instead of one – because that is what index
parallelism is for: exploring alternatives inside a job, not splitting fixed
work. Compare it on time-per-variant, not on total time.
Run one approach at a time:
./parallel.py serial
./parallel.py indexed
./parallel.py processes
See the “Parallel Job Execution” tutorial for the accompanying discussion.
- Requires:
yosys, opensta; freepdk45 (via lambdapdk)
- Source:
examples/parallel (entry point
parallel.py)
pex_calibration#
Calibrate OpenROAD’s pre-route parasitic estimate for FreePDK45.
This is a thin wrapper around the reusable utility app
siliconcompiler.tools.openroad.utils.pex_calibrate. It runs the two-phase
calibration on the bundled demo survey (gcd, picorv32, aes and jpeg) and prints
the add_openroad_rclayer / add_openroad_rccorrection lines to paste into
a PDK setup.
The same thing from the command line:
python -m siliconcompiler.tools.openroad.utils.pex_calibrate freepdk45_demo
To calibrate your own PDK, point TARGET at your target and pass your own
designs (see the designs argument of calibrate). For the full write-up
see the “Calibrating the parasitic estimate (PEX)” tutorial (pex_calibration)
in the documentation.
- Requires:
yosys, openroad, opensta; freepdk45 (via lambdapdk)
- Source:
examples/pex_calibration (entry point
calibrate.py)
picorv32#
A RISC-V CPU core, optionally wired to an SRAM.
Sources are fetched from the upstream PicoRV32 repository at a pinned commit
rather than vendored, and the rtl.memory fileset composes the core with a
single-port RAM from lambdalib. Those two techniques – third-party sources
and building a design out of other designs – are what the example is for.
Walked through in Building Your Own SoC.
- Requires:
yosys, openroad, opensta, klayout; freepdk45, asap7 or gf180 (via lambdapdk)
- Source:
examples/picorv32 (entry point
make.py)
soda#
The SODA Synthesizer front end, driven from SiliconCompiler.
mm is a batched matrix multiply in the TOSA dialect –
mm-no_weights model, which is what a stateless torch.matmul exports to.
This script takes it through the SODA path, each stage exposed as an
smake target:
smake elaborate # MLIR to Verilog: soda-opt plus Bambu, nothing else
smake syn # ...and on through synthesis and timing
smake asic # ...and on to GDSII
smake compare # baseline against optimized, on area and timing
smake unrolled # the optimized strategy at a different unroll depth
smake model # regenerate mm.mlir from PyTorch (needs requirements.txt)
smake check # verify every referenced file resolves
compare is the reason both strategies are here: baseline lowers the
kernel with no HLS-oriented optimization, optimized runs soda-opt’s Bambu
pipeline over it first, and the difference between the two is what the SODA
papers report. soda-opt has a third strategy, transformed, which rewrites the
kernel under a transform dialect schedule; it needs a schedule to be worth
running, so it is left to
SODATransformedElaborationFlow rather
than shipped here with a schedule that does nothing.
Each strategy is a flow of its own, and every flow that elaborates a design
takes one as its frontend, which is how the SODA front end reaches GDSII
without a backend of its own: everything downstream of Bambu – which upstream
is an OpenROAD-flow-scripts config.mk – is SiliconCompiler’s own ASIC flow.
- Requires:
mlir, soda, bambu (elaborate); plus yosys, opensta (syn); plus openroad, klayout (asic); freepdk45 (via lambdapdk)
- Source:
examples/soda (entry point
make.py)
sva_sby#
Formal property checking with SymbiYosys.
Five scripts covering the available PropertyCheckFlow modes – singly, in
combination, and selectable. Run any of them directly:
demo.py– bounded model check: is the assertion true for 100 cycles?prove.py– unbounded proof by k-induction: is it true for all reachable states?cover.py– cover: is a stated condition reachable at all?fifo.py– all three modes at once, against a FIFO carrying named assertions.counter_formal.py– the same on a counter, with the mode as an argument.
The first three mirror the official SymbiYosys quickstart, so they are directly
comparable with its .sby files.
- Requires:
sby, yosys, and an SMT solver – bitwuzla by default (boolector is the other supported choice; see the
engineparameter).- Source:
examples/sva_sby (entry point
demo.py)
uniquify#
Uniquify parameterized modules for hardening.
A hardened macro has no parameters, so before hardening a parameterized module we must discover which concrete parameter combinations it is instantiated with across the design, generate a parameter-free variant for each (to harden), and a parameterized wrapper that dispatches to them. This mirrors how lambdalib maps an abstract cell onto hardened macros.
The whole lifecycle is driven by the Uniquified helper on the
heartbeat_top design (which depends on the parameterized heartbeat and
prescaler modules):
construct – enumerate + generate, and register the new filesets,
build – harden each variant into a macro (needs EDA tools),
wireup – alias the wrappers in and inject the macros into the parent.
- Requires:
yosys, openroad, opensta, klayout; skywater130 (via lambdapdk)
- Source:
examples/uniquify (entry point
uniquify.py)