Skip to content

About

Claude Code plugin: design-space & power exploration skills for the boson EDA toolkit

Resources

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

 

History

24 Commits

Folders and files

Repository files navigation

boson-explore

A Claude Code plugin of design-space and power exploration skills for boson, partcl's GPU-accelerated EDA toolkit. Each skill drives Claude through a real synthesis → STA → power sweep — every number in the output table is from an actual boson run, not an estimate.

boson itself is partcl's product and is not included here; you need a boson binary and a Liberty (.lib) file for your standard-cell library to use these skills. The bundled example design needs neither a paid PDK nor a testbench — see below.

What's in here

Four skills. Each SKILL.md is a short router: what the skill is for, the rules every mode shares, and a table that sends Claude to the one reference file the task needs. The detailed workflow loads only when that mode is chosen.

  • skills/boson-explore — explore a block's area/power/timing design space with real boson runs.
    • Tradeoff table (references/tradeoff-table.md) — Sweep clock period and/or RTL parameters through boson, get back an area/power/timing tradeoff table. Auto-invoked by Claude when you ask things like "sweep this design and show me the power/timing tradeoff" or "which config is smallest".
    • Sweep video (references/sweep-video.md) — Run a parameter × clock-period sweep (one real compile+place+STA+power per point, DEF written) and render it as an animated GIF/MP4: a boson terminal replaying each point's compile, the parameter grid lighting up, a PPA scatter (area vs achieved clock, size = power) filling in, and the real placement of each point. Ends on the Pareto front. Triggers on "make a sweep video", "animate the PPA space".
  • skills/boson-close-timing — close timing or find fmax without changing the RTL: constraints first, then the cheapest recipe.
    • Effort ladder (references/ladder.md) — Close timing at a target clock with the cheapest boson recipe that works: an escalation ladder (-effort high → -draws 3 → -select_candidates → -datapath_search, optional eco_optimize) that stops at the first rung meeting timing, plus an fmax search. Hands back the ladder table and the recommended compile Tcl. Triggers on "close timing at X ns", "what's the fmax", "which effort should I use". Sample run (picorv32 @ 7 ns on sky130, --target-ns 7 --find-fmax --max-rung 2):

      recipe period (ns) timing WNS (ns) achieved (MHz) cells area (µm²) power (mW)
      medium 7 VIOLATED -0.899 127 14,365 139,411 22.0
      high 7 VIOLATED -0.899 127 14,365 139,411 22.0
      high+draws3 7 VIOLATED -0.899 127 14,364 139,405 22.0
      medium 7.9 MET +0.001 127 14,366 139,414 19.5
      medium 7.74 VIOLATED -0.159 127 14,364 139,406 19.9

      Verdict: no rung closes 7 ns; fmax ≈ 127 MHz (closes at 7.9 ns, fails at 7.74). On this core the extra effort and placement draws changed nothing — the critical path is architectural, which is what boson-rtl-optimize (meet timing) is for.

    • Constraint and engine loop (references/constraint-engine-loop.md) and placement continuity (references/placement-continuity.md) for suspect SDC, synthesis failures and QoR that moves after netlist edits.

  • skills/boson-rtl-optimize — change the RTL with boson as the judge.
    • Meet timing (references/meet-timing.md) — When settings can't close timing and the RTL has to change: timing_probe.py turns a fast boson compile into critical paths that map back to source (launch/capture register names survive synthesis, plus RTL-named nets, logic depth, slowest cells, fanout), and the skill drives an edit → probe → edit loop with hard rules — non-RTL levers first, one edit per probe, restructure before pipeline, ask before any latency change, clean git tree, run the project's tests, confirm at medium effort. Sample probe (picorv32 @ 5 ns on sky130):

      period 5 ns · effort fast · WNS -1.442 ns (VIOLATED) · 252/4234 endpoints violating · 14810 cells
      ### path 1: slack -1.442 ns (VIOLATED), 21 logic stages, arrival 6.179 ns
      - from `latched_store_reg/Q`
      - to   `mem_addr_reg[31]/D`
      - RTL-named nets on the path: `latched_store`
      - slowest stages: sky130_fd_sc_hd__or4_1 0.659 ns, sky130_fd_sc_hd__or4_1 0.653 ns, sky130_fd_sc_hd__a22oi_4 0.498 ns
      - high fanout: `n2972` drives 86 loads
      
    • Evolve (references/evolve.md) — An evolutionary RTL-optimisation loop with boson as the evaluator. The objective is max Fmax (1/(T − WNS)), min area or min power, optionally with caps on the others, e.g. area ≤ +15 %. Each candidate is one hypothesis, committed, passed through an equivalence gate (lint, sound formal miter, lockstep co-simulation with directed corners), then scored by boson: compile → place → repair → timing/area/power. The skill includes anti-gaming rules, a results ledger and a budget. It ends with a declared final that is rerun and signed off. Triggers on "optimise this RTL for Fmax", "run an RTL optimisation loop".

  • skills/boson-diagnose — why a boson result is bad, and the evidence for partcl.
    • Journal debug (references/journal-debug.md) — Run on your own machine against a boson run of your design: reads the netlist, timing / QoR / check_timing reports, SDC, log and boson's decision journal (decision_log_file), ties each failing path to the decisions that shaped it (adder architecture, sizing that flip-flopped, hold repair that ate setup, repairs that were rolled back, ignored constraints, unbuffered high-fanout nets), lists the netlist's current issues, and builds boson-debug-bundle.tar.gz for partcl. Every design name, path, user/host name and library name is replaced by a consistent token (u3/r12_reg[4], clk0, LIBX); the decoding map stays with you, and a leak check must pass before the tarball is written. Nothing is uploaded. Triggers on "what did boson do wrong", "why is my netlist bad", "prepare a debug bundle for partcl".
    • Datapath audit (references/datapath-audit.md) — What boson actually built for the arithmetic on the critical paths: per adder/subtractor/comparator, the architecture the datapath selector chose (ripple, carry-select, Sklansky, Brent-Kung, Han-Carlson, ...), the mapped cells it puts on each path against that architecture's depth, and the share of its cells each logic rewrite (dc2, dretime, prefix_scan) restructured. Built on compile -provenance. Triggers on "did it use Han-Carlson or ripple", "did dc2 undo the adder".
    • Minimal repro (references/minimal-repro.md) — Debug a few paths that are far deeper than the clock allows: name the RTL construct on the path, compile it alone as a module-level boson run under the same clock, then A/B equivalent rewrites, widths and clocks of that construct. The result is a finding (coding-style sensitivity, architecture limit, or context) and a debug report that keeps RTL text and names in the user's environment. Includes path_levels.py, which counts logic levels per path, excluding buffers and inverters. Triggers on "is this the RTL or boson", "why is this path so deep", "the full run is too slow to debug".
    • Reference compare (references/compare-reference.md) — Explain why a boson netlist is worse than a reference netlist of the same RTL and library (another tool's result, or an earlier boson version's), in patterns partcl can fix. First checks the runs are comparable: boson version, a wire model recalibrated from the global route (PAR-252), app variables and the stage-by-stage QoR trajectory (run_ab.py). Then splits the std-cell area gap by mapping pattern with every cell classed by its Liberty function, not its name (cell_mix.py: full adders against split sum + carry cells, XOR/XNOR, muxes against complex gates, gates wired as XNOR by tied inputs, clock cells in data logic, VT mix), says what the XORs are for and compares the cone of one output (logic_patterns.py), compares buffer trees by distance and sink count with buffer spacing from the DEF (buffer_trees.py, route_layers.py), and groups failing paths into families with their buffer delay against the violation (path_families.py). Ends in ranked, evidence-backed findings, each with a concrete example and the next experiment. Triggers on "why is boson's area bigger than the other tool's", "why did the new version regress", "write up what we found for partcl".
    • DC datapath compare (references/compare-dc.md) — Compare a boson netlist with a Design Compiler netlist of the same RTL and split the QoR gap into the part inside the datapath operators (adders, multipliers, comparators, shifters) and the part outside them. Both netlists are timed in one boson session with the same libraries and SDC. DC cells are labelled by the operator names DC gives them (DP_OP_*, add_x_12, DW02_mult, ...), boson cells by -provenance. Each failing endpoint's slack gap is split exactly into datapath, logic, buffering, launch and setup. A label-balance check reports the split as inconclusive when DC flattened its operators. dw_microbench.py compares isolated operators in both tools. Triggers on "how much of the gap to the DC netlist is in the datapath". Design Compiler and DesignWare are trademarks of Synopsys, Inc.
    • Liberty table shapes (references/liberty-shapes.md) — Check that boson reads every table shape in your Liberty files. shape_census.py groups every table into shape classes (table, timing_type, variables in order, dimensions, overrides) and flags tables whose value count does not fit their own grid. shape_probe.py loads one verbatim example of each class into boson in isolation, records load errors and warnings, and times delay, transition, clock-to-Q, setup, hold, recovery and removal tables at two exact, off-diagonal index points against the table's own values. The report stays local; an anonymized per-shape summary can be sent to partcl with report_feedback. Triggers on "boson can't parse my lib", "invalid constraint table", "does boson read every table correctly".
  • feedback/ — the standard "Skill feedback" section that every customer-facing skill ends its report with: off-script actions, missing framework, wrong guidance, missing inputs/coverage, and outcome. It is recorded in skill_feedback.json by skill_feedback.py, anonymized on the customer's machine, and sent to partcl only when the user sources the generated boson report_feedback script.
  • commands/ — slash commands that jump straight to a mode: /boson-dse, /boson-sweep-video (explore); /boson-ppa-optimize (close timing); /boson-rtl-fix, /boson-rtl-evolve (RTL optimize); /boson-diagnose, /boson-netlist-debug, /boson-datapath-audit, /boson-minimal-repro, /boson-reference-compare, /boson-dc-datapath-compare, /boson-liberty-shapes (diagnose).
  • designs/picorv32/ — a vendored copy of picorv32 (ISC license), a small RISC-V core with ~19 real synthesis-affecting parameters (BARREL_SHIFTER, ENABLE_FAST_MUL, COMPRESSED_ISA, ENABLE_IRQ, ...) — enough design space to make the tradeoff interesting from one file.

