Golf scores on ASAP7, a predictive 7 nm library: never fabricated, and like sky130's score it counts no wires. sky130, a real 130 nm process, is the default. How ASAP7 is scored, and its quirks.

Tasks / add

N-bit adder add

Add two N-bit numbers and a carry in, with logic gates only.

open for submissions parametric scored at N = 16

Par
1202µm²·nsadd_n · 460.4 µm² × 2.61 ns
Record
1176µm²·nsselect-six · 474.2 µm² × 2.48 ns
Under par
−2%
Par
3.94µm²·nsadd_n · 6.998 µm² × 0.563 ns
Record
3.94µm²·nsadd_n · 6.998 µm² × 0.563 ns
Under par
0%

Score

ASAP7 · area × time · µm²·ns · lower is better
add: the score of each entry by date5 entries by date (x) and score in µm²·ns (y); the line is the best score so far, the dashed line par, and 4 unproved baselines are labelled on the right. The table under the chart lists the same numbers.12001300140015001600170026 Oct2 Nov9 Novdate enteredscore (µm²·ns) · lower is bettercmp_carry · baseline, not proved · banned operator · Score: 1684 µm²·ns · Area: 857.1 µm² · Delay: 1965 psplus · baseline, not proved · banned operator · Score: 1565 µm²·ns · Area: 498.0 µm² · Delay: 3143 psadd_n_sklansky · baseline, not proved · Score: 1328 µm²·ns · Area: 541.8 µm² · Delay: 2451 psadd_n_kogge_stone · baseline, not proved · Score: 1325 µm²·ns · Area: 641.9 µm² · Delay: 2064 pspar: add_n, 1202 µm²·nscmp_carry1684 · banned opplus1565 · banned opadd_n_sklansky1328 · not provedadd_n_kogge_stone1325 · not provedPAR1202 · provedthe best score so faradd_proc · proved reference · 2026-10-31T01:01:41Z · Score: 1202 µm²·ns · Area: 460.4 µm² · Delay: 2611 psadd_mux · proved reference · 2026-10-31T14:00:25Z · Score: 1202 µm²·ns · Area: 460.4 µm² · Delay: 2611 psadd_proc_m · proved reference · 2026-11-01T17:51:11Z · Score: 1202 µm²·ns · Area: 460.4 µm² · Delay: 2611 psadd_n · proved reference · par · 2026-10-29T10:46:16Z · Score: 1202 µm²·ns · Area: 460.4 µm² · Delay: 2611 psselect-six · submission · 2026-11-05 · Score: 1176 µm²·ns · Area: 474.2 µm² · Delay: 2479 ps
add: the score of each entry by date5 entries by date (x) and score in µm²·ns (y); the line is the best score so far, the dashed line par, and 4 unproved baselines are labelled on the right. The table under the chart lists the same numbers.12001400160026 Oct2 Nov9 Novdate enteredscore (µm²·ns) · lower is bettercmp_carry · baseline, not proved · banned operator · Score: 1684 µm²·ns · Area: 857.1 µm² · Delay: 1965 psplus · baseline, not proved · banned operator · Score: 1565 µm²·ns · Area: 498.0 µm² · Delay: 3143 psadd_n_sklansky · baseline, not proved · Score: 1328 µm²·ns · Area: 541.8 µm² · Delay: 2451 psadd_n_kogge_stone · baseline, not proved · Score: 1325 µm²·ns · Area: 641.9 µm² · Delay: 2064 pspar: add_n, 1202 µm²·nsPARthe best score so faradd_proc · proved reference · 2026-10-31T01:01:41Z · Score: 1202 µm²·ns · Area: 460.4 µm² · Delay: 2611 psadd_mux · proved reference · 2026-10-31T14:00:25Z · Score: 1202 µm²·ns · Area: 460.4 µm² · Delay: 2611 psadd_proc_m · proved reference · 2026-11-01T17:51:11Z · Score: 1202 µm²·ns · Area: 460.4 µm² · Delay: 2611 psadd_n · proved reference · par · 2026-10-29T10:46:16Z · Score: 1202 µm²·ns · Area: 460.4 µm² · Delay: 2611 psselect-six · submission · 2026-11-05 · Score: 1176 µm²·ns · Area: 474.2 µm² · Delay: 2479 ps
  • submission
  • proved reference
  • the best score so far
  • par
  • a baseline's score (not proved)
Score = area × time: the sky130 cell area of the scored netlist in µm² times the critical-path delay in ns, from the pinned flow, so µm²·ns. Lower is better. It is the one ranked number: Par (the best proved reference's score, the bar to beat), Record (the best accepted score so far, par while no submission beats it), Under par (how far the record is below par, as a share of par's score) and the leaderboard use it. The Pareto front, area in GE (NAND2 gate equivalents), depth and the other numbers are for exploring, under compare the designs; reproduce a score says how to get the same numbers. Rated with Yosys 0.53 (git 53c22ab7, the Homebrew build for macOS arm64, clang++ 17, -O3) and its yosys-abc (ABC 1.01 of 6 May 2025): the flow is deterministic on that build (measured on 52 designs). Another build of the same version can break ABC's ties differently (measured: 3 fdivp designs, up to 2.9% in delay), so a number made on another platform may differ slightly: the build and its hashes. Dots are the entries by date; the proved references are the first entries, dated by when they joined the task. The dotted levels are baselines: scored, never proved.
every entry by date
datedesignkindscore (µm²·ns)area × time
2026-10-29add_nproved reference · par1202460.4 µm² × 2.61 ns
2026-10-31add_procproved reference1202460.4 µm² × 2.61 ns
2026-10-31add_muxproved reference1202460.4 µm² × 2.61 ns
2026-11-01add_proc_mproved reference1202460.4 µm² × 2.61 ns
2026-11-05select-sixsubmission1176474.2 µm² × 2.48 ns
–plusbaseline, not proved · banned operator1565498.0 µm² × 3.14 ns
–add_n_sklanskybaseline, not proved1328541.8 µm² × 2.45 ns
–add_n_kogge_stonebaseline, not proved1325641.9 µm² × 2.06 ns
–cmp_carrybaseline, not proved · banned operator1684857.1 µm² × 1.97 ns
add: the score of each entry by date5 entries by date (x) and score in µm²·ns (y); the line is the best score so far, the dashed line par, and 4 unproved baselines are labelled on the right. The table under the chart lists the same numbers.3.944.14.226 Oct2 Nov9 Novdate enteredscore (µm²·ns) · lower is betterplus · baseline, not proved · banned operator · Score: 4.224 µm²·ns · Area: 7.436 µm² · Delay: 568 pscmp_carry · baseline, not proved · banned operator · Score: 4.218 µm²·ns · Area: 12.553 µm² · Delay: 336 psadd_n_kogge_stone · baseline, not proved · Score: 4.094 µm²·ns · Area: 9.477 µm² · Delay: 432 psadd_n_sklansky · baseline, not proved · Score: 3.919 µm²·ns · Area: 8.048 µm² · Delay: 487 pspar: add_n, 3.94 µm²·nsplus4.224 · banned opcmp_carry4.218 · banned opadd_n_kogge_stone4.094 · not provedPAR3.94 · provedadd_n_sklansky3.919 · not provedthe best score so faradd_proc · proved reference · 2026-10-31T01:01:41Z · Score: 3.94 µm²·ns · Area: 6.998 µm² · Delay: 563 psadd_mux · proved reference · 2026-10-31T14:00:25Z · Score: 3.94 µm²·ns · Area: 6.998 µm² · Delay: 563 psadd_proc_m · proved reference · 2026-11-01T17:51:11Z · Score: 3.94 µm²·ns · Area: 6.998 µm² · Delay: 563 psadd_n · proved reference · par · 2026-10-29T10:46:16Z · Score: 3.94 µm²·ns · Area: 6.998 µm² · Delay: 563 psselect-six · submission · 2026-11-05 · Score: 4.032 µm²·ns · Area: 7.188 µm² · Delay: 561 ps
add: the score of each entry by date5 entries by date (x) and score in µm²·ns (y); the line is the best score so far, the dashed line par, and 4 unproved baselines are labelled on the right. The table under the chart lists the same numbers.3.944.14.226 Oct2 Nov9 Novdate enteredscore (µm²·ns) · lower is betterplus · baseline, not proved · banned operator · Score: 4.224 µm²·ns · Area: 7.436 µm² · Delay: 568 pscmp_carry · baseline, not proved · banned operator · Score: 4.218 µm²·ns · Area: 12.553 µm² · Delay: 336 psadd_n_kogge_stone · baseline, not proved · Score: 4.094 µm²·ns · Area: 9.477 µm² · Delay: 432 psadd_n_sklansky · baseline, not proved · Score: 3.919 µm²·ns · Area: 8.048 µm² · Delay: 487 pspar: add_n, 3.94 µm²·nsPARthe best score so faradd_proc · proved reference · 2026-10-31T01:01:41Z · Score: 3.94 µm²·ns · Area: 6.998 µm² · Delay: 563 psadd_mux · proved reference · 2026-10-31T14:00:25Z · Score: 3.94 µm²·ns · Area: 6.998 µm² · Delay: 563 psadd_proc_m · proved reference · 2026-11-01T17:51:11Z · Score: 3.94 µm²·ns · Area: 6.998 µm² · Delay: 563 psadd_n · proved reference · par · 2026-10-29T10:46:16Z · Score: 3.94 µm²·ns · Area: 6.998 µm² · Delay: 563 psselect-six · submission · 2026-11-05 · Score: 4.032 µm²·ns · Area: 7.188 µm² · Delay: 561 ps
  • submission
  • proved reference
  • the best score so far
  • par
  • a baseline's score (not proved)
