Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Benchmarks

The benchmark suite measures the CMOS backend on a set of small combinational designs. Each benchmark is a directory with the design and its own config:

benchmarks/
  run.py
  c17/
    c17.mlir
    c17.toml
  maj3/
    maj3.mlir
    maj3.toml
  ...

Every config is complete, so any benchmark runs on its own:

$ ./target/release/macro_gen --config benchmarks/c17/c17.toml --emit-verilog --add-buffer

All configs target SKY130 (tt, 1.8 V) with a load of 64 C_inv per output and inputs limited to 1 C_inv. Edit include_path to point at your SKY130 install.

Designs

BenchmarkWhat it exercises
invA single inverter driving the full load: the basic buffering case.
nand2AND followed by NOT, folded back into one NAND2 stage.
c17ISCAS-85 c17: six NAND2s, two outputs, reconvergent fanout.
aoi21Inverting complex cell, one stage.
oai22Inverting complex cell with two-high stacks in both networks.
and_or_chainNon-inverting complex cell: AOI21 plus an inverter.
maj3Majority (full adder carry) as a complex cell plus an inverter.
mux2A 2:1 mux from AND, OR and NOT, mapped gate by gate.
dec2to4A decoder with four outputs sharing inverted inputs.
and8An 8 input AND, imported as a chain of AND2 gates.

Running the suite

$ export CIRCT_DIR=/path/to/circt
$ benchmarks/run.py                          # every benchmark
$ benchmarks/run.py c17 maj3                 # a subset
$ benchmarks/run.py --mode non-invertible    # keep output polarity

The runner builds macro_gen (--release --features circt) and runs every config with --emit-verilog --add-buffer <mode>, several at a time (-j). Each run characterizes the reference inverter in ngspice, which takes about 40 seconds. It then reads each run’s report and prints a summary table, which it also writes to benchmarks/build/summary.md. Each benchmark’s netlists, report and full log land in benchmarks/build/<name>/. The runner exits with an error if any benchmark fails.

Results

SKY130 tt, γ = 2.68, --add-buffer invertible. Arrows read unbuffered → buffered; delay is the logical effort estimate of the worst output in τ (an FO4 inverter is 5 τ).

BenchmarkCellsTransistorsLogic stagesF (worst)Added invStage effortDelay (τ)
and814 → 2242 → 58142.363e+1389.02 → 1.55147.3 → 63.2
and_or_chain2 → 48 → 122128211.31 → 3.3627.4 → 20.2
aoi211 → 46 → 1211283128.00 → 3.36131.7 → 20.2
c176 → 1224 → 3632977614.39 → 2.9849.2 → 26.9
dec2to410 → 2128 → 50323161113.23 → 3.3143.7 → 26.9
inv1 → 32 → 6164264.00 → 4.0065.0 → 15.0
maj32 → 414 → 182442.5221.04 → 4.5950.5 → 28.8
mux27 → 720 → 205655.203.66 → 3.6625.3 → 25.3
nand21 → 34 → 8181.38281.38 → 4.3383.4 → 17.0
oai221 → 48 → 1411283128.00 → 3.36132.0 → 20.5

Buffering brings the lone inverter from 65 τ to 15 τ (three stages at f = 4) and c17 from 49 τ to 27 τ. and8 and mux2 show the cost of mapping gate by gate (see Limitations).

Adding a benchmark

Create benchmarks/<name>/ with <name>.mlir, whose top hw.module is <name>, and a <name>.toml config (copy one from another benchmark and change its [circt] section and header comment). The runner picks it up automatically.