Quick start

/plugin marketplace add partcleda/boson-explore-plugin
/plugin install boson-explore@boson-explore-marketplace

(Or clone it and drop any skills/<name> directory into your own .claude/skills/ — the skills work standalone.)

Then, in a project (or just ask Claude directly):

Sweep picorv32 across a few clock periods and configs and show me the power/area/timing tradeoff.

Claude will reach for the boson-explore skill and run skills/boson-explore/scripts/boson_dse.py.

Or invoke the underlying script yourself:

python3 skills/boson-explore/scripts/boson_dse.py \
  --rtl designs/picorv32/picorv32.v --top picorv32 \
  --liberty <path-to-a-liberty-file> \
  --periods 6,8,12,20 \
  --presets min-area,balanced,max-perf

Point --liberty at any Liberty file for your own standard-cell library, or at SkyWater's open sky130 sky130_fd_sc_hd corner libs (https://github.com/google/skywater-pdk) to reproduce the example exactly.

Demo

Sweep video (boson-explore sweep video, picorv32 on sky130: ENABLE_FAST_MUL × TWO_CYCLE_ALU × COMPRESSED_ISA × {4, 6, 12 ns} — 24 real compile+place+STA+power runs, 4 in parallel, ~2 h wall on a busy host):

picorv32 24-point sweep — final frame

