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 / mul / reference

Reference mul_wallace

proved referenceproved reference scored at N = 16

A proved reference of mul, written or adapted by the maintainers and shipped with the task: its design and its proof mul_wallace.lean (264 code lines). A Wallace tree: carry-save adders reduce the rows three at a time, then a ripple final adder. It is shown with parshown with par, never a player's entry (proved references).

Area

8 966.10µm²

8 966.0992 µm² exactly

Beats 0% · matches 0%

0 of 2 other players beaten, 0 equal.

vs par
+4.7% largermul_tree_h · 8 563.21 µm²
on this page
10th of 10 designs
cells
1 502
flops
0
repair
0 buffers, 0 tie cells
GE
2 113.894 extra

Performance · time

5 982ps

the delay: the latest output arrival, p[30] rising

Beats 50% · matches 0%

1 of 2 other players beaten, 0 equal.

vs par
−0.2% fastermul_tree_h · 5 992 ps
on this page
4th of 10 designs
Fmax-eq.
167.2 MHz derived
critical path
56 cells
unit depth
62 extra

Score · area × time

53 635µm²·ns

8 966.0992 µm² × 5 982 ps

Beats 0% · matches 0%

0 of 2 other players beaten, 0 equal.

vs par
+4.5% worsemul_tree_h · 51 311 µm²·ns
on this page
7th of 10 designs
board
a proved reference, shown with par: never ranked
Pareto
dominated on this page by late-carry, dadda_ks_16 and dadda_rc_16

On the board, of 2 other players: 0 beaten, 0 level, 1 trade off, 1 ahead.

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 mul's other players at this revision (2 players, 2 records), never the references, the baselines or a rejected design; each player counts once, at their best, and ties are exact at the recorded unit; advisory, recomputed at every build, never stored in a record and never used by the ranking.

On the board, another player is beaten when this design dominates every record of theirs, level when none of theirs is better and one is identical (the rest dominated), ahead when a record of theirs dominates this design, and a trade off otherwise (one of theirs better on one axis, worse on the other).

“On this page” and “Pareto” compare with the 10 designs of the area-time plot (5 references, 2 submissions and 3 baselines): not a ranking.

Area

133.917µm²

133.91730 µm² exactly

Beats 0% · matches 0%

0 of 2 other players beaten, 0 equal.

vs par
+4.7% largermul_tree_h · 127.954 µm²
on this page
10th of 10 designs
cells
1 513
flops
0
repair
0 buffers, 0 tie cells
GE
2 113.894 extra

Performance · time

1 186ps

the delay: the latest output arrival

Beats 50% · matches 0%

1 of 2 other players beaten, 0 equal.

vs par
+2.2% slowermul_tree_h · 1 160 ps
on this page
6th of 10 designs
Fmax-eq.
843.2 MHz derived
unit depth
62 extra

Score · area × time

158.8µm²·ns

133.91730 µm² × 1 186 ps

Beats 0% · matches 0%

0 of 2 other players beaten, 0 equal.

vs par
+7.0% worsemul_tree_h · 148.4 µm²·ns
on this page
8th of 10 designs
board
a proved reference, shown with par: never ranked
Pareto
dominated on this page by late-carry, dadda_ks_16, dadda_rc_16, yosys_mul and mul_tree_h

On the board, of 2 other players: 0 beaten, 0 level, 1 trade off, 1 ahead.

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 mul's other players at this revision (2 players, 2 records), never the references, the baselines or a rejected design; each player counts once, at their best, and ties are exact at the recorded unit; advisory, recomputed at every build, never stored in a record and never used by the ranking.

On the board, another player is beaten when this design dominates every record of theirs, level when none of theirs is better and one is identical (the rest dominated), ahead when a record of theirs dominates this design, and a trade off otherwise (one of theirs better on one axis, worse on the other).

“On this page” and “Pareto” compare with the 10 designs of the area-time plot (5 references, 2 submissions and 3 baselines): not a ranking.

The sources

mul_wallace.svdownload
// svGolf task `mul` -- reference solution 4: a WALLACE-TREE multiplier (tape of rows, 3:2 carry-save
// adder rows), parametric in N.
//
// The tape T is one 2-D packed array of 3N-1 rows of 2N bits. Rows 0 .. N-1 are the N partial
// products (row j = (a & {N{b[j]}}) << j) and row N is an all-zero dummy row, so N+1 rows are live
// at the start. Carry-save adder number g (g = 0 .. N-2) reads the three OLDEST live rows 3g, 3g+1,
// 3g+2 and APPENDS two rows: the sum row x ^ y ^ z at position N+1+2g and the carry row
// maj(x, y, z) << 1 at position N+2+2g. Each adder consumes three live rows and appends two, so after
// the N-1 adders exactly two rows remain, at positions 3N-3 and 3N-2: that is Wallace's reduction
// in its queue form (group the rows by threes, replace each group by its sum and carry row; the
// number of live rows shrinks by a factor 2/3 per level, so there are about log_{3/2}(N) levels).
// A 2N-bit ripple-carry adder adds the last two rows. Every sum is taken modulo 2^(2N), exactly
// the width of the product, so every carry out of bit 2N-1 is dropped without an argument.
//
// There is no localparam, no division, no conditional generate and no stage counter: every index is
// affine in N and the genvars (reads at 3*g+k, writes at N+1+2*g and N+2+2*g). A shifted partial
// product is a GATHER read of `ae`, the zero-padded copy of `a`, so no write leaves its vector.
module mul_n #(parameter int N = 16) (
  input  logic [N-1:0]   a, b,
  output logic [2*N-1:0] p
);
  logic [4*N-2:0]          ae;   // ae[x] = a[x-(2N-1)] for 2N-1 <= x < 3N-1, else 0
  logic [3*N-2:0][2*N-1:0] T;    // the tape of rows
  logic [2*N:0]            K;    // final-adder carries

  assign ae[2*N-2:0]       = '0;
  assign ae[3*N-2:2*N-1]   = a;
  assign ae[4*N-2:3*N-1]   = '0;
  assign T[N]              = '0;
  assign K[0]              = 1'b0;

  genvar j, g, c;
  generate
    // the N partial products: row j is a, shifted left by j and gated by b[j] (a gather read of ae)
    for (j = 0; j < N; j++) begin : g_leaf
      for (c = 0; c < 2*N; c++) begin : g_lc
        assign T[j][c] = ae[c + 2*N - 1 - j] & b[j];
      end
    end
    // carry-save adder g: rows 3g, 3g+1, 3g+2 in, rows N+1+2g (sum) and N+2+2g (carry) appended
    for (g = 0; g < N-1; g++) begin : g_csa
      assign T[N+2+2*g][0] = 1'b0;
      for (c = 0; c < 2*N; c++) begin : g_sum
        assign T[N+1+2*g][c] = T[3*g][c] ^ T[3*g+1][c] ^ T[3*g+2][c];
      end
      for (c = 0; c < 2*N-1; c++) begin : g_car
        assign T[N+2+2*g][c+1] = (T[3*g][c] & T[3*g+1][c]) | (T[3*g+2][c] & (T[3*g][c] ^ T[3*g+1][c]));
      end
    end
    // final carry-propagate (ripple) adder of the last two rows, positions 3N-3 and 3N-2
    for (c = 0; c < 2*N; c++) begin : g_fin
      assign p[c]   = T[3*N-3][c] ^ T[3*N-2][c] ^ K[c];
      assign K[c+1] = (T[3*N-3][c] & T[3*N-2][c]) | (K[c] & (T[3*N-3][c] ^ T[3*N-2][c]));
    end
  endgenerate