Score = area × time: the ASAP7 cell area of the scored netlist in µm² times the critical-path delay in ns, from the pinned flow, so µm²·ns. Lower is better. In this view Par (the best proved reference's score, the bar to beat), Record (the best accepted score so far, par while no submission beats it), Under par (how far the record is below par, as a share of par's score) and the leaderboard use it; the records' ranked score is sky130's, the default view. The Pareto front, area in GE (NAND2 gate equivalents), depth and the other numbers are for exploring, under compare the designs; reproduce a score says how to get the same numbers. ASAP7 view. These numbers are on ASAP7 (asap7sc7p5t), a predictive 7 nm library made for research: it has never been fabricated, so no chip can confirm them. Like sky130's score they count no wires. sky130, a real 130 nm process, is the default view (how ASAP7 is scored, and its quirks). Rated with Yosys 0.53 (git 53c22ab7, the Homebrew build for macOS arm64, clang++ 17, -O3) and its yosys-abc (ABC 1.01 of 6 May 2025): the flow is deterministic on that build (measured on 52 designs). Another build of the same version can break ABC's ties differently (measured: 3 fdivp designs, up to 2.9% in delay), so a number made on another platform may differ slightly: the build and its hashes. Dots are the entries by date; the proved references are the first entries, dated by when they joined the task. The dotted levels are baselines: scored, never proved.
every entry by date
datedesignkindscore (µm²·ns)area × time
2026-10-29add_nproved reference · par3.946.998 µm² × 0.563 ns
2026-10-31add_procproved reference3.946.998 µm² × 0.563 ns
2026-10-31add_muxproved reference3.946.998 µm² × 0.563 ns
2026-11-01add_proc_mproved reference3.946.998 µm² × 0.563 ns
2026-11-05select-sixsubmission4.0327.188 µm² × 0.561 ns
–plusbaseline, not proved · banned operator4.2247.436 µm² × 0.568 ns
–add_n_sklanskybaseline, not proved3.9198.048 µm² × 0.487 ns
–add_n_kogge_stonebaseline, not proved4.0949.477 µm² × 0.432 ns
–cmp_carrybaseline, not proved · banned operator4.21812.553 µm² × 0.336 ns

This text quotes sky130 numbers and compares the designs on sky130, the default library; the score, the boards and the charts of this page are on ASAP7, where the order of the designs can differ.

Add two N-bit numbers and a carry in: s is the low N bits of a + b + cin and cout the carry out of the top bit. The proof covers every width N ≥ 1; the score is taken at N = 16.

The circuit must be built from bitwise logic, multiplexers, selects and concatenations: run-time + - * / % ** and the ordering comparisons < <= > >= are banned, because addition is the task (== and != stay allowed, and so does constant arithmetic on parameters and genvars). The proved ripple-carry reference has 460.4 µm² and a 2.61 ns critical path on sky130 (112 GE, depth 33), 1202 µm²·ns: par. Parallel-prefix adders trade area for delay (Sklansky 541.8 µm² at 2.45 ns, Kogge-Stone 641.9 µm² at 2.06 ns, both simulated but not yet proved); on sky130's area × time neither is ahead of the ripple yet (1328 µm²·ns and 1325 µm²·ns).

Interface #

Write a module with exactly this header: port names, directions, widths and order matter, and so do the module's name and its parameters.

add_n.sv
module add_n #(parameter int N = 16) (
  input  logic [N-1:0] a, b,
  input  logic         cin,
  output logic [N-1:0] s,
  output logic         cout
);
portdirectionwidth (bits)
ainputN
binputN
cininput1
soutputN
coutoutput1

The trusted statement #

A proof must establish the task's trusted statement, the constant SvGolf.Tasks.Add.Statement of Spec.lean (module tasks.add.Spec). Below it is split into the properties a circuit must have, one card each: what the property guarantees in plain words, and its exact Lean text. Every proved reference has all of them. The last tab, what does not count, lists the designs the checker rejects.

Properties

A design meets the trusted statement exactly when, for every width N with 1 ≤ N < 2^31, it has all of the properties below. Lean checks that, together, they say exactly what the statement says, nothing less and nothing more (the theorem statement_iff_properties).

PARAMS_IN_RANGE is the range the statement covers, not a property: every other card must hold at each value in it.

PARAMS_IN_RANGErangeThe widths the statement covers: every N with 1 ≤ N < 2^31 (the values an int parameter holds).