(Still frame; ▶ demo/picorv32_sweep24.mp4 is the 1080p video — the GIF of this one is ~60 MB, so it isn't checked in; render it yourself with --gif.) What it showed: the iterative multiplier configs reach 148–169 MHz when pushed with a 4 ns target, while ENABLE_FAST_MUL (a combinational multiplier) costs ~7K extra cells (+50 %) and lowers achieved clock to 100–120 MHz — its product path becomes the critical path. TWO_CYCLE_ALU and the C extension are within noise of each other. And the target matters: the same RTL lands at ~125 MHz with a 12 ns target because the timing-driven loop stops once it's met.

The smaller 8-point run (ENABLE_MUL × BARREL_SHIFTER × {8, 20 ns}) is in demo/picorv32_sweep.{gif,mp4}; it was made with:

S=skills/boson-explore/scripts/video
python3 $S/run_sweep.py --rtl designs/picorv32/picorv32.v --top picorv32 \
  --liberty <sky130_fd_sc_hd__tt_025C_1v80.lib> --lef <sky130_fd_sc_hd__nom.tlef> --lef <sky130_fd_sc_hd.lef> \
  --axis ENABLE_MUL=0,1 --axis BARREL_SHIFTER=0,1 --periods 8,20 \
  --color-by ENABLE_MUL --marker-by BARREL_SHIFTER \
  --label "ENABLE_MUL:0=no multiplier" --label "ENABLE_MUL:1=hardware MUL" \
  --label "BARREL_SHIFTER:0=serial shifter" --label "BARREL_SHIFTER:1=barrel shifter" \
  --title "picorv32 · sky130 · design space" --runs runs
python3 $S/render_video.py --runs runs --gif demo/picorv32_sweep.gif --mp4 demo/picorv32_sweep.mp4
point cells area (µm²) WNS (ns) achieved power
no MUL · serial shifter · 8 ns 12,570 122,081 −0.067 124 MHz 17.1 mW
no MUL · barrel shifter · 8 ns 13,295 125,960 +0.032 126 MHz 17.2 mW
MUL · serial shifter · 8 ns 13,788 136,560 +0.088 126 MHz 19.1 mW
MUL · barrel shifter · 8 ns 14,366 139,414 +0.101 127 MHz 19.2 mW
(same four at 20 ns) 12.4–14.3K 120–138K +6.2…+6.6 73–75 MHz 6.8–7.6 mW

The timing-driven compile hits ~125 MHz on sky130 for every config at the 8 ns target; the multiplier and barrel shifter cost ~5–15 % area and power and buy no fmax here. The 20 ns points are the low-power corner (the tool stops optimising once timing is met, so they land at ~7 mW).

Tradeoff table (boson-explore tradeoff table, preset sweep):

boson_dse.gif

Sample output

Real output from --rtl designs/picorv32/picorv32.v --periods 6,20 --presets min-area,balanced,max-perf against SkyWater sky130 (sky130_fd_sc_hd, tt corner):

Preset Period (ns) Timing WNS (ns) Cells Area (um^2) Power (mW)
min-area 6.0 VIOLATED -6.596 5310 52042.4 13.0898
min-area 20.0 MET 7.404 5310 52042.4 3.9270
balanced 6.0 VIOLATED -7.208 14811 140850.1 33.9246
balanced 20.0 MET 6.792 14811 140850.1 10.1774
max-perf 6.0 VIOLATED -14.467 18845 198915.8 38.9075
max-perf 20.0 VIOLATED -0.467 18845 198915.8 11.6723

The non-obvious part: max-perf (barrel shifter, fast multiplier, all IRQ/ counter features on) is not "faster" here — it has the worst WNS at both periods, because those features add combinational depth to the critical path per cycle. min-area closes timing at 20ns with 3x less power and a third of the cells max-perf needs, and still can't close at 6ns. That's the kind of tradeoff this skill is for surfacing — real numbers, not intuition.

Adding your own design / skill

The sweep script's PARAM_PRESETS dict is picorv32-specific — for another design, either edit it to that design's own parameters, or drive boson's compile ... -G NAME=VALUE flags directly (see skills/boson-explore/references/tradeoff-table.md for the exact command shapes boson expects).

A new workflow goes in as a mode of the skill whose intent it serves: a reference file under that skill's references/, its scripts under scripts/<mode>/, its tests under tests/<mode>/, and one row in the routing table of that skill's SKILL.md. Keep SKILL.md to the routing table and the rules every mode shares; a new skill is only for a new user intent that none of the four covers. PRs adding modes — floorplan / utilization sweeps, clock-gating power compares, effort-level compares — are welcome.

Disclaimer and no liability

These skills, scripts and documents are provided "AS IS", without warranty of any kind, express or implied, including fitness for a particular purpose and non-infringement. partcl accepts no liability for any use of them or for any result, decision, design, netlist, report or loss that comes from using them, as set out in sections 7 and 8 of the Apache-2.0 license. You are responsible for checking every result before relying on it, and for using third-party tools, their outputs and their results in accordance with your own licenses for those tools.

Design Compiler, DesignWare and PrimeTime are trademarks of Synopsys, Inc. Other product names are trademarks of their owners. They are named only to describe the files and reports these skills read; no endorsement or affiliation is implied.

License

This plugin's own code is Apache-2.0 (LICENSE). designs/picorv32/ is ISC-licensed, vendored from its upstream project — see designs/picorv32/LICENSE.

About

Claude Code plugin: design-space & power exploration skills for the boson EDA toolkit

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages