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

gcd, then aes for something larger

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

picorv32, macro_reuse, uniquify

Sweep, parallelise, or analyse a build

parallel, oh_experiments, pex_calibration

See every project type in one place

heartbeat

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 engine parameter).

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):

  1. construct – enumerate + generate, and register the new filesets,

  2. build – harden each variant into a macro (needs EDA tools),

  3. 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)