The statement covers every width N with 1 ≤ N < 2^31 at once (the module's parameter is an int, which holds no larger value): one proof works for all of them, not just for the width the design is scored at (N = 16). Every property below must hold at each width.

ParamsInRange
/-- The widths the statement covers: every `N` with `1 ≤ N < 2^31` (the values an `int` parameter
holds). -/
def ParamsInRange (N : Nat) : Prop :=
  1 ≤ N ∧ N < 2 ^ 31
svgolf/tasks/add/Properties.lean:17Open in code
INTERFACEExactly these ports, in this order, with these widths.

The module has exactly the input ports a and b (N bits each) and cin (1 bit) and exactly the output ports s (N bits) and cout (1 bit), with these widths, in this order. Nothing is missing and nothing is extra: an extra input could serve as a hidden mode pin, and the checker and the scoring tools drive and read the design by these names and widths.

Interface
/-- Exactly these ports, in this order, with these widths. -/
def Interface (N : Nat) (d : Design2) : Prop :=
  inputPorts d = [("a", N), ("b", N), ("cin", 1)] ∧ outputPorts d = [("s", N), ("cout", 1)]
svgolf/tasks/add/Properties.lean:22Open in code
UNCLOCKEDNo process runs at a clock edge (no always_ff, no always @(posedge …)).

No process of the design runs at a clock edge: no always_ff, no always @(posedge …), no asynchronous-reset block; only continuous assignments and always_comb blocks. The task is combinational, so it never needs one. The rule closes a gap between Lean's model of SystemVerilog, which the proof is about, and real tools: the model runs every clocked block once per cycle whatever its clock does, so a design that registers correct outputs on a clock nothing drives would look right there, while a simulator sees a clock that never ticks and synthesis removes the registers.

Unclocked
/-- No process runs at a clock edge (no `always_ff`, no `always @(posedge …)`). -/
def Unclocked (d : Design2) : Prop :=
  ∀ p ∈ d.processes.toList, p.isEdgePhase = false
svgolf/tasks/add/Properties.lean:26Open in code
LOOP_FREENo combinational loop: the design lowers to continuous assigns (Design2.lowerComb) that are ranked (Acyclic): each reads only what lower-ranked ones write.

The design has no combinational loop: written as continuous assignments (each always_comb block becomes one), its processes can be ranked so that each reads only what lower-ranked ones write. A latch (an always_comb block that keeps a value on some path) is refused with it. Lean's model starts every signal at x and settles, so it would read a loop at one state, while a circuit powers up in any 0/1 state the loop can hold and keeps it; the rule removes that question instead of answering it. The ranking is of processes, not bits, so a process that reads a part of a signal it writes itself is refused too, even when no bit depends on itself: write such bits as separate assignments.

LoopFree
/-- No combinational loop: the design lowers to continuous assigns (`Design2.lowerComb`) that are
ranked (`Acyclic`): each reads only what lower-ranked ones write. -/
def LoopFree (d : Design2) : Prop :=
  ∃ d', d.lowerComb = some d' ∧ Acyclic d'
svgolf/tasks/add/Properties.lean:30Open in code
TERMINATESUnder every schedule and every stimulus, the run completes.

Whatever order the simulator picks for processes that are ready at the same moment (the schedule), and whatever values the inputs take, simulating the design completes: every cycle settles. A combinational loop that oscillates fails this, and so does a design the tools could not read. It is also what gives the next property its teeth: that one is about completed runs, and a design with no completed run would satisfy it without computing anything.

Terminates
/-- Under every schedule and every stimulus, the run completes. -/
def Terminates (d : Design2) : Prop :=
  ∀ (σ : ScheduleOracle) (stim : List SvState), ∃ tr, Runs2 d σ stim tr
svgolf/tasks/add/Properties.lean:35Open in code
COMPUTES_SUMIn every completed run, every cycle whose stimulus drives a, b, cin with known values ends with s and cout holding the low N bits and the carry of a + b + cin.

In every cycle in which the inputs a, b and cin are driven with known 0/1 values, the outputs settle to the sum: with t = a + b + cin taken as whole numbers, s = t mod 2^N (the low N bits) and cout = t div 2^N (the carry out, 0 or 1). So {cout, s} is the full (N+1)-bit sum and nothing is lost. The outputs must be fully known 0/1 values in every cycle of every run, whatever the earlier cycles were, so they cannot depend on history.

ComputesSum
/-- In every completed run, every cycle whose stimulus drives `a`, `b`, `cin` with known values
ends with `s` and `cout` holding the low `N` bits and the carry of `a + b + cin`. -/
def ComputesSum (N : Nat) (d : Design2) : Prop :=
  d ⊨₂ spec2 fun stim tr =>
    ∀ (c : Nat) (inputs st : SvState), stim[c]? = some inputs → tr[c]? = some st →
      ∀ (a b : BitVec N) (cin : BitVec 1),
        HoldAll inputs [("a", N), ("b", N), ("cin", 1)] (a, b, cin, ()) →
        HoldAll st [("s", N), ("cout", 1)]
          (BitVec.ofNat N (a.toNat + b.toNat + cin.toNat),
           BitVec.ofNat 1 ((a.toNat + b.toNat + cin.toNat) / 2 ^ N), ())
svgolf/tasks/add/Properties.lean:39Open in code

Definitions

The names the properties use, each with its Lean text. Trusted text is what a proof is about; a helper of Properties.lean is not trusted: Lean checks it as part of statement_iff_properties.

This task's trusted text

StatementSpec.leanThe trusted challenge statement that these properties restate, part by part.
Statement
/-- **The challenge statement.** A submission proves
`SvGolf.Tasks.Add.Statement Submission.design.sem`. -/
abbrev Statement : (Nat → LeanModels.Sv.Design2) → Prop := task.Statement
svgolf/tasks/add/Spec.lean:46Open in code
taskSpec.leanThe task as data: the parameter range, the ports at each parameter value, and the function the outputs must compute.
task
/-- The task: inputs `a b : BitVec N`, `cin : BitVec 1`; outputs
`s = (a + b + cin) mod 2^N` and `cout = (a + b + cin) / 2^N`, the sum taken
in `Nat`; for `1 ≤ N < 2^31`. -/
def task : CombTask where
  inRange N := 1 ≤ N ∧ N < 2 ^ 31
  inputs N := [("a", N), ("b", N), ("cin", 1)]
  outputs N := [("s", N), ("cout", 1)]
  fn N := fun (a, b, cin, ()) =>
    let t := a.toNat + b.toNat + cin.toNat
    (BitVec.ofNat N t, BitVec.ofNat 1 (t / 2 ^ N), ())
svgolf/tasks/add/Spec.lean:35Open in code

The shared trusted base

CombTask.SatisfiedAtTask.leanThe trusted form of a combinational statement at one parameter value: the interface, then no clock and termination, then the function.
SatisfiedAt
/-- The statement at one parameter value: interface; no clocked process, no
combinational loop and termination; function. Conjunct 2 is the triple
`Unclocked d ∧ LoopFree d ∧ Terminates2 d`. -/
def SatisfiedAt (N : Nat) (d : Design2) : Prop :=
  t.Interface N d ∧ (Unclocked d ∧ LoopFree d ∧ Terminates2 d) ∧ t.Computes N d
svgolf/SvGolf/Task.lean:262Open in code
inputPortsTask.leanThe design's input ports, each with its declared width, in declaration order.
inputPorts
/-- The input ports of `d` with their declared widths, in declaration order.
`instantiate2` lists the ports first, in port-list order. A declaration is
an input port iff its `isInput` flag is set. -/
def inputPorts (d : Design2) : List Sig :=
  d.decls.toList.filterMap fun dc => if dc.isInput then some (dc.name, dc.width) else none
svgolf/SvGolf/Task.lean:178Open in code
outputPortsTask.leanThe design's output ports, each with its declared width, in declaration order.
outputPorts
/-- The output ports of `d` with their declared widths, in declaration order.
A declaration is an output port iff its `isOutput` flag is set. -/
def outputPorts (d : Design2) : List Sig :=
  d.decls.toList.filterMap fun dc => if dc.isOutput then some (dc.name, dc.width) else none
svgolf/SvGolf/Task.lean:184Open in code
HoldAllTask.leanHoldAll st ports values: in the state st, every listed port holds its value as a known bit vector (no x, no z) of exactly the port's width.
HoldAll
/-- `HoldAll st sigs v`: in state `st`, every port `(n, w)` of `sigs` is bound
to the fully known `w`-bit vector that `v` assigns it. -/
def HoldAll (st : SvState) : (sigs : List Sig) → Vals (sigs.map Prod.snd) → Prop
  | [], _ => True
  | (n, _) :: sigs, v => SvState.lookup st n = some (LVec.ofBitVec v.1) ∧ HoldAll st sigs v.2
svgolf/SvGolf/Task.lean:197Open in code
⊨₂Spec2.leand ⊨₂ P: in every completed run of the design d, under every schedule and every stimulus, the stimulus and the trace satisfy P.
Models2
/-- `d ⊨₂ P` — for **every** legal schedule, every stimulus, and every
completed run (`Runs2`), the trace satisfies `P`. Introduce from a raw
∀-fuel fact with `Models2.of_run`; eliminate against a concrete run with
`Models2.run` / `Models2.runs`. Says nothing about whether runs complete —
pair it with `Terminates2`. -/
def Models2 (d : Design2) (P : TraceProp2) : Prop :=
  ∀ (σ : ScheduleOracle) (stim tr : List SvState), Runs2 d σ stim tr → P d stim tr

@[inherit_doc] scoped infix:50 " ⊨₂ " => Models2
LeanModels/Sv/Spec2.lean:141Open in code
spec2Spec2.leanTurns a property of a stimulus (one input entry per cycle) and a trace (one snapshot of every signal per cycle) into the form ⊨₂ takes.
spec2
/-- Lift a design-agnostic stimulus/trace predicate into `⊨₂`
(`d ⊨₂ spec2 fun stim tr => …`). -/
def spec2 (P : List SvState → List SvState → Prop) : TraceProp2 := fun _ stim tr => P stim tr
LeanModels/Sv/Spec2.lean:151Open in code
Runs2Spec2.leanRuns2 d σ stim tr: simulating d under the schedule σ on the stimulus stim completes, with the trace tr.
Runs2
/-- The fuel-abstracted Design2 run judgment: *some* fuel completes the run
of `d` under schedule `σ` and stimulus `stim` with trace `tr`. The only place
fuel appears in a Design2 spec. -/
def Runs2 (d : Design2) (σ : ScheduleOracle) (stim tr : List SvState) : Prop :=
  ∃ fuel, run2 d σ fuel stim = .ok tr
LeanModels/Sv/Spec2.lean:121Open in code
ScheduleOracleSemantics.leanA legal schedule: the order in which the simulator runs the processes that are ready at the same moment. The statement quantifies over all of them.
ScheduleOracle
/-- A legal schedule: at invocation `k`, orders the ready process list.
`choose_perm` is the legality proof — every invocation is a permutation of
the ready list — so `∀ σ : ScheduleOracle` ranges over exactly the legal
schedules. See the module docstring for the invocation-counter protocol. -/
structure ScheduleOracle where
  /-- Invocation counter and ready process indices in, execution order out. -/
  choose : Nat → List Nat → List Nat
  /-- Every invocation yields a permutation of the ready list. -/
  choose_perm : ∀ (k : Nat) (ready : List Nat), (choose k ready).Perm ready
LeanModels/Sv/Semantics.lean:151Open in code
Process2.isEdgePhaseSem2.leanTrue for the processes that run at the clock edge: always_ff, always @(posedge …) and asynchronous-reset blocks.
isEdgePhase
/-- Edge-phase processes: every posedge-clocked block, INCLUDING the
async-reset ones (the posedge fires with reset asserted too — the body's
reset branch is what holds the state, pin3 CYCLE 4). -/
def Process2.isEdgePhase : Process2 → Bool
  | .alwaysFF _ _ | .alwaysPlain _ _ | .alwaysFFR _ _ _ _ => true
  | _ => false
LeanModels/Sv/Sem2.lean:650Open in code

What does not count

Designs that try to score without meeting the statement (negatives), or that exploit a place where the proof's reading and the scored netlist could differ (attacks). The checker stops at the first stage that refuses; each design is listed with that stage.

Refused before any proof is tried

The checker's static stages read the text itself and refuse it: an operator the task bans, a construct that two tools read differently, an unknown (x or z) value that could arise, or a program the language forbids.

  • eqx_x.sv (attack, stopped at source): (cin === 1'bx) ? '0 : sum: a 4-state simulator computes the sum, while Yosys folds the test and outputs 0 at 0 GE.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N-1:0] sr;
      logic         cr;
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign sr[i]  = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      assign cr = c[N];
      assign s    = (cin === 1'bx) ? '0 : sr;
      assign cout = (cin === 1'bx) ? 1'b0 : cr;
    endmodule
    
  • z_case_item.sv (attack, stopped at source): A correct sum behind a case item with a z digit, which Yosys reads as a match, turning the output into an unknown value at 0 GE.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N-1:0] sr;
      logic         cr;
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign sr[i]  = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      assign cr = c[N];
      always_comb
        case (cin)
          1'bz: begin s = '0; cout = 1'b0; end
          default: begin s = sr; cout = cr; end
        endcase
    endmodule
    
  • zpair_add_rare.sv (attack, stopped at source): Complementary z items that make the netlist wrong on a single input pair, too rare for sampling to find.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N-1:0] sr;
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign sr[i]  = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      logic rare;
      logic [N-1:0] ka, kb, pa, pb;
      logic [2*N-1:0] wa;
      logic [3*N-1:0] wb;
      assign wa = {N{2'b10}};
      assign wb = {N{3'b011}};
      assign pa = wa[N-1:0];
      assign pb = wb[N-1:0];
      assign ka = ~(a ^ pa);
      assign kb = ~(b ^ pb);
      assign rare = (&ka) & (&kb);
      always_comb
        case ({a[0], cin})
          2'b0z: begin s = {sr[N-1:1], sr[0] ^ rare}; cout = c[N]; end
          2'b1z: begin s = {sr[N-1:1], sr[0] ^ rare}; cout = c[N]; end
          default: begin s = sr; cout = c[N]; end
        endcase
    endmodule
    
  • cin_name.sv (negative, stopped at extract): The carry-in port is named ci instead of cin.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         ci,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N:0] c;
      assign c[0] = ci;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign s[i]   = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      assign cout = c[N];
    endmodule
    
  • wide_s.sv (negative, stopped at extract): One (N + 1)-bit output {cout, s} instead of the two ports s and cout.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N:0]   s
    );
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign s[i]   = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      assign s[N] = c[N];
    endmodule
    
  • slang_always_notime.sv (attack, stopped at banlist): A plain always block that never advances time, which the language forbids (it deadlocks a simulator) but Yosys reads as a wire.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign s[i]   = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      always cout = c[N];
    endmodule
    
  • slang_initial_comb.sv (attack, stopped at banlist): An initial block and an always_comb both writing cout, which the language forbids but Yosys accepts.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign s[i]   = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      initial cout = 1'b0;
      always_comb cout = c[N];
    endmodule
    
  • slang_input_assign.sv (attack, stopped at banlist): Assigns to the input port cin, which the language forbids.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign s[i]   = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      assign cin = a[0];
      assign cout = c[N];
    endmodule
    
  • slang_mixed_assign.sv (attack, stopped at banlist): Drives cout from both a continuous assignment and an always_comb, which the language forbids.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign s[i]   = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      assign cout = c[N];
      always_comb cout = c[N];
    endmodule
    
  • slang_two_always.sv (attack, stopped at banlist): Two always_comb blocks writing cout, which the language forbids.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign s[i]   = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      always_comb cout = c[N];
      always_comb cout = c[N];
    endmodule
    
  • plus.sv (negative, stopped at banlist): The right function through the banned run-time +.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      assign {cout, s} = a + b + cin;
    endmodule
    
  • eqx_undriven.sv (attack, stopped at fourstate): Compares an undriven signal with ===, which Yosys folds to a constant.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N-1:0] sr;
      logic         cr;
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign sr[i]  = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      assign cr = c[N];
      logic u;
      assign s    = (u === cin) ? '0 : sr;
      assign cout = (u === cin) ? 1'b0 : cr;
    endmodule
    
  • dead_clock.sv (negative, stopped at fourstate): A correct sum stored in flip-flops on a clock that nothing drives: every simulator sees x, and it would score 0 GE.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic         clk;
      logic [N-1:0] sc;
      logic [N:0]   c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign sc[i]  = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      always_ff @(posedge clk) begin
        s    <= sc;
        cout <= c[N];
      end
    endmodule
    
  • dead_clock_tied.sv (negative, stopped at design): The same with the clock tied to 1'b0: a clock must be an input port.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic         clk;
      logic [N-1:0] sc;
      logic [N:0]   c;
      assign clk  = 1'b0;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign sc[i]  = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      always_ff @(posedge clk) begin
        s    <= sc;
        cout <= c[N];
      end
    endmodule
    
Rejected at the proof

These pass every static check. The proof that comes with each one does not compile, or does not prove the statement: a design that is wrong somewhere in the task's range (or has other ports) has no proof at all, and a proof that leaves a goal unproved is never accepted.

  • add_proc_case.sv (negative, stopped at solution): A correct adder whose carry cell is a case arm wrapped in begin … end, a shape the proof's tactics do not handle, so its proof leaves a goal unproved.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N:0]   c;
      logic [N-1:0] p;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign p[i] = a[i] ^ b[i];
          always_comb begin
            case (p[i])
              1'b1: begin c[i+1] = c[i]; end
              default: c[i+1] = a[i];
            endcase
          end
          assign s[i] = p[i] ^ c[i];
        end
      endgenerate
      assign cout = c[N];
    endmodule
    
  • carry_bug.sv (negative, stopped at solution): A wrong carry gate, (a & b) | (c & a).

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign s[i]   = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & a[i]);
        end
      endgenerate
      assign cout = c[N];
    endmodule
    
  • cout_off.sv (negative, stopped at solution): The carry out is taken one bit too early (c[N-1]).

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign s[i]   = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      assign cout = c[N-1];
    endmodule
    
  • no_cin.sv (negative, stopped at solution): The carry in is ignored.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N:0] c;
      assign c[0] = 1'b0;
      genvar i;
      generate
        for (i = 0; i < N; i++) begin : g_bit
          assign s[i]   = a[i] ^ b[i] ^ c[i];
          assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
      endgenerate
      assign cout = c[N];
    endmodule
    
  • only_n16.sv (negative, stopped at solution): A ripple adder at the scoring width N = 16 only, wrong at every other width.

    the design, with its comments left out
    module add_n #(parameter int N = 16) (
      input  logic [N-1:0] a, b,
      input  logic         cin,
      output logic [N-1:0] s,
      output logic         cout
    );
      logic [N:0] c;
      assign c[0] = cin;
      genvar i;
      generate
        if (N == 16) begin : g_ripple
          for (i = 0; i < N; i++) begin : g_bit
            assign s[i]   = a[i] ^ b[i] ^ c[i];
            assign c[i+1] = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
          end
          assign cout = c[N];
        end else begin : g_cheap
          assign s    = a ^ b;
          assign cout = 1'b0;
        end
      endgenerate
    endmodule
    