endmodule
mul_wallace.lean (264 code lines)
import Submission.Design
import SvGolf.Comb
import LeanModels.Sv.CombEqTactic
import LeanModels.Sv.CombLib

/-!
# Reference solution 4 for task `mul`: a Wallace-tree multiplier (a tape of rows, 3:2 carry-save adders), 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/mul_wallace.sv`: ONE 2-D packed array `T`, the TAPE, of
`3N-1` rows of `2N` bits. Rows `0 .. N-1` are the partial products (row `j` is `a · b[j] · 2^j`),
row `N` is an all-zero dummy row, so `N+1` rows are live at the start. Carry-save adder number `g`
(`g = 0 .. N-2`) reads the three oldest live rows `3g`, `3g+1`, `3g+2` and APPENDS the sum row
`x ^ y ^ z` at position `N+1+2g` and the carry row `maj(x, y, z) << 1` at position `N+2+2g`; after
the `N-1` adders two rows remain, at positions `3N-3` and `3N-2`, and a `2N`-bit ripple-carry
adder adds them. This is Wallace's reduction by groups of three rows, in its queue form (the live
rows shrink by a factor 2/3 per level). There is no stage loop, no localparam, no division and no
conditional generate: every index is affine in `N` and the genvars (`3*g+k`, `N+1+2*g`, `N+2+2*g`),
so the existing fragment of `sv_structure` / `sv_equations` reads the design as it is.

## Route (the file is in this order)

1. **Arithmetic** (`TapeArith`, plain Lean, no ls-sv): `csa_row` (a row of 3:2 counters with the
   carry row shifted by one column preserves the column-weighted sum, up to the dropped top carry),
   `lane_gated` (a partial-product row is the shifted `a`, gated by a bit of `b`), and `tape_mul`:
   the sum modulo `2^(2N)` of the LIVE window `[3g, N+1+2g)` of the tape (`csum V (3g) (N+1-g)`) is
   `a · b` for every `g ≤ N-1`, by induction on `g`: at `g = 0` the window is the partial products
   and the dummy row, and adder `g` replaces its first three rows by the two rows appended at its
   far end, which `csa_row` shows to have the same sum modulo `2^(2N)`. At `g = N-1` the window is
   the two last rows, and the final adder is `ripple_row` of the library.
2. **Structure** (`tape_struct`): `sv_structure` (`CombDesign ∧ Acyclic`); the goals compare 2-D windows and
   close by `intros; sv_rowmajor; omega`. The rank is a lexicographic key `(stage, adder)` of each
   site identity (`tapeKey`): inputs, constants and the dummy row, the partial products, the adders
   in order of `g` (an adder reads only rows below `N+1+2g`, which earlier adders wrote), the ripple
   adder column by column. `tape_struct` needs `maxHeartbeats 1000000`.
3. **Ports** (`tape_interface`): `sv_interface`.
4. **Equations, bridge and coverage** (`solution`): the printed equations of `sv_equations` are bridged to
   the clean facts of `tape_mul` one `sv_bridge eq_x` per fact (the `Int` index forms of the netlist
   against the `Nat` indices of the arithmetic: congruence and `omega`).
5. **Coverage** (`solution`, the same theorem): the coverage goals of `sv_equations` are the reads of the
   tape (a row `3g+k` or `3N-3`, `3N-2` at a column) and of the carry chain `K`; the closing
   `all_goals … sv_cover` proves them, solving the writer from the read (a partial product, the dummy
   row, or a sum or carry row of adder `(r-N-1)/2`).
-/

/-! ## 1. The arithmetic (plain Lean, `CombLib` only)

The Wallace tape multiplier: `tape_mul` proves `p = a * b` from the netlist equations as clean Boolean
facts about bit functions; nothing here mentions a design or a state. -/
namespace TapeArith
open LeanModels.Sv.CombLib

theorem bfVal_false {f : Nat → Bool} {n : Nat} (h : ∀ j < n, f j = false) : bfVal f n = 0 := by
  induction n with
  | zero => rfl
  | succ n ih =>
    simp only [bfVal]
    rw [ih (fun j hj => h j (by omega)), h n (by omega)]
    simp

