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 / clmul / record

Record bfb3c58778b6

reference: par, not an entryreference: par, not an entry scored at N = 16

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

clmul_n.svdownload
// 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.

_44_ · sky130_fd_sc_hd__and2_1 and2_1 _45_ · sky130_fd_sc_hd__nand2_1 nand2_1 _46_ · sky130_fd_sc_hd__and2_1 and2_1 _47_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _48_ · sky130_fd_sc_hd__and2_1 and2_1 _49_ · sky130_fd_sc_hd__and2_1 and2_1 _50_ · sky130_fd_sc_hd__and2_1 and2_1 _51_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _52_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _53_ · sky130_fd_sc_hd__nand2_1 nand2_1 _54_ · sky130_fd_sc_hd__and2_1 and2_1 _55_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _56_ · sky130_fd_sc_hd__and2_1 and2_1 _57_ · sky130_fd_sc_hd__and2_1 and2_1 _58_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _59_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _60_ · sky130_fd_sc_hd__and2_1 and2_1 _61_ · sky130_fd_sc_hd__and2_1 and2_1 _62_ · sky130_fd_sc_hd__and2_1 and2_1 _63_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _64_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _65_ · sky130_fd_sc_hd__nand2_1 nand2_1 _66_ · sky130_fd_sc_hd__and2_1 and2_1 _67_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _68_ · sky130_fd_sc_hd__and2_1 and2_1 a b p 0 1 2 3 4 5 6 0 1 2 3 0 1 2 3

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:

  1. a[2]
  2. _54_ and2_1
  3. _55_ xnor2_1
  4. _59_ xnor2_1
  5. p[3]
#netedgedriven bycellarrival (ps)transition (ps)stage (ps)
0b[10]fallinput port–132.237.0
1_0663_fall_1158_and2_1286.642.7154.4
2_0665_rise_1160_xnor2_1458.3156.5171.7
3_0669_rise_1164_xnor2_1605.4156.0147.1
4_0670_rise_1165_xnor2_1753.4156.5148.0
5_0684_fall_1179_xnor2_1854.562.3101.1
6_452_rise_1187_xnor2_11 114.5264.5260.0

Cells

at N = 16 · scored