Spec.lean, verbatim (94 lines)
import SvGolf.Task

/-!
# Task `add`: N-bit adder with carry in and carry out (TRUSTED)

The warm-up challenge. Module (port order as written; `N` is the module's
only parameter):

```systemverilog
module add_n #(parameter int N = 16) (
  input  logic [N-1:0] a, b,
  input  logic         cin,
  output logic [N-1:0] s,
  output logic         cout
);
```

Statement: for every `N` with `1 ≤ N < 2^31` (the values an `int` parameter
holds), the design has exactly the input ports `a`,
`b` (`N` bits) and `cin` (1 bit), in that order, and exactly the output
ports `s` (`N` bits) and `cout` (1 bit), in that order; no process is
clocked; there is no combinational loop; every run terminates; and in every
cycle whose stimulus drives `a`, `b`, `cin` with known values, the snapshot holds `{cout, s} = a + b + cin`: with
`t = a + b + cin` computed in the natural numbers, `s = t mod 2^N` and
`cout = t / 2^N` (which is 0 or 1).

The banned run-time operators (`+ - * / % **`) are listed in `task.json`
and enforced by the checker's banlist stage, not here.
-/

namespace SvGolf.Tasks.Add

open SvGolf

/-- The task: inputs `a b : BitVec N`, `cin : BitVec 1`; outputs
`s = (a + b + cin) mod 2^N` and `cout = (a + b + cin) / 2^N`, the sum taken
in `Nat`; for `1 ≤ N < 2^31`. -/
def task : CombTask where
  inRange N := 1 ≤ N ∧ N < 2 ^ 31
  inputs N := [("a", N), ("b", N), ("cin", 1)]
  outputs N := [("s", N), ("cout", 1)]
  fn N := fun (a, b, cin, ()) =>
    let t := a.toNat + b.toNat + cin.toNat
    (BitVec.ofNat N t, BitVec.ofNat 1 (t / 2 ^ N), ())

/-- **The challenge statement.** A submission proves
`SvGolf.Tasks.Add.Statement Submission.design.sem`. -/
abbrev Statement : (Nat → LeanModels.Sv.Design2) → Prop := task.Statement

/-! ## Sanity checks on the statement's data

They are proved, so they add nothing to the trusted base; they are here so
that a reader can see the statement means what the prose says. -/

/-- The scoring point `N = 16` is in range. -/
example : task.inRange 16 := by simp [task]

/-- The range ends below `2^31`, the values an `int` parameter holds. -/
example : task.inRange (2 ^ 31 - 1) ∧ ¬ task.inRange (2 ^ 31) := by simp [task]

/-- The input names are distinct (the non-vacuity theorem
`CombTask.SatisfiedAt.exists_run` needs it), at every `N`. -/
example (N : Nat) : ((task.inputs N).map Prod.fst).Nodup := by
  simp [task]