/-- A row of 3:2 counters, the carry row shifted one column: column `c` of `s`/`cy`, with
`sh (c+1) = cy c`. The top carry `cy (W-1)` is dropped from `sh`. -/
theorem csa_row (n : Nat) (x y z s cy sh : Nat → Bool)
    (hs : ∀ c < n + 1, s c = (x c ^^ y c ^^ z c))
    (hcy : ∀ c < n + 1, cy c = ((x c && y c) || (z c && (x c ^^ y c))))
    (hsh0 : sh 0 = false) (hsh : ∀ c, c + 1 < n + 1 → sh (c + 1) = cy c) :
    bfVal s (n + 1) + bfVal sh (n + 1) + 2 ^ (n + 1) * (cy n).toNat =
      bfVal x (n + 1) + bfVal y (n + 1) + bfVal z (n + 1) := by
  have key : ∀ m, m ≤ n + 1 →
      bfVal s m + 2 * bfVal cy m = bfVal x m + bfVal y m + bfVal z m := by
    intro m
    induction m with
    | zero => intro _; simp [bfVal]
    | succ m ih =>
      intro hm
      have ih := ih (by omega)
      have hfa := fullAdder_arith (x m) (y m) (z m)
      rw [← hs m (by omega), ← hcy m (by omega)] at hfa
      simp only [bfVal]
      have : 2 ^ m * ((s m).toNat + 2 * (cy m).toNat) =
          2 ^ m * ((x m).toNat + (y m).toNat + (z m).toNat) := by rw [hfa]
      generalize (s m).toNat = S0 at *
      generalize (cy m).toNat = C0 at *
      generalize (x m).toNat = X0 at *
      generalize (y m).toNat = Y0 at *
      generalize (z m).toNat = Z0 at *
      generalize 2 ^ m = P at *
      grind
  have hsh' : bfVal sh (n + 1) = 2 * bfVal cy n := by
    rw [bfVal_shift, hsh0]
    have : bfVal (fun j => sh (j + 1)) n = bfVal cy n :=
      bfVal_congr (fun j hj => hsh j (by omega))
    rw [this]; simp
  have hk := key (n + 1) (Nat.le_refl _)
  rw [hsh']
  simp only [bfVal, Nat.pow_succ] at hk ⊢
  generalize 2 ^ n = P at *
  generalize (cy n).toNat = C0 at *
  grind

/-! ### The leaves: a gated, shifted copy of `a` -/

/-- The zero-padded copy `ae` of `a`, read at offset `2N-1-r`, is `a` shifted left by `r`
(for `r ≤ N`: nothing is cut off). -/
theorem lane_val {N : Nat} (hN : 1 ≤ N) (a : BitVec N) (ae : Nat → Bool)
    (h1 : ∀ k, k < 2 * N - 1 → ae k = false)
    (h2 : ∀ k, k < N → ae (2 * N - 1 + k) = a.getLsbD k)
    (h3 : ∀ k, k < N → ae (3 * N - 1 + k) = false)
    (r : Nat) (hr : r ≤ N) :
    bfVal (fun c => ae (c + (2 * N - 1 - r))) (2 * N) = a.toNat * 2 ^ r := by
  have hs1 := bfVal_split (fun c => ae (c + (2 * N - 1 - r))) r (2 * N - r)
  rw [show r + (2 * N - r) = 2 * N by omega] at hs1
  rw [hs1]
  have hlow : bfVal (fun c => ae (c + (2 * N - 1 - r))) r = 0 :=
    bfVal_false (fun j hj => h1 _ (by omega))
  rw [hlow]
  have hs2 := bfVal_split (fun j => ae (r + j + (2 * N - 1 - r))) N (N - r)
  rw [show N + (N - r) = 2 * N - r by omega] at hs2
  rw [hs2]
  have hmid : bfVal (fun j => ae (r + j + (2 * N - 1 - r))) N = a.toNat := by
    rw [← bfVal_bv a]
    exact bfVal_congr (fun j hj => by
      have : r + j + (2 * N - 1 - r) = 2 * N - 1 + j := by omega
      rw [this]; exact h2 j hj)
  have hhigh : bfVal (fun j => (fun j => ae (r + j + (2 * N - 1 - r))) (N + j)) (N - r) = 0 :=
    bfVal_false (fun j hj => by
      show ae (r + (N + j) + (2 * N - 1 - r)) = false
      have : r + (N + j) + (2 * N - 1 - r) = 3 * N - 1 + j := by omega
      rw [this]; exact h3 j (by omega))
  rw [hmid, hhigh]
  simp only [Nat.zero_add, Nat.mul_zero, Nat.add_zero]
  rw [Nat.mul_comm]

/-- The value of a gated lane. -/
theorem lane_gated {N : Nat} (hN : 1 ≤ N) (a : BitVec N) (ae : Nat → Bool)
    (h1 : ∀ k, k < 2 * N - 1 → ae k = false)
    (h2 : ∀ k, k < N → ae (2 * N - 1 + k) = a.getLsbD k)
    (h3 : ∀ k, k < N → ae (3 * N - 1 + k) = false)
    (r : Nat) (g : Bool) (hg : g = true → r ≤ N) :
    bfVal (fun c => ae (c + (2 * N - 1 - r)) && g) (2 * N) = g.toNat * (a.toNat * 2 ^ r) := by
  rw [bfVal_and]
  cases g with
  | false => simp
  | true => simp only [Bool.toNat_true]; rw [lane_val hN a ae h1 h2 h3 r (hg rfl)]


/-! ### Sums over a stretch of tape rows -/

def csum (V : Nat → Nat) : Nat → Nat → Nat
  | _, 0 => 0
  | s, n + 1 => csum V s n + V (s + n)

theorem csum_front (V : Nat → Nat) (n : Nat) : ∀ s, csum V s (n + 1) = V s + csum V (s + 1) n := by
  induction n with
  | zero => intro s; simp [csum]
  | succ n ih =>
    intro s
    have e : s + 1 + n = s + (n + 1) := by omega
    have e2 : csum V (s + 1) (n + 1) = csum V (s + 1) n + V (s + 1 + n) := rfl
    rw [csum, ih s, e2, e]
    omega

/-- Three rows off the front. -/
theorem csum_front3 (V : Nat → Nat) (n s : Nat) :
    csum V s (n + 3) = V s + V (s + 1) + V (s + 2) + csum V (s + 3) n := by
  rw [csum_front, csum_front, csum_front]
  simp only [Nat.add_assoc, Nat.reduceAdd]

/-- Leaves: the first `N` rows hold the partial products, one row per bit of `b`. -/
theorem csum_leaves (a : Nat) (g : Nat → Bool) (V : Nat → Nat) (N : Nat)
    (hV : ∀ j, j < N → V j = (g j).toNat * (a * 2 ^ j)) :
    ∀ n, n ≤ N → csum V 0 n = a * bfVal g n := by
  intro n
  induction n with
  | zero => intro _; simp [csum, bfVal]
  | succ n ih =>
    intro hn
    have ih := ih (by omega)
    rw [csum, ih, Nat.zero_add, hV n (by omega)]
    simp only [bfVal]
    generalize 2 ^ n = P
    generalize (g n).toNat = B0
    generalize bfVal g n = F
    grind

/-- **The whole multiplier**, from the equations of the tape as clean Boolean facts. -/
theorem tape_mul {N : Nat} (hN : 1 ≤ N) (a b : BitVec N) (p : BitVec (2 * N))
    (ae : Nat → Bool) (T : Nat → Nat → Bool) (K : Nat → Bool)
    (hae1 : ∀ k, k < 2 * N - 1 → ae k = false)
    (hae2 : ∀ k, k < N → ae (2 * N - 1 + k) = a.getLsbD k)
    (hae3 : ∀ k, k < N → ae (3 * N - 1 + k) = false)
    (hleaf : ∀ j, j < N → ∀ c, c < 2 * N → T j c = (ae (c + (2 * N - 1 - j)) && b.getLsbD j))
    (hdum : ∀ c, c < 2 * N → T N c = false)
    (hsum : ∀ g, g < N - 1 → ∀ c, c < 2 * N →
      T (N + 1 + 2 * g) c = (T (3 * g) c ^^ T (3 * g + 1) c ^^ T (3 * g + 2) c))
    (hcar0 : ∀ g, g < N - 1 → T (N + 2 + 2 * g) 0 = false)
    (hcar : ∀ g, g < N - 1 → ∀ c, c < 2 * N - 1 →
      T (N + 2 + 2 * g) (c + 1) = ((T (3 * g) c && T (3 * g + 1) c) ||
        (T (3 * g + 2) c && (T (3 * g) c ^^ T (3 * g + 1) c))))
    (hK0 : K 0 = false)
    (hp : ∀ c, c < 2 * N → p.getLsbD c = (T (3 * N - 3) c ^^ T (3 * N - 2) c ^^ K c))
    (hK : ∀ c, c < 2 * N → K (c + 1) =
      ((T (3 * N - 3) c && T (3 * N - 2) c) || (K c && (T (3 * N - 3) c ^^ T (3 * N - 2) c)))) :
    p = BitVec.ofNat (2 * N) (a.toNat * b.toNat) := by
  obtain ⟨n, hn⟩ : ∃ n, 2 * N = n + 1 := ⟨2 * N - 1, by omega⟩
  let V : Nat → Nat := fun m => bfVal (T m) (2 * N)
  -- the leaves: one shifted copy of `a` per bit of `b`
  have hleafV : ∀ j, j < N → V j = (b.getLsbD j).toNat * (a.toNat * 2 ^ j) := by
    intro j hj
    show bfVal (T j) (2 * N) = _
    have e1 : bfVal (T j) (2 * N) =
        bfVal (fun c => ae (c + (2 * N - 1 - j)) && b.getLsbD j) (2 * N) :=
      bfVal_congr (fun c hc => hleaf j hj c hc)
    rw [e1, lane_gated hN a ae hae1 hae2 hae3 j (b.getLsbD j) (fun _ => by omega)]
  have hdumV : V N = 0 := bfVal_false (fun c hc => hdum c hc)
  have hbase : csum V 0 (N + 1) = a.toNat * b.toNat := by
    show csum V 0 N + V (0 + N) = _
    rw [csum_leaves a.toNat b.getLsbD V N hleafV N (Nat.le_refl N), bfVal_bv, Nat.zero_add, hdumV]
    rfl
  -- one carry-save adder: rows 3g, 3g+1, 3g+2 are replaced by the two appended rows
  have hcsa : ∀ g, g < N - 1 → ∃ q, V (N + 1 + 2 * g) + V (N + 2 + 2 * g) + 2 ^ (2 * N) * q =
      V (3 * g) + V (3 * g + 1) + V (3 * g + 2) := by
    intro g hg
    have h := csa_row n (T (3 * g)) (T (3 * g + 1)) (T (3 * g + 2)) (T (N + 1 + 2 * g))
      (fun c => (T (3 * g) c && T (3 * g + 1) c) || (T (3 * g + 2) c && (T (3 * g) c ^^ T (3 * g + 1) c)))
      (T (N + 2 + 2 * g))
      (fun c hc => hsum g hg c (by omega)) (fun _ _ => rfl) (hcar0 g hg)
      (fun c hc => hcar g hg c (by omega))
    rw [← hn] at h
    exact ⟨_, by simp only [V]; omega⟩
  -- the invariant: the live window `[3g, N+1+2g)` sums to `a * b` modulo `2^(2N)`
  have hwin : ∀ g, g ≤ N - 1 → csum V (3 * g) (N + 1 - g) % 2 ^ (2 * N) =
      (a.toNat * b.toNat) % 2 ^ (2 * N) := by
    intro g
    induction g with
    | zero => intro _; simpa using congrArg (· % 2 ^ (2 * N)) hbase
    | succ g ih =>
      intro hg
      have ih := ih (by omega)
      obtain ⟨q, hq⟩ := hcsa g (by omega)
      have e1 : csum V (3 * g) (N + 1 - g) = V (3 * g) + V (3 * g + 1) + V (3 * g + 2) +
          csum V (3 * g + 3) (N - 2 - g) := by
        rw [show N + 1 - g = (N - 2 - g) + 3 by omega, csum_front3]
      have e2 : csum V (3 * (g + 1)) (N + 1 - (g + 1)) =
          csum V (3 * g + 3) (N - 2 - g) + V (N + 1 + 2 * g) + V (N + 2 + 2 * g) := by
        rw [show N + 1 - (g + 1) = (N - 2 - g) + 2 by omega, show 3 * (g + 1) = 3 * g + 3 by omega]
        show csum V (3 * g + 3) (N - 2 - g + 1) + V (3 * g + 3 + (N - 2 - g + 1)) = _
        show csum V (3 * g + 3) (N - 2 - g) + V (3 * g + 3 + (N - 2 - g)) +
          V (3 * g + 3 + (N - 2 - g + 1)) = _
        rw [show 3 * g + 3 + (N - 2 - g) = N + 1 + 2 * g by omega,
          show 3 * g + 3 + (N - 2 - g + 1) = N + 2 + 2 * g by omega]
      rw [e1] at ih
      rw [e2]
      have h3 : (csum V (3 * g + 3) (N - 2 - g) + V (N + 1 + 2 * g) + V (N + 2 + 2 * g) +
          2 ^ (2 * N) * q) % 2 ^ (2 * N) =
          (V (3 * g) + V (3 * g + 1) + V (3 * g + 2) + csum V (3 * g + 3) (N - 2 - g)) % 2 ^ (2 * N) := by
        congr 1; omega
      rw [Nat.add_mul_mod_self_left] at h3
      rw [h3, ih]
  -- the last window: the two remaining rows, at positions `3N-3` and `3N-2`
  have hlast := hwin (N - 1) (Nat.le_refl _)
  rw [show N + 1 - (N - 1) = 2 by omega] at hlast
  have e3 : csum V (3 * (N - 1)) 2 = V (3 * N - 3) + V (3 * N - 2) := by
    show csum V (3 * (N - 1)) 0 + V (3 * (N - 1) + 0) + V (3 * (N - 1) + 1) = _
    rw [show 3 * (N - 1) + 0 = 3 * N - 3 by omega, show 3 * (N - 1) + 1 = 3 * N - 2 by omega]
    simp [csum]
  rw [e3] at hlast
  -- the final adder
  have hrip := ripple_row (2 * N) (T (3 * N - 3)) (T (3 * N - 2))
    (fun c => T (3 * N - 3) c ^^ T (3 * N - 2) c) p.getLsbD K
    (fun _ _ => rfl) (fun c hc => hp c hc) (fun c hc => hK c hc)
  rw [hK0, bfVal_bv] at hrip
  simp only [Bool.toNat_false, Nat.add_zero] at hrip
  have hlt : p.toNat < 2 ^ (2 * N) := p.isLt
  have hpv : p.toNat = (V (3 * N - 3) + V (3 * N - 2)) % 2 ^ (2 * N) := by
    have := sum_split hlt (t := V (3 * N - 3) + V (3 * N - 2)) (q := (K (2 * N)).toNat)
      (by simp only [V]; omega)
    exact this.1
  apply BitVec.eq_of_toNat_eq
  rw [BitVec.toNat_ofNat, hpv, hlast]

end TapeArith
namespace Submission

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


/-! ## 2. Structure: `sv_structure` -/

/-- The rank: `(stage, adder, phase)`. -/
def tapeKey : SiteId → Key
  | .plain _ => (0, 0, 0)
  | .fam "g_lc" _ _ => (1, 0, 0)
  | .fam "g_csa" _ [g] => (2, g.toNat, 0)
  | .fam "g_sum" _ [g, _] => (2, g.toNat, 0)
  | .fam "g_car" _ [g, _] => (2, g.toNat, 0)
  | .fam "g_fin" 0 [c] => (3, c.toNat, 1)
  | .fam "g_fin" _ [c] => (3, c.toNat, 0)
  | .fam _ _ _ => (3, 0, 0)

set_option maxHeartbeats 1000000 in
/-- `CombDesign` and `Acyclic` for every `N ≥ 1`, from the lexicographic key: ONE application of the
soundness theorem and one round of obligations for both. -/
theorem tape_struct (N : Nat) (hN : 1 ≤ N) :
    CombDesign (design.sem N) ∧ Acyclic (design.sem N) ∧ SharedObl design.pdesign [N] := by
  sv_structure (lexRank := tapeKey)
  all_goals (intros; sv_rowmajor; omega)


/-! ## 3. The ports -/

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


/-! ## 4. Bridge, equations and coverage of the tape reads

Every cell the design reads must have a writer. A read of the tape `T` at row `r`, column `c` is
written by one of five assigns: the partial-product loop (a row `r < N`), the dummy row `r = N`,
the sum row of an adder (`r = N+1+2g`), or the carry row of an adder (`r = N+2+2g`: column 0 by its
own assign, columns `c ≥ 1` by the carry loop). `sv_cover` closes these coverage goals itself: it
solves the adder index from the read's row (`g := (r - N - 1) / 2`, the parity is part of the
condition it hands to `omega`) and walks the disjunction of writers (`CombCover.lean`). -/

