A budget nobody signed is advice; a budget with an owner per row is a contract the review can enforce, and the table is where that contract lives. NanoSoC's budgets are small enough to show the complete shape: area rows owned by block owners, power rows owned per domain, bandwidth rows owned per master, each with the margin rule that decides what a miss means.
Every row carries five fields: the item, the budgeted number, the owner who signed it, the margin rule that applies, and the current status. Ownership means the named person explains variances and proposes covers; it never means they may change the number alone. The margin rule says how much miss the row absorbs itself (restructure, trade) before escalation. Status is one of three words: on track, at risk, or over with a waiver in flight. The table below shows the NanoSoC shape with illustrative owners; the project fills real names.
Row | Budget | Owner (illustrative) | Margin rule | Status |
|---|---|---|---|---|
Core area 0.655 mm2 in 0.940 | 69.7% utilisation | Integrator | Headroom 0.285; trades then governance | On track |
Fabric area 0.040 mm2 | Synthesis estimate | Fabric owner | Trade with SBR slack first | On track |
RUN power 82.74 mW | State-table total | Power owner | 5% band after normalisation | On track |
DMA stream 341.3 MB/s | Against 361.4 supply | DMA owner | Placement rule first, then arbitration | At risk if same-bank |
SLEEP power 1.40 mW | Leakage-dominated | Power owner | Clamp count plus enables checked | On track |
The script checks the contract table mechanically: every row has an owner, a rule and a status, and the area rows still sum inside the budget.
rows = [
("core-area", 0.655, 0.940, "integrator"),
("xbar-area", 0.040, None, "fabric-owner"),
("run-power", 82.74, None, "power-owner"),
("dma-bw", 341.3, 361.4, "dma-owner"),
("sleep-power", 1.40, None, "power-owner"),
]
for name, value, limit, owner in rows:
assert owner, name
if limit is not None:
assert value <= limit, (name, value, limit)
owners = {r[3] for r in rows}
assert len(owners) >= 3
print(f"PASS: {len(rows)} rows owned by {len(owners)} owners; all limits hold")No unowned rows: every number has a name beside it.
Margin rules quoted per row, not one global sentence.
Status updated on a fixed monthly schedule, with at-risk rows carrying a dated recovery plan.
Audit the table monthly: confirm each owner still owns the row (reorganisations silently orphan rows), each number still matches the latest measurement, and each at-risk row has moved since last month or escalated. A row at risk for two cycles without escalation is the process failing, not the block.
Status values need working definitions or every owner grades generously. On track means measured inside the band with no trend toward the edge; at risk means inside the band but trending out, with a dated recovery plan attached; over means outside the band with a waiver or change entry in flight. Reorganisations orphan rows silently — a named owner who left the project is the same as no owner — so the audit confirms each name is a person who attended the last review, not a role on a chart.
Advice. Nobody explains its variance and nobody may change it, so it drifts until tapeout. Assign an owner before the next review or delete the row.