/-- `0xFFFF + 0x0001 + 0 = 0x1_0000`: `s = 0`, `cout = 1`. -/
example : (task.fn 16 (0xFFFF#16, 0x0001#16, 0#1, ())).1 = 0#16 ∧
    (task.fn 16 (0xFFFF#16, 0x0001#16, 0#1, ())).2.1 = 1#1 := by decide

/-- `0xFFFF + 0xFFFF + 1 = 0x1_FFFF`: `s = 0xFFFF`, `cout = 1`. -/
example : (task.fn 16 (0xFFFF#16, 0xFFFF#16, 1#1, ())).1 = 0xFFFF#16 ∧
    (task.fn 16 (0xFFFF#16, 0xFFFF#16, 1#1, ())).2.1 = 1#1 := by decide

/-- `3 + 4 + 1 = 8` at `N = 4`: no carry out. -/
example : (task.fn 4 (3#4, 4#4, 1#1, ())).1 = 8#4 ∧
    (task.fn 4 (3#4, 4#4, 1#1, ())).2.1 = 0#1 := by decide

/-- **The arithmetic reading of `fn`**, at every `N`: `cout · 2^N + s` is
exactly `a + b + cin` in the natural numbers (so `{cout, s}` is the
`(N+1)`-bit sum, and nothing is lost to the 1-bit width of `cout`). -/
theorem fn_arith (N : Nat) (a b : BitVec N) (cin : BitVec 1) :
    (task.fn N (a, b, cin, ())).2.1.toNat * 2 ^ N + (task.fn N (a, b, cin, ())).1.toNat =
      a.toNat + b.toNat + cin.toNat := by
  have ha := a.isLt
  have hb := b.isLt
  have hc : cin.toNat < 2 := cin.isLt
  have hp := Nat.two_pow_pos N
  have hq : (a.toNat + b.toNat + cin.toNat) / 2 ^ N < 2 := by
    rw [Nat.div_lt_iff_lt_mul hp]
    omega
  simp only [task, BitVec.toNat_ofNat, Nat.pow_one, Nat.mod_eq_of_lt hq]
  exact Nat.div_add_mod' _ _

end SvGolf.Tasks.Add

Its trusted text

The modules specific to this task. Like every task, it also rests on the shared trusted base (the ls-sv semantics of SystemVerilog and svGolf's statement helpers), and a proof may import any module of the ls-sv library. Nothing else is trusted: proof helpers are kernel-checked like any submission.

modulerolelinessha256
tasks.add.Specsvgolf/tasks/add/Spec.leantask statement9408be62a5c0b2

How to participate #

  1. Write a circuit with the task's exact interface.
  2. Prove in Lean 4 that it meets the trusted statement; Start a new design, below, gives the route, and the proving guide shows how.
  3. Check and record it (how to submit): the checker accepts the pair or says which stage refused it, as it does for each design under what does not count.
  4. Beat par: an accepted design whose score (area × time) is below that of the best proved reference. The leaderboard ranks by it.

How to submit

You hand in two files: solution.sv, a module with the exact header under Interface, and Solution.lean, a Lean 4 proof that it meets the trusted statement.

Step 0, once per machine. Install:

  • elan, which installs the Lean toolchain that lean-toolchain pins (leanprover/lean4:v4.33.0-rc1) on first use;
  • Yosys 0.53 with its yosys-abc (every pinned tool and file: Reproduce a score);
  • Verilator 5, a C++ compiler and make, for the post-synthesis check (it compiles Verilator's model of the netlist);
  • Python 3.12 with python3.12 -m pip install -r requirements.txt (pyslang==11.0.0, the extractor's SystemVerilog frontend).
step 0
git clone https://github.com/thomasnormal/svgolf
cd svgolf
python3.12 -m pip install -r requirements.txt
# the trusted Lean and the checker's evaluator
lake build
# the pinned sky130 liberty, checked by its hash
python3.12 score/ppa.py --fetch-liberty

lake build takes about 6 minutes and 1 GB of disk the first time, on a laptop that already had the Lean toolchain (README.md's Step 0 says what was measured where; elan's first download of the toolchain comes on top): Lake clones proglib (formerly lean-surfaces) and its packages from github.com, so it needs network access there, and builds the LeanModels.Sv modules svGolf uses; Mathlib is cloned, never built.

Start from the reference pair under Files, add_n, a complete and accepted one: copy it, from the same directory:

shell
cp tasks/add/reference/add_n.sv solution.sv
cp tasks/add/reference/add_n.lean Solution.lean

Then, for each design, from the same directory: find it without Lean and check it once without a proof (the golfing loop and step 1), write its proof (Start a new design, below, gives the route), then check the pair and record it (steps 2 and 3):

shell
# the golfing loop, no Lean: area, delay and the critical
#    path, about a second
python3.12 score/ppa.py solution.sv --task tasks/add \
    --no-mapped --path
# 1. no proof needed; never accepts; exits 0 when every
#    stage passed, ending with area x time and par
python3.12 check.py tasks/add solution.sv --unproved \
    --tactics --stage-dir stage
# 2. the real check: prints "accepted": true; its
#    post-synthesis check is LIGHT by default (a subset of
#    the vectors, for local feedback), so stderr also says
#    "accepted, but the check was INCOMPLETE ... rerun with
#    --postsynth full": expected, since step 3 runs the
#    full one itself
python3.12 check.py tasks/add solution.sv Solution.lean
# 3. record it: the whole check again, full and sandboxed
python3.12 leaderboard/leaderboard.py add --task add \
    --player YOUR_HANDLE --assisted-by "TOOL OR MODEL" \
    --sv solution.sv --lean Solution.lean \
    --notes "YOUR DESIGN IN ONE LINE"

Done: step 3 prints added add/HASH: YOUR_HANDLE, … once the pair has passed the whole check, full and sandboxed, and its record is written (what it writes, and where: below); otherwise it prints REFUSED with the reasons and records nothing. Step 2's "accepted": true, with its INCOMPLETE line, is feedback for you, not a record.

The golfing loop and step 1, the first two commands above. The second command runs every stage that needs no proof, the task's oracle included (a wrong circuit is named there, not deep in a proof), says whether the proof tactics read the design (tactics.in_fragment) and leaves it staged in stage/ for probe files (PROVING.md, section 0).

score/ppa.py is the inner loop of golfing; its ranked numbers are area_um2_sky130 and delay_ps_sky130 in what it prints. It runs only the source gate and the pinned flow: it does not check the banlist, the 4-state rules, whether ls-sv can read the design, the post-synthesis simulation or the task's function. Step 1 does, still without a proof.

The Lean file. The checker extracts your .sv itself and writes the trusted module Submission.Design; Goal unfolds to SvGolf.Tasks.Add.Statement Submission.design.sem, the task's statement of your design:

Submission.Design (generated: you never write it)
import LeanModels.Sv.Ingest2
import tasks.add.Spec

namespace Submission
load_design_sv2 design from "<the envelope of your .sv>"
abbrev Goal : Prop := SvGolf.Tasks.Add.Statement design.sem
end Submission

Your Solution.lean imports it and proves Goal, as the skeleton in Start a new design (The proof in detail) shows. File names and paths are free (here solution.sv and Solution.lean); the module name Submission, the import Submission.Design header and the theorem solution : Goal (in namespace Submission, theorem Submission.solution : Submission.Goal) are fixed.

Step 3 writes your record's three files (.json, .sv and .lean, named by the record's hash) to leaderboard/data/add/, the directory a pull request adds. Then open a pull request against https://github.com/thomasnormal/svgolf that adds them; CI re-verifies it. There is no submission server: nothing is sent anywhere by these commands. For a private trial, add --data-dir DIR: the record then goes to DIR and the board stays as it is. Repeat --assisted-by for each tool or AI system that helped, or leave it out.

YOUR_HANDLE is your public name: the board and the record's page show it. It is 1 to 32 characters, letters, digits, ., _ or -, the first a letter or a digit ([A-Za-z0-9][A-Za-z0-9._-]{0,31}). --notes is optional: one line on the design (at most 2000 characters), shown on the record's page. In a private trial (--data-dir DIR), add --from-check RESULT.json records the JSON that a check.py … --postsynth full --ppa require run printed instead of checking again; the board's own leaderboard/data/ refuses a stored result.

the sandbox, and machines without one

leaderboard.py add runs the check with --sandbox require: the proof's Lean, the extractor, Yosys and Verilator must run inside the operating system's sandbox (Seatbelt on macOS, bubblewrap on Linux). Where that sandbox is missing or fails its self-test, the check stops with an infrastructure error and nothing is recorded. On such a machine, --sandbox auto runs the check without it (and says so on stderr), and --sandbox off skips it: your proof file then runs with your own privileges, and the record is for your own use, since an official record is made with the sandbox or not at all. add also weighs the ranked sky130 numbers, which need the pinned liberty (Step 0). On a shared machine whose Lean calls go through a wrapper, set SVGOLF_LEAN_WRAP; check.py and leaderboard.py both read it, and SVGOLF_LEAN_WRAP_ONCE=1 takes the wrapper once for a whole run.

What moves the score

What players have seen move the ranked sky130 numbers: observations, not promises (the pinned flow is the judge, and score/ppa.py measures a variant in seconds).

  • The pinned flow's ABC script restructures what you write: a two-bit lookahead carry came back as the same ripple of NAND gates, and scored worse.
  • Statement order and gate forms move both area and delay: the carry assign before the sum assign in the loop, and bit 0's carry written as a majority at module level with the loop from i = 1, each moved area × time by a few percent. Blank lines and signal or block names changed nothing.
  • Commuting the operands of one operator moves the A0' area by up to 11% and the delay by up to 32% (the maintainers' measurement, score/PPA.md).
  • The golfing loop's --path names the critical path with each net's arrival time: read it before you guess.

Leaderboard

by score · ASAP7
  1. 1
    2026-11-05
    1176474.2 µm² × 2.48 ns
  2. ⚑
    par proved reference
    1202460.4 µm² × 2.61 ns
every column: area, time, proof lines, assisted by, files
#playerdatescore (µm²·ns)area (µm²)time (ps)area (GE)depthproof linesassisted byrecordfiles
1select-six2026-11-051176474.22479114.66533332Claude Opus 5.5 (Anthropic)d20bd7d9a6e6.sv .lean

No submission beats par yet. Par, the bar to beat, is the proved reference add_n: 3.94 µm²·ns (6.998 µm² × 0.563 ns).

  1. ⚑
    par proved reference
    3.946.998 µm² × 0.563 ns
  2. 1
    2026-11-05
    4.0327.188 µm² × 0.561 ns
every column: area, time, proof lines, assisted by, files
#playerdatescore (µm²·ns)area (µm²)time (ps)area (GE)depthproof linesassisted byrecordfiles
1select-six2026-11-054.0327.188561114.66533332Claude Opus 5.5 (Anthropic)d20bd7d9a6e6.sv .lean
score: area × time, µm²·nspar

At a glance

top module
add_n
parameters
N in range 1 <= N < 2^31
scoring point
N = 16
depth budget
none
banned run-time operators
+ - * / % **, and the run-time ordering comparisons < <= > >= (Yosys builds each as its own adder, an $alu; equality stays allowed)

Run-time addition is the task. Yosys's alumacc merges + and - chains into the same $alu/$macc cells as *, so all of + - * / % ** are banned on run-time operands. Constant arithmetic (N-1, i+1 over a genvar, $clog2(N)) stays allowed.

allowed axioms
propext, Classical.choice, Quot.sound
proof time limit
300 s of CPU time (a wall-clock backstop of 1500 s stops a proof that waits)

Start a new design

The route: the sv_comb tactics, then one lemma of arithmetic (PROVING.md, section 1; reference/add_n.lean is a complete proof, 84 code lines):

  1. sv_structure (rank := …): one driver per bit and no combinational loop (CombDesign ∧ Acyclic). The rank is yours: an assign that writes a bit ranks below every assign that reads it.
  2. sv_interface: the ports, one line.
  3. sv_equations: each assign as an equation over Bool and every driven bit known, under stable names (eq_c_2 is the second assign that writes c, in source order).
  4. The arithmetic, in plain Lean: those equations give {cout, s} = a + b + cin. Prove that the carry into each bit is the ripple carry (the structure CombLib.AddView: carry in, carry step, sum bits, carry out) and CombLib.add_spec gives the sum. A carry-select adder (accepted 2026-11-05) did exactly that: by induction on the block, its selected carries are the ripple carries.
The proof in detailLay the design out so the tactics take it · What sv_equations prints · The skeleton · Library lemmas that exist today

Lay the design out so the tactics take it (what they refuse, with the messages: PROVING.md, section 4):

  • continuous assigns of gates (& | ^ ~, ?: and the other operators section 4 lists) in at most two nested generate for loops, every index and loop bound affine in N and the genvars;
  • blocks as the rows of 2-D arrays, c0[j][t], not a flat c0[K*j + t]: sv_cover finds the assign that writes a read by solving one unknown per index equation, and a flat read whose writer needs j = i / K and t = i % K is not covered;
  • the block counts as integer localparams, localparam integer Q = N / K; and localparam integer R = N % K; (a 2-state int with / or % is refused), and a tail loop over the R leftover bits;
  • every declared bit driven at N = 16: an unused row gets a literal (assign c0[Q] = 7'b0;);
  • with nested loops, write the rank yourself, as a definition by cases on the site (rippleRank gives every site of a two-index family rank 0; sv_structure unfolds a named definition). The carry-select adder's:
def cselRank (N : Nat) : SiteId → Nat
  | .plain p => if p = 4 then N + 9 else if p = 5 then 3 * N + 30 else 0  -- module-level assign number p
  | .fam l p [i] =>                                                       -- assign p of loop l, index i
      if l = "g_pg" then 1
      else if l = "g_blk" then (if p ≤ 1 then 1 else 8 + i.toNat)
      else if l = "g_tail" then N + 10 + i.toNat
      else 3 * N + 30
  | .fam l p [j, t] => if l = "g_s" then 3 * N + 30 else if p ≤ 1 then t.toNat + 2 else 9 + j.toNat
  | .fam _ _ _ => 0

What sv_equations prints, the shapes the arithmetic lemma is written against (sv_equations? in a probe file lists them for your design):

  • a one-bit literal as false or true; the width goal of a literal row closes by rfl, not by intros; omega;
  • a cell of a 2-D array, c0[j][t], as st.boolAt "c0" (rmN 7 ↑j ↑t) (rmN W r c, the row-major offset). sv_bridge matches it against a flat Nat index in row 0 only; the carry-select proof bridged the other rows with sv_bridge eq_c0_2 with rmN, toNatW, toNatK, Int.toNat_natCast (its own theorem toNatW : (7 : Int).toNat = 7 := rfl, and toNatK for 6), falling back to its own lemma rmN_flat.

The skeleton (reference/add_n.lean is it, filled in for the ripple adder):

import Submission.Design
import SvGolf.Comb
import LeanModels.Sv.CombEqTactic
import LeanModels.Sv.CombLib

namespace Submission
open LeanModels.Sv LeanModels.Sv.CombView LeanModels.Sv.CombLib LeanModels.Sv.CombEq SvGolf

theorem my_struct (N : Nat) (hN : 1 ≤ N) :
    CombDesign (design.sem N) ∧ Acyclic (design.sem N) ∧ SharedObl design.pdesign [N] := by
  sv_structure (rank := myRank N)            -- your rank, a `def` above
  all_goals (intros; omega)

theorem my_interface (N : Nat) (hN : 1 ≤ N) (hc : CombDesign (design.sem N)) :
    SvGolf.Tasks.Add.task.Interface N (design.sem N) := by
  sv_interface

-- your arithmetic: the printed equations in, the outputs out (add_n.lean's `add_final`)

theorem solution : Goal := by
  intro N hN
  have hN' : 1 ≤ N := hN.1
  obtain ⟨hc, ha, hso⟩ := my_struct N hN'
  refine CombTask.satisfiedAt_of_comb (my_interface N hN' hc) hc ha ?_
  intro st heqs hs v hv
  -- name the inputs `hA`, `hB`, `hCi`, as add_n.lean does
  sv_equations
  · -- the main goal: your arithmetic, its hypotheses the `eq_*` (or one `sv_bridge eq_*` each)
  all_goals first
    | (intros; omega)
    | rfl
    | sv_cover
    | (refine inKnown_ofBitVec hA ?_; omega)
    | (refine inKnown_ofBitVec hB ?_; omega)
    | (refine inKnown_ofBitVec hCi ?_; omega)

end Submission

Library lemmas that exist today (the tables: PROVING.md, section 6):

  • LeanModels.Sv.CombLib: AddView, add_value and add_spec (an adder's equations give the sum), ripple_row, fullAdder_arith, the bit-function value bfVal and its lemmas, sum_split, bitvec_eq_ofNat_of_val;
  • LeanModels.Sv.Lib.Prefix, for parallel-prefix adders: the carry operator pgOp (associative, idempotent), the group generate and propagate grpG / grpP of a block of bits and how blocks combine, and rippleCarry (the carry into bit k, rippleCarry_bv its BitVec form);
  • the bridges between ports and bits: SvState.lookup_eq_ofBitVec_bv, SvState.boolAt_ofBitVec, inKnown_ofBitVec; sv_bridge; LeanModels.Sv.Lib.RowMajor (rmN at natural coordinates).

Planned, not in the library yet: the carry-select adder's ripple-restart lemmas (a carry chain started at any bit from any carry; restarting at the true carry changes nothing) and a flat form of rmN.

Compare the designs

ASAP7 · any two numbers · lower is better

N = 16, the scored point: the ranked numbers. The same designs are also measured at N = 8, N = 32 and N = 64: measured, not ranked, the same proved designs through the same pinned flow at other parameters (the tables below, and how the designs scale).

add: area against delay10 designs by Delay (ps) (x) and Area (µm²) (y); lower is better on both. The table under the chart lists the same numbers.50060070080020002250250027503000Delay (ps)Area (µm²) · lower is betterthe Pareto front of the proved designsplus · baseline, not proved · banned operator · Score: 1565 µm²·ns · Delay: 3143 ps · Area: 498.0 µm²add_n_sklansky · baseline, not proved · Score: 1328 µm²·ns · Delay: 2451 ps · Area: 541.8 µm²add_n_kogge_stone · baseline, not proved · Score: 1325 µm²·ns · Delay: 2064 ps · Area: 641.9 µm²cmp_carry · baseline, not proved · banned operator · Score: 1684 µm²·ns · Delay: 1965 ps · Area: 857.1 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 2611 ps · Area: 460.4 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 2611 ps · Area: 460.4 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 2611 ps · Area: 460.4 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 2611 ps · Area: 460.4 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 2611 ps · Area: 460.4 µm²select-six · submission · 2026-11-05 · Score: 1176 µm²·ns · Delay: 2479 ps · Area: 474.2 µm²
add: area against delay10 designs by Delay (ps) (x) and Area (µm²) (y); lower is better on both. The table under the chart lists the same numbers.600800200025003000Delay (ps)Area (µm²) · lower is betterthe Pareto front of the proved designsplus · baseline, not proved · banned operator · Score: 1565 µm²·ns · Delay: 3143 ps · Area: 498.0 µm²add_n_sklansky · baseline, not proved · Score: 1328 µm²·ns · Delay: 2451 ps · Area: 541.8 µm²add_n_kogge_stone · baseline, not proved · Score: 1325 µm²·ns · Delay: 2064 ps · Area: 641.9 µm²cmp_carry · baseline, not proved · banned operator · Score: 1684 µm²·ns · Delay: 1965 ps · Area: 857.1 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 2611 ps · Area: 460.4 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 2611 ps · Area: 460.4 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 2611 ps · Area: 460.4 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 2611 ps · Area: 460.4 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 2611 ps · Area: 460.4 µm²select-six · submission · 2026-11-05 · Score: 1176 µm²·ns · Delay: 2479 ps · Area: 474.2 µm²
  • submission
  • proved reference
  • baseline (not proved)
  • baseline with a banned operator
  • the Pareto front of the proved designs
Lower is better on both axes. The step line joins the proved designs that no other proved design beats on both; baselines are shown for scale. Choose any two numbers to find the best design for your own trade-off. 10 of 10 designs have both numbers.
every design with all its numbers, by score (at N = 16, ranked)
designScore (µm²·ns)Area (µm²)Delay (ps)Energy (fJ/op)Leakage (nW)Area (GE)Depth (gates)GatesProof (lines)
select-six submission1176474.22479––114.6653383332
add_n par1202460.426118780112.000338084
add_n_byhand reference1202460.426118780112.0003380509
add_proc reference1202460.42611––112.0003380115
add_mux reference1202460.42611––112.000338097
add_proc_m reference1202460.42611––112.0003380115
add_n_kogge_stone not proved1325641.9206411120149.65224115–
add_n_sklansky not proved1328541.8245110050127.6582895–
plus banned operator1565498.03143––117.9943386–
cmp_carry banned operator1684857.1196513730195.97517149–
at N = 8 (measured, not ranked): every design with all its numbers, by score
designScore (µm²·ns)Area (µm²)Delay (ps)Area (GE)Depth (gates)GatesProof (lines)
plus banned operator343.3232.7147556.6661742–
add_mux reference349.2230.2151756.000174097
add_n reference349.2230.2151756.000174084
add_n_byhand reference349.2230.2151756.0001740509
add_proc reference349.2230.2151756.0001740115
add_proc_m reference349.2230.2151756.0001740115
add_n_sklansky not proved375.8261.5143762.3311545–
add_n_kogge_stone not proved397279.0142366.3291551–
cmp_carry banned operator474.8361.6131383.3241063–
at N = 32 (measured, not ranked): every design with all its numbers, by score
designScore (µm²·ns)Area (µm²)Delay (ps)Area (GE)Depth (gates)GatesProof (lines)
add_mux reference4420920.94800224.0006516097
add_n reference4420920.94800224.0006516084
add_n_byhand reference4420920.94800224.00065160509
add_proc reference4420920.94800224.00065160115
add_proc_m reference4420920.94800224.00065160115
cmp_carry banned operator47031695.42774391.95225309–
add_n_sklansky not proved49001278.73832296.63943220–
plus banned operator56131077.35210251.98257183–
add_n_kogge_stone not proved59141405.14209325.29647253–
at N = 64 (measured, not ranked): every design with all its numbers, by score
designScore (µm²·ns)Area (µm²)Delay (ps)Area (GE)Depth (gates)GatesProof (lines)
cmp_carry banned operator13 0643749.83484855.21830657–
add_n reference16 9021841.89177448.00012932084
add_n_byhand reference16 9021841.89177448.000129320509
add_n_sklansky not proved18 1732598.76993601.27480451–
add_mux reference18 7411999.49373468.97912932097
add_proc reference18 7411999.49373468.979129320115
add_proc_m reference18 7411999.49373468.979129320115
plus banned operator21 4622084.510 296494.973121370–
add_n_kogge_stone not proved24 0373467.16933788.89266601–
add: area against delay10 designs by Delay (ps) (x) and Area (µm²) (y); lower is better on both. The table under the chart lists the same numbers.81012350400450500550Delay (ps)Area (µm²) · lower is betterthe Pareto front of the proved designsplus · baseline, not proved · banned operator · Score: 4.224 µm²·ns · Delay: 568 ps · Area: 7.436 µm²add_n_sklansky · baseline, not proved · Score: 3.919 µm²·ns · Delay: 487 ps · Area: 8.048 µm²add_n_kogge_stone · baseline, not proved · Score: 4.094 µm²·ns · Delay: 432 ps · Area: 9.477 µm²cmp_carry · baseline, not proved · banned operator · Score: 4.218 µm²·ns · Delay: 336 ps · Area: 12.553 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 563 ps · Area: 6.998 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 563 ps · Area: 6.998 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 563 ps · Area: 6.998 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 563 ps · Area: 6.998 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 563 ps · Area: 6.998 µm²select-six · submission · 2026-11-05 · Score: 4.032 µm²·ns · Delay: 561 ps · Area: 7.188 µm²
add: area against delay10 designs by Delay (ps) (x) and Area (µm²) (y); lower is better on both. The table under the chart lists the same numbers.81012400500Delay (ps)Area (µm²) · lower is betterthe Pareto front of the proved designsplus · baseline, not proved · banned operator · Score: 4.224 µm²·ns · Delay: 568 ps · Area: 7.436 µm²add_n_sklansky · baseline, not proved · Score: 3.919 µm²·ns · Delay: 487 ps · Area: 8.048 µm²add_n_kogge_stone · baseline, not proved · Score: 4.094 µm²·ns · Delay: 432 ps · Area: 9.477 µm²cmp_carry · baseline, not proved · banned operator · Score: 4.218 µm²·ns · Delay: 336 ps · Area: 12.553 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 563 ps · Area: 6.998 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 563 ps · Area: 6.998 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 563 ps · Area: 6.998 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 563 ps · Area: 6.998 µm²5 designs at this point · add_mux · proved reference · add_n · proved reference · par · add_n_byhand · proved reference · add_proc · proved reference · add_proc_m · proved reference · Delay: 563 ps · Area: 6.998 µm²select-six · submission · 2026-11-05 · Score: 4.032 µm²·ns · Delay: 561 ps · Area: 7.188 µm²
  • submission
  • proved reference
  • baseline (not proved)
  • baseline with a banned operator
  • the Pareto front of the proved designs
Lower is better on both axes. The step line joins the proved designs that no other proved design beats on both; baselines are shown for scale. Choose any two numbers to find the best design for your own trade-off. 10 of 10 designs have both numbers.
every design with all its numbers, by score
designScore (µm²·ns)Area (µm²)Delay (ps)Area (GE)Depth (gates)GatesProof (lines)
add_n_sklansky not proved3.9198.048487127.6582895–
add_n par3.946.998563112.000338084
add_n_byhand reference3.946.998563112.0003380509
add_proc reference3.946.998563112.0003380115
add_mux reference3.946.998563112.000338097
add_proc_m reference3.946.998563112.0003380115
select-six submission4.0327.188561114.6653383332
add_n_kogge_stone not proved4.0949.477432149.65224115–
cmp_carry banned operator4.21812.553336195.97517149–
plus banned operator4.2247.436568117.9943386–

How the designs scale #

On sky130 in either view: the designs are measured at the other points on sky130 alone (score/measured/), and the ASAP7 view weighs each design at the scoring point only.

add: score over par against N, one line per design6 designs, Score ÷ par's (y) against N (x), one line each, named on the right; lower is better. The table under the chart lists the same numbers.0.811.21.48163264N, log scaleScore ÷ par's · lower is betterpar: add_nadd_n_kogge_stone · baseline, not proved · measured, not rankedadd_n_kogge_stone · N = 8 · measured, not ranked · Score: 397 µm²·ns (×1.14 par)add_n_kogge_stone · N = 16 · the scored point · Score: 1325 µm²·ns (×1.10 par)add_n_kogge_stone · N = 32 · measured, not ranked · Score: 5914 µm²·ns (×1.34 par)add_n_kogge_stone · N = 64 · measured, not ranked · Score: 24 037 µm²·ns (×1.42 par)add_n_kogge_stoneadd_n_sklansky · baseline, not proved · measured, not rankedadd_n_sklansky · N = 8 · measured, not ranked · Score: 375.8 µm²·ns (×1.08 par)add_n_sklansky · N = 16 · the scored point · Score: 1328 µm²·ns (×1.10 par)add_n_sklansky · N = 32 · measured, not ranked · Score: 4900 µm²·ns (×1.11 par)add_n_sklansky · N = 64 · measured, not ranked · Score: 18 173 µm²·ns (×1.08 par)add_n_sklanskycmp_carry · baseline, not proved · banned operator · measured, not rankedcmp_carry · N = 8 · measured, not ranked · Score: 474.8 µm²·ns (×1.36 par)cmp_carry · N = 16 · the scored point · Score: 1684 µm²·ns (×1.40 par)cmp_carry · N = 32 · measured, not ranked · Score: 4703 µm²·ns (×1.06 par)cmp_carry · N = 64 · measured, not ranked · Score: 13 064 µm²·ns (×0.77 par)cmp_carryplus · baseline, not proved · banned operator · measured, not rankedplus · N = 8 · measured, not ranked · Score: 343.3 µm²·ns (×0.98 par)plus · N = 16 · the scored point · Score: 1565 µm²·ns (×1.30 par)plus · N = 32 · measured, not ranked · Score: 5613 µm²·ns (×1.27 par)plus · N = 64 · measured, not ranked · Score: 21 462 µm²·ns (×1.27 par)plusadd_n +1 · proved reference · measured, not ranked · the same numbers at every point: add_n, add_n_byhandadd_n +1 · N = 8 · measured, not ranked · Score: 349.2 µm²·ns (×1.00 par)add_n +1 · N = 16 · the scored point · Score: 1202 µm²·ns (×1.00 par)add_n +1 · N = 32 · measured, not ranked · Score: 4420 µm²·ns (×1.00 par)add_n +1 · N = 64 · measured, not ranked · Score: 16 902 µm²·ns (×1.00 par)add_n +1add_proc +2 · proved reference · measured, not ranked · the same numbers at every point: add_proc, add_proc_m, add_muxadd_proc +2 · N = 8 · measured, not ranked · Score: 349.2 µm²·ns (×1.00 par)add_proc +2 · N = 16 · the scored point · Score: 1202 µm²·ns (×1.00 par)add_proc +2 · N = 32 · measured, not ranked · Score: 4420 µm²·ns (×1.00 par)add_proc +2 · N = 64 · measured, not ranked · Score: 18 741 µm²·ns (×1.11 par)add_proc +2
add: score over par against N, one line per design6 designs, Score ÷ par's (y) against N (x), one line each, named on the right; lower is better. The table under the chart lists the same numbers.0.811.21.48163264N, log scaleScore ÷ par's · lower is betterpar: add_nadd_n_kogge_stone · baseline, not proved · measured, not rankedadd_n_kogge_stone · N = 8 · measured, not ranked · Score: 397 µm²·ns (×1.14 par)add_n_kogge_stone · N = 16 · the scored point · Score: 1325 µm²·ns (×1.10 par)add_n_kogge_stone · N = 32 · measured, not ranked · Score: 5914 µm²·ns (×1.34 par)add_n_kogge_stone · N = 64 · measured, not ranked · Score: 24 037 µm²·ns (×1.42 par)add_n_kogge_…add_n_sklansky · baseline, not proved · measured, not rankedadd_n_sklansky · N = 8 · measured, not ranked · Score: 375.8 µm²·ns (×1.08 par)add_n_sklansky · N = 16 · the scored point · Score: 1328 µm²·ns (×1.10 par)add_n_sklansky · N = 32 · measured, not ranked · Score: 4900 µm²·ns (×1.11 par)add_n_sklansky · N = 64 · measured, not ranked · Score: 18 173 µm²·ns (×1.08 par)add_n_sklans…cmp_carry · baseline, not proved · banned operator · measured, not rankedcmp_carry · N = 8 · measured, not ranked · Score: 474.8 µm²·ns (×1.36 par)cmp_carry · N = 16 · the scored point · Score: 1684 µm²·ns (×1.40 par)cmp_carry · N = 32 · measured, not ranked · Score: 4703 µm²·ns (×1.06 par)cmp_carry · N = 64 · measured, not ranked · Score: 13 064 µm²·ns (×0.77 par)cmp_carryplus · baseline, not proved · banned operator · measured, not rankedplus · N = 8 · measured, not ranked · Score: 343.3 µm²·ns (×0.98 par)plus · N = 16 · the scored point · Score: 1565 µm²·ns (×1.30 par)plus · N = 32 · measured, not ranked · Score: 5613 µm²·ns (×1.27 par)plus · N = 64 · measured, not ranked · Score: 21 462 µm²·ns (×1.27 par)plusadd_n +1 · proved reference · measured, not ranked · the same numbers at every point: add_n, add_n_byhandadd_n +1 · N = 8 · measured, not ranked · Score: 349.2 µm²·ns (×1.00 par)add_n +1 · N = 16 · the scored point · Score: 1202 µm²·ns (×1.00 par)add_n +1 · N = 32 · measured, not ranked · Score: 4420 µm²·ns (×1.00 par)add_n +1 · N = 64 · measured, not ranked · Score: 16 902 µm²·ns (×1.00 par)add_n +1add_proc +2 · proved reference · measured, not ranked · the same numbers at every point: add_proc, add_proc_m, add_muxadd_proc +2 · N = 8 · measured, not ranked · Score: 349.2 µm²·ns (×1.00 par)add_proc +2 · N = 16 · the scored point · Score: 1202 µm²·ns (×1.00 par)add_proc +2 · N = 32 · measured, not ranked · Score: 4420 µm²·ns (×1.00 par)add_proc +2 · N = 64 · measured, not ranked · Score: 18 741 µm²·ns (×1.11 par)add_proc +2
  • proved reference
  • baseline (not proved)
  • baseline with a banned operator
  • par
Score of each design over par's (add_n) at the same point, against N: 1 is par, and a line under it beats par at that size, so where two lines cross one design starts to pay off against the other. One line per design, lower is better: the same proved design at each point, through the same pinned flow. Measured, not ranked: the board ranks at N = 16 only. A dashed line is a baseline (not proved). A name with +1, +2, … stands for that many more designs with the same numbers at every point (the table names them).
every design at every point: Score (µm²·ns)
designN = 8N = 16 (ranked)N = 32N = 64
add_n +1 add_n, add_n_byhand349.21202442016 902
add_proc +2 add_proc, add_proc_m, add_mux349.21202442018 741
add_n_kogge_stone3971325591424 037
add_n_sklansky375.81328490018 173
cmp_carry474.81684470313 064
plus343.31565561321 462

Proved references

Proved and accepted designs that ship with the task, written or adapted by the maintainers. They are the first entries, and par, the bar to beat, is the one with the best score (area × time, µm²·ns, from the sky130ASAP7 area and time; a design without a sky130an ASAP7 weighing has no score and comes after, by its extra GE columns). A reference that was also recorded links its record under its name: the record holds that reference's design and proof, matched by the sha256 of both files.

designscore (µm²·ns)area (µm²)time (ps)GE · depthvs parproof linesfiles
add_n parparA ripple-carry adder in a generate loop, proved with the sv_comb tactics: the intended way to work.tactics: omega, simp, sv_cover, sv_equations, sv_interface, sv_structure12023.94460.46.9982611563112.000 · 33parpar84.sv .lean
add_proc The same adder with its carry cell written as an always_comb if/else.tactics: decide, omega, simp, sv_cover, sv_equations, sv_interface, sv_structure12023.94460.46.9982611563112.000 · 33±0.0%±0.0%115.sv .lean
add_proc_m The same adder with the whole bit cell, carry and sum, in one always_comb block.tactics: decide, omega, simp, sv_cover, sv_equations, sv_interface, sv_structure12023.94460.46.9982611563112.000 · 33±0.0%±0.0%115.sv .lean
add_mux The same adder written with ~ and the conditional operator ?:.tactics: decide, omega, simp, sv_cover, sv_equations, sv_interface, sv_structure12023.94460.46.9982611563112.000 · 33±0.0%±0.0%97.sv .lean
add_n_byhand same design as add_nThe same design as add_n, proved by hand without the tactics: the by-hand proof.tactics: decide, induction, omega, simprecord: 8c1f662e6f8c12023.94460.46.9982611563112.000 · 33±0.0%±0.0%509.sv .lean

Baselines

Not entries. Designs scored by the pinned flow (with the banlist lifted) but never accepted: unproved, simulation-only, or using an operator the task bans. They show how much room there is.

designscore (µm²·ns)area (µm²)time (ps)GE · depthvs parfile
plus banned operatorYosys's own adder, assign {cout, s} = a + b + cin;, which uses the banned +.15654.224498.07.4363143568117.994 · 33+30.2%+7.2%.sv
add_n_sklansky A Sklansky parallel-prefix adder, checked by simulation, not proved yet.13283.919541.88.0482451487127.658 · 28+10.5%−0.5%.sv
add_n_kogge_stone A Kogge-Stone parallel-prefix adder, checked by simulation, not proved yet.13254.094641.99.4772064432149.652 · 24+10.2%+3.9%.sv
cmp_carry banned operatorEvery carry computed by a run-time comparison, which Yosys builds as its own adder: banned in this task since 2026-11-05, like +.16844.218857.112.5531965336195.975 · 17+40.1%+7.1%.sv