set_option maxHeartbeats 500000 in
theorem solution : Goal := by
  intro N hN
  have hN' : 1 ≤ N := hN.1
  obtain ⟨hc, ha, hso⟩ := tape_struct N hN'
  refine CombTask.satisfiedAt_of_comb (tape_interface N hN' hc) hc ha ?_
  intro st heqs hs v hv
  obtain ⟨x, y, ⟨⟩⟩ := v
  simp only [SvGolf.Tasks.Mul.task, HoldAll_cons, HoldAll_nil, and_true] at hv ⊢
  obtain ⟨hA, hB⟩ := hv
  sv_equations
  · obtain ⟨⟨vp, hvp, hvpw⟩, -⟩ := known_p_g_fin_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
    rw [hvp, SvState.lookup_eq_ofBitVec_bv (W := 2 * N) hvp (by omega)
      (fun k hk => (known_p_g_fin_0 k (by omega)).2)]
    congr 2
    refine TapeArith.tape_mul hN' x y (XF.bv (2 * N) (st.boolAt "p")) (st.boolAt "ae")
      (st.cell "T" (2 * N)) (st.boolAt "K") ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_
    · sv_bridge eq_ae_plain_0
    · sv_bridge eq_ae_plain_1 with ba
    · sv_bridge eq_ae_plain_2
    · sv_bridge eq_T_g_lc_0 with bb
    · sv_bridge eq_T_plain_3
    · sv_bridge eq_T_g_sum_0
    · sv_bridge eq_T_g_csa_0
    · sv_bridge eq_T_g_car_0
    · sv_bridge eq_K_plain_4
    · sv_bridge eq_p_g_fin_0 with XF.getLsbD_bv
    · sv_bridge eq_K_g_fin_1
  case inputsKnown_1 => exact inKnown_ofBitVec hA (by omega)
  case inputsKnown_2 => exact inKnown_ofBitVec hB (by omega)
  all_goals first | (intros; omega) | (intros; rfl) | 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.

_271_ · sky130_fd_sc_hd__and2_1 and2_1 _272_ · sky130_fd_sc_hd__nand2_1 nand2_1 _273_ · sky130_fd_sc_hd__and2_1 and2_1 _274_ · sky130_fd_sc_hd__and2_1 and2_1 _275_ · sky130_fd_sc_hd__and2_1 and2_1 _276_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _277_ · sky130_fd_sc_hd__and2_1 and2_1 _278_ · sky130_fd_sc_hd__nand2_1 nand2_1 _279_ · sky130_fd_sc_hd__nand2_1 nand2_1 _280_ · sky130_fd_sc_hd__xor2_1 xor2_1 _281_ · sky130_fd_sc_hd__and2_1 and2_1 _282_ · sky130_fd_sc_hd__nand2_1 nand2_1 _283_ · sky130_fd_sc_hd__xor2_1 xor2_1 _284_ · sky130_fd_sc_hd__and2_1 and2_1 _285_ · sky130_fd_sc_hd__and2_1 and2_1 _286_ · sky130_fd_sc_hd__and2_1 and2_1 _287_ · sky130_fd_sc_hd__and2_1 and2_1 _288_ · sky130_fd_sc_hd__nand2_1 nand2_1 _289_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _290_ · sky130_fd_sc_hd__nand2_1 nand2_1 _291_ · sky130_fd_sc_hd__xor2_1 xor2_1 _292_ · sky130_fd_sc_hd__and2_1 and2_1 _293_ · sky130_fd_sc_hd__nand2_1 nand2_1 _294_ · sky130_fd_sc_hd__xor2_1 xor2_1 _295_ · sky130_fd_sc_hd__nand2_1 nand2_1 _296_ · sky130_fd_sc_hd__nand2_1 nand2_1 _297_ · sky130_fd_sc_hd__xor2_1 xor2_1 _298_ · sky130_fd_sc_hd__and2_1 and2_1 _299_ · sky130_fd_sc_hd__xor2_1 xor2_1 _300_ · sky130_fd_sc_hd__xor2_1 xor2_1 _301_ · sky130_fd_sc_hd__and2_1 and2_1 _302_ · sky130_fd_sc_hd__nand2_1 nand2_1 _303_ · sky130_fd_sc_hd__nand2_1 nand2_1 _304_ · sky130_fd_sc_hd__xor2_1 xor2_1 _305_ · sky130_fd_sc_hd__and2_1 and2_1 _306_ · sky130_fd_sc_hd__nand2_1 nand2_1 _307_ · sky130_fd_sc_hd__xor2_1 xor2_1 _308_ · sky130_fd_sc_hd__nand2_1 nand2_1 _309_ · sky130_fd_sc_hd__nand2_1 nand2_1 _310_ · sky130_fd_sc_hd__or2_1 or2_1 _311_ · sky130_fd_sc_hd__and2_1 and2_1 _312_ · sky130_fd_sc_hd__and2_1 and2_1 _313_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _314_ · sky130_fd_sc_hd__nand2_1 nand2_1 _315_ · sky130_fd_sc_hd__xor2_1 xor2_1 _316_ · sky130_fd_sc_hd__nand2b_1 nand2b_1 _317_ · sky130_fd_sc_hd__nand2_1 nand2_1 _318_ · sky130_fd_sc_hd__and2_1 and2_1 _319_ · sky130_fd_sc_hd__and2_1 and2_1 _320_ · sky130_fd_sc_hd__nand2_1 nand2_1 _321_ · sky130_fd_sc_hd__xnor2_1 xnor2_1 _322_ · sky130_fd_sc_hd__nand2_1 nand2_1 _323_ · sky130_fd_sc_hd__and2_1 and2_1 _324_ · sky130_fd_sc_hd__xor2_1 xor2_1 _325_ · sky130_fd_sc_hd__nand2_1 nand2_1 _326_ · sky130_fd_sc_hd__and2_1 and2_1 _327_ · sky130_fd_sc_hd__nand2_1 nand2_1 _328_ · sky130_fd_sc_hd__xor2_1 xor2_1 _329_ · sky130_fd_sc_hd__nand2_1 nand2_1 _330_ · sky130_fd_sc_hd__xor2_1 xor2_1 _331_ · sky130_fd_sc_hd__nand2_1 nand2_1 _332_ · sky130_fd_sc_hd__nor2b_1 nor2b_1 _333_ · sky130_fd_sc_hd__nand2_1 nand2_1 _334_ · sky130_fd_sc_hd__xor2_1 xor2_1 _335_ · sky130_fd_sc_hd__nand2_1 nand2_1 _336_ · sky130_fd_sc_hd__xor2_1 xor2_1 _337_ · sky130_fd_sc_hd__and2_1 and2_1 _338_ · sky130_fd_sc_hd__nand2_1 nand2_1 a b p 0 1 2 3 4 5 6 7 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: 68 cells here, 1 502 at the scoring point. The critical path at N = 4 (12 cells, ending at p[6] rising, 1 837 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: 68 cells, 25 nand2_1, 21 and2_1, 15 xor2_1, 4 xnor2_1, 1 nand2b_1, 1 nor2b_1, 1 or2_1. There (measured, not ranked): 410.39 µm², 1 837 ps. Open the drawing on its own (SVG, 43.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: 57 nets, 56 cells, to p[30] rising at 5 982 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 12 cells to p[6] rising (1 837 ps there); each cell is a link to it in the drawing:

  1. a[3]
  2. _286_ and2_1
  3. _289_ xnor2_1
  4. _291_ xor2_1
  5. _294_ xor2_1
  6. _296_ nand2_1
  7. _312_ and2_1
  8. _313_ xnor2_1
  9. _314_ nand2_1
  10. _317_ nand2_1
  11. _329_ nand2_1
  12. _331_ nand2_1
  13. _336_ xor2_1
  14. p[6]
every stage (57 rows)
#netedgedriven bycellarrival (ps)transition (ps)stage (ps)
0b[6]fallinput port–129.935.0
1_4950_fall_5888_and2_1293.051.7163.1
2_3550_rise_5952_xor2_1493.6190.5200.6
3_3623_rise_6018_xor2_1710.4190.5216.8
4_3625_rise_6020_xor2_1927.2190.5216.8
5_3651_rise_6044_xor2_11 143.7190.2216.5
6_3680_rise_6070_xor2_11 358.8190.5215.1
7_3697_rise_6086_xor2_11 575.3190.2216.5
8_3726_rise_6112_xor2_11 790.4190.5215.1
9_3731_rise_6117_xor2_11 995.5174.4205.1
10_3739_rise_6124_xor2_12 210.0190.2214.5
11_3777_rise_6158_xor2_12 425.1190.5215.1
12_3816_rise_6194_xor2_12 641.9190.5216.8
13_3897_rise_6268_xor2_12 858.7190.5216.8
14_3898_fall_6269_nand2_12 930.445.971.7
15_3899_rise_6270_nand2_13 017.680.187.2
16_3901_fall_6272_nand2_13 067.245.949.6
17_3902_rise_6273_nand2_13 154.480.187.2
18_3904_fall_6275_nand2_13 204.045.949.6
19_3905_rise_6276_nand2_13 291.280.187.2
20_3908_fall_6278_nand2_13 340.845.949.6
21_3909_rise_6279_nand2_13 428.080.187.2
22_3911_fall_6281_nand2_13 477.545.949.5
23_3912_rise_6282_nand2_13 564.780.187.2
24_3914_fall_6284_nand2_13 614.345.949.6
25_3915_rise_6285_nand2_13 701.580.187.2
26_3917_fall_6287_nand2_13 751.145.949.6
27_3919_rise_6288_nand2_13 838.380.187.2
28_3921_fall_6290_nand2_13 887.945.949.6
29_3922_rise_6291_nand2_13 975.180.187.2
30_3924_fall_6293_nand2_14 024.745.949.6
31_3925_rise_6294_nand2_14 111.880.187.1
32_3927_fall_6296_nand2_14 161.445.949.6
33_3928_rise_6297_nand2_14 248.680.187.2
34_3931_fall_6299_nand2_14 298.245.949.6
35_3932_rise_6300_nand2_14 385.480.187.2
36_3934_fall_6302_nand2_14 435.045.949.6
37_3935_rise_6303_nand2_14 522.280.187.2
38_3937_fall_6305_nand2_14 571.845.949.6
39_3938_rise_6306_nand2_14 659.080.187.2
40_3941_fall_6308_nand2_14 708.545.949.5
41_3942_rise_6309_nand2_14 795.780.187.2
42_3944_fall_6311_nand2_14 845.345.949.6
43_3945_rise_6312_nand2_14 932.580.187.2
44_3947_fall_6314_nand2_14 982.145.949.6
45_3948_rise_6315_nand2_15 069.380.187.2
46_3991_fall_6354_nand2_15 118.945.949.6
47_3992_rise_6356_nand2_15 206.180.187.2
48_4028_fall_6388_nand2_15 255.645.949.5
49_4029_rise_6390_nand2_15 342.880.187.2
50_4057_fall_6416_nand2_15 392.445.949.6
51_4059_rise_6418_nand2_15 479.680.187.2
52_4081_fall_6438_nand2_15 529.245.949.6
53_4082_rise_6440_nand2_15 616.480.187.2
54_4096_fall_6453_nand2_15 666.247.749.8
55_4098_rise_6456_nand2_15 747.080.180.8
56_3516_rise_6467_xor2_15 982.3247.2235.3

Cells

at N = 16 · scored

the cells of the repaired netlist, by area9 bars; the table beside the chart lists the same numbers.xor2_1: 4186.52 µm² (µm² · 478 cells)xor2_14186.52 µm² · 478 cellsnand2_1: 2544.94 µm² (µm² · 678 cells)nand2_12544.94 µm² · 678 cellsand2_1: 1883.06 µm² (µm² · 301 cells)and2_11883.06 µm² · 301 cellsxnor2_1: 227.72 µm² (µm² · 26 cells)xnor2_1227.72 µm² · 26 cellsnor2b_1: 37.54 µm² (µm² · 6 cells)nor2b_137.54 µm² · 6 cellsor2_1: 37.54 µm² (µm² · 6 cells)or2_137.54 µm² · 6 cellsmux2_1: 22.52 µm² (µm² · 2 cells)mux2_122.52 µm² · 2 cellsnand2b_1: 18.77 µm² (µm² · 3 cells)nand2b_118.77 µm² · 3 cellsnor2_1: 7.51 µm² (µm² · 2 cells)nor2_17.51 µm² · 2 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
xor2_14788.75844186.515246.7%
nand2_16783.75362544.940828.4%
and2_13016.25601883.056021.0%
xnor2_1268.7584227.71842.5%
nor2b_166.256037.53600.4%
or2_166.256037.53600.4%
mux2_1211.260822.52160.3%
nand2b_136.256018.76800.2%
nor2_123.75367.50720.1%
total1 5028966.0992

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 netlist9 bars; the table beside the chart lists the same numbers.NAND: 678 cells (678.000 GE)NAND678 678.000 GEXOR: 478 cells (956.000 GE)XOR478 956.000 GEAND: 301 cells (401.233 GE)AND301 401.233 GEXNOR: 26 cells (52.000 GE)XNOR26 52.000 GEANDNOT: 6 cells (7.998 GE)ANDNOT6 7.998 GEOR: 6 cells (7.998 GE)OR6 7.998 GEORNOT: 3 cells (3.999 GE)ORNOT3 3.999 GEMUX: 2 cells (4.666 GE)MUX2 4.666 GENOR: 2 cells (2.000 GE)NOR2 2.000 GE
Cells by type; area is the count weighted by the pinned GE table.
cellcountGE eachGE total
NAND6781.000678.000
XOR4782.000956.000
AND3011.333401.233
XNOR262.00052.000
ANDNOT61.3337.998
OR61.3337.998
ORNOT31.3333.999
MUX22.3334.666
NOR21.0002.000
total15022113.894

The reference

task
mul
design
mul_wallace.sv sha256 4369d9943d3ff63630a41058184b139e23e061aa2c27b361ebe53d220c00ae09
proof
mul_wallace.lean, 264 code lines
tactics seen
grind, induction, omega, simp, sv_cover, sv_equations, sv_interface, sv_rowmajor, sv_structure
same design as
–
recorded
no: the checker's run details (build time, axioms, the post-synthesis vectors) are kept for recorded designs only
downloads
mul_wallace.sv mul_wallace.lean

Area against time

µm² × ps · lower left is better · ASAP7
mul: this design's sky130 area against time, among the task's designs10 designs by sky130 area (µm²) (x) and time (ps) (y), this one ringed; lower left is better; 2 beyond the view, counted at its edges. The table under the chart lists the same numbers.500055006000650070007500800082008400860088009000sky130 area (µm²)time (ps) · lower is betterpar's score: area × time = 51 311 µm²·nsthe Pareto front of the entriesdadda_ks_16 · baseline, not proved · Score: 46 009 µm²·ns · Area: 8937.3 µm² · Delay: 5148 psdadda_rc_16 · baseline, not proved · Score: 44 946 µm²·ns · Area: 8230.4 µm² · Delay: 5461 psyosys_mul · baseline, not proved · banned operator · Score: 55 259 µm²·ns · Area: 8826.0 µm² · Delay: 6261 psmul_tree_h · proved reference · par · 2026-10-30T12:20:05Z · Score: 51 311 µm²·ns · Area: 8563.2 µm² · Delay: 5992 psmul_tree · proved reference · 2026-10-30T03:37:11Z · Score: 52 729 µm²·ns · Area: 8603.3 µm² · Delay: 6129 psplus-minus-two · submission · 2026-11-05 · Score: 50 498 µm²·ns · Area: 7978.9 µm² · Delay: 6329 pslate-carry · submission · 2026-11-05 · Score: 42 530 µm²·ns · Area: 7961.4 µm² · Delay: 5342 psthis design · mul_wallace · proved reference · 2026-10-30T05:26:59Z · Score: 53 635 µm²·ns · Area: 8966.1 µm² · Delay: 5982 psparthis design2 designs beyond the view (above)▴ 2
mul: this design's sky130 area against time, among the task's designs10 designs by sky130 area (µm²) (x) and time (ps) (y), this one ringed; lower left is better; 2 beyond the view, counted at its edges. The table under the chart lists the same numbers.500060007000800085009000sky130 area (µm²)time (ps) · lower is betterpar's score: area × time = 51 311 µm²·nsthe Pareto front of the entriesdadda_ks_16 · baseline, not proved · Score: 46 009 µm²·ns · Area: 8937.3 µm² · Delay: 5148 psdadda_rc_16 · baseline, not proved · Score: 44 946 µm²·ns · Area: 8230.4 µm² · Delay: 5461 psyosys_mul · baseline, not proved · banned operator · Score: 55 259 µm²·ns · Area: 8826.0 µm² · Delay: 6261 psmul_tree_h · proved reference · par · 2026-10-30T12:20:05Z · Score: 51 311 µm²·ns · Area: 8563.2 µm² · Delay: 5992 psmul_tree · proved reference · 2026-10-30T03:37:11Z · Score: 52 729 µm²·ns · Area: 8603.3 µm² · Delay: 6129 psplus-minus-two · submission · 2026-11-05 · Score: 50 498 µm²·ns · Area: 7978.9 µm² · Delay: 6329 pslate-carry · submission · 2026-11-05 · Score: 42 530 µm²·ns · Area: 7961.4 µm² · Delay: 5342 psthis design · mul_wallace · proved reference · 2026-10-30T05:26:59Z · Score: 53 635 µm²·ns · Area: 8966.1 µm² · Delay: 5982 psparthis design2 designs beyond the view (above)▴ 2
  • submission
  • proved reference
  • baseline (not proved)
  • baseline with a banned operator
  • the Pareto front of the entries
  • this design
  • par's score: area × time = 51 311 µ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. Fitted to the cluster: 2 designs beyond the view, counted at its edge (◂ ▸ ▴ ▾); “All designs” shows them.
the designs as numbers, by score
designkindarea (µm²)time (ps)score (µm²·ns)
late-carry submission7 961.395 34242 530
dadda_rc_16 baseline, not proved8 230.395 46144 946
dadda_ks_16 baseline, not proved8 937.325 14846 009
plus-minus-two submission7 978.906 32950 498
mul_tree_h proved reference · par8 563.215 99251 311
mul_tree proved reference8 603.256 12952 729
mul_wallace · this designproved reference8 966.105 98253 635
yosys_mul baseline, not proved · banned operator8 825.966 26155 259
mul_n proved reference8 290.4510 90790 424
mul_n_byhand proved reference8 290.4510 90790 424
mul: this design's ASAP7 area against time, among the task's designs10 designs by ASAP7 area (µm²) (x) and time (ps) (y), this one ringed; lower left is better; 2 beyond the view, counted at its edges. The table under the chart lists the same numbers.100012001400120125130ASAP7 area (µm²)time (ps) · lower is betterpar's score: area × time = 148.4 µm²·nsthe Pareto front of the entriesdadda_ks_16 · baseline, not proved · Score: 120.1 µm²·ns · Area: 133.174 µm² · Delay: 902 psdadda_rc_16 · baseline, not proved · Score: 135.7 µm²·ns · Area: 123.391 µm² · Delay: 1100 psyosys_mul · baseline, not proved · banned operator · Score: 150.1 µm²·ns · Area: 131.789 µm² · Delay: 1139 psmul_tree_h · proved reference · par · 2026-10-30T12:20:05Z · Score: 148.4 µm²·ns · Area: 127.954 µm² · Delay: 1160 psmul_tree · proved reference · 2026-10-30T03:37:11Z · Score: 153.1 µm²·ns · Area: 128.552 µm² · Delay: 1191 pslate-carry · submission · 2026-11-05 · Score: 131.5 µm²·ns · Area: 120.854 µm² · Delay: 1088 psplus-minus-two · submission · 2026-11-05 · Score: 156.5 µm²·ns · Area: 119.746 µm² · Delay: 1307 psthis design · mul_wallace · proved reference · 2026-10-30T05:26:59Z · Score: 158.8 µm²·ns · Area: 133.917 µm² · Delay: 1186 psparthis design2 designs beyond the view (above)▴ 2
mul: this design's ASAP7 area against time, among the task's designs10 designs by ASAP7 area (µm²) (x) and time (ps) (y), this one ringed; lower left is better; 2 beyond the view, counted at its edges. The table under the chart lists the same numbers.100012001400120125130ASAP7 area (µm²)time (ps) · lower is betterpar's score: area × time = 148.4 µm²·nsthe Pareto front of the entriesdadda_ks_16 · baseline, not proved · Score: 120.1 µm²·ns · Area: 133.174 µm² · Delay: 902 psdadda_rc_16 · baseline, not proved · Score: 135.7 µm²·ns · Area: 123.391 µm² · Delay: 1100 psyosys_mul · baseline, not proved · banned operator · Score: 150.1 µm²·ns · Area: 131.789 µm² · Delay: 1139 psmul_tree_h · proved reference · par · 2026-10-30T12:20:05Z · Score: 148.4 µm²·ns · Area: 127.954 µm² · Delay: 1160 psmul_tree · proved reference · 2026-10-30T03:37:11Z · Score: 153.1 µm²·ns · Area: 128.552 µm² · Delay: 1191 pslate-carry · submission · 2026-11-05 · Score: 131.5 µm²·ns · Area: 120.854 µm² · Delay: 1088 psplus-minus-two · submission · 2026-11-05 · Score: 156.5 µm²·ns · Area: 119.746 µm² · Delay: 1307 psthis design · mul_wallace · proved reference · 2026-10-30T05:26:59Z · Score: 158.8 µm²·ns · Area: 133.917 µm² · Delay: 1186 psparthis design2 designs beyond the view (above)▴ 2
  • submission
  • proved reference
  • baseline (not proved)
  • baseline with a banned operator
  • the Pareto front of the entries
  • this design
  • par's score: area × time = 148.4 µ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. Fitted to the cluster: 2 designs beyond the view, counted at its edge (◂ ▸ ▴ ▾); “All designs” shows them.
the designs as numbers, by score
designkindarea (µm²)time (ps)score (µm²·ns)
dadda_ks_16 baseline, not proved133.174902120.1
late-carry submission120.8541 088131.5
dadda_rc_16 baseline, not proved123.3911 100135.7
mul_tree_h proved reference · par127.9541 160148.4
yosys_mul baseline, not proved · banned operator131.7891 139150.1
mul_tree proved reference128.5521 191153.1
plus-minus-two submission119.7461 307156.5
mul_wallace · this designproved reference133.9171 186158.8
mul_n proved reference123.9301 981245.5
mul_n_byhand proved reference123.9301 981245.5

Reproduce

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/mul/reference/mul_wallace.sv --task tasks/mul --path \
    --json out.json --netlist scored.v --repaired-netlist repaired.v

Expect, in out.json:

ppa.netlist_sha256
d1d74a81134a7ba2a0edb6670629e5b1733ab125d010aa41cde225d086604fd4
ppa.repair.netlist_sha256
b52cf6114bdddf5fe9ff756cce278976543b0c2404bf013d3f65fb3854ea7a39
ppa.area_e4um2_sky130
89660992
ppa.delay_ps_sky130
5982

The schematic and the critical-path data are site/schematics/mul/4369d9943d3ff636.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 c3db23ad732eea22…).

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/mul/reference/mul_wallace.sv --task tasks/mul --pdk asap7 --no-mapped \
    --json out.json

Expect, in out.json:

ppa.netlist_sha256
d1d74a81134a7ba2a0edb6670629e5b1733ab125d010aa41cde225d086604fd4
ppa.repair.netlist_sha256
00792cf1155fc968d66dfdd3574e90f74ae29aee98a4f645ffe1257d376da98f
ppa.area_e5um2_asap7
13391730
ppa.delay_ps_asap7
1186

leaderboard/asap7/mul.json keeps these numbers; python3.12 leaderboard/leaderboard.py asap7 --rescore --task mul weighs every design of the task again and compares, bit for bit.