Record bfb3c58778b6
Recorded by the maintainers from the proved reference clmul_n: its design and its proof clmul_n.lean (238 code lines). The N × N array: AND partial products summed by rows of XORs, the multiplier's shape without carries. The record shows that reference passing the whole checker. It is par, the bar to beatpar, the bar to beat, not a player's entry, and it is not ranked among the submissions (proved references).
Area
3 429.54µm²
3 429.5392 µm² exactly
- vs par
- this design is par
- cells
- 481
- flops
- 0
- repair
- 0 buffers, 0 tie cells
- GE
- 772.267 extra
- A1′
- 2 941.57 µm² research
Performance · time
1 114ps
the delay: the latest output arrival, p[15] rising
- vs par
- this design is par
- Fmax-eq.
- 897.7 MHz derived
- critical path
- 6 cells
- unit depth
- 6 extra
- A1′
- 957 ps research
Score · area × time
3821µm²·ns
3 429.5392 µm² × 1 114 ps
- vs par
- this design is par
- board
- par, the bar to beat: never ranked
No other player has a ranked record on clmul yet: the beats and matches lines come with the first one.
how these numbers are measured and compared
Area: sky130 A0′, the repaired netlist. Time: NLDM, inputs driven by buf_8, 10 fF per output bit, no wires.
Area, time and score are ranked (the leaderboard orders by the score); a number tagged extra, derived or research is shown, never ranked. Fmax-equivalent = 10⁶ / time in ps, for comparison with sites that quote Fmax.
The field is the ranked records of clmul's other players at this revision (0 players, 0 records), never the references, the baselines or a rejected design; advisory, recomputed at every build, never stored in a record and never used by the ranking.
This design is the only one with sky130 numbers on this page, so the cards have no “on this page” or “Pareto” row.
Area
50.257µm²
50.25726 µm² exactly
- vs par
- this design is par
- on this page
- 6th of 6 designs
- cells
- 481
- flops
- 0
- repair
- 0 buffers, 0 tie cells
- GE
- 772.267 extra
Performance · time
197ps
the delay: the latest output arrival
- vs par
- this design is par
- on this page
- 2nd of 6 designs
- Fmax-eq.
- 5076.1 MHz derived
- unit depth
- 6 extra
Score · area × time
9.901µm²·ns
50.25726 µm² × 197 ps
- vs par
- this design is par
- on this page
- 2nd of 6 designs
- board
- par, the bar to beat: never ranked
- Pareto
- dominated on this page by school_tree_16
No other player has a ranked record on clmul yet: the beats and matches lines come with the first one.
how these numbers are measured and compared
Area: ASAP7 A0′ (asap7_a0_v1), the same scored netlist, each gate its least-area ASAP7 build, repaired by buffering. Time: NLDM, inputs driven by BUFx8, 2.5 fF per output bit, no wires; a table read below its grid is read at its floor. ASAP7: a predictive 7 nm library, never fabricated; no wires, like sky130's score (how ASAP7 is scored, and its quirks).
Area, time and score order this view's board (by the score); the records' ranked score is sky130's, the default view; a number tagged extra, derived or research is shown, never ranked. Fmax-equivalent = 10⁶ / time in ps, for comparison with sites that quote Fmax.
The field is the ranked records of clmul's other players at this revision (0 players, 0 records), never the references, the baselines or a rejected design; advisory, recomputed at every build, never stored in a record and never used by the ranking.
“On this page” and “Pareto” compare with the 6 designs of the area-time plot (1 reference and 5 baselines): not a ranking.
The sources
// svGolf task `clmul` -- reference solution: an N x N -> 2N-1 carry-less (GF(2)[x]) array multiplier.
//
// The product polynomial p = a (x) b has coefficients p_k = XOR over i + j = k of (a_i AND b_j).
// The array is `mul_n`'s with XOR where `mul_n` has a full adder, and no carries: row i (0 <= i < N)
// holds r[i][j] = XOR over t <= i of a[t] & b[i + j - t] (a term whose b index is >= N is 0), the
// accumulator of the first i + 1 rows shifted down by i, so
// r[0][j] = a[0] & b[j]
// r[i][j] = r[i-1][j+1] ^ (a[i] & b[j]) for 1 <= i < N and 0 <= j < N-1
// r[i][N-1] = a[i] & b[N-1] for 1 <= i < N (nothing above it in row i-1)
// Output bit i < N is bit 0 of row i (p_i = r[i][0]); the top N-1 bits are the upper N-1 bits of the
// last row (p_{N+m} = r[N-1][m+1], 0 <= m < N-1; no iteration at N = 1).
// Bitwise operators only; genvar loops step with `++` (ls-sv's tier).
module clmul_n #(parameter int N = 16) (
input logic [N-1:0] a, b,
output logic [2*N-2:0] p
);
logic [N-1:0][N-1:0] r;
genvar i, j, m;
generate
for (j = 0; j < N; j++) begin : g_row0
assign r[0][j] = a[0] & b[j];
end
for (i = 1; i < N; i++) begin : g_row
for (j = 0; j < N-1; j++) begin : g_bit
assign r[i][j] = r[i-1][j+1] ^ (a[i] & b[j]);
end
assign r[i][N-1] = a[i] & b[N-1];
end
for (i = 0; i < N; i++) begin : g_lo
assign p[i] = r[i][0];
end
for (m = 0; m < N-1; m++) begin : g_hi
assign p[N+m] = r[N-1][m+1];
end
endgenerate
endmodule
clmul_n.lean (238 code lines)
import Submission.Design
import tasks.clmul.Spec
import SvGolf.Comb
import LeanModels.Sv.CombEqTactic
import LeanModels.Sv.CombLib
/-!
# Reference solution for task `clmul`, proved with the `sv_comb` tactics
This is a submission file like any player's `Solution.lean`. The checker generates the module
`Submission.Design` (`Submission.design`, `Submission.Goal`); this file proves
theorem Submission.solution : Submission.Goal
for EVERY `N ≥ 1`. The design is `reference/clmul_n.sv`, the carry-less array multiplier: one 2-D signal `r`
(`N` rows of `N` bits), four `generate for` loops (the first row, the other rows with an inner loop, the low
output bits, the high output bits), the shape of `mul_n` with XOR where `mul_n` has a full adder.
## Route
1. **Structure** (`clmul_struct`): `sv_structure` proves `CombDesign ∧ Acyclic` in one theorem; the rank is a
lexicographic key `(row, 0, 0)` of each site identity (`clmulKey`: a row depends on the row above only, the
output bits come after every row); the goals it leaves are closed by `intros; sv_rowmajor; omega`. The key
goes through a partial classifier of the five site families (`clmulFamily?`), and `clmul_sites_classified`
proves it covers every site, so a change to the generated layout fails loudly instead of taking a default.
2. **Ports** (`clmul_interface`): `sv_interface`.
3. **Equations** (in `solution`): `sv_equations` derives the five equations (`eq_r_g_row0_0`, `eq_r_g_bit_0`,
`eq_r_g_row_1`, `eq_p_g_lo_0`, `eq_p_g_hi_0`) and the knownness of every driven bit; the obligations close by
`intros; omega` and `sv_cover`.
4. **Arithmetic and bridge**: the five equations are the fields of `View`, over the cells `st.cell "r" N i j` of
the 2-D signal; each field is one `sv_bridge`. `view_spec` is the mathematics: the row invariant
`r i j = XOR over t ≤ i of A t & B (i + j - t)` (`view_row`, an induction on the row) and the collapse of the
Spec's double sum (`bx_pair`), then `getLsbD_ofBits` and `coeff_eq` turn the bit statement into the Spec's
`BitVec`.
-/
namespace Submission
open LeanModels.Sv LeanModels.Sv.CombView LeanModels.Sv.CombLib LeanModels.Sv.CombEq SvGolf
open SvGolf.Tasks.Clmul
/-! ## 0. The arithmetic: plain Lean, no ls-sv -/
namespace ClmulArith
/-- `bx f n`: the XOR of `f 0, …, f (n-1)`. -/
def bx (f : Nat → Bool) : Nat → Bool
| 0 => false
| n + 1 => bx f n ^^ f n
theorem bx_congr {f g : Nat → Bool} {n : Nat} (h : ∀ j, j < n → f j = g j) : bx f n = bx g n := by
induction n with
| zero => rfl
| succ n ih => simp only [bx]; rw [ih (fun j hj => h j (by omega)), h n (by omega)]
theorem bx_trunc {f : Nat → Bool} {n m : Nat} (hnm : n ≤ m) (h : ∀ j, n ≤ j → j < m → f j = false) :
bx f m = bx f n := by
induction m with
| zero =>
have : n = 0 := by omega
subst this; rfl
| succ m ih =>
by_cases hn : n = m + 1
· subst hn; rfl
· simp only [bx]
rw [ih (by omega) (fun j hj1 hj2 => h j hj1 (by omega)), h m (by omega) (by omega)]
simp
theorem foldl_xor (f : Nat → Bool) (n : Nat) (acc : Bool) :
(List.range n).foldl (fun acc i => acc ^^ f i) acc = (acc ^^ bx f n) := by
induction n generalizing acc with
| zero => simp [bx]
| succ n ih =>
rw [List.range_succ, List.foldl_append]
simp only [List.foldl_cons, List.foldl_nil]
rw [ih]
simp only [bx]
cases acc <;> cases bx f n <;> cases f n <;> rfl
/-- The Spec's double sum is the nested `bx`. -/
theorem coeff_eq (N : Nat) (a b : BitVec N) (k : Nat) :
coeff N a b k =
bx (fun i => bx (fun j => decide (i + j = k) && a.getLsbD i && b.getLsbD j) N) N := by
unfold coeff
simp only [foldl_xor]
simp
theorem bx_pair (i k : Nat) (x : Bool) (c : Nat → Bool) (n : Nat) :
bx (fun j => decide (i + j = k) && x && c j) n = (decide (i ≤ k ∧ k - i < n) && x && c (k - i)) := by
induction n with
| zero => simp [bx]
| succ n ih =>
simp only [bx, ih]
by_cases h : i + n = k
· have h1 : k - i = n := by omega
have h2 : ¬ (k - i < n) := by omega
have h3 : i ≤ k ∧ k - i < n + 1 := by omega
simp [h, h1, h3]
· have h4 : (decide (i ≤ k ∧ k - i < n + 1)) = (decide (i ≤ k ∧ k - i < n)) := by
apply decide_eq_decide.mpr; omega
have h5 : decide (i + n = k) = false := by simp [h]
rw [h5, h4]; simp
theorem getLsbD_ofBits : ∀ (n : Nat) (f : Nat → Bool) (k : Nat),
(ofBits n f).getLsbD k = (decide (k < n) && f k)
| 0, f, k => by simp [ofBits]
| n + 1, f, k => by
rw [ofBits, BitVec.getLsbD_append, getLsbD_ofBits n]
cases k with
| zero => simp
| succ k => simp
/-- The accumulator of rows `0 .. i`, read at column `j`: `XOR over t ≤ i` of `A t & B (i + j - t)`, a term
whose `B` index is `≥ N` being `0`. -/
def rowSum (N : Nat) (A B : Nat → Bool) (i j : Nat) : Bool :=
bx (fun t => decide (i + j - t < N) && A t && B (i + j - t)) (i + 1)
/-- The array's equations over `Nat`-indexed Boolean functions. -/
structure View (N : Nat) (A B : Nat → Bool) (P : Nat → Bool) (r : Nat → Nat → Bool) : Prop where
row0 : ∀ j, j < N → r 0 j = (A 0 && B j)
row_def : ∀ i, 1 ≤ i → i < N → ∀ j, j + 1 < N → r i j = (r (i - 1) (j + 1) ^^ (A i && B j))
row_top : ∀ i, 1 ≤ i → i < N → r i (N - 1) = (A i && B (N - 1))
p_low : ∀ i, i < N → P i = r i 0
p_high : ∀ m, m + 1 < N → P (N + m) = r (N - 1) (m + 1)
theorem bx_succ (f : Nat → Bool) (n : Nat) : bx f (n + 1) = (bx f n ^^ f n) := rfl
theorem bx_false {f : Nat → Bool} {n : Nat} (h : ∀ t, t < n → f t = false) : bx f n = false := by
induction n with
| zero => rfl
| succ n ih => rw [bx_succ, ih (fun t ht => h t (by omega)), h n (by omega)]; rfl
theorem rowSum_big {N : Nat} {A B : Nat → Bool} {i j : Nat} (hj : N ≤ j) : rowSum N A B i j = false := by
unfold rowSum
apply bx_false
intro t ht
have : ¬ (i + j - t < N) := by omega
simp [this]
theorem rowSum_succ (N : Nat) (A B : Nat → Bool) (i j : Nat) :
rowSum N A B (i + 1) j = (rowSum N A B i (j + 1) ^^ (decide (j < N) && A (i + 1) && B j)) := by
have e : ∀ t, i + 1 + j - t = i + (j + 1) - t := fun t => by omega
have e2 : i + 1 + j - (i + 1) = j := by omega
unfold rowSum
rw [bx_succ _ (i + 1)]
congr 1
· apply bx_congr
intro t ht
simp only [e]
· simp only [e2]
theorem view_row {N : Nat} {A B : Nat → Bool} {P : Nat → Bool} {r : Nat → Nat → Bool}
(hv : View N A B P r) :
∀ i, i < N → ∀ j, j < N → r i j = rowSum N A B i j := by
intro i
induction i with
| zero =>
intro hi j hj
rw [hv.row0 j hj]
simp [rowSum, bx, hj]
| succ i ih =>
intro hi j hj
rw [rowSum_succ]
by_cases hjN : j + 1 < N
· rw [hv.row_def (i + 1) (by omega) hi j hjN]
simp only [Nat.add_sub_cancel]
rw [ih (by omega) (j + 1) hjN]
simp [hj]
· have hj' : j = N - 1 := by omega
subst hj'
rw [hv.row_top (i + 1) (by omega) hi, rowSum_big (N := N) (i := i) (j := N - 1 + 1) (by omega)]
simp [hj]
theorem view_spec {N : Nat} (hN : 1 ≤ N) {A B : Nat → Bool} {P : Nat → Bool} {r : Nat → Nat → Bool}
(hv : View N A B P r) :
∀ k, k < 2 * N - 1 →
P k = bx (fun i => bx (fun j => decide (i + j = k) && A i && B j) N) N := by
intro k hk
have inner : (fun i => bx (fun j => decide (i + j = k) && A i && B j) N)
= (fun i => decide (i ≤ k ∧ k - i < N) && A i && B (k - i)) := by
funext i
exact bx_pair i k (A i) B N
rw [inner]
by_cases hkN : k < N
· rw [hv.p_low k hkN, view_row hv k hkN 0 (by omega)]
unfold rowSum
rw [bx_trunc (f := fun i => decide (i ≤ k ∧ k - i < N) && A i && B (k - i)) (n := k + 1) (m := N)
(by omega) (fun j hj1 _ => by simp; omega)]
apply bx_congr
intro t ht
have h1 : k + 0 - t = k - t := by omega
have h2 : decide (k - t < N) = true := by simp; omega
have h3 : decide (t ≤ k ∧ k - t < N) = true := by simp; omega
rw [h1, h2, h3]
· obtain ⟨m, rfl⟩ : ∃ m, k = N + m := ⟨k - N, by omega⟩
rw [hv.p_high m (by omega), view_row hv (N - 1) (by omega) (m + 1) (by omega)]
unfold rowSum
have e : N - 1 + 1 = N := by omega
rw [e]
apply bx_congr
intro t ht
have e1 : N - 1 + (m + 1) = N + m := by omega
rw [e1]
have h3 : decide (t ≤ N + m ∧ N + m - t < N) = decide (N + m - t < N) := by
apply decide_eq_decide.mpr; omega
rw [h3]
end ClmulArith
/-! ## 1. Structure: `sv_structure` -/
/-- The five site families of the design, one per generated assign. -/
inductive ClmulFamily where
| row0 -- r[0][j] = a[0] & b[j]
| bit -- r[i][j] = r[i-1][j+1] ^ (a[i] & b[j])
| row -- r[i][N-1] = a[i] & b[N-1]
| lo -- p[i] = r[i][0]
| hi -- p[N+m] = r[N-1][m+1]
/-- The partial classifier, on a site's static key (`idKey`: the label of its innermost block, the position of its
assign in that block, its number of loop indices). Every family is named; anything else is `none`, never a default
rank, and `clmul_sites_classified` proves no site of the design is `none`. -/
def clmulFamily? : String × Nat × Nat → Option ClmulFamily
| ("g_row0", 0, 1) => some .row0
| ("g_bit", 0, 2) => some .bit
| ("g_row", 1, 1) => some .row
| ("g_lo", 0, 1) => some .lo
| ("g_hi", 0, 1) => some .hi
| _ => none
/-- A site's loop indices, outermost first. -/
def siteIdx : SiteId → List Int
| .plain _ => []
| .fam _ _ idx => idx
/-- A family's key at the member's loop indices: a lexicographic `(row, 0, 0)`. The first row reads only the
inputs; row `i` (the outer index of `g_bit`, the index of `g_row`) reads row `i - 1` (`r[i-1][j+1]`); the output
bits read the rows, so they come last. -/
def ClmulFamily.key (N : Nat) (idx : List Int) : ClmulFamily → Key
| .row0 => (0, 0, 0)
| .bit | .row => ((idx.headD 0).toNat, 0, 0)
| .lo | .hi => (N, 0, 0)
/-- The rank: the key of the site's family. The `none` arm is unreachable (`clmul_sites_classified`). -/
def clmulKey (N : Nat) (s : SiteId) : Key :=
match clmulFamily? (idKey s) with
| some f => f.key N (siteIdx s)
| none => (N + 1, 0, 0)
/-- **Site coverage**: every located site of the design is in a named family, at every valuation of its loop
indices. A change to the generated layout (a renamed block, a moved or added assign) fails here. -/
theorem clmul_sites_classified :
∀ s, design.pdesign.summary = .ok s → ∀ ls ∈ s.lsites, ∀ σ, (clmulFamily? (idKey (ls.id σ))).isSome := by
intro s hs ls hls σ
have h : (match design.pdesign.summary with
| .ok s => s.lsites.all fun ls => (clmulFamily? ls.key).isSome
| .error _ => false) = true := by decide
simp only [hs, List.all_eq_true] at h
rw [idKey_id]
exact h ls hls
/-! The diagnostic for the same fact: the static keys of the unclassified sites. If the layout changes, this
names the sites that `clmul_sites_classified` fails on. -/
/-- info: [] -/
#guard_msgs in
#eval match design.pdesign.summary with
| .ok s => (s.lsites.map LSite.key).filter fun k => (clmulFamily? k).isNone
| .error e => [(e, 0, 0)]
set_option maxHeartbeats 400000 in
/-- `CombDesign` and `Acyclic` for every `N ≥ 1`, from the lexicographic key. -/
theorem clmul_struct (N : Nat) (hN : 1 ≤ N) :
CombDesign (design.sem N) ∧ Acyclic (design.sem N) ∧ SharedObl design.pdesign [N] := by
sv_structure (lexRank := clmulKey N)
all_goals (intros; sv_rowmajor; first | omega | (simp [clmulFamily?, idKey, ClmulFamily.key, siteIdx] <;> omega))
/-! ## 2. The ports (the task's `Interface`) -/
/-- The task's interface: exactly the ports `a`, `b` (`N` bits) and `p` (`2N-1` bits). -/
theorem clmul_interface (N : Nat) (hN : 1 ≤ N) (hc : CombDesign (design.sem N)) :
SvGolf.Tasks.Clmul.task.Interface N (design.sem N) := by
sv_interface
/-! ## 3. The statement: bridge and arithmetic; `sv_cover` closes the coverage -/
set_option maxHeartbeats 400000 in
/-- **The reference solution**: the `clmul` statement, for every `N ≥ 1`. -/
theorem solution : Goal := by
intro N hN
have hN' : 1 ≤ N := hN.1
obtain ⟨hc, ha, hso⟩ := clmul_struct N hN'
refine CombTask.satisfiedAt_of_comb (clmul_interface N hN' hc) hc ha ?_
intro st heqs hs v hv
obtain ⟨x, y, ⟨⟩⟩ := v
simp only [SvGolf.Tasks.Clmul.task, HoldAll_cons, HoldAll_nil, and_true] at hv ⊢
obtain ⟨hA, hB⟩ := hv
sv_equations
· obtain ⟨⟨vp, hvp, hvpw⟩, -⟩ := known_p_g_lo_0 0 (by omega)
have ba : ∀ i, i < N → st.boolAt "a" i = x.getLsbD i := fun i hi => SvState.boolAt_ofBitVec hA hi
have bb : ∀ i, i < N → st.boolAt "b" i = y.getLsbD i := fun i hi => SvState.boolAt_ofBitVec hB hi
have hkp : ∀ k, k < 2 * N - 1 → KnownBit st "p" k := by
intro k hk
by_cases h : k < N
· exact (known_p_g_lo_0 k h).2
· obtain ⟨m, rfl⟩ : ∃ m, k = N + m := ⟨k - N, by omega⟩
have := (known_p_g_hi_0 m (by omega)).2
rwa [show ((N : Int) + (m : Int)).toNat = N + m by omega] at this
have hview : ClmulArith.View N x.getLsbD y.getLsbD (st.boolAt "p") (st.cell "r" N) := by
refine { row0 := ?_, row_def := ?_, row_top := ?_, p_low := ?_, p_high := ?_ }
· sv_bridge eq_r_g_row0_0 with ba, bb
· sv_bridge eq_r_g_bit_0 with ba, bb
· sv_bridge eq_r_g_row_1 with ba, bb
· sv_bridge eq_p_g_lo_0
· sv_bridge eq_p_g_hi_0
have hbits := ClmulArith.view_spec hN' hview
rw [hvp, SvState.lookup_eq_ofBitVec_bv (W := 2 * N - 1) hvp (by omega) hkp]
congr 2
apply BitVec.eq_of_getLsbD_eq
intro k hk
rw [XF.getLsbD_bv hk, ClmulArith.getLsbD_ofBits, hbits k hk, ← ClmulArith.coeff_eq]
simp [hk]
case inputsKnown_1 => exact inKnown_ofBitVec hA (by omega)
case inputsKnown_2 => exact inKnown_ofBitVec hB (by omega)
all_goals first | (intros; omega) | sv_cover
/--
info: 'Submission.solution' depends on axioms: [propext, Classical.choice, Quot.sound]
-/
#guard_msgs (whitespace := lax) in
#print axioms solution
end Submission
The netlist
The netlist card shows the sky130 weighing (its cells, its critical path): the ASAP7 view changes the overview above, not this card.
Schematic
drawn at N = 4
Drawn at N = 4, a display instance; scored at N = 16. Only this drawing and the notes under it are at the smaller size: the critical path, the cells and every other number on this page are the scored netlist's.
It is the same design through the same pinned flow at a smaller size (ppa.py --param), so that what it does can be seen: 25 cells here, 481 at the scoring point. The critical path at N = 4 (3 cells, ending at p[3] rising, 645 ps there) is in the accent colour. Drawn by netlistsvg with svGolf's sky130 skin (derived from netlistsvg's default skin, as the drawing is: MIT licence, Copyright (c) 2016 Neil Turley, the notice): one symbol per cell function, the cell above it, the instance on hover; nor2b and nand2b are drawn with the bubble on their inverted input. The cells of the path are listed under Critical path, each a link to the cell here.
The netlist at N = 4: 25 cells, 13 and2_1, 9 xnor2_1, 3 nand2_1. There (measured, not ranked): 171.41 µm², 645 ps. Open the drawing on its own (SVG, 17.7 KB) to pan and zoom it with the browser's own controls.
Critical path
at N = 16 · scored
The path the ranked delay ends on, at the scoring point N = 16: 7 nets, 6 cells, to p[15] rising at 1 114 ps. Each row is a net of the repaired netlist with the arrival and the transition the STA computed there (NLDM tables, the larger transition carried; no wires). The first row is an input: its arrival is the input driver's own delay (buf_8 fed by a 50 ps ramp). From ppa.py --path (critical_path_timing); the instance names are the scored netlist's, not the schematic's (drawn at a smaller size).
In the schematic, drawn at N = 4, the critical path is 3 cells to p[3] rising (645 ps there); each cell is a link to it in the drawing:
| # | net | edge | driven by | cell | arrival (ps) | transition (ps) | stage (ps) |
|---|---|---|---|---|---|---|---|
| 0 | b[10] | fall | input port | – | 132.2 | 37.0 | |
| 1 | _0663_ | fall | _1158_ | and2_1 | 286.6 | 42.7 | 154.4 |
| 2 | _0665_ | rise | _1160_ | xnor2_1 | 458.3 | 156.5 | 171.7 |
| 3 | _0669_ | rise | _1164_ | xnor2_1 | 605.4 | 156.0 | 147.1 |
| 4 | _0670_ | rise | _1165_ | xnor2_1 | 753.4 | 156.5 | 148.0 |
| 5 | _0684_ | fall | _1179_ | xnor2_1 | 854.5 | 62.3 | 101.1 |
| 6 | _452_ | rise | _1187_ | xnor2_1 | 1 114.5 | 264.5 | 260.0 |
Cells
at N = 16 · scored
| cell | count | µm² each | µm² in all | share |
|---|---|---|---|---|
xnor2_1 | 225 | 8.7584 | 1970.6400 | 57.5% |
and2_1 | 199 | 6.2560 | 1244.9440 | 36.3% |
nand2_1 | 57 | 3.7536 | 213.9552 | 6.2% |
| total | 481 | 3429.5392 |
Repair (buffer_trees_v1): 0 buffers on 0 nets, 0 tie cells, 1 weighing round; nothing is resized.
Legality: worst load 0.144 × max_capacitance, worst transition 0.178 × max_transition; 0 timing-table reads outside the characterized grid.
the gate mix of the extra GE column (the pinned GE table, score/ge.json)
| cell | count | GE each | GE total |
|---|---|---|---|
XNOR | 225 | 2.000 | 450.000 |
AND | 199 | 1.333 | 265.267 |
NAND | 57 | 1.000 | 57.000 |
| total | 481 | 772.267 |
The record
- task
clmul- player
- svgolf-reference
- assisted by
- Claude (Anthropic)
- submitted
- 2026-11-07
- notes
- reference solution
- scoring point
- N = 16
- design
clmul_n.svsha2564637e72ba5368a35cf427b948aeab0ba3ce8aa6c2f249d2ab90f1ef44372f1ad- proof
clmul_n.leansha256c54a36897565a7eaf366dd21850757f7c32bba7ece34ffdac930df05dae88bf4: the proof of the referenceclmul_n(clmul_n.lean, 238 code lines)- canonical text
- sha256
943a14ddf3945bc4bea101573c12ca613ba971f028bf386573d39ed612207310 - record hash
bfb3c58778b624c3de1cbe0d46c15560a9534ddc13da8f512b8931457989f745- downloads
bfb3c58778b6.svbfb3c58778b6.leanbfb3c58778b6.json
The proof
- code lines
- 238
- build time
- 16.64 s
- axioms
Classical.choice,Quot.sound,propext- tactics seen
decide,induction,omega,simp,sv_cover,sv_equations,sv_interface,sv_rowmajor,sv_structure- imports
Submission.Design,tasks.clmul.Spec,SvGolf.Comb,LeanModels.Sv.CombEqTactic,LeanModels.Sv.CombLib
Checker and flow
Checked under the pinned flow of this site's boards.
- Yosys
Yosys 0.53 (git sha1 53c22ab7c0ced80861c7536c5dae682c30fb5834, clang++ 17.0.0 -fPIC -O3)- Verilator
Verilator 5.042 2025-11-02 rev UNKNOWN.REV- Lean toolchain
leanprover/lean4:v4.33.0-rc1- svGolf revision
d1f3cae6f01a088007a57b31ff8baa6b839d6f74- lean-surfaces revision
d1f3cae6f01a088007a57b31ff8baa6b839d6f74- canonicalization script
bbd11227d45dc1365f27597fd45c565fe721ba2648450588fc4fd983d00b367b- scoring script
ea58219d8ef14c3bad265218ee266ccdb709ac9d4dc5258edc34d51ee83a0445- GE table
6a29196a3f4b58241f4c9af650c9141e4632b737214d563a11ba142a725c4bea- extractor
4930696021c588c75dc890034c534c95560ad9a28a4955b87d1f8d68b5edbc0c- canonical RTLIL
308149de643dedabab540218ac8e9dc7d31c45ce69c49626cab6c267e2c57c74
the checker's files (sha256)
| file | sha256 |
|---|---|
check.py | e708084f72f955b0ae1aaabe469dba3eacc5a91484a1ed81bcc073b60f3c0b6d |
check/ | 3145eb578ca71e452eff05a398e8ad04673e6c72ca5343b234cb22e2cefe65a6 |
check/ | fb51d72510b515460866c2798aad3c6f55295536e627b92854c3580af215bb91 |
check/ | 73856a45905724544247ad29042bdc2f1778271ec07b15cdb3a5f214685165c1 |
check/ | 076db01a9791bcc25ee84e9b0033604a4b675f00b212eab0c864078e6a4748b7 |
check/ | 4e1ee2110c63f24e033dd689c929ea686ddf10f4db23b9057c6fb711394c7558 |
lakefile.toml | f35a88404367d22906effc14d644aac9a9cad47dfd3b704ea8fec88acfaf9c4d |
lean-toolchain | 62c2d9c0fc1ec4c67e151c11eff41ca004ef38e179cf9476c230406e6defedef |
score/ | f18c14c23a14d55db63e202f42cc424dc84c1dd1c337f132ad60859dc9d5d33a |
score/ | bbd11227d45dc1365f27597fd45c565fe721ba2648450588fc4fd983d00b367b |
score/ | 95332451ae3754226fb87b46027385b46a91121e7eb9ae25b302bce756d90475 |
score/ | 6a29196a3f4b58241f4c9af650c9141e4632b737214d563a11ba142a725c4bea |
score/ | 54b93ca63888009d0671c8978e8ab7bf4fb8ce303bc78d3b4e1f83d946cc3201 |
score/ | 912031912c3e3f6790725161753e95415df34846bd8c27dde3eb707747ddbcbe |
score/ | 93547b343dbac135737e98516b1004a780e1cf2f579e1bd7fed82c908c6d4125 |
score/ | 4b8688ba3f4d67681658e5944afe878592adf588cd416a8b47597ebe06deb045 |
score/ | d66a6086a37a97f5985266057051979fb6a8a3c557d3ef9c42acc1b5e41502d8 |
score/ | 71d2e3b82f8813ec64a58f0a46909ca23dfab377db44eda6f294b713f45ae781 |
score/ | 11952f61058051c9e8de91a801b672d07e66a29308e978156c04ffd9f0dbef45 |
score/ | ea58219d8ef14c3bad265218ee266ccdb709ac9d4dc5258edc34d51ee83a0445 |
score/ | c3874dbfc85921a87df6eacdfc6b2c9a0e2b34edd5738951e0d8bdb51f4558b2 |
Post-synthesis check
ls-sv's reading of the design and the scored netlist, simulated on the same vectors, agreed on every one. The vectors are a sample of the inputs: a guard against the two tools disagreeing, not a proof.
- mode
- full
- vectors
- 630
- full set
- 630
- mismatches
- 0
- point
- N=16
- seed
3af21d27c8f0cf7df60eb1a206b0feb72244e5e46139a179b6e03331eb6b06ac- salted
- no
Area against time
- proved reference
- the Pareto front of the entries
- this design
- par's score: area × time = 3821 µm²·ns
the designs as numbers, by score
| design | kind | area (µm²) | time (ps) | score (µm²·ns) |
|---|---|---|---|---|
clmul_n · this design | proved reference · par | 3 429.54 | 1 114 | 3821 |
- proved reference
- baseline (not proved)
- the Pareto front of the entries
- this design
- par's score: area × time = 9.901 µm²·ns
the designs as numbers, by score
| design | kind | area (µm²) | time (ps) | score (µm²·ns) |
|---|---|---|---|---|
school_tree_16 | baseline, not proved | 50.141 | 171 | 8.574 |
clmul_n · this design | proved reference · par | 50.257 | 197 | 9.901 |
kara_b8_16 | baseline, not proved | 41.903 | 251 | 10.52 |
kara_b4_16 | baseline, not proved | 40.620 | 302 | 12.27 |
kara_b2_16 | baseline, not proved | 43.988 | 332 | 14.6 |
kara_full_16 | baseline, not proved | 44.250 | 338 | 14.96 |
Reproduce and verify
From svgolf/, with the pinned tools (reproduce a score lists them):
# the ranked numbers, at the scoring point (from svgolf/, with the pinned Yosys and liberty)
python3.12 score/ppa.py tasks/clmul/reference/clmul_n.sv --task tasks/clmul --path \
--json out.json --netlist scored.v --repaired-netlist repaired.v
Expect, in out.json:
- score.rtlil_sha256
308149de643dedabab540218ac8e9dc7d31c45ce69c49626cab6c267e2c57c74- ppa.netlist_sha256
53ab6ddd5ef519de7f4338e18b7fd5f7df17d163840a02d6cddc1ff8e60a29c0- ppa.repair.netlist_sha256
dc11ba038ed78876109233ff0982e8286f3f5d17a6afbcd2f80747fc9b677caa- ppa.area_e4um2_sky130
34295392- ppa.delay_ps_sky130
1114
The schematic and the critical-path data are site/schematics/clmul/4637e72ba5368a35.json and its .svg, written by site/gen_schematics.py (the display instance is ppa.py ... --param N=4 --repaired-netlist, drawn by netlistsvg 1.0.2; repaired netlist sha256 10c4c368703b17b6…).
From svgolf/, with the pinned tools (reproduce a score lists them):
# the ASAP7 view's numbers, at the scoring point (from svgolf/, with the pinned Yosys; once:
# python3.12 score/ppa.py --pdk asap7 --fetch-liberty, the five pinned ASAP7 files into score/lib/asap7/)
python3.12 score/ppa.py tasks/clmul/reference/clmul_n.sv --task tasks/clmul --pdk asap7 --no-mapped \
--json out.json
Expect, in out.json:
- ppa.netlist_sha256
53ab6ddd5ef519de7f4338e18b7fd5f7df17d163840a02d6cddc1ff8e60a29c0- ppa.repair.netlist_sha256
b060140d469af0bebbb191c8ffd298ab15960c7825ed4eda8b35b8412b9db1c8- ppa.area_e5um2_asap7
5025726- ppa.delay_ps_asap7
197
leaderboard/asap7/clmul.json keeps these numbers; python3.12 leaderboard/leaderboard.py asap7 --rescore --task clmul weighs every design of the task again and compares, bit for bit.
Verify the record
Download the three files, then from svgolf/:
# re-run the whole check on this record's files (the cost of the original check)
H=bfb3c58778b624c3de1cbe0d46c15560a9534ddc13da8f512b8931457989f745
mkdir -p rec/clmul && cp "$H.json" "$H.sv" "$H.lean" rec/clmul/
python3.12 leaderboard/leaderboard.py verify --data-dir rec --task clmul --full
verify --offline checks only the hashes and the arithmetic; plain verify also rescores the design (no Lean; seconds for most designs, a minute or more for the largest), on sky130 and on ASAP7.