the cells of the repaired netlist, by area3 bars; the table beside the chart lists the same numbers.xnor2_1: 1970.64 µm² (µm² · 225 cells)xnor2_11970.64 µm² · 225 cellsand2_1: 1244.94 µm² (µm² · 199 cells)and2_11244.94 µm² · 199 cellsnand2_1: 213.96 µm² (µm² · 57 cells)nand2_1213.96 µm² · 57 cells
The area of each cell type in the repaired A0′ netlist, at the scoring point: the count times the cell's area in the pinned liberty. Their sum is the ranked area.
cellcountµm² eachµm² in allshare
xnor2_12258.75841970.640057.5%
and2_11996.25601244.944036.3%
nand2_1573.7536213.95526.2%
total4813429.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)
gate mix: cells of each type in the scored netlist3 bars; the table beside the chart lists the same numbers.XNOR: 225 cells (450.000 GE)XNOR225 450.000 GEAND: 199 cells (265.267 GE)AND199 265.267 GENAND: 57 cells (57.000 GE)NAND57 57.000 GE
Cells by type; area is the count weighted by the pinned GE table.
cellcountGE eachGE total
XNOR2252.000450.000
AND1991.333265.267
NAND571.00057.000
total481772.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.sv sha256 4637e72ba5368a35cf427b948aeab0ba3ce8aa6c2f249d2ab90f1ef44372f1ad
proof
clmul_n.lean sha256 c54a36897565a7eaf366dd21850757f7c32bba7ece34ffdac930df05dae88bf4: the proof of the reference clmul_n (clmul_n.lean, 238 code lines)
canonical text
sha256 943a14ddf3945bc4bea101573c12ca613ba971f028bf386573d39ed612207310
record hash
bfb3c58778b624c3de1cbe0d46c15560a9534ddc13da8f512b8931457989f745
downloads
bfb3c58778b6.sv bfb3c58778b6.lean bfb3c58778b6.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)
filesha256
check.pye708084f72f955b0ae1aaabe469dba3eacc5a91484a1ed81bcc073b60f3c0b6d
check/Comparator.lean3145eb578ca71e452eff05a398e8ad04673e6c72ca5343b234cb22e2cefe65a6
check/SvEval.leanfb51d72510b515460866c2798aad3c6f55295536e627b92854c3580af215bb91
check/clocked_rules.py73856a45905724544247ad29042bdc2f1778271ec07b15cdb3a5f214685165c1
check/envelope.py076db01a9791bcc25ee84e9b0033604a4b675f00b212eab0c864078e6a4748b7
check/postsynth.py4e1ee2110c63f24e033dd689c929ea686ddf10f4db23b9057c6fb711394c7558
lakefile.tomlf35a88404367d22906effc14d644aac9a9cad47dfd3b704ea8fec88acfaf9c4d
lean-toolchain62c2d9c0fc1ec4c67e151c11eff41ca004ef38e179cf9476c230406e6defedef
score/banlist.pyf18c14c23a14d55db63e202f42cc424dc84c1dd1c337f132ad60859dc9d5d33a
score/canon.ysbbd11227d45dc1365f27597fd45c565fe721ba2648450588fc4fd983d00b367b
score/fourstate.py95332451ae3754226fb87b46027385b46a91121e7eb9ae25b302bce756d90475
score/ge.json6a29196a3f4b58241f4c9af650c9141e4632b737214d563a11ba142a725c4bea
score/ge_seq.json54b93ca63888009d0671c8978e8ab7bf4fb8ce303bc78d3b4e1f83d946cc3201
score/ppa.py912031912c3e3f6790725161753e95415df34846bd8c27dde3eb707747ddbcbe
score/ppa_mapped.ys93547b343dbac135737e98516b1004a780e1cf2f579e1bd7fed82c908c6d4125
score/ppa_mapped_pins.json4b8688ba3f4d67681658e5944afe878592adf588cd416a8b47597ebe06deb045
score/ppa_pins.jsond66a6086a37a97f5985266057051979fb6a8a3c557d3ef9c42acc1b5e41502d8
score/score.py71d2e3b82f8813ec64a58f0a46909ca23dfab377db44eda6f294b713f45ae781
score/srcgate.py11952f61058051c9e8de91a801b672d07e66a29308e978156c04ffd9f0dbef45
score/svgolf.ysea58219d8ef14c3bad265218ee266ccdb709ac9d4dc5258edc34d51ee83a0445
score/svgolf_seq.ysc3874dbfc85921a87df6eacdfc6b2c9a0e2b34edd5738951e0d8bdb51f4558b2

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

µm² × ps · lower left is better · ASAP7
clmul: this design's sky130 area against time, among the task's designs1 design by sky130 area (µm²) (x) and time (ps) (y), this one ringed; lower left is better. The table under the chart lists the same numbers.10501100115032003300340035003600sky130 area (µm²)time (ps) · lower is betterpar's score: area × time = 3821 µm²·nsthe Pareto front of the entriesthis design · clmul_n · proved reference · par · 2026-11-01T14:52:49Z · Score: 3821 µm²·ns · Area: 3429.5 µm² · Delay: 1114 psthis design · par
clmul: this design's sky130 area against time, among the task's designs1 design by sky130 area (µm²) (x) and time (ps) (y), this one ringed; lower left is better. The table under the chart lists the same numbers.105011001150320034003600sky130 area (µm²)time (ps) · lower is betterpar's score: area × time = 3821 µm²·nsthe Pareto front of the entriesthis design · clmul_n · proved reference · par · 2026-11-01T14:52:49Z · Score: 3821 µm²·ns · Area: 3429.5 µm² · Delay: 1114 psthis design · par
  • proved reference
  • the Pareto front of the entries
  • this design
  • par's score: area × time = 3821 µm²·ns
