1. Status and Evidence
Honeycomb now has a first generated RTL cell tied to the book's documented
boundary. The book proves the executable semantics, kernel arithmetic,
block-float identity, small analytical design rules, the RTL DSL execute path
against step, the encoded-word fetch bridge feeding that execute path, the
abstract lifecycle protocol around reset, host writes, start, and execute
gating, and the mesh transport-and-composition model that lifts the single cell
to the flat fabric. The first-cell 256-entry physical memory index is explicit in those
contracts. A first sky130/OpenLane run was recorded for the earlier
inferred-memory cell; that run exposed the expected standard-cell memory
expansion and did not reach pre-PNR timing. The hot memories now sit behind
honeycomb_sram macro-adapter submodules, and a second sky130 synthesis run is
recorded against that boundary: the memories bind as SRAM macros and the mapped
flip-flop count collapses by roughly fifty times. The macro-backed
honeycomb_cell_mac now routes to a clean powered close, meeting setup and hold
across all nine corners. The book does not yet prove parser-level SystemVerilog
refinement, does not reach a signoff-clean GDS, and does not claim fabricated
silicon or measured Honeycomb hardware.
namespace Honeycomb
inductive Evidence where
| proved
| modeled
| recorded
| target
deriving Repr, DecidableEq
structure StatusClaim where
name : String
evidence : Evidence
closed : Bool
deriving Repr
structure SynthesisAttempt where
runDate : String
tool : String
pdk : String
flow : String
runTag : String
boundedMinutes : Nat
reachedPrePnrSta : Bool
yosysCheckProblems : Nat
memoriesRemaining : Nat
postDffCells : Nat
mappedSky130Flops : Nat
postDffSequentialAreaUm2 : String
finalAbcCompleted : Bool
deriving Repr
structure MacroSynthesisResult where
runDate : String
tool : String
pdk : String
flow : String
runTag : String
reachedPrePnrSta : Bool
checkProblems : Nat
inferredMemoriesRemaining : Nat
sramMacroInstances : Nat
physicalSramMacros : Nat
mappedCells : Nat
mappedSky130Flops : Nat
stdCellLogicAreaUm2 : String
oneSramMacroAreaUm2 : String
finalMapCompleted : Bool
cycleFaithful : Bool
deriving Repr
structure PnrAttempt where
runDate : String
tool : String
pdk : String
cell : String
clockPeriodNs : Nat
dieWidthUm : Nat
dieHeightUm : Nat
sramMacrosPlaced : Nat
reachedStage : String
nomCornerSetupMet : Bool
nomCornerHoldMet : Bool
routed : Bool
criticalPath : String
deriving Repr
structure MacTimingRun where
runDate : String
tool : String
pdk : String
clockPeriodNs : Nat
combWorstPathNs : String
combSlackNs : String
pipeWorstPathNs : String
pipeSlackNs : String
goldenEquivalent : Bool
deriving Repr
def honeycombStatus : List StatusClaim :=
[ { name := "fixed-width processor semantics", evidence := .proved,
closed := true },
{ name := "branch-free kernel dot correctness", evidence := .proved,
closed := true },
{ name := "cycle-level kernel scheduler refinement", evidence := .proved,
closed := true },
{ name := "block-float scale identity (an exact algebraic theorem: defer the shared scale to the block boundary; exponent/width/rounding representation is milestone-5 scope, stated in the chapter)", evidence := .proved,
closed := true },
{ name := "the machine computes the exact dot product (R5): n ISA steps of a resident kmac loop equal krun n under the prefix-fit obligation — both hardware wraps absorbed by the abstraction, accumulator exact as an integer (kmac_loop_exact)",
evidence := .proved, closed := true },
{ name := "quantized kernel no-overflow bounds", evidence := .proved,
closed := true },
{ name := "load lattice and utilization design rules", evidence := .modeled,
closed := true },
{ name := "GPU comparison constants", evidence := .recorded,
closed := true },
{ name := "generated single-cell RTL from Lean DSL", evidence := .recorded,
closed := true },
{ name := "single-cycle execute-path cycle-model refinement (cellExecCycle refines the ISA step)", evidence := .proved,
closed := true },
{ name := "cell execute stage refined at the AST level (R3): the generated case_-opcode statement tree, evaluated under a width/sign-aware semantics with read-stage wires pinned to the model, commits exactly execDecoded's pc/acc/pointers/halt/registers for every opcode and ALU funct — the hand-mirrored exec tree is no longer trusted by eye; preparing it caught and fixed the stw and funct-decode divergences",
evidence := .proved, closed := true },
{ name := "cell read/decode stage refined at the AST level (R3 complete): the base cell's combinational stage — field decode proved against the encoding layer, SystemVerilog's sign-extending widening assignments, operand formation, SRAM read addressing, and the st/stw write ports — computes from the sequential state and the encoded 32-bit instruction word exactly the overlay the exec-stage theorem consumes (cellRead_refines_envOf); the residual boundary is the honeycomb_sram read-port contract, whose address inputs are proved (cellRead_sram_addresses) and whose write ports carry exactly execDecoded's st/stw effect",
evidence := .proved, closed := true },
{ name := "pipelined-product exec arms refined (R3 complete): with prod pinned to the model's product for the committing instruction, the mac/fpipe dispatch tree commits execDecoded exactly on mac/kmac (cellMacExecC_mac/kmac); the fpipe tree is proved equal to the mac tree and, beyond the multiply arms, the dispatch is proved to select the base tree's own arm ASTs",
evidence := .proved, closed := true },
{ name := "encoded instruction fetch to execute-path refinement",
evidence := .proved, closed := true },
{ name := "abstract cell lifecycle refinement", evidence := .proved,
closed := true },
{ name := "fully synchronous-read cell refinement", evidence := .proved,
closed := true },
{ name := "pipelined fetch cell control-hazard refinement",
evidence := .proved, closed := true },
{ name := "generated pipelined-fetch RTL cell", evidence := .recorded,
closed := true },
{ name := "operand pipeline data-hazard safe-overlap theorem",
evidence := .proved, closed := true },
{ name := "full pipeline: composed fetch+operand overlap commits the ISA trace, one instr/cycle (proved)",
evidence := .proved, closed := true },
{ name := "run-level trace composition (R4): syncRun/pRun/fpRun are simulation theorems, not prose — 3n clocks of the sync cell, and the pipelined cells' computed schedules (at most 2n clocks, one per hit + two per bubble), each equal n iterations of the cycle model and, while the machine keeps executing, exactly n ISA steps (stepN)",
evidence := .proved, closed := true },
{ name := "generated synchronous-read RTL cell", evidence := .recorded,
closed := true },
{ name := "first-cell physical memory index contract", evidence := .proved,
closed := true },
{ name := "sky130/OpenLane inferred-memory synthesis attempt",
evidence := .recorded, closed := true },
{ name := "honeycomb_sram macro-adapter RTL boundary", evidence := .recorded,
closed := true },
{ name := "sky130 macro-adapter synthesis area", evidence := .recorded,
closed := true },
{ name := "sky130 macro place-and-route timing attempt",
evidence := .recorded, closed := true },
{ name := "pipelined-multiplier MAC closes timing (routed)",
evidence := .recorded, closed := true },
{ name := "pipelined-multiplier cell honeycomb_cell_mac (generated, golden)",
evidence := .recorded, closed := true },
{ name := "first routed macro cell: clean powered route, zero DRC, all nine corners met",
evidence := .recorded, closed := true },
{ name := "streaming kmac datapath: one MAC/cycle, routed clean on nine corners, 59 pJ/MAC measured",
evidence := .recorded, closed := true },
{ name := "generated general pipeline cell honeycomb_cell_fpipe (sync macros, read-stall interlock, golden)",
evidence := .recorded, closed := true },
{ name := "mesh transport and uniform-composition model", evidence := .proved,
closed := true },
{ name := "generated router and single-flit RTL from Lean DSL, golden-tested",
evidence := .recorded, closed := true },
{ name := "generated 1x2 multi-cell mesh RTL, host-write delivered across fabric",
evidence := .recorded, closed := true },
{ name := "cell-to-network aperture: net-store encodes the transport inject",
evidence := .proved, closed := true },
{ name := "network send is a conservative ISA extension (no regression, proved)",
evidence := .proved, closed := true },
{ name := "net-cell cycle model refines step and emits the packet, proved",
evidence := .proved, closed := true },
{ name := "dimension-order routing is deadlock-free (acyclic channel dependency)",
evidence := .proved, closed := true },
{ name := "generated net-cell and program-injection mesh RTL, golden-tested",
evidence := .recorded, closed := true },
{ name := "generated multi-hop line RTL: per-cell routers, store-and-forward, golden-tested",
evidence := .recorded, closed := true },
{ name := "generated 2x2 grid RTL: dimension-order routing turns a corner, golden-tested",
evidence := .recorded, closed := true },
{ name := "generated flow-controlled grid RTL: two packets contend, arbitrated, none lost",
evidence := .recorded, closed := true },
{ name := "general N×M mesh generator, emitted 3x3 with bidirectional links, golden-tested",
evidence := .recorded, closed := true },
{ name := "program on the mesh drives the fabric: cell-net st routes to a remote cell, golden-tested",
evidence := .recorded, closed := true },
{ name := "network backpressure: a net-store stalls until accepted, no packet dropped, golden-tested",
evidence := .recorded, closed := true },
{ name := "uniform tile array RTL: identical cell+router tiles, role by program, golden-tested",
evidence := .recorded, closed := true },
{ name := "remote boot: one tile starts another over the fabric, golden-tested",
evidence := .recorded, closed := true },
{ name := "remote boot loader: a tile loads a program into another's instr memory then starts it, golden-tested",
evidence := .recorded, closed := true },
{ name := "self-governed load capability: remote instr-write/start gated on target halted",
evidence := .recorded, closed := true },
{ name := "cross-tile schedule: one tile scatters work to several and gathers results, golden-tested",
evidence := .recorded, closed := true },
{ name := "hostless boot ROM: uniform image, coordinate self-selects the root, array self-boots, golden-tested",
evidence := .recorded, closed := true },
{ name := "capability-gated delivery: token+mailbox decode authorizes remote effects (unforgeable by exact 64-bit token, data confined to the mailbox, private state unwritable by peers) — proved, RTL twin golden-tested",
evidence := .proved, closed := true },
{ name := "fabric availability: round-robin bounded-wait fairness (now deployed in every station's arbiters, see R2 claim below) and a per-tile token-bucket injection quota bound a malicious tile's footprint (no starvation) — proved",
evidence := .proved, closed := true },
{ name := "router RTL refines the routing model: the generated honeycomb_router AST, under a DSL evaluation semantics, computes exactly routeDir/neighbour/arrival — proved",
evidence := .proved, closed := true },
{ name := "flit RTL refines InFlight.advance: under a sequential always_ff semantics the generated honeycomb_flit register update steps position by hop, carrying dst/payload, staying valid — proved",
evidence := .proved, closed := true },
{ name := "flit delivery timing refined: iterating the flit clock tracks InFlight.advanceN (hops k) and reaches the destination at exactly cycle manhattan src dst — proved",
evidence := .proved, closed := true },
{ name := "mesh delivery isolation refined: the generated per-cell delivery strobe fires for exactly the destination cell and no other (RTL image of injected_packet_delivered's isolation) — proved",
evidence := .proved, closed := true },
{ name := "capability decode RTL refines capDecode — all five effects (R6): the generated honeycomb_capgate, under the DSL semantics, computes exactly capDecode's effect including the read-tagged get gate (token via BitVec.toNat, op/is_read/halted mapped, 9-bit mailbox = inMailbox) — proved",
evidence := .proved, closed := true },
{ name := "capability hygiene (R6): the threat model is stated (adversarial programs, trusted fabric, plaintext tokens, guess-resistance-not-crypto); the allocator is proved well-formed (alloc_WF: bounded, pairwise-disjoint regions with pairwise-distinct tokens for the first 2^64 mints); the response-leg authorization gap is recorded at honeycomb_readresp",
evidence := .proved, closed := true },
{ name := "get response leg authorized (milestone 9, model): the read request carries a return capability and the reply is an ordinary capability-checked put through it — both legs of a lowered get are authorized at their gates, the served value lands in exactly the requester's reply cell and nowhere else, and a forged response is inert; the RTL echo of the return capability remains milestone-9 work (honeycomb_readresp still responds by convention)",
evidence := .proved, closed := true },
{ name := "flow-controlled station no-loss (per-input-port buffers): an input port accepts iff its own buffer is free, a live non-departing packet is held unchanged (backpressure never drops it), a departing one frees its buffer, a free buffer latches its port's offer — proved on the generated honeycomb_fstation AST",
evidence := .proved, closed := true },
{ name := "deadlock freedom transfers to the fabric's own resources: each station buffer is one directed channel, every wait edge strictly raises the buffer rank, and no ring of waiting buffers can close (no_bufwait_cycle) — the R1 shared-buffer head-on deadlock is structurally excluded, witnessed by the hline3 golden test (old station wedges, per-port station delivers both) — proved / recorded",
evidence := .proved, closed := true },
{ name := "flow-controlled hop (two composed stations): a concurrent-composition semantics for one east link proves a full link buffer holds the upstream (backpressure) and an empty one forwards the packet in one clock — it leaves the upstream buffer and arrives unchanged downstream, packet count conserved — proved",
evidence := .proved, closed := true },
{ name := "concurrent join (three composed stations, the fgrid2 corner): two upstreams offering one downstream on different ports the same cycle are both accepted at once — both upstreams free, both packets land unchanged in distinct per-port buffers, none lost — proved",
evidence := .proved, closed := true },
{ name := "output serialisation (one station, one link): two buffers contending for the same outgoing link are serialised by the deployed pointer round-robin arbiter — the winner's packet rides the offer and departs on the grant, the loser is held in place unchanged, and the pointer steps past the winner — proved (station_serialises)",
evidence := .proved, closed := true },
{ name := "round-robin fairness deployed in the fabric (R2): every station's output and delivery arbiters are the pointer scan rrFirst, with bounded wait proved against adversarial per-grant requests (rr_ptr_served_within: served within 5 grants); on the generated chain the rotated pointer serves the previous loser even against a refilled rival (station_serves_loser), and the tb_rrfair golden drives a line-rate flooder that starves transit under fixed priority but not under the deployed arbiter — proved / recorded",
evidence := .proved, closed := true },
{ name := "signoff-clean routed tile: honeycomb_cell_mac tightened to 2.49 mm^2 (2.24x), zero-DRC route, KLayout DRC + netgen LVS clean, setup/hold at all nine corners",
evidence := .recorded, closed := true },
{ name := "signoff-tile power ladder refreshed (R9): the record netlist (all memories ce-gated, nine-corner close) measured with the same vectorless and activity methods — 7.36 mW vectorless nominal TT (6.67-7.99 across corners), kmac 4.02 mW / 117 pJ per cycle / 0.58 nJ per MAC activity-driven; the gate-all result carries to the signoff tile, its 8-of-9-corner caveat is resolved, and the SRAM share of a running cell stays ~15%",
evidence := .recorded, closed := true },
{ name := "reset fully timed (R9): the blanket rst_n false-path — written for an old floorplan's quarter-nanosecond recovery miss, and silently untiming the reset's functional fan-in to the SRAM write enables — is removed; recovery, removal, and the functional paths meet at every corner on the record run, so the only remaining SDC exception is the combinational debug taps",
evidence := .recorded, closed := true },
{ name := "gate-level golden (R8): the routed signoff netlist and the routed kmac pipe pass their full golden suites at gate level (scripts/gls-mac.sh, gls-kmac.sh); the first run caught a real RTL-vs-netlist divergence — the clock-gated data macro froze the debug read port the RTL modeled as always-live — fixed by a one-cycle gate stretch plus a pulse read recipe, both now part of the RTL contract and exercised by both suites",
evidence := .recorded, closed := true },
{ name := "perimeter injection non-interference (milestone 8, model): destination-disjoint DMA injectors commute (dmaRun_comm — each injector's effect at a tile is a function of that tile alone), untargeted tiles are untouched, and each injector's weight/program regions land exactly as if it ran alone (dmaMultiRun_isolated + landed corollaries) — the region-to-injector assignment contract is the disjointness hypothesis; RTL rendering and the two-injector golden remain",
evidence := .proved, closed := true },
{ name := "assembler correctness (R10): pass 1's label map proved correct (asmFind_resolves), pass 2's emission indexed (asmEmit_get_blz/liLbl), and end to end an assembled branch encodes exactly the word distance to its label (assemble_blz_resolves); undefined/duplicate labels and unfitting offsets are build errors (the undefined-label hazard fired in production first — an orphaned branch target assembled to 0 and wedged the Sv32 walk), and a fitting offset survives encode/decode exactly (encWord_blz_imm_exact)",
evidence := .proved, closed := true },
{ name := "randomized lock-step co-sim (R8): seeded random programs with forward-only control flow (total by construction), their per-retire architectural trace computed by the Lean ISA step function itself, checked against the base cell every cycle and the five-phase signoff cell at every retire — at RTL and on the routed netlist at gate level — plus the final register file; covers out-of-range functs, full-range immediates, and wrapped memory indexes in bulk",
evidence := .recorded, closed := true },
{ name := "parser-level SystemVerilog refinement", evidence := .target,
closed := false },
{ name := "Honeycomb silicon", evidence := .target,
closed := false } ]
def honeycombCellOpenLaneAttempt : SynthesisAttempt :=
{ runDate := "2026-07-07",
tool := "OpenLane v2.3.10",
pdk := "sky130A open_pdks 0fe599b2afb6708d281543108caf8310912f54af",
flow := "Classic through OpenROAD.STAPrePNR",
runTag := "synthesis-2026-07-07-classic",
boundedMinutes := 30,
reachedPrePnrSta := false,
yosysCheckProblems := 0,
memoriesRemaining := 0,
postDffCells := 318547,
mappedSky130Flops := 40994,
postDffSequentialAreaUm2 := "875972.627200",
finalAbcCompleted := false }
def honeycombCellMacroSynth : MacroSynthesisResult :=
{ runDate := "2026-07-07",
tool := "Yosys 0.52",
pdk := "sky130 open_pdks 0fe599b2afb6708d281543108caf8310912f54af",
flow :=
"synth + dfflibmap + abc; honeycomb_sram adapters blackboxed as SRAM macros",
runTag := "macro-synth-2026-07-07",
reachedPrePnrSta := false,
checkProblems := 0,
inferredMemoriesRemaining := 0,
sramMacroInstances := 4,
physicalSramMacros := 5,
mappedCells := 16511,
mappedSky130Flops := 802,
stdCellLogicAreaUm2 := "125809.411200",
oneSramMacroAreaUm2 := "190712.550000",
finalMapCompleted := true,
cycleFaithful := false }
def honeycombCellSyncPnr : PnrAttempt :=
{ runDate := "2026-07-07",
tool := "OpenLane v2.3.10",
pdk := "sky130A open_pdks 0fe599b2afb6708d281543108caf8310912f54af",
cell := "honeycomb_cell_sync, adapters bound to sky130_sram_1kbyte_1rw1r_32x256_8",
clockPeriodNs := 30,
dieWidthUm := 2720,
dieHeightUm := 1300,
sramMacrosPlaced := 5,
reachedStage := "post-CTS STA; routing not reached",
nomCornerSetupMet := true,
nomCornerHoldMet := true,
routed := false,
criticalPath := "64-bit multiply-accumulate" }
def honeycombMacTiming : MacTimingRun :=
{ runDate := "2026-07-07",
tool := "OpenLane v2.3.10",
pdk := "sky130A open_pdks 0fe599b2afb6708d281543108caf8310912f54af",
clockPeriodNs := 25,
combWorstPathNs := "26.281357",
combSlackNs := "-0.777316",
pipeWorstPathNs := "20.841551",
pipeSlackNs := "4.871030",
goldenEquivalent := true }
def honeycombCellMacPnr : PnrAttempt :=
{ runDate := "2026-07-09",
tool := "OpenLane v2.3.10",
pdk := "sky130A open_pdks 0fe599b2afb6708d281543108caf8310912f54af",
cell := "honeycomb_cell_mac, pipelined multiplier and registered SRAM outputs, powered macros, tightened single-row tile",
clockPeriodNs := 29,
dieWidthUm := 2800,
dieHeightUm := 890,
sramMacrosPlaced := 5,
reachedStage := "detailed routing 100% with zero DRC, clean KLayout signoff DRC and netgen LVS; setup and hold close across all nine corners (worst setup +3.20 ns at the slow corner, worst hold +0.34 ns), on the tightened 2.49 mm^2 single-row tile with the reset fully timed (the rst_n false-path is gone: recovery, removal, and the functional reset fan-in to the SRAM write enables all meet), the gated memories debug-capable (one-cycle gate stretch), and only the combinational debug reads false-pathed; delay-mapped synthesis buys the ALU-writeback cone its margin at +38% stdcell area",
nomCornerSetupMet := true,
nomCornerHoldMet := true,
routed := true,
criticalPath := "sky130 SRAM access, ss_100C_1v60 slow corner" }
/-- Residual signal-DRC violations after the powered `honeycomb_cell_mac` route.
Zero once the SRAM macro `vccd1`/`vssd1` pins are tied through
`PDN_MACRO_CONNECTIONS`; the earlier 23 were signal-into-untied-power shorts. -/
def honeycombCellMacResidualDrc : Nat := 0
/-! Post-PNR sky130 estimates. Timing and area come from the `mac-tile5` final
metrics — the tightened single-row tile the PnrAttempt above records, with the
reset fully timed and the debug-capable gated memories — and are
machine-checked against the committed snapshot
(`openlane/records/honeycomb_cell_mac-mac-tile5.metrics.json`) by
`scripts/check-pnr-metrics.sh` in CI, so they can no longer silently drift
(review R9; the check immediately caught a stale 36.6 MHz STA-implied limit
carried over from the earlier, looser `mac-signoff4` floorplan). The power
constants below are the `mac-signoff4`-era estimates the lever-by-lever
narrative on the performance page is written against; the signoff tile's own
refreshed ladder (vectorless + activity, review R9) is the `Tile2` block
further down. None of these are measured silicon numbers. -/
def honeycombCellMacRoutedLowerBoundMhz : String := "34.5"
def honeycombCellMacStaImpliedLimitMhz : String := "38.8"
def honeycombCellMacPowerNomTtMw : String := "11.36"
def honeycombCellMacPowerRangeMw : String := "10.33-12.25"
def honeycombCellMacEnergyNomTtPjCycle : String := "329"
def honeycombCellMacEnergyRangePjCycle : String := "300-355"
def honeycombCellMacStdcellAreaMm2 : String := "0.278"
def honeycombCellMacSramAreaMm2 : String := "0.954"
def honeycombCellMacInstanceAreaMm2 : String := "1.231"
def honeycombCellMacDieAreaMm2 : String := "2.49"
/-! Latency from the RTL cycle model, confirmed by the golden simulation: the
five-phase mac cell (fetch, read, mul1, mul2, wb) retires one kmac MAC every five
physical clocks, so at the 29 ns routed clock the datapath does one MAC per 145 ns
(about 6.9 M MAC/s per cell). These are the current sky130 anchor's throughput
figures, not an architecture target. -/
def honeycombCellMacCyclesPerMac : Nat := 5
def honeycombCellMacNsPerMac : String := "145"
def honeycombCellMacThroughputMMacS : String := "6.9"
/-! Activity-driven power (nom_tt_025C_1v80, 29 ns clock). Gate-level simulation of
the routed `mac-signoff4` netlist under steady-state workloads dumps switching
activity that OpenROAD annotates onto the placed design (`scripts/power-activity.sh`,
`test/power/README.md`). This replaces the vectorless estimate above with a
workload-specific one. The headline finding: about 99% of the cell's power is
residency and clocking (SRAM macros ~70% + clock tree ~15% + registers ~15%); the
MAC arithmetic adds only ~1-2%. The fully-loaded 1.42 nJ/MAC is a residency-
dominated standing cost inflated by five-cycle-per-MAC control and no clock gating,
not an arithmetic-efficiency number; the marginal compute is ~30 pJ/MAC (~14 pJ of
it operand-dependent multiply). sky130 estimate, not silicon. -/
def honeycombCellMacActivityIdleMw : String := "9.59"
def honeycombCellMacActivityKmacMw : String := "9.80"
def honeycombCellMacActivityPjCycle : String := "284"
def : String := "70"
def : String := "15"
def : String := "15"
def : String := "2"
def honeycombCellMacFullLoadedNjPerMac : String := "1.42"
def honeycombCellMacMarginalPjPerMac : String := "30"
def honeycombCellMacMultiplyPjPerMac : String := "14"
/-! First residency lever applied and measured: access-driven clock gating of the
scalar data memory. The data memory is untouched by a resident kmac loop, yet the
ungated cell clocks its two SRAM macros every cycle. A `ce`-gated adapter (a real
sky130 integrated clock-gate cell in the synthesis wrapper) stops those macro
clocks when no load/store is in flight. Re-placed-and-routed (`mac-gated5`) it
closes setup and hold across all nine corners with zero DRC and clean LVS, and the
activity-driven power drops accordingly: SRAM macro power 6.71 -> 4.06 mW, kmac
total 9.80 -> 7.13 mW (about 27% lower), 1.42 -> 1.03 nJ/MAC. Functionally
transparent — the golden suite passes with the gating exercised. sky130 estimate,
not silicon; the deeper levers (gate the other memories, pipeline the MAC) remain. -/
def honeycombCellMacGatedIdleMw : String := "6.88"
def honeycombCellMacGatedKmacMw : String := "7.13"
def honeycombCellMacGatedMacroMw : String := "4.06"
def honeycombCellMacGatedNjPerMac : String := "1.03"
def honeycombCellMacGatedReductionPct : String := "27"
def honeycombCellMacGatedClosesTiming : Bool := true
/-! Second lever measured: extend access-driven gating to the instruction, weight
and stream memories. Their read addresses (pc, wptr, sptr) are stable across an
instruction's five phases, so each is clocked once per instruction (the fetch
phase) instead of every cycle; a host write clocks the addressed memory
regardless. Golden passes with the gating exercised. Activity-driven power falls
much further — SRAM macro power 6.71 -> 0.59 mW, kmac total 9.80 -> 3.72 mW (about
62% lower), 1.42 -> 0.54 nJ/MAC — beating the projected 0.58 nJ/MAC, and the SRAM
is no longer the dominant term (about 16% of cell power, down from 70%). Timing:
hold closes across all nine corners (the quasi-static host-preload paths are
false-pathed for hold in `timing.sdc`) with zero DRC and clean LVS, but one setup
path through instruction decode misses by 0.27 ns at the slow ss_100C_1v60 corner
— the integrated clock gate's read delay tightens it — so this gate-all point is
recorded as measured power on an 8-of-9-corner close, with full closure (e.g. a
slightly relaxed clock or leaving the instruction memory ungated) left as
follow-up. sky130 estimate, not silicon. -/
def honeycombCellMacGatedAllIdleMw : String := "3.10"
def honeycombCellMacGatedAllKmacMw : String := "3.72"
def honeycombCellMacGatedAllMacroMw : String := "0.59"
def honeycombCellMacGatedAllNjPerMac : String := "0.54"
def honeycombCellMacGatedAllReductionPct : String := "62"
def : String := "16"
/-! R9 power-ladder refresh, measured on the signoff tile itself
(2026-07-12, `mac-tile5` — the record run: all memories ce-gated with the
debug gate stretch, reset fully timed, delay-mapped synthesis). The ladder
above was measured on `mac-signoff4`-era netlists; the signoff tile is
re-measured on its own routed netlist with the same two methods:
`scripts/power-vectorless.sh` (default-toggle `report_power`, three stdcell
corners, TT-only SRAM library — the recorded caveat) and
`scripts/power-activity.sh` (gate-level simulation of the routed netlist,
VCD-annotated, nom_tt, 29 ns; the netlist reproduces the golden kmac
accumulator exactly). Vectorless: 7.36 mW nominal TT, 6.67–7.99 mW across
corners (213 / 193–232 pJ per cycle). Activity: idle 3.43 mW, clracc
4.08 mW, kmac 4.02 mW — 117 pJ/cycle, 0.58 nJ/MAC fully loaded at five
cycles per MAC; kmac decomposition: sequential 37.2%, clock 41.8%, macros
14.7%, combinational 6.3%. Conclusions: the gate-all result carries to the
signoff tile — kmac 3.72 mW on the gate-all experiment, 3.88 on the earlier
tile2 floorplan, 4.02 here, where the delta is the +38% delay-mapped
stdcell area — the gate-all point's recorded 8-of-9-corner caveat is
resolved (this tile closes all nine with the reset timed), and the SRAM
share of a running cell stays ~15%, down from ~70% ungated. Method notes,
recorded honestly: on the gated tile the idle→kmac step is dominated by
waking the kernel macros, so it is not comparable to the ungated
marginal-compute figure above; and the multiply-isolation differencing
(kmac − clracc) does not transfer — constant-address clracc measures
slightly *above* kmac — so no operand-dependent multiply figure is quoted
for the gated tile. sky130 estimates, not silicon. -/
def honeycombCellMacSignoffVectorlessNomTtMw : String := "7.36"
def honeycombCellMacSignoffVectorlessRangeMw : String := "6.67-7.99"
def honeycombCellMacSignoffVectorlessPjCycle : String := "213"
def honeycombCellMacSignoffVectorlessRangePjCycle : String := "193-232"
def honeycombCellMacSignoffIdleMw : String := "3.43"
def honeycombCellMacSignoffClraccMw : String := "4.08"
def honeycombCellMacSignoffKmacMw : String := "4.02"
def honeycombCellMacSignoffPjCycle : String := "117"
def honeycombCellMacSignoffNjPerMac : String := "0.58"
/-! Streaming kmac datapath measured -- the pipelining lever. The dedicated
dot-product cell `honeycomb_kmac_pipe` issues one MAC per cycle (the RTL image of the
scheduling chapter's shift-register pipeline, proved to retire the same accumulator at
any latency), so at the 29 ns clock it retires 34.5 M MAC/s, five times the five-phase
mac cell's 6.9. Re-placed-and-routed it closes setup and hold across all nine corners
with zero DRC and clean LVS at +10.28 ns setup slack (headroom to ~53 MHz), on 0.47
mm^2 -- two SRAM macros instead of five. Activity-driven power over 200 streamed MACs
is 2.02 mW at nom_tt, about 59 pJ/MAC: ~9x better than the all-memories-gated mac cell
(540 pJ/MAC) and ~24x better than the ungated baseline (1420 pJ/MAC), because the
dedicated datapath needs only the weight and stream macros and amortizes the standing
power over one MAC every cycle. sky130 estimate, not silicon. -/
def honeycombKmacPipeMMacS : String := "34.5"
def honeycombKmacPipePjPerMac : String := "59"
def honeycombKmacPipePowerMw : String := "2.02"
def honeycombKmacPipeInstanceAreaMm2 : String := "0.47"
def honeycombKmacPipeSetupSlackNs : String := "10.28"
def honeycombKmacPipeSramMacros : Nat := 2
def honeycombKmacPipeClosesTiming : Bool := true
def rtlReleased : Bool := true
def honeycombSiliconExists : Bool := false
theorem rtl_no_silicon_status :
rtlReleased = true /\ honeycombSiliconExists = false := ⊢ rtlReleased = true ∧ honeycombSiliconExists = false
All goals completed! 🐙
theorem openlane_attempt_did_not_reach_sta :
honeycombCellOpenLaneAttempt.reachedPrePnrSta = false := rfl
theorem openlane_attempt_erased_inferred_memories :
honeycombCellOpenLaneAttempt.memoriesRemaining = 0 := rfl
theorem macro_synth_completed_mapping :
honeycombCellMacroSynth.finalMapCompleted = true := rfl
theorem macro_synth_kept_memories_as_macros :
honeycombCellMacroSynth.inferredMemoriesRemaining = 0
/\ honeycombCellMacroSynth.sramMacroInstances = 4 := ⊢ honeycombCellMacroSynth.inferredMemoriesRemaining = 0 ∧ honeycombCellMacroSynth.sramMacroInstances = 4 All goals completed! 🐙
theorem macro_synth_collapsed_flops :
honeycombCellMacroSynth.mappedSky130Flops
< honeycombCellOpenLaneAttempt.mappedSky130Flops := ⊢ honeycombCellMacroSynth.mappedSky130Flops < honeycombCellOpenLaneAttempt.mappedSky130Flops All goals completed! 🐙
theorem macro_synth_not_cycle_faithful :
honeycombCellMacroSynth.cycleFaithful = false := rfl
theorem pnr_met_nominal_but_did_not_route :
honeycombCellSyncPnr.nomCornerSetupMet = true
/\ honeycombCellSyncPnr.routed = false := ⊢ honeycombCellSyncPnr.nomCornerSetupMet = true ∧ honeycombCellSyncPnr.routed = false All goals completed! 🐙
-- The pipelined multiplier routes with positive slack at the clock the
-- combinational one violates, while retiring the identical dot product.
theorem mac_pipeline_closes_and_is_equivalent :
honeycombMacTiming.goldenEquivalent = true := rfl
-- With the multiply pipelined, the SRAM outputs registered, the macro power
-- pins tied off, and a roomier floorplan, the cell is the first to route to a
-- clean powered close: zero DRC and setup+hold met across all nine corners.
theorem mac_cell_routes_with_timing_met :
honeycombCellMacPnr.nomCornerSetupMet = true
/\ honeycombCellMacPnr.routed = true
/\ honeycombCellMacResidualDrc = 0 := ⊢ honeycombCellMacPnr.nomCornerSetupMet = true ∧ honeycombCellMacPnr.routed = true ∧ honeycombCellMacResidualDrc = 0 All goals completed! 🐙
-- The five placed macros hold 5 KiB: four 256-entry memories, the 64-bit data
-- memory being two 32-bit macros. The die was chosen loosely for easy routing.
def pnrSramBits : Nat := honeycombCellSyncPnr.sramMacrosPlaced * 32 * 256
def pnrDieAreaUm2 : Nat := honeycombCellSyncPnr.dieWidthUm * honeycombCellSyncPnr.dieHeightUm
theorem pnr_sram_is_forty_kibit :
pnrSramBits = 40960 := ⊢ pnrSramBits = 40960 All goals completed! 🐙
end Honeycomb
The status vocabulary is intentionally conservative:
-
proved means the claim is a Lean theorem in this book.
-
modeled means the claim follows from a checked analytical model and its stated constants.
-
recorded means a measured or externally observed constant is copied into the book as evidence, but the book does not reproduce the measurement.
-
target means design intent, not completed implementation.
This distinction matters because Honeycomb is meant to become hardware. The book can be exact about a processor contract today while still being explicit that parser-level RTL refinement, timing closure, physical area, and power are future work.
The recorded OpenLane run is deliberately conservative evidence, not a usable
tile-area claim. It used the generated honeycomb_cell as-is, with inferred
256-entry program, scalar-data, resident-weight, and stream memories. Yosys
reported zero pre-synthesis check problems and no inferred latches, but replaced
all memories with registers. After DFF legalization the design contained 318547
cells and 40994 mapped sky130 flip-flops; the reported 875972.627200 square
microns covers the mapped sequential cells, while the remaining combinational
primitives were still before the final technology-mapped netlist. Final ABC
mapping did not complete within the bounded run, so no pre-PNR timing number is
recorded.
The important warning is architectural rather than cosmetic: the bare inferred-memory cell is a simulator and proof boundary, but standard-cell synthesis turns the hot storage into a very large flop-and-mux fabric. A credible physical area and timing number needs a macro-backed memory boundary.
The second run answers that warning. With the four hot memories behind
honeycomb_sram adapters, the same sky130 standard-cell library, and the
sky130_sram_1kbyte_1rw1r_32x256_8 macro bound as a blackbox, synthesis reaches
a complete technology-mapped netlist. The program, resident-weight, and stream
memories become one 32-bit SRAM macro each, and the 64-bit scalar-data memory
becomes a dual-read 64-bit adapter that maps to two of the same 32×256 macros,
for five physical SRAM macros in all. The mapped design keeps just 802 sky130
flip-flops for the register file and control state, down from 40994, and 16511
total mapped cells, down from 318547, with zero synthesis check problems and no
inferred memories left in the logic. The standard-cell logic occupies about
125809 square microns, dominated by the 64-bit MAC datapath; each SRAM macro is
about 190712 square microns, so a macro-backed tile is roughly nine-tenths SRAM
by area.
This is deliberately recorded as a synthesis-shape experiment, not a
cycle-faithful implementation. The proved honeycomb_sram adapter reads
combinationally, while the sky130 macro is a synchronous-read SRAM. Binding the
macro therefore demonstrates area and mappability at the documented boundary; a
cycle-accurate macro cell needs a registered-read pipeline stage and its own
refinement obligation.
That registered-read cell is the fully synchronous honeycomb_cell_sync, and a first
placed-macro OpenLane run was made against it. The four adapters bound to five
sky130_sram_1kbyte_1rw1r_32x256_8 macros — 5 KiB of SRAM in all: 256 words of
32 bits per macro, with the 64-bit data memory using two. The run reached
synthesis, floorplan, macro placement, clock-tree synthesis, and post-CTS static
timing. At a 30 ns clock the nominal corner met both setup and hold, but the slow
corner left the 64-bit multiply-accumulate path several nanoseconds short even
after post-CTS resizing, so routing was not attempted. The critical path is the
arithmetic, not the SRAM: closing it needs a slower clock or a pipelined
multiplier.
The area of that run is not a tile-area claim. The die was set to 2720 by 1300 microns, about 3.54 square millimeters, chosen loosely so the five macros and their routing had room; it is only about a third utilized. The real content is roughly one square millimeter — about 0.95 for the five SRAM macros and 0.13 for the standard-cell logic — so a tightened floorplan would be far smaller. What the run establishes is a real placed-and-clocked macro cell with an honest timing bottleneck, not a finished tile.
That bottleneck was then attacked directly. The critical path is the 32-bit signed multiply, not the accumulate: a combinational multiply-accumulate and one with the product merely registered route to essentially the same worst path, so the multiplier itself must be pipelined. Splitting the multiply into a half-width partial-product stage and a combine-and-accumulate stage — a two-cycle latency that the scheduling chapter's conservation law already proves leaves the accumulator unchanged — was placed and routed against the combinational baseline. Both were checked to retire the identical signed dot product first. At a 25 ns clock the combinational multiply-accumulate misses timing with a routed worst path of 26.3 ns (−0.78 ns slack), while the pipelined multiplier meets it with a 20.8 ns worst path (+4.87 ns slack): a roughly one-fifth shorter critical path, from a timing violation to comfortable margin, for the same arithmetic. A deeper split would shorten it further. This is the route by which the macro cell reaches timing closure — pipelining the multiply, with the kernel result already proved invariant to the added latency.
That multiplier was then folded into the cell. honeycomb_cell_mac is the fully
synchronous cell with the combinational multiply replaced by the two-stage
honeycomb_mul2, running each instruction over five phases — fetch, read, mul1,
mul2, wb — with the accumulate in the write-back phase taking the pipelined
product. It is generated from the same DSL, CI-checked, and passes the full
golden program suite with identical architectural results, so the integration is
correct. Placed and routed with the SRAM macros, it confirms the multiply is now
off the critical path: the worst path no longer starts in the multiplier but at
the instruction SRAM macro, whose clock-to-output access alone is about eleven
nanoseconds, followed by the decode logic it feeds. At a 20 ns clock the cell
improves on the combinational-multiply cell — from a −3.15 ns to a −2.23 ns
nominal-corner worst path — but does not close, and the slow corner behaves as
before, now on the SRAM path rather than the multiply. The honest lesson is that
pipelining the multiply was necessary but not sufficient: the next bottleneck is
the SRAM read itself, which closing requires registering the fetched instruction
into its own pipeline stage so the macro's access latency stops sharing a cycle
with the logic downstream of it.
That step was taken. The cell now re-registers its instruction, resident-weight, and streamed-operand SRAM outputs into standard-cell flip-flops each cycle, so the macro's roughly eleven-nanosecond clock-to-output is isolated on its own SRAM-to-register path, and decode and the multiplier both start from fast registers. This fits the same five-phase schedule -- the register consumes the slack of the read phase -- and the full golden suite still passes with identical results.
Placed and routed on five powered sky130_sram_1kbyte_1rw1r_32x256_8 macros
(scripts/pnr-mac.sh), with the macros' vccd1/vssd1 pins tied to VPWR/VGND
through PDN_MACRO_CONNECTIONS, detailed routing finishes 100% with zero DRC
violations, and post-route static timing closes setup and hold across all nine
corners at a 29 ns clock -- worst setup +1.66 ns, worst hold +0.15 ns at the slow
ss100C1v60 corner, after post-GRT design repair. This is the first Honeycomb
cell to reach a clean, powered physical close; earlier cells stalled in synthesis
or in the post-CTS timing resizer before ever routing.
Two earlier numbers were corrected along the way. A previously-recorded "22 ns closes all corners, 15 ns nominal" timing and "twenty-three residual DRC violations" shared one root cause: the SRAM macro power pins were left unconnected, so the router drove signal wires into the untied power shapes -- the DRC shorts -- and the timing was read off an unpowered netlist, which is not a physical result. Tying the macro power pins removed the shorts and moved the honest close to 29 ns. The residual max-slew and max-capacitance violations that remain (~937 at the slow corner on that loose die) are structural, on the SRAM macro pins and the clock tree, and are a signoff-waiver class rather than in-circuit failures.
That loose 3100 by 1800 micron (5.58 mm^2) die was then tightened to a true tile.
The real content is only about 1.13 mm^2 -- 0.95 for the five SRAM macros and just
0.18 for the standard-cell logic -- so the whitespace was the floorplan, not the
design. The five macros are packed into a single row with their pin-heavy south
edge facing one shared logic channel, so pin-escape routing distributes across the
full width instead of concentrating (a two-row layout, tried first, forced all
five macros' pins into one central channel and congested global routing). The die
comes down to 2800 by 890 microns -- 2.49 mm^2, about 47 percent utilized -- a
2.24-fold shrink that still routes clean. One signoff exception is declared in
the SDC: the combinational debug read ports, which are external observation taps
rather than in-circuit paths. The reset carries no exception at all (review R9):
the earlier blanket rst_n false-path — written for a floorplan that missed
recovery by a quarter nanosecond, and silently untiming the reset's functional
fan-in to the SRAM write enables — is removed, and recovery, removal, and the
functional paths all meet at every corner. The record run also carries the
one-cycle clock-gate stretch that makes the gated data memory debug-readable
(the R8 gate-level-simulation finding), and delay-mapped synthesis, which buys
the ALU-writeback cone its margin at +38 percent stdcell area (0.278 versus
0.204 mm^2; the die is unchanged). On this tile, detailed routing finishes 100
percent with zero DRC, setup and hold close across all nine corners (worst
setup +3.20 ns, worst hold +0.34 ns), and full signoff passes: KLayout DRC is
clean and netgen LVS matches the layout to the netlist, producing final GDS, LEF,
and lib views. The residual max-slew and max-capacitance (about 1300 at the slow
corner) are structural -- antenna diodes, the unmodeled top-level clock-input net,
and the vendor SRAM macro pins -- and are waived, not in-circuit failures. The
antenna class itself was re-evaluated with heuristic diode insertion (review R9):
it cuts the antenna waivers by two thirds but loads the nets with thousands of
extra slew and fanout waivers, a quarter more stdcell area, and 1.5 ns of setup
margin -- a worse ledger, so the record keeps no insertion and the antenna nets
stand as a documented tapeout-time item for a targeted per-net pass. So the
honest state is a signoff-clean, tile-area macro cell that closes timing at every
corner on powered macros, generated from the same proved DSL and passing the same
golden programs.