Reference mul_tree
A proved reference of mul, written or adapted by the maintainers and shipped with the task: its design and its proof mul_tree.lean (322 code lines). A log-depth carry-save tree of 4:2 compressors over the partial-product rows, with a ripple final adder. It is shown with parshown with par, never a player's entry (proved references).
Area
8 603.25µm²
8 603.2512 µm² exactly
Beats 0% · matches 0%
0 of 2 other players beaten, 0 equal.
- vs par
- +0.5% largermul_tree_h · 8 563.21 µm²
- on this page
- 7th of 10 designs
- cells
- 1 456
- flops
- 0
- repair
- 0 buffers, 0 tie cells
- GE
- 2 034.904 extra
Performance · time
6 129ps
the delay: the latest output arrival, p[30] rising
Beats 50% · matches 0%
1 of 2 other players beaten, 0 equal.
- vs par
- +2.3% slowermul_tree_h · 5 992 ps
- on this page
- 6th of 10 designs
- Fmax-eq.
- 163.2 MHz derived
- critical path
- 58 cells
- unit depth
- 63 extra
Score · area × time
52 729µm²·ns
8 603.2512 µm² × 6 129 ps
Beats 0% · matches 0%
0 of 2 other players beaten, 0 equal.
- vs par
- +2.8% worsemul_tree_h · 51 311 µm²·ns
- on this page
- 6th of 10 designs
- board
- a proved reference, shown with par: never ranked
- Pareto
- dominated on this page by late-carry, dadda_rc_16 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: 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
128.552µm²
128.55186 µm² exactly
Beats 0% · matches 0%
0 of 2 other players beaten, 0 equal.
- vs par
- +0.5% largermul_tree_h · 127.954 µm²
- on this page
- 7th of 10 designs
- cells
- 1 458
- flops
- 0
- repair
- 0 buffers, 0 tie cells
- GE
- 2 034.904 extra
Performance · time
1 191ps
the delay: the latest output arrival
Beats 50% · matches 0%
1 of 2 other players beaten, 0 equal.
- vs par
- +2.7% slowermul_tree_h · 1 160 ps
- on this page
- 7th of 10 designs
- Fmax-eq.
- 839.6 MHz derived
- unit depth
- 63 extra
Score · area × time
153.1µm²·ns
128.55186 µm² × 1 191 ps
Beats 50% · matches 0%
1 of 2 other players beaten, 0 equal.
- vs par
- +3.2% worsemul_tree_h · 148.4 µm²·ns
- on this page
- 6th of 10 designs
- board
- a proved reference, shown with par: never ranked
- Pareto
- dominated on this page by late-carry, dadda_rc_16 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
// svGolf task `mul` -- reference solution 3: a log-depth carry-save TREE multiplier, parametric in N.
//
// The N partial-product rows pp[j] are the N leaves (a single row each: sum row S = pp[j], carry
// row C = 0) of one balanced binary tree in a binary-HEAP numbering: the root is node 0, node k has
// the children 2k+1 and 2k+2, the N-1 internal nodes are 0 .. N-2 and the N leaves N-1 .. 2N-2.
// An internal node whose children are both leaves (2k+1 >= N-1) just pairs them, S = S[2k+1],
// C = S[2k+2]: two rows are already a carry-save pair. Every other internal node is a 4:2
// compressor on its two children's pairs: two stacked rows of 3:2 counters (full adders), the
// first row X/Y, the second S/C. So the carry-save part has ceil(log2 N) - 1 levels of two full
// adders, and the two rows of the root go through a ripple-carry final adder.
//
// Which nodes pair and which compress is decided by the constant vectors `th` (th[x] = 1 iff
// x >= N-1) and `nth` (its complement), read at the affine index 2k+1: a node-level multiplexer
// whose select is a constant, which synthesis removes. The heap numbering needs no stage counter,
// no localparam, no conditional generate and no division: every index and bound is affine in N and
// the genvars. A shifted partial product is a GATHER read of `ae`, the zero-padded copy of `a`, so no
// write ever leaves its vector. All sums are taken modulo 2^(2N), exactly the width of the product.
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 [2*N-2:0] th, nth; // th[x] = (x >= N-1), nth = its complement
logic [2*N-2:0][2*N-1:0] S, C; // sum / carry row of each heap node
logic [N-1:0][2*N-1:0] X, Y; // first-row sum / carry of node k (row N-1 unused)
logic [2*N:0] R; // 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 X[N-1] = '0;
assign Y[N-1] = '0;
assign R[0] = 1'b0;
genvar j, k, c, x;
generate
for (x = 0; x < N-1; x++) begin : g_thlo
assign th[x] = 1'b0;
assign nth[x] = 1'b1;
end
for (x = 0; x < N; x++) begin : g_thhi
assign th[N-1+x] = 1'b1;
assign nth[N-1+x] = 1'b0;
end
// leaves: node N-1+j is the partial-product row j, shifted left by 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 S[N-1+j][c] = ae[c + 2*N - 1 - j] & b[j];
assign C[N-1+j][c] = 1'b0;
end
end
// internal nodes: pair two leaves (th), or a 4:2 compressor (nth) on the children 2k+1, 2k+2
for (k = 0; k < N-1; k++) begin : g_node
assign Y[k][0] = 1'b0;
assign C[k][0] = th[2*k+1] & S[2*k+2][0];
for (c = 0; c < 2*N; c++) begin : g_col
assign X[k][c] = S[2*k+1][c] ^ C[2*k+1][c] ^ S[2*k+2][c];
assign S[k][c] = (th[2*k+1] & S[2*k+1][c]) | (nth[2*k+1] & (X[k][c] ^ Y[k][c] ^ C[2*k+2][c]));
end
for (c = 0; c < 2*N-1; c++) begin : g_car
assign Y[k][c+1] = (S[2*k+1][c] & C[2*k+1][c]) | (S[2*k+2][c] & (S[2*k+1][c] ^ C[2*k+1][c]));
assign C[k][c+1] = (th[2*k+1] & S[2*k+2][c+1])
| (nth[2*k+1] & ((X[k][c] & Y[k][c]) | (C[2*k+2][c] & (X[k][c] ^ Y[k][c]))));
end
end
// final carry-propagate (ripple) adder of the root's two rows
for (c = 0; c < 2*N; c++) begin : g_fin
assign p[c] = S[0][c] ^ C[0][c] ^ R[c];
assign R[c+1] = (S[0][c] & C[0][c]) | (R[c] & (S[0][c] ^ C[0][c]));
end
endgenerate
endmodule
mul_tree.lean (322 code lines)
import Submission.Design
import SvGolf.Comb
import LeanModels.Sv.CombEqTactic
import LeanModels.Sv.CombLib
/-!
# Reference solution 3 for task `mul`: a carry-save tree multiplier, 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_tree.sv`: the `N` partial-product rows are the `N`
leaves (nodes `N-1 .. 2N-2`) of a binary HEAP (node `k` has the children `2k+1`, `2k+2`; the root is
node 0), each leaf a sum row `S = a·b_j·2^j` with a zero carry row `C`. An internal node whose two
children are leaves (`2k+1 ≥ N-1`, selected by the constant vector `th`) just pairs them,
`(S, C) = (S[2k+1], S[2k+2])`; every other internal node is a 4:2 compressor, two stacked rows of
full adders, on its children's pairs. The root's two rows go through a ripple-carry adder. The
carry-save part has depth `⌈log₂ N⌉ - 1` compressors; there is no stage loop, no localparam, no
conditional generate and no division in the design, so the existing fragment of `sv_structure` /
`sv_equations` reads it as it is.
## Route (the file is in this order)
1. **Arithmetic** (`TreeArith`, plain Lean, no ls-sv): `csa_row` (a row of 3:2 counters with the
carry row shifted by one column preserves the sum, up to the dropped top carry), `node_sum` (a
4:2 node preserves the value of its two pairs, up to `2^(2N)`), `lane_gated` (a leaf row is the
shifted `a`, gated by a bit of `b`), and `tree_mul`: the sums over the CUT `{t, …, 2t}` of the
heap, `csum V t (t+1)`, are invariant modulo `2^(2N)` while `t` runs from `N-1` (the leaves:
`a · b` exactly) down to `0` (the root), because node `t` has exactly the children `2t+1` and
`2t+2`, which are the two elements by which the cut `{t+1, …, 2t+2}` exceeds `{t+1, …, 2t}`; a
pairing node preserves the value exactly (its children have zero carry rows), a compressor
up to `2^(2N)`. The final adder is `ripple_row` of the library.
2. **Structure** (`tree_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, node order,
phase)` of each site identity (`treeKey`): inputs and constants, the leaves, the internal nodes
from the highest heap index down to the root (two phases each: the first row of counters, then
the second), the ripple adder column by column. `tree_struct` needs `maxHeartbeats 1000000`.
The loops over `2*N` columns need the generate-fuel bound `4 · N + 60` of the tactic library
(`AutoObl`; it was `N + 60`).
3. **Ports** (`tree_interface`): `sv_interface`.
4. **Equations, bridge and coverage** (`solution`): the printed equations of `sv_equations` are bridged
to the clean facts of `tree_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 heap reads
(`S`, `C`, `X`, `Y` at a row and a column, the constant selects `th` / `nth`, and the carry
chain `R`); the closing `all_goals … sv_cover` proves them, solving the writer (leaf rows `≥ N-1`,
node rows below, the column-0 assigns) from the read.
-/
/-! ## 1. The arithmetic (plain Lean, `CombLib` only)
The heap-indexed 4:2 carry-save tree multiplier: `tree_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 TreeArith
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
/-- A 4:2 compressor node: two stacked rows of counters, on a window of `n+1` columns, preserves
the sum exactly up to the two dropped top carries. -/
theorem node_sum (n : Nat) (SL CL SR CR S C X Y : Nat → Bool)
(hX : ∀ c < n + 1, X c = (SL c ^^ CL c ^^ SR c))
(hY0 : Y 0 = false)
(hY : ∀ c, c + 1 < n + 1 → Y (c + 1) = ((SL c && CL c) || (SR c && (SL c ^^ CL c))))
(hS : ∀ c < n + 1, S c = (X c ^^ Y c ^^ CR c))
(hC0 : C 0 = false)
(hC : ∀ c, c + 1 < n + 1 → C (c + 1) = ((X c && Y c) || (CR c && (X c ^^ Y c)))) :
∃ q, bfVal S (n + 1) + bfVal C (n + 1) + 2 ^ (n + 1) * q =
(bfVal SL (n + 1) + bfVal CL (n + 1)) + (bfVal SR (n + 1) + bfVal CR (n + 1)) := by
have h1 := csa_row n SL CL SR X (fun c => (SL c && CL c) || (SR c && (SL c ^^ CL c))) Y
hX (fun _ _ => rfl) hY0 hY
have h2 := csa_row n X Y CR S (fun c => (X c && Y c) || (CR c && (X c ^^ Y c))) C
hS (fun _ _ => rfl) hC0 hC
refine ⟨(((SL n && CL n) || (SR n && (SL n ^^ CL n))).toNat) +
((X n && Y n) || (CR n && (X n ^^ Y n))).toNat, ?_⟩
simp only [Nat.mul_add] at h1 h2 ⊢
generalize 2 ^ (n + 1) = P at *
omega
/-! ### 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 heap nodes -/
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
/-- Leaves: `csum` of the leaf values is `a · b`, one row per bit of `b`. -/
theorem csum_leaves (N : Nat) (a : Nat) (g : Nat → Bool) (V : Nat → Nat)
(hV : ∀ j, j < N → V (N - 1 + j) = (g j).toNat * (a * 2 ^ j)) :
∀ n, n ≤ N → csum V (N - 1) 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, 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 netlist as clean Boolean facts. -/
theorem tree_mul {N : Nat} (hN : 1 ≤ N) (a b : BitVec N) (p : BitVec (2 * N))
(ae th nth : Nat → Bool) (S C X Y : Nat → Nat → Bool) (R : 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)
(hthlo : ∀ x, x < N - 1 → th x = false)
(hnthlo : ∀ x, x < N - 1 → nth x = true)
(hthhi : ∀ x, x < N → th (N - 1 + x) = true)
(hnthhi : ∀ x, x < N → nth (N - 1 + x) = false)
(hleafS : ∀ j, j < N → ∀ c, c < 2 * N →
S (N - 1 + j) c = (ae (c + (2 * N - 1 - j)) && b.getLsbD j))
(hleafC : ∀ j, j < N → ∀ c, c < 2 * N → C (N - 1 + j) c = false)
(hY0 : ∀ k, k < N - 1 → Y k 0 = false)
(hC0 : ∀ k, k < N - 1 → C k 0 = (th (2 * k + 1) && S (2 * k + 2) 0))
(hX : ∀ k, k < N - 1 → ∀ c, c < 2 * N →
X k c = (S (2 * k + 1) c ^^ C (2 * k + 1) c ^^ S (2 * k + 2) c))
(hS : ∀ k, k < N - 1 → ∀ c, c < 2 * N →
S k c = ((th (2 * k + 1) && S (2 * k + 1) c) ||
(nth (2 * k + 1) && (X k c ^^ Y k c ^^ C (2 * k + 2) c))))
(hY : ∀ k, k < N - 1 → ∀ c, c < 2 * N - 1 →
Y k (c + 1) = ((S (2 * k + 1) c && C (2 * k + 1) c) ||
(S (2 * k + 2) c && (S (2 * k + 1) c ^^ C (2 * k + 1) c))))
(hC : ∀ k, k < N - 1 → ∀ c, c < 2 * N - 1 →
C k (c + 1) = ((th (2 * k + 1) && S (2 * k + 2) (c + 1)) ||
(nth (2 * k + 1) && ((X k c && Y k c) || (C (2 * k + 2) c && (X k c ^^ Y k c))))))
(hR0 : R 0 = false)
(hp : ∀ c, c < 2 * N → p.getLsbD c = (S 0 c ^^ C 0 c ^^ R c))
(hR : ∀ c, c < 2 * N → R (c + 1) =
((S 0 c && C 0 c) || (R c && (S 0 c ^^ C 0 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 (S m) (2 * N) + bfVal (C m) (2 * N)
-- the leaves: one shifted copy of `a` per bit of `b`
have hleaf : ∀ j, j < N → V (N - 1 + j) = (b.getLsbD j).toNat * (a.toNat * 2 ^ j) := by
intro j hj
have e1 : bfVal (S (N - 1 + j)) (2 * N) =
bfVal (fun c => ae (c + (2 * N - 1 - j)) && b.getLsbD j) (2 * N) :=
bfVal_congr (fun c hc => hleafS j hj c hc)
have e2 : bfVal (C (N - 1 + j)) (2 * N) = 0 :=
bfVal_false (fun c hc => hleafC j hj c hc)
show bfVal (S (N - 1 + j)) (2 * N) + bfVal (C (N - 1 + j)) (2 * N) = _
rw [e1, e2, lane_gated hN a ae hae1 hae2 hae3 j (b.getLsbD j) (fun _ => by omega)]
omega
have hleaves : csum V (N - 1) N = a.toNat * b.toNat := by
rw [csum_leaves N a.toNat b.getLsbD V hleaf N (Nat.le_refl N), bfVal_bv]
-- a leaf has no carry row
have hCleaf : ∀ m, N - 1 ≤ m → m ≤ 2 * N - 2 → ∀ c, c < 2 * N → C m c = false := by
intro m h1 h2 c hc
have := hleafC (m - (N - 1)) (by omega) c hc
rwa [show N - 1 + (m - (N - 1)) = m by omega] at this
-- the nodes
have hnode : ∀ k, k < N - 1 → ∃ q, V k + 2 ^ (2 * N) * q = V (2 * k + 1) + V (2 * k + 2) := by
intro k hk
by_cases hb : 2 * k + 1 < N - 1
· -- a 4:2 compressor
have ht := hthlo (2 * k + 1) hb
have hnt := hnthlo (2 * k + 1) hb
obtain ⟨q, hq⟩ := node_sum n (S (2 * k + 1)) (C (2 * k + 1)) (S (2 * k + 2)) (C (2 * k + 2))
(S k) (C k) (X k) (Y k)
(fun c hc => hX k hk c (by omega)) (hY0 k hk)
(fun c hc => hY k hk c (by omega))
(fun c hc => by rw [hS k hk c (by omega), ht, hnt]; simp)
(by rw [hC0 k hk, ht]; simp)
(fun c hc => by rw [hC k hk c (by omega), ht, hnt]; simp)
rw [← hn] at hq
exact ⟨q, by simp only [V]; omega⟩
· -- two leaves are paired
have ht : th (2 * k + 1) = true := by
have := hthhi (2 * k + 1 - (N - 1)) (by omega)
rwa [show N - 1 + (2 * k + 1 - (N - 1)) = 2 * k + 1 by omega] at this
have hnt : nth (2 * k + 1) = false := by
have := hnthhi (2 * k + 1 - (N - 1)) (by omega)
rwa [show N - 1 + (2 * k + 1 - (N - 1)) = 2 * k + 1 by omega] at this
have hSk : ∀ c, c < 2 * N → S k c = S (2 * k + 1) c := by
intro c hc; rw [hS k hk c hc, ht, hnt]; simp
have hCk : ∀ c, c < 2 * N → C k c = S (2 * k + 2) c := by
intro c hc
cases c with
| zero => rw [hC0 k hk, ht]; simp
| succ c => rw [hC k hk c (by omega), ht, hnt]; simp
have e1 : bfVal (S k) (2 * N) = bfVal (S (2 * k + 1)) (2 * N) := bfVal_congr hSk
have e2 : bfVal (C k) (2 * N) = bfVal (S (2 * k + 2)) (2 * N) := bfVal_congr hCk
have e3 : bfVal (C (2 * k + 1)) (2 * N) = 0 :=
bfVal_false (fun c hc => hCleaf (2 * k + 1) (by omega) (by omega) c hc)
have e4 : bfVal (C (2 * k + 2)) (2 * N) = 0 :=
bfVal_false (fun c hc => hCleaf (2 * k + 2) (by omega) (by omega) c hc)
exact ⟨0, by simp only [V]; omega⟩
-- the cut sums
have hcut : ∀ t, t < N - 1 → ∃ q, csum V t (t + 1) + 2 ^ (2 * N) * q = csum V (t + 1) (t + 2) := by
intro t ht
obtain ⟨q, hq⟩ := hnode t ht
refine ⟨q, ?_⟩
have f1 : csum V t (t + 1) = V t + csum V (t + 1) t := csum_front V t t
have f2 : csum V (t + 1) (t + 2) = csum V (t + 1) t + V (t + 1 + t) + V (t + 1 + (t + 1)) := rfl
rw [f1, f2, show t + 1 + t = 2 * t + 1 by omega, show t + 1 + (t + 1) = 2 * t + 2 by omega]
omega
have hdown : ∀ d, d ≤ N - 1 → csum V (N - 1 - d) (N - 1 - d + 1) % 2 ^ (2 * N) =
(a.toNat * b.toNat) % 2 ^ (2 * N) := by
intro d
induction d with
| zero =>
intro _
rw [show N - 1 - 0 + 1 = N by omega, Nat.sub_zero, hleaves]
| succ d ih =>
intro hd
have ih := ih (by omega)
obtain ⟨q, hq⟩ := hcut (N - 1 - (d + 1)) (by omega)
rw [show N - 1 - (d + 1) + 1 = N - 1 - d by omega,
show N - 1 - (d + 1) + 2 = N - 1 - d + 1 by omega] at hq
rw [← ih, ← hq, Nat.add_mul_mod_self_left, show N - 1 - (d + 1) + 1 = N - 1 - d by omega]
have hroot := hdown (N - 1) (Nat.le_refl _)
rw [Nat.sub_self, show (0 : Nat) + 1 = 1 from rfl] at hroot
have hV0 : csum V 0 1 = V 0 := by simp [csum]
rw [hV0] at hroot
-- the final adder
have hrip := ripple_row (2 * N) (S 0) (C 0) (fun c => S 0 c ^^ C 0 c) p.getLsbD R
(fun _ _ => rfl) (fun c hc => hp c hc) (fun c hc => hR c hc)
rw [hR0, 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 0 % 2 ^ (2 * N) := by
have := sum_split hlt (t := V 0) (q := (R (2 * N)).toNat) (by simp only [V]; omega)
exact this.1
apply BitVec.eq_of_toNat_eq
rw [BitVec.toNat_ofNat, hpv, hroot]
end TreeArith
namespace Submission
open LeanModels.Sv LeanModels.Sv.CombView LeanModels.Sv.CombLib LeanModels.Sv.CombEq SvGolf
/-! ## 2. Structure: `sv_structure` -/
/-- The rank: `(stage, node order, phase)`. Inputs and constants (the thermometers `th`, `nth`
included) first, then the leaves, then the internal nodes from the last (deepest, highest heap
index) to the root, in two phases (the first row of counters, then the second), then the ripple
final adder column by column. -/
def treeKey (N : Nat) : SiteId → Key
| .plain _ => (0, 0, 0)
| .fam "g_thlo" _ _ => (0, 0, 0)
| .fam "g_thhi" _ _ => (0, 0, 0)
| .fam "g_lc" _ _ => (1, 0, 0)
| .fam "g_node" _ [k] => (2, N - 1 - k.toNat, 0)
| .fam "g_col" 0 [k, _] => (2, N - 1 - k.toNat, 1)
| .fam "g_col" _ [k, _] => (2, N - 1 - k.toNat, 2)
| .fam "g_car" 0 [k, _] => (2, N - 1 - k.toNat, 1)
| .fam "g_car" _ [k, _] => (2, N - 1 - k.toNat, 2)
| .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 tree_struct (N : Nat) (hN : 1 ≤ N) :
CombDesign (design.sem N) ∧ Acyclic (design.sem N) ∧ SharedObl design.pdesign [N] := by
sv_structure (lexRank := treeKey N)
all_goals (intros; sv_rowmajor; omega)
/-! ## 3. The ports -/
theorem tree_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 heap reads
Every cell the tree reads must have a writer. The heap rows `[0, N-1)` are written by the node loop,
the rows `[N-1, 2N-1)` by the leaf loop; a carry row is also written in column 0 by its own assign.
`sv_cover` closes these coverage goals itself (it solves the writer's loop indices from the read's row
and column and walks the disjunction of writers, `CombCover.lean`), so `solution` only lists the
equations it bridges. -/
set_option maxHeartbeats 600000 in
theorem solution : Goal := by
intro N hN
have hN' : 1 ≤ N := hN.1
obtain ⟨hc, ha, hso⟩ := tree_struct N hN'
refine CombTask.satisfiedAt_of_comb (tree_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 TreeArith.tree_mul hN' x y (XF.bv (2 * N) (st.boolAt "p")) (st.boolAt "ae") (st.boolAt "th")
(st.boolAt "nth") (st.cell "S" (2 * N)) (st.cell "C" (2 * N)) (st.cell "X" (2 * N))
(st.cell "Y" (2 * N)) (st.boolAt "R")
?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_ ?_
· sv_bridge eq_ae_plain_0
· sv_bridge eq_ae_plain_1 with ba
· sv_bridge eq_ae_plain_2
· sv_bridge eq_th_g_thlo_0
· sv_bridge eq_nth_g_thlo_1
· sv_bridge eq_th_g_thhi_0
· sv_bridge eq_nth_g_thhi_1
· sv_bridge eq_S_g_lc_0 with bb
· sv_bridge eq_C_g_lc_1
· sv_bridge eq_Y_g_node_0
· sv_bridge eq_C_g_node_1
· sv_bridge eq_X_g_col_0
· sv_bridge eq_S_g_col_1
· sv_bridge eq_Y_g_car_0
· sv_bridge eq_C_g_car_1
· sv_bridge eq_R_plain_5
· sv_bridge eq_p_g_fin_0 with XF.getLsbD_bv
· sv_bridge eq_R_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.
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: 64 cells here, 1 456 at the scoring point. The critical path at N = 4 (11 cells, ending at p[6] rising, 1 777 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: 64 cells, 27 nand2_1, 18 and2_1, 16 xor2_1, 3 xnor2_1. There (measured, not ranked): 380.36 µm², 1 777 ps. Open the drawing on its own (SVG, 40.2 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: 59 nets, 58 cells, to p[30] rising at 6 129 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 11 cells to p[6] rising (1 777 ps there); each cell is a link to it in the drawing:
a[3]_559_and2_1_562_xnor2_1_564_xor2_1_566_xor2_1_568_xor2_1_569_and2_1_584_nand2_1_586_nand2_1_594_nand2_1_596_nand2_1_602_xor2_1p[6]
every stage (59 rows)
| # | net | edge | driven by | cell | arrival (ps) | transition (ps) | stage (ps) |
|---|---|---|---|---|---|---|---|
| 0 | a[7] | fall | input port | – | 128.1 | 33.5 | |
| 1 | _09795_ | fall | _10753_ | and2_1 | 290.6 | 51.7 | 162.5 |
| 2 | _09841_ | rise | _10800_ | xor2_1 | 491.3 | 190.5 | 200.7 |
| 3 | _09843_ | rise | _10802_ | xor2_1 | 708.0 | 190.5 | 216.7 |
| 4 | _09845_ | rise | _10804_ | xor2_1 | 924.8 | 190.5 | 216.8 |
| 5 | _09847_ | rise | _10806_ | xor2_1 | 1 141.6 | 190.5 | 216.8 |
| 6 | _09849_ | rise | _10808_ | xor2_1 | 1 358.4 | 190.5 | 216.8 |
| 7 | _09851_ | rise | _10810_ | xor2_1 | 1 575.1 | 190.5 | 216.7 |
| 8 | _09853_ | rise | _10812_ | xor2_1 | 1 791.9 | 190.5 | 216.8 |
| 9 | _09855_ | rise | _10814_ | xor2_1 | 2 008.7 | 190.5 | 216.8 |
| 10 | _09857_ | rise | _10816_ | xor2_1 | 2 225.4 | 190.5 | 216.7 |
| 11 | _09859_ | rise | _10818_ | xor2_1 | 2 430.5 | 174.4 | 205.1 |
| 12 | _09861_ | rise | _10820_ | xor2_1 | 2 645.3 | 190.5 | 214.8 |
| 13 | _09863_ | rise | _10822_ | xor2_1 | 2 862.0 | 190.5 | 216.7 |
| 14 | _09864_ | fall | _10823_ | nand2_1 | 2 933.8 | 45.9 | 71.8 |
| 15 | _09865_ | rise | _10825_ | nand2_1 | 3 021.0 | 80.1 | 87.2 |
| 16 | _09918_ | fall | _10878_ | nand2_1 | 3 070.6 | 45.9 | 49.6 |
| 17 | _09919_ | rise | _10880_ | nand2_1 | 3 157.8 | 80.1 | 87.2 |
| 18 | _09976_ | fall | _10937_ | nand2_1 | 3 207.4 | 45.9 | 49.6 |
| 19 | _09977_ | rise | _10939_ | nand2_1 | 3 294.6 | 80.1 | 87.2 |
| 20 | _10040_ | fall | _11002_ | nand2_1 | 3 344.1 | 45.9 | 49.5 |
| 21 | _10041_ | rise | _11004_ | nand2_1 | 3 431.3 | 80.1 | 87.2 |
| 22 | _10110_ | fall | _11073_ | nand2_1 | 3 480.9 | 45.9 | 49.6 |
| 23 | _10111_ | rise | _11075_ | nand2_1 | 3 568.1 | 80.1 | 87.2 |
| 24 | _10187_ | fall | _11151_ | nand2_1 | 3 617.7 | 45.9 | 49.6 |
| 25 | _10188_ | rise | _11153_ | nand2_1 | 3 704.9 | 80.1 | 87.2 |
| 26 | _10273_ | fall | _11235_ | nand2_1 | 3 754.5 | 45.9 | 49.6 |
| 27 | _10274_ | rise | _11237_ | nand2_1 | 3 841.7 | 80.1 | 87.2 |
| 28 | _10369_ | fall | _11324_ | nand2_1 | 3 891.2 | 45.9 | 49.5 |
| 29 | _10370_ | rise | _11326_ | nand2_1 | 3 978.4 | 80.1 | 87.2 |
| 30 | _10465_ | fall | _11412_ | nand2_1 | 4 028.0 | 45.9 | 49.6 |
| 31 | _10466_ | rise | _11414_ | nand2_1 | 4 115.2 | 80.1 | 87.2 |
| 32 | _10554_ | fall | _11494_ | nand2_1 | 4 164.8 | 45.9 | 49.6 |
| 33 | _10555_ | rise | _11496_ | nand2_1 | 4 252.0 | 80.1 | 87.2 |
| 34 | _09217_ | fall | _11574_ | nand2_1 | 4 301.6 | 45.9 | 49.6 |
| 35 | _09218_ | rise | _11576_ | nand2_1 | 4 388.8 | 80.1 | 87.2 |
| 36 | _09297_ | fall | _11647_ | nand2_1 | 4 438.3 | 45.9 | 49.5 |
| 37 | _09298_ | rise | _11649_ | nand2_1 | 4 525.5 | 80.1 | 87.2 |
| 38 | _09368_ | fall | _11714_ | nand2_1 | 4 575.1 | 45.9 | 49.6 |
| 39 | _09369_ | rise | _11716_ | nand2_1 | 4 662.3 | 80.1 | 87.2 |
| 40 | _09433_ | fall | _11774_ | nand2_1 | 4 711.9 | 45.9 | 49.6 |
| 41 | _09434_ | rise | _11776_ | nand2_1 | 4 799.1 | 80.1 | 87.2 |
| 42 | _09496_ | fall | _11832_ | nand2_1 | 4 848.7 | 45.9 | 49.6 |
| 43 | _09497_ | rise | _11834_ | nand2_1 | 4 935.9 | 80.1 | 87.2 |
| 44 | _09551_ | fall | _11883_ | nand2_1 | 4 985.5 | 45.9 | 49.6 |
| 45 | _09552_ | rise | _11885_ | nand2_1 | 5 072.6 | 80.1 | 87.1 |
| 46 | _09600_ | fall | _11928_ | nand2_1 | 5 122.2 | 45.9 | 49.6 |
| 47 | _09601_ | rise | _11930_ | nand2_1 | 5 209.4 | 80.1 | 87.2 |
| 48 | _09639_ | fall | _11965_ | nand2_1 | 5 259.0 | 45.9 | 49.6 |
| 49 | _09641_ | rise | _11967_ | nand2_1 | 5 346.2 | 80.1 | 87.2 |
| 50 | _09676_ | fall | _11999_ | nand2_1 | 5 395.8 | 45.9 | 49.6 |
| 51 | _09677_ | rise | _12001_ | nand2_1 | 5 483.0 | 80.1 | 87.2 |
| 52 | _09704_ | fall | _12026_ | nand2_1 | 5 532.6 | 45.9 | 49.6 |
| 53 | _09706_ | rise | _12028_ | nand2_1 | 5 619.8 | 80.1 | 87.2 |
| 54 | _09727_ | fall | _12047_ | nand2_1 | 5 669.3 | 45.9 | 49.5 |
| 55 | _09728_ | rise | _12049_ | nand2_1 | 5 756.5 | 80.1 | 87.2 |
| 56 | _09741_ | fall | _12061_ | nand2_1 | 5 806.1 | 45.9 | 49.6 |
| 57 | _09742_ | rise | _12063_ | nand2_1 | 5 893.3 | 80.1 | 87.2 |
| 58 | _9191_ | rise | _12073_ | xor2_1 | 6 128.5 | 247.2 | 235.2 |
Cells
at N = 16 · scored
| cell | count | µm² each | µm² in all | share |
|---|---|---|---|---|
xor2_1 | 464 | 8.7584 | 4063.8976 | 47.2% |
nand2_1 | 684 | 3.7536 | 2567.4624 | 29.8% |
and2_1 | 286 | 6.2560 | 1789.2160 | 20.8% |
xnor2_1 | 19 | 8.7584 | 166.4096 | 1.9% |
nand2b_1 | 2 | 6.2560 | 12.5120 | 0.1% |
nor2_1 | 1 | 3.7536 | 3.7536 | 0.0% |
| total | 1 456 | 8603.2512 |
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 |
|---|---|---|---|
NAND | 684 | 1.000 | 684.000 |
XOR | 464 | 2.000 | 928.000 |
AND | 286 | 1.333 | 381.238 |
XNOR | 19 | 2.000 | 38.000 |
ORNOT | 2 | 1.333 | 2.666 |
NOR | 1 | 1.000 | 1.000 |
| total | 1456 | 2034.904 |
The reference
- task
mul- design
mul_tree.svsha256dca1d7da6838f8f7eaaa2ee3094aa6148f5881d99fb5693c546da161d9056d37- proof
mul_tree.lean, 322 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_tree.svmul_tree.lean
Area against time
- 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
the designs as numbers, by score
| design | kind | area (µm²) | time (ps) | score (µm²·ns) |
|---|---|---|---|---|
| late-carry | submission | 7 961.39 | 5 342 | 42 530 |
dadda_rc_16 | baseline, not proved | 8 230.39 | 5 461 | 44 946 |
dadda_ks_16 | baseline, not proved | 8 937.32 | 5 148 | 46 009 |
| plus-minus-two | submission | 7 978.90 | 6 329 | 50 498 |
mul_tree_h | proved reference · par | 8 563.21 | 5 992 | 51 311 |
mul_tree · this design | proved reference | 8 603.25 | 6 129 | 52 729 |
mul_wallace | proved reference | 8 966.10 | 5 982 | 53 635 |
yosys_mul | baseline, not proved · banned operator | 8 825.96 | 6 261 | 55 259 |
mul_n | proved reference | 8 290.45 | 10 907 | 90 424 |
mul_n_byhand | proved reference | 8 290.45 | 10 907 | 90 424 |
- 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
the designs as numbers, by score
| design | kind | area (µm²) | time (ps) | score (µm²·ns) |
|---|---|---|---|---|
dadda_ks_16 | baseline, not proved | 133.174 | 902 | 120.1 |
| late-carry | submission | 120.854 | 1 088 | 131.5 |
dadda_rc_16 | baseline, not proved | 123.391 | 1 100 | 135.7 |
mul_tree_h | proved reference · par | 127.954 | 1 160 | 148.4 |
yosys_mul | baseline, not proved · banned operator | 131.789 | 1 139 | 150.1 |
mul_tree · this design | proved reference | 128.552 | 1 191 | 153.1 |
| plus-minus-two | submission | 119.746 | 1 307 | 156.5 |
mul_wallace | proved reference | 133.917 | 1 186 | 158.8 |
mul_n | proved reference | 123.930 | 1 981 | 245.5 |
mul_n_byhand | proved reference | 123.930 | 1 981 | 245.5 |
Reproduce
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/mul/reference/mul_tree.sv --task tasks/mul --path \
--json out.json --netlist scored.v --repaired-netlist repaired.v
Expect, in out.json:
- ppa.netlist_sha256
e3cd41f4226ce33d1990d9b5ec3297d9e8d4ca7b7b7c596491c02b6379678ea2- ppa.repair.netlist_sha256
8b0ed1dbc11ad9b8301feb7d1cb4069cb46494cc00ab2e86721371a93bb7db41- ppa.area_e4um2_sky130
86032512- ppa.delay_ps_sky130
6129
The schematic and the critical-path data are site/schematics/mul/dca1d7da6838f8f7.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 a70d73d9a220079d…).
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/mul/reference/mul_tree.sv --task tasks/mul --pdk asap7 --no-mapped \
--json out.json
Expect, in out.json:
- ppa.netlist_sha256
e3cd41f4226ce33d1990d9b5ec3297d9e8d4ca7b7b7c596491c02b6379678ea2- ppa.repair.netlist_sha256
b26b9b997eca012dda81d81d65e9e2d186deedf45ce841cb4ad5892b0e9acbcb- ppa.area_e5um2_asap7
12855186- ppa.delay_ps_asap7
1191
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.