sky130 area (x) against the ranked time (y); lower left is better on both. The step line is the Pareto front of the entries (the proved references and the players' ranked records); a design under par's score curve has a better score than par. Baselines are drawn for scale: scored, never proved. Every design is in view.
the designs as numbers, by score
designkindarea (µm²)time (ps)score (µm²·ns)
clmul_n · this designproved reference · par3 429.541 1143821
clmul: this design's ASAP7 area against time, among the task's designs6 designs by ASAP7 area (µm²) (x) and time (ps) (y), this one ringed; lower left is better. The table under the chart lists the same numbers.200250300404244464850ASAP7 area (µm²)time (ps) · lower is betterpar's score: area × time = 9.901 µm²·nsthe Pareto front of the entriesschool_tree_16 · baseline, not proved · Score: 8.574 µm²·ns · Area: 50.141 µm² · Delay: 171 pskara_b8_16 · baseline, not proved · Score: 10.52 µm²·ns · Area: 41.903 µm² · Delay: 251 pskara_b4_16 · baseline, not proved · Score: 12.27 µm²·ns · Area: 40.620 µm² · Delay: 302 pskara_b2_16 · baseline, not proved · Score: 14.6 µm²·ns · Area: 43.988 µm² · Delay: 332 pskara_full_16 · baseline, not proved · Score: 14.96 µm²·ns · Area: 44.250 µm² · Delay: 338 psthis design · clmul_n · proved reference · par · 2026-11-01T14:52:49Z · Score: 9.901 µm²·ns · Area: 50.257 µm² · Delay: 197 psthis design · par
clmul: this design's ASAP7 area against time, among the task's designs6 designs by ASAP7 area (µm²) (x) and time (ps) (y), this one ringed; lower left is better. The table under the chart lists the same numbers.200250300404550ASAP7 area (µm²)time (ps) · lower is betterpar's score: area × time = 9.901 µm²·nsthe Pareto front of the entriesschool_tree_16 · baseline, not proved · Score: 8.574 µm²·ns · Area: 50.141 µm² · Delay: 171 pskara_b8_16 · baseline, not proved · Score: 10.52 µm²·ns · Area: 41.903 µm² · Delay: 251 pskara_b4_16 · baseline, not proved · Score: 12.27 µm²·ns · Area: 40.620 µm² · Delay: 302 pskara_b2_16 · baseline, not proved · Score: 14.6 µm²·ns · Area: 43.988 µm² · Delay: 332 pskara_full_16 · baseline, not proved · Score: 14.96 µm²·ns · Area: 44.250 µm² · Delay: 338 psthis design · clmul_n · proved reference · par · 2026-11-01T14:52:49Z · Score: 9.901 µm²·ns · Area: 50.257 µm² · Delay: 197 psthis design · par
  • proved reference
  • baseline (not proved)
  • the Pareto front of the entries
  • this design
  • par's score: area × time = 9.901 µm²·ns
ASAP7 area (x) against the ASAP7 time (y); lower left is better on both. The step line is the Pareto front of the entries (the proved references and the players' ranked records); a design under par's score curve has a better score than par. Baselines are drawn for scale: scored, never proved. Every design is in view.
the designs as numbers, by score
designkindarea (µm²)time (ps)score (µm²·ns)
school_tree_16 baseline, not proved50.1411718.574
clmul_n · this designproved reference · par50.2571979.901
kara_b8_16 baseline, not proved41.90325110.52
kara_b4_16 baseline, not proved40.62030212.27
kara_b2_16 baseline, not proved43.98833214.6
kara_full_16 baseline, not proved44.25033814.96

Reproduce and verify

From svgolf/, with the pinned tools (reproduce a score lists them):

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

shell
# 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/:

shell
# 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.