r2g-rtl2gds Skill
Execute a staged, artifact-first open-source EDA flow from specification to GDSII with full signoff checks using OpenROAD-flow-scripts (ORFS). Prefer deterministic scripts for execution, keeping the agent focused on planning, generation, diagnosis, and iteration.
Environment Setup
Every flow script sources scripts/flow/_env.sh on entry, which autodetects
ORFS + tool paths and lets the user override any single value. You do not
need to source anything manually.
Resolution order (first hit wins, per value)
- Variable already set in the caller's environment —
ORFS_ROOT=... run_orfs.sh ... wins unconditionally.
- User env file — path in
$R2G_ENV_FILE (if set).
- In-skill override file —
references/env.local.sh (copy from references/env.local.sh.template).
- ORFS-provided env —
$ORFS_ROOT/env.sh (once ORFS_ROOT is known).
- System-wide env —
/opt/openroad_tools_env.sh (if present).
- Autodetect —
command -v <tool> on $PATH, then a list of well-known install paths (e.g. $ORFS_ROOT/tools/install/OpenROAD/bin/openroad, $HOME/oss-cad-suite/bin/yosys, /usr/local/bin/klayout).
Checking what the skill found
bash scripts/flow/check_env.sh
Prints the resolved ORFS_ROOT, every tool binary it picked, and the
platforms it can see. Exits non-zero if a required tool is missing.
Overriding just a few values
# One-off override for a single run
ORFS_ROOT=/opt/ORFS OPENROAD_EXE=/opt/openroad/bin/openroad \
bash scripts/flow/run_orfs.sh design_cases/my_design nangate45
# Or persist overrides in a file
cp references/env.local.sh.template references/env.local.sh
# ...then edit the exports you care about; every subsequent flow picks them up.
Available platforms
nangate45, sky130hd, sky130hs, asap7, gf180, ihp-sg13g2 (default: nangate45).
Workflow
1. Normalize the Specification First
- Convert free-form requirements into a structured specification before writing RTL.
- Read
references/spec-template.md and produce input/normalized-spec.yaml.
- If clock/reset, IO, target flow, or timing targets are missing, stop and ask the user or record explicit assumptions.
2. Initialize a Project Directory
- Create a run folder under
design_cases/<design-name>/ using scripts/project/init_project.py.
- The layout follows
references/workflow.md.
- Directories created:
input/, rtl/, tb/, constraints/, lint/, sim/, synth/, backend/, drc/, lvs/, rcx/, reports/.
3. Generate RTL and Testbench Separately
- Write RTL to
rtl/design.v.
- Write testbench to
tb/testbench.v.
- Keep assumptions and design notes in
reports/rtl-notes.md.
4. Run Validation in Strict Order
- Run
scripts/project/validate_config.py <project-dir> before ORFS backend to catch config/RTL issues early.
- Run lint/syntax checks before simulation.
- Run simulation before synthesis.
- Run synthesis before backend (ORFS).
- Do not skip failed stages unless the user explicitly requests it.
5. Run Backend with ORFS
- Prepare
constraints/config.mk and constraints/constraint.sdc.
- Use
scripts/flow/run_orfs.sh to invoke the ORFS Makefile.
- ORFS runs place-and-route natively (no Docker required).
- Collect results from the ORFS results directory.
5b. Check Timing Before Signoff (Tiered WNS + TNS)
After ORFS completes, extract PPA and run the timing gate:
- Run
scripts/extract/extract_ppa.py <project-dir> reports/ppa.json to extract timing metrics.
- Run
scripts/reports/check_timing.py <project-dir> to classify WNS and TNS and write reports/timing_check.json.
- The script independently classifies WNS and TNS, then takes the worse of the two as the combined tier. A design with small WNS but large TNS (many slightly-violating paths) is caught.
- Read
reports/timing_check.json and act on the tier:
| Tier |
Criteria |
Agent Action |
| clean |
WNS >= 0, TNS >= 0 |
Proceed to signoff. |
| minor |
WNS >= -2.0 AND TNS >= -10.0 |
Auto-fix: update clk_period in constraint.sdc to suggested_clock_period from the JSON, then re-run backend. Report the fix to the user after the fact. |
| moderate |
WNS >= -5.0 AND TNS >= -100.0 (but not clean/minor) |
Stop. Present the numbered options from the JSON to the user. Wait for their choice. |
| severe |
WNS < -5.0 OR TNS < -100.0 |
Stop. Present options with strong warning. |
| unconstrained |
WNS > 1e+30 |
Stop. SDC clock port mismatch. Present options. Do NOT proceed. |
- The JSON includes
wns_tier and tns_tier fields so the agent can explain which metric triggered the tier (e.g., "TNS escalated this from minor to moderate").
- Only proceed to signoff checks (step 6) after timing is resolved.
5a. (Optional) Fmax search — find the fastest closing period
Before committing to a clock period, you can characterize the design's Fmax:
python3 scripts/reports/fmax_search.py <project-dir> [platform] [--verify]
Loose-first search using cheap placement-stage timing (each probe runs only
ORFS_STAGES="synth floorplan place"). It reports a predicted-signoff Fmax
(reports/fmax_search.json), corrected by a learned per-family slack-deterioration
model. The number is a proxy (UNVERIFIED) — post-place timing is optimistic vs
signoff. Pass --verify to confirm the winner with one full flow (and feed the
result back to tighten the model). This does NOT replace the step-8 check_timing
gate, which still runs on the final backend.
Knobs: --probe-timeout, --place-fast (whole-search conservative lower bound
for hang-prone designs), --keep-variants. The search is sequential; cross-design
parallelism is achieved by running multiple invocations concurrently.
6. Run Signoff Checks (DRC, LVS, RCX)
After a successful backend run, run signoff checks in order:
DRC (Design Rule Check)
Two tool options are available:
KLayout DRC (default) — scripts/flow/run_drc.sh <project-dir> [platform]
- Uses ORFS
make drc target with platform .lydrc rules
- Outputs:
drc/6_drc.lyrdb, drc/6_drc_count.rpt, drc/6_drc.log
Magic DRC (sky130 only) — scripts/flow/run_magic_drc.sh <project-dir> [platform]
- Uses Magic's built-in DRC engine with sky130A tech file
- Requires the sky130A PDK; the script reads
$PDK_ROOT/sky130A/libs.tech/magic/sky130A.tech
(set PDK_ROOT via references/env.local.sh — /opt/pdks is only the fallback default).
- Outputs:
drc/magic_drc.rpt, drc/magic_drc_count.rpt, drc/magic_drc_result.json
- Supported platforms: sky130hd, sky130hs
LVS (Layout vs Schematic)
Two tool options are available:
KLayout LVS (default) — scripts/flow/run_lvs.sh <project-dir> [platform]
- Uses ORFS
make lvs target with platform .lylvs rules + CDL netlist
- Gracefully skips platforms without LVS rules (produces
lvs/lvs_result.json with status "skipped")
- Outputs:
lvs/6_lvs.lvsdb, lvs/6_lvs.log, lvs/6_final.cdl
- nangate45: uses adapted FreePDK45 rules with
connect_implicit("VDD"/"VSS") for bulk merging and schematic.purge for unused cell pins (e.g., QN on DFFR_X1)
- Large design warning: KLayout LVS on designs >100K cells (black_parrot, swerv) takes >60 minutes. Use
LVS_TIMEOUT=7200 for these designs. The default 3600s may not be enough.
Netgen LVS (sky130 only) — scripts/flow/run_netgen_lvs.sh <project-dir> [platform]
- Two-step flow: Magic extracts SPICE from GDS, then Netgen compares against Verilog netlist
- Requires the sky130A PDK (Magic tech +
$PDK_ROOT/sky130A/libs.tech/netgen/sky130A_setup.tcl).
Set PDK_ROOT via references/env.local.sh; /opt/pdks is only the fallback default.
- Outputs:
lvs/extracted.spice, lvs/netgen_lvs.rpt, lvs/netgen_lvs_result.json
- Supported platforms: sky130hd, sky130hs
- This is the production sky130 LVS path — prefer it over KLayout LVS on sky130 (the
ORFS KLayout sky130 rule deck is not production-grade; see
references/failure-patterns.md,
"sky130 LVS").
- Antenna-diode designs are handled automatically: the script normalizes Magic's diode
X-subcircuit instances to D devices (perim=→pj=) and runs netgen with
MAGIC_EXT_USE_GDS=1, so sky130_fd_sc_hd__diode_2 matches instead of flattening.
- Designs with port-to-port feedthroughs (
assign out_port = in_port) need
export POST_GLOBAL_PLACE_TCL = <skill>/scripts/flow/orfs_hooks/buffer_port_feedthroughs.tcl
in config.mk before the backend run — SPICE cannot express two top-level ports on one
net, so without the hook LVS fails "Top level cell failed pin matching". The hook is a
no-op for designs without feedthroughs (safe to set everywhere); a backend re-run is
required when adding it. See references/failure-patterns.md, "sky130 LVS" cause 5.
RCX (Parasitic Extraction)
- RCX —
scripts/flow/run_rcx.sh <project-dir> [platform]
- OpenRCX parasitic extraction via OpenROAD
- Generates Tcl script (
rcx/run_rcx.tcl) with define_process_corner, extract_parasitics, write_spef
- Reads
6_final.odb from ORFS results, writes SPEF output
- Outputs:
rcx/6_final.spef, rcx/rcx.log, rcx/run_rcx.tcl
Extract results into JSON for reporting and dashboard:
scripts/extract/extract_drc.py <project-root> reports/drc.json
scripts/extract/extract_lvs.py <project-root> reports/lvs.json
scripts/extract/extract_rcx.py <project-root> reports/rcx.json
- If DRC/LVS is
fail, attempt automated real-layout fixes:
scripts/flow/fix_signoff.sh <project-dir> [platform] [--check drc|lvs|both]
(See references/signoff-fixing.md.)
- If the backend aborted at
route (congestion / DRT timeout, exit 124 — orfs_status=fail,
orfs_fail_stage=route), relieve it BEFORE signoff:
scripts/flow/fix_signoff.sh <project-dir> sky130hd --check route (lowers CORE_UTILIZATION so
DRT converges; learnable + A/B-validated route_relief). See references/failure-patterns.md
"Routing Congestion".
Fix-Learning Loop
The skill learns from every fix attempt so candidate strategies are proposed in
evidence-ranked order on the next similar violation.
- Record.
fix_signoff.sh and check_timing.py --journal append lossless,
session-keyed rows to reports/fix_log.jsonl (one per iteration: strategy, before/after
counts, pre-fix violation class, verdict). fix_signoff.sh uses an adaptive budget (base
3 iters, hard cap 8, early-stop after 2 non-improving iters past the base).
- Ingest. Step-10 ingest (
knowledge/ingest_run.py) reads fix_log.jsonl into the
Tier-1 fix_events table and writes a run_violations snapshot for every run — clean
or not (the full violation landscape). It then auto-runs fix_log_manager.manage()
(toggle R2G_FIX_AUTOLEARN, default on).
- Learn.
learn_heuristics.py derives Tier-2 fix_trajectories (per-episode path,
including abandoned episodes and failed strategies — negative learning) and folds them
into Tier-3 fix_recipes inside heuristics.json.
- Apply. When a recipe exists for the design's family/platform/violation class,
diagnose_signoff_fix.py reorders the strategy list by empirical clearance — there is no
hard gate, all real-fix strategies are always proposed, priority-ordered.
diagnose_signoff_fix.py <proj> --check drc --list prints the evidence-ranked candidate
set as JSON. Hard safety clamps are unchanged.
- Symptom index. Learned repair experience is keyed by a symptom signature
(
knowledge/symptom.py: {check, class, predicates} → a stable symptom_id), NOT the
design-family name. learn_heuristics.py emits a top-level symptoms[symptom_id]
projection in heuristics.json (pooled across families/platforms, with by_platform +
evidence_designs provenance); diagnose_signoff_fix.py looks recipes up by symptom and
seeds an informed cross-platform prior for untried strategies (so a fix learned on
nangate45 transfers to e.g. sky130hd). It also surfaces the matching active prose lesson
(via search_failures.lessons_for_symptom) at the fix-decision point. monitor_health.py
(degradation alerts) and analyze_execution.py (fix-proposal triage) are operator-invoked
CLIs over the same store.
See references/signoff-fixing.md ("Fix-Learning Loop") and knowledge/README.md.
Engineer Loop (campaign mode)
Use campaign mode when you need to run the full flow unattended across many designs — or
when you want the A/B-gated recipe-learning cycle to run autonomously. The campaign
orchestrator (scripts/loop/engineer_loop.py) drives the flow scripts, ingests results,
triggers learning, and manages A/B trials without human gates.
# Add a project to the campaign ledger
python3 scripts/loop/engineer_loop.py add \
--ledger design_cases/_batch/campaign.jsonl \
--project design_cases/my_design [--platform nangate45]
# Run the campaign (optionally limit to N designs)
python3 scripts/loop/engineer_loop.py run \
--ledger design_cases/_batch/campaign.jsonl [--max N]
# Inspect per-design state
python3 scripts/loop/engineer_loop.py status \
--ledger design_cases/_batch/campaign.jsonl
The ledger is JSONL (last-state-wins); kill/restart is safe — the campaign resumes where it
left off. States: pending → flow → signoff → fixing → clean | escalated | abandoned.
Hard rules for campaign mode:
- Phase-1 runs workers=1 (single-process); do not run two campaigns sharing a
DESIGN_NAME
concurrently.
- Never run two configs with the same
DESIGN_NAME + FLOW_VARIANT concurrently.
- Never run more than one LVS job concurrently for designs > 100 K cells.
- Only
promoted recipes affect live strategy ranking; shadow and candidate recipes are
inert until their A/B trial completes.
When the loop opens an escalation (unknown symptom, exhausted catalog, unseen crash, or
repeated regression), drain it following the agent runbook in
references/engineer-loop.md ("Escalation Drain"). That document also covers provenance
queries (trace_provenance.py) and the full safety-invariant list.
Platform Support Matrix
| Platform |
KLayout DRC |
KLayout LVS |
Magic DRC |
Netgen LVS |
RCX |
| nangate45 |
Yes |
Yes |
No |
No |
Yes |
| sky130hd |
Yes |
Yes |
Yes |
Yes |
Yes |
| sky130hs |
Yes |
Yes |
Yes |
Yes |
Yes |
| asap7 |
Yes |
No |
No |
No |
Yes |
| gf180 |
Yes |
Yes |
No |
No |
Yes |
| ihp-sg13g2 |
Yes |
Yes |
No |
No |
Yes |
7. Treat Artifacts as Source of Truth
- Save logs, reports, VCD waveforms, netlists, SPEF, configurations, and summary files.
- Prefer file outputs over GUI tools. GUI viewers like GTKWave/KLayout are optional helpers.
8. Diagnose Before Editing
- For failures, read
references/failure-patterns.md.
- Classify the failure: specification gap, RTL bug, testbench bug, synthesis issue, backend/configuration issue, DRC violation, LVS mismatch, or RCX extraction error.
- Fix the smallest plausible cause first.
9. Summarize Each Stage Clearly
- State pass/fail status.
- List key artifact paths.
- Record assumptions, blockers, and next recommended actions.
- For signoff: report DRC violation count, LVS match/skip status, RCX net count and total capacitance.
10. Ingest the Run into the Knowledge Store
After every flow — successful, failed, or partial — run:
python3 r2g-rtl2gds/knowledge/ingest_run.py design_cases/<project>
This reads the structured JSON artifacts produced by the extraction scripts
and appends one row to r2g-rtl2gds/knowledge/knowledge.sqlite. It never
parses raw ORFS logs.
Then rebuild derived artifacts:
python3 r2g-rtl2gds/knowledge/learn_heuristics.py
python3 r2g-rtl2gds/knowledge/mine_rules.py
knowledge/heuristics.json is consumed automatically by
suggest_config.py on the next project — no CLI changes required.
knowledge/failure_candidates.json is a review queue, not a rule
source. Surface new signatures to the user and, if confirmed, edit
references/failure-patterns.md by hand.
A family/platform pair appears in heuristics.json only after at least
3 successful runs under that configuration.
10b. Share / Transfer the Knowledge Store Across Users (git-friendly)
knowledge.sqlite is the tracked, committed store — a fresh clone is pre-trained
immediately. A binary SQLite blob cannot be combined across operators (git only
3-way-merges text; two operators' campaigns would conflict and one would clobber the
other), so when you need to share or merge experience across operators,
knowledge/knowledge_sync.py is an on-demand tool: it exports a deterministic,
git-friendly text bundle (knowledge/store/, one NDJSON file per table — regenerable,
not committed by default) and performs a real honesty-gated cross-operator union:
# After learning, re-export the committed text bundle (keeps it in sync with the DB):
python3 knowledge/knowledge_sync.py export
# A NEW user folds another operator's experience into their local store. The merge is
# ADDITIVE (dedups by natural content key — run_id/symptom_id are portable; surrogate
# ids are re-assigned) and is REFUSED+rolled back if it would break an honesty gate:
python3 knowledge/knowledge_sync.py merge --bundle path/to/their/store
python3 knowledge/knowledge_sync.py merge --from-db path/to/their/knowledge.sqlite
# Bootstrap a fresh store from a bundle only (rebuilds knowledge.sqlite):
python3 knowledge/knowledge_sync.py import --bundle knowledge/store --db knowledge/knowledge.sqlite
# Honesty CI gate (the real gate — runs the 5 honesty gates over the committed store):
python3 knowledge/honesty.py --db knowledge/knowledge.sqlite
# On-demand drift check for an EXPORTED bundle you intend to share (reports
# "no committed bundle" by design when none exists — NOT a CI gate post-revert):
python3 knowledge/knowledge_sync.py status
Commit workflow: knowledge.sqlite is the committed store — commit it (and
heuristics.json) after ingest/learn, as before. The knowledge/store/ bundle is gitignored
and only produced on demand (export) when you want to hand experience to another operator or
review a diff; status confirms an exported bundle matches the DB. After any merge, run
learn() + engineer_loop ab-drain so imported recipes re-validate locally. See
knowledge/README.md ("Sharing the store across users").
Hard Rules
- Do not start backend if simulation is failing.
- Do not start ORFS if synthesis failed or the top module is unclear.
- Do not start signoff checks (DRC/LVS/RCX) if backend did not produce a GDS/ODB.
- Run
check_timing.py after every backend run. It checks both WNS and TNS. For minor violations (WNS >= -2.0 AND TNS >= -10.0), auto-fix by increasing clock period and re-running. For moderate/severe/unconstrained, stop and present numbered fix options — do not proceed without the user's decision.
- Do not silently invent missing interfaces, clocks, resets, or timing targets without documenting assumptions.
- Prefer single-clock MVP flows. Macro designs (fakeram45) are supported with proper config (see "Macro / Hard Memory Designs"). Escalate to the user before attempting CDC, multi-clock, or DFT.
- Use the scripts in
scripts/ for repeatable operations instead of re-inventing shell commands each time.
- Do not hand-source any system env file before running EDA tools — every flow script sources
scripts/flow/_env.sh, which autodetects ORFS and tool paths (see "Environment Setup"). /opt/openroad_tools_env.sh is only one optional source in that chain and may be absent.
- When a batch produces a mix of pass/fail, diagnose with
references/failure-patterns.md (see "Batch-Campaign Failure Patterns") and apply the repo-level batch fixer before any code changes. That fixer (tools/fix_orfs_failures.py in the agent-r2g repository — not shipped with the installed skill) handles the six dominant failure modes (memory inference, IO-pin perimeter overflow, place density >1, PDN straps, missing include dirs, stage timeouts) by rewriting config.mk. When running standalone, apply the same patterns by hand using references/failure-patterns.md. Do not hand-edit configs case-by-case in batch — extend the fix tool so future batches self-heal.
- Floorplan sizing policy (validated on 495-design batch):
- Explicit DIE_AREA is only safe when pin count ≤ ~200 and RTL fits in the area. Prefer
CORE_UTILIZATION when in doubt.
- When PPL-0024 reports a required perimeter, derive
DIE_AREA = 0 0 S S with S = ceil((required_perim / 4) * 1.3) rounded up to 10um.
- For designs with memory inference, set
SYNTH_MEMORY_MAX_BITS = 131072 (default 4096 is too tight for register files and FIFOs).
Default Project Layout
design_cases/<design-name>/
├── input/
│ ├── raw-spec.md
│ └── normalized-spec.yaml
├── rtl/
│ └── design.v
├── tb/
│ └── testbench.v
├── constraints/
│ ├── config.mk
│ └── constraint.sdc
├── lint/
│ └── lint.log
├── sim/
│ ├── sim.log
│ └── output.vcd
├── synth/
│ ├── synth.ys
│ ├── synth.log
│ └── synth_output.v
├── backend/
│ └── RUN_<timestamp>/
│ ├── final/ # GDS, DEF, ODB
│ ├── logs/ # Per-stage logs
│ ├── reports/ # Timing, area, power
│ ├── drc/ # DRC results (copied)
│ ├── lvs/ # LVS results (copied)
│ └── rcx/ # RCX results (copied)
├── drc/
│ ├── 6_drc.lyrdb # KLayout DRC violation database (XML)
│ ├── 6_drc_count.rpt # Violation count
│ ├── 6_drc.log # DRC log
│ └── drc_run.log # Full make output
├── lvs/
│ ├── 6_lvs.lvsdb # KLayout LVS comparison database (XML)
│ ├── 6_lvs.log # LVS log
│ ├── 6_final.cdl # CDL netlist
│ ├── lvs_run.log # Full make output
│ └── lvs_result.json # Only if skipped (no rules)
├── rcx/
│ ├── 6_final.spef # SPEF parasitic data
│ ├── rcx.log # OpenRCX extraction log
│ └── run_rcx.tcl # Generated Tcl extraction script
├── labels/ # Dataset labels (Y): congestion/wirelength/timing/irdrop CSVs (run_labels.sh)
├── features/ # Dataset features (X): nodes/edges/metadata CSVs (run_features.sh)
├── reports/
│ ├── ppa.json # PPA metrics + geometry
│ ├── progress.json # ORFS stage completion
│ ├── run-history.json # Multi-run comparison
│ ├── run-compare.json # Baseline vs current delta
│ ├── diagnosis.json # Issue detection & suggestions
│ ├── drc.json # DRC summary (violations, categories)
│ ├── lvs.json # LVS summary (match/mismatch/skipped)
│ ├── rcx.json # RCX summary (net count, cap, res)
│ └── demo-summary.md # Human-readable summary
└── metadata.json
Resource Map
- Read
references/spec-template.md when the specification is incomplete or ambiguous.
- Read
references/workflow.md when you need the phase-by-phase execution order.
- Read
references/orfs-playbook.md before setting up or debugging the ORFS backend.
- Read
references/failure-patterns.md when a run fails and you need a triage path.
- Read
references/ppa-report-guide.md when summarizing synthesis/backend reports.
- Read
references/label-extraction.md when building the physical-design dataset (per-cell/per-net labels + stats).
- Read
references/feature-extraction.md when building the graph-feature (X) side of the dataset (per-node/per-edge/metadata CSVs + stats).
- Read
scripts/extract/techlib/ for the shared per-platform tech layer consumed by both stages: profile.py (supply voltage, tap patterns, cell-type strategy per ORFS platform), resolve.py (the Python backend for resolve_platform_paths.sh — same KEY=VALUE contract), def_parse.py (single DEF/SDC parser), lef.py (routing-layer names, pitch/direction, regex matcher), liberty.py (cell/pin/net classifiers), cell_types.py (cell_type_id map — curated for nangate45, runtime-built for all others).
- Use scripts in
scripts/ for initialization, spec normalization, environment checks, lint, simulation, synthesis, ORFS backend, DRC, LVS, RCX extraction, result collection, GDS preview rendering, dashboard generation, and run summaries.
- Use
scripts/flow/orfs_hooks/ for Tcl sourced into ORFS stages via the generic
PRE_<STAGE>_TCL / POST_<STAGE>_TCL env hooks (set them in config.mk, not the shell —
ORFS scrubs exported variables). Currently: buffer_port_feedthroughs.tcl
(POST_GLOBAL_PLACE_TCL) splits port-to-port feedthrough nets behind real buffers so
Netgen LVS top-level pins match; a no-op for designs without feedthroughs.
- Use
assets/examples/simple-arbiter/ as the first smoke-test case.
- Use
assets/config-template.mk and assets/constraint-template.sdc as default backend configuration templates.
Quick Start
Prerequisites
Required Tools (all installed on this machine):
python3 (3.13+)
yosys (synthesis)
iverilog + vvp (simulation)
openroad (place & route, OpenRCX)
Optional Tools (also available):
verilator (faster lint/simulation)
klayout (GDS visualization, DRC, LVS)
magic (DRC, SPICE extraction for sky130)
netgen-lvs (LVS comparison for sky130)
gtkwave (waveform viewing)
sta / opensta (static timing analysis)
Running a Full Flow
No manual env setup needed — flow scripts autodetect ORFS/tools via scripts/flow/_env.sh. Run scripts/flow/check_env.sh to confirm what was found.
Initialize a run directory with scripts/project/init_project.py <design-name>.
Save user requirements to input/raw-spec.md.
Normalize them into input/normalized-spec.yaml using scripts/project/normalize_spec.py.
Write or copy rtl/design.v and tb/testbench.v.
Run scripts/flow/check_env.sh to verify tool availability.
Run scripts/flow/run_lint.sh, then scripts/flow/run_sim.sh, then scripts/flow/run_synth.sh.
After those pass, prepare constraints/config.mk and constraints/constraint.sdc.
Run scripts/flow/run_orfs.sh <project-dir> for the backend.
Extract PPA: scripts/extract/extract_ppa.py <project-dir> reports/ppa.json
Run timing gate: scripts/reports/check_timing.py <project-dir> — reads reports/timing_check.json:
tier=clean: proceed to step 12.
tier=minor: auto-fix clock period per suggested_clock_period, re-run step 9, then re-check.
tier=moderate/severe/unconstrained: stop, present options to user, wait for decision.
- Check
wns_tier and tns_tier to explain which metric drove the tier.
Run signoff checks (only after timing gate passes or user approves):
scripts/flow/run_drc.sh <project-dir> [platform] (KLayout DRC)
scripts/flow/run_magic_drc.sh <project-dir> [platform] (Magic DRC, sky130 only)
scripts/flow/run_lvs.sh <project-dir> [platform] (KLayout LVS)
scripts/flow/run_netgen_lvs.sh <project-dir> [platform] (Netgen LVS, sky130 only)
scripts/flow/run_rcx.sh <project-dir> [platform]
Extract remaining results:
scripts/extract/extract_drc.py <project-root> reports/drc.json
scripts/extract/extract_lvs.py <project-root> reports/lvs.json
scripts/extract/extract_rcx.py <project-root> reports/rcx.json
- If DRC/LVS status is
fail, attempt real layout fixes (antenna diode insertion +
repair iters, route effort, density relief; LVS triage):
scripts/flow/fix_signoff.sh <project-dir> [platform] [--check drc|lvs|both] [--max-iters 3]
Real-fixes-only — never relaxes the rule deck. Residual stuck/timeout/KLayout-crash
cases are reported honestly. See references/signoff-fixing.md.
13b. Extract dataset labels (optional, for dataset building):
scripts/flow/run_labels.sh <project-dir> [platform]
- Emits per-cell/per-net label CSVs to
<project-dir>/labels/ (congestion,
wirelength, timing, IR drop) and a per-design reports/labels_stats.json.
- Fail-soft: a missing input or per-label tool error is recorded, not fatal.
- Platform-agnostic: liberty/lef/supply-voltage are resolved from the ORFS
platform config. See
references/label-extraction.md.
- Batch backfill across completed designs:
tools/run_labels_batch.sh.
13c. Extract dataset features (optional, for dataset building — the X side of 13b's Y):
scripts/flow/run_features.sh <project-dir> [platform]
- Emits graph-feature CSVs to
<project-dir>/features/: metadata.csv (graph-level),
nodes_{gate,net,iopin,pin}.csv, edges_{gate_pin,pin_net,iopin_net}.csv, plus a
per-design reports/features_stats.json.
- Reads the same
6_final.def (+ optional 6_final.spef) as the labels, so feature
rows join the label rows on graph_id+inst_name/net_name. Fail-soft; SPEF
absence degrades cap columns to 0.
- Platform-agnostic: liberty/tech-lef are resolved from the ORFS platform config and
cell-type/routing-layer vocabularies adapt per platform. See
references/feature-extraction.md.
- Batch backfill across completed designs:
tools/run_features_batch.sh.
Diagnose issues: scripts/reports/build_diagnosis.py <project-root> reports/diagnosis.json
Get config suggestions: knowledge/suggest_config.py <project-dir> (optional, useful for tuning)
Collect artifacts with scripts/reports/collect_reports.py and summarize with scripts/reports/summarize_run.py.
Generate the dashboard with scripts/dashboard/generate_multi_project_dashboard.py.
The index page carries two read-only knowledge-store panels at the top (above the
project grid), computed by scripts/reports/build_lineage_view.py:
- Knowledge Store Health — total runs, ORFS status distribution, % partial/unknown,
learnable family/platform pairs (≥3 successes via
knowledge_db.is_success), signoff
positives, and whether heuristics.json is populated (the EMPTY case renders red — the
screaming diagnostic that learning is inert).
- Config Tuning Provenance — the
config_lineage diff chain per design/platform
(changed/added/removed config keys + orfs/drc/lvs outcome delta prev→cur).
INVARIANT: these panels are a strictly descriptive, READ-ONLY projection over
knowledge.sqlite / config_lineage / heuristics.json (opened mode=ro; the projection
writes only JSON). They are NEVER wired into suggest_config as an auto-tuner. The
config-variant lineage is a loose single-parent diff chain, not a true DAG.
Serve it with scripts/dashboard/serve_multi_project_dashboard.py 8765.
MVP Scope
Default to an MVP flow that supports:
- Single module or small design
- Single clock domain
- Simple reset behavior
- Generated or hand-authored Verilog RTL
- Testbench-driven simulation
- Yosys synthesis
- ORFS backend run with nangate45 platform
- DRC signoff check
- LVS signoff check (where platform supports it)
- OpenRCX parasitic extraction (SPEF)
- Report collection, signoff summary, and dashboard
Escalate to the user before attempting CDC, multi-clock constraints, DFT, or signoff-quality closure.
Macro / Hard Memory Designs (Validated)
Macro designs using fakeram45 on nangate45 are supported and validated (riscv32i, tinyRocket, swerv, bp_multi_top — all produce GDS + pass RCX). LVS passes for designs <150K cells; designs >150K cells may need extended LVS timeout.
Some designs instantiate hard memory macros (fakeram45 on nangate45, SRAM on sky130). These require extra config:
Verilog blackbox stubs — Provide module definitions for all macros referenced in the RTL. For designs using SYNTH_HIERARCHICAL=1, stubs must be actual module implementations (not (* blackbox *) attributes), because Yosys CELLMATCH pass needs cost info. Wrap the fakeram macros inside the BSG-style wrapper modules with real port connections.
ADDITIONAL_LEFS / ADDITIONAL_LIBS — Point to the platform's LEF and LIB files for each macro type.
CDL_FILE for LVS — The platform config.mk sets a default CDL_FILE that only includes standard cells. Macro designs need a combined CDL with both standard cells and fakeram subcircuit definitions. Use override export CDL_FILE (the override keyword is critical — without it, the platform config.mk, which is included after the design config, will silently overwrite your CDL_FILE).
MACRO_PLACEMENT_TCL — Provide a Tcl script for macro placement. Use find_macros (not all_macros) to check for macros, and call global_placement before macro_placement:
if {[find_macros] != ""} {
global_placement -density [place_density_with_lb_addon] -pad_left 2 -pad_right 2
macro_placement -halo {10 10} -style corner_max_wl
}
GDS_ALLOW_EMPTY — Set export GDS_ALLOW_EMPTY = fakeram.* so ORFS allows empty GDS cells for the macro stubs.
Safety flags — Large macro designs need SKIP_CTS_REPAIR_TIMING=1 and SKIP_LAST_GASP=1 to avoid OpenROAD crashes.
Behavioral SRAM Stubs (Alternative to Macro Mapping)
When the design's SRAM macros are undefined in the RTL set (e.g., Chipyard
BOOM's freepdk45_sram_*, generic foundry stubs without LEF/LIB) AND the
total memory bits are modest (<~256K bits), substitute behavioral
flop-array implementations instead of mapping to fakeram45.
Use tools/gen_openram_behavioral_stubs.py <wrapper.v> <stubs.v> (a repo-level helper in the agent-r2g repository — not bundled with the installed skill) to
auto-generate behavioral Verilog for every freepdk45_sram_<ports>_<rows>x<cols>[_<gran>]
referenced. The generator handles both 1rw0r (single-port) and 1w1r
(write-port + read-port, independent clocks) styles, with optional
write-mask granularity.
Why behavioral instead of fakeram45:
- fakeram45 is single-port only — cannot represent BOOM's
1w1r macros.
- fakeram45 widths (32/39/64/etc.) don't match arbitrary BOOM widths
(40, 44, 52, 56, 124) without padding waste.
- Behavioral stubs let Yosys infer memories cleanly; ORFS handles them
as plain logic with no macro placement needed.
When NOT to use behavioral stubs:
- Total memory bits > ~50K — Yosys's
memory_map pass turns each
read port into a wide mux tree. At BOOM SmallSEBoom's 168K total bits,
the post-mapping cell count exceeds ~1M gates and ABC's speed
script grinds beyond the 4 h ORFS_TIMEOUT. The earlier guidance
(512K) was too optimistic; lowered after a 2h28m ABC failure.
- Designs that need real silicon (taping out) — use real macros.
- The skill currently caps
SYNTH_MEMORY_MAX_BITS per memory at 65536.
Single memories larger than that should use real macros.
When behavioral stubs hit the ABC ceiling but you still want to avoid
real macros, try SYNTH_HIERARCHICAL=1 before switching to fakeram45.
With hierarchical synth, ABC is invoked separately per Yosys module —
each freepdk45_sram_* stub becomes its own small ABC run (≤32K gates
per memory) instead of one giant 1M-gate ABC pass.
Validated:
- DMA-class designs (Faraday DMA, ff_ram flop array): pass behavioral.
- AES / ibex / CRC / iscas89 (no SRAM macros, total memory ≤ ~10K bits): pass.
- Faraday RISC (3 unique
tsyncram_* sizes, 87K total memory bits,
79 RTL files, dual SYSCLK/BUSCLK): synth passes in 213 s under
SYNTH_HIERARCHICAL=1 + ABC_AREA=1. Yosys peak 553 MB; ABC ran
per kept module (5 ABC invocations, 57 s combined). Confirms
hierarchical mode lifts the behavioral ceiling well past the 50K-bit
flat-mode limit when single memories stay <16K bits each.
- BOOM SmallSEBoom (17 SRAM types, 168K total memory bits, ~360K-line top):
flat-mode ABC fails (2h28m wall, 5.36 GB peak). Retry with
SYNTH_HIERARCHICAL=1 is the recommended next step; if that still
fails, fall back to mapping the four 1rw0r macros (61K bits total)
to fakeram45 and keep the thirteen 1w1r macros behavioral.
- See
docs/faraday_viability.md for the per-design SRAM scale audit.
ORFS Backend Details
config.mk Format
export DESIGN_NAME = <top_module>
export PLATFORM = nangate45
export VERILOG_FILES = <absolute_path_to_rtl>
export SDC_FILE = <absolute_path_to_sdc>
export CORE_UTILIZATION = 30
export PLACE_DENSITY_LB_ADDON = 0.20
For macro designs, add (note the override on CDL_FILE):
export ADDITIONAL_LEFS = $(PLATFORM_DIR)/lef/fakeram45_64x32.lef
export ADDITIONAL_LIBS = $(PLATFORM_DIR)/lib/fakeram45_64x32.lib
export GDS_ALLOW_EMPTY = fakeram.*
export MACRO_PLACEMENT_TCL = /absolute/path/to/macro_placement.tcl
override export CDL_FILE = /absolute/path/to/combined_with_fakerams.cdl
The override keyword on CDL_FILE is essential: ORFS includes the platform config.mk after the design config.mk, so a bare export CDL_FILE gets silently overwritten by the platform default (which only has standard cells).
For sky130 (and any design whose RTL contains port-to-port assign out = in feedthroughs),
also add the stage hook that keeps Netgen LVS top-level pins matchable:
# Split port-to-port feedthrough nets so Netgen LVS top-level pins match
export POST_GLOBAL_PLACE_TCL = <skill>/scripts/flow/orfs_hooks/buffer_port_feedthroughs.tcl
Set it in config.mk (not the shell — ORFS scrubs exported variables). It is a no-op for
designs without feedthroughs, so it is safe to set unconditionally.
config.mk Validation Rules (Hard)
Before running ORFS, validate every config.mk against these rules:
- PLACE_DENSITY_LB_ADDON ≥ 0.10 — Values below 0.10 cause placement divergence (NesterovSolve stuck). Use 0.20+ for macro designs.
- Bus-heavy designs need CORE_UTILIZATION ≤ 15% — Crossbars, interconnect fabrics, and bus arbiters have high routing demand.
- Large macro designs need safety flags — Designs with >50K instances or SRAM macros (swerv, black_parrot, ibex) must include:
export SKIP_CTS_REPAIR_TIMING = 1
export SKIP_LAST_GASP = 1
Without these, OpenROAD may SIGSEGV during CTS timing repair.
- All VERILOG_FILES must be absolute paths and point to existing files.
- DESIGN_NAME must exactly match the RTL top module name.
constraint.sdc Format
current_design <top_module>
set clk_name core_clock
set clk_port_name clk
set clk_period 10.0
set clk_io_pct 0.2
set clk_port [get_ports $clk_port_name]
create_clock -name $clk_name -period $clk_period $clk_port
set non_clock_inputs [all_inputs -no_clocks]
set_input_delay [expr $clk_period * $clk_io_pct] -clock $clk_name $non_clock_inputs
set_output_delay [expr $clk_period * $clk_io_pct] -clock $clk_name [all_outputs]
Running ORFS
The scripts/flow/run_orfs.sh script:
- Copies RTL and constraints to an ORFS-compatible design directory
- Derives a unique
FLOW_VARIANT from the project directory name (prevents collisions)
- Runs
make DESIGN_CONFIG=<config.mk> FLOW_VARIANT=<variant> with optional timeout
- Collects results back to the project directory
Resource control via environment variables:
ORFS_TIMEOUT=7200 # Per-stage max runtime in seconds (default: 2 hours)
ORFS_MAX_CPUS=4 # Limit CPU cores via taskset (default: all)
PLACE_FAST=1 # Disable GPL_TIMING_DRIVEN/ROUTABILITY_DRIVEN — use for
# BOOM-class designs (>1M nets) where the timing-repair
# loop in gpl spins for hours after Nesterov has already
# converged. CTS/route still apply timing closure.
ROUTE_FAS
…(truncated)
1---2name: r2g-rtl2gds3description: Drive an open-source EDA workflow from RTL to GDS with signoff checks (DRC, LVS, RCX) using OpenROAD-flow-scripts (ORFS), Yosys, KLayout, and OpenRCX. Use when the user wants to turn a hardware spec or RTL into synthesis results, place-and-route, GDS output, signoff verification, parasitic extraction, or report summaries. Also use when iterating on PPA, diagnosing flow failures, or viewing a multi-project dashboard. Use when this capability is needed.4---5# r2g-rtl2gds Skill67Execute a staged, artifact-first open-source EDA flow from specification to GDSII with full signoff checks using OpenROAD-flow-scripts (ORFS). Prefer deterministic scripts for execution, keeping the agent focused on planning, generation, diagnosis, and iteration.89## Environment Setup1011Every flow script sources `scripts/flow/_env.sh` on entry, which autodetects12ORFS + tool paths and lets the user override any single value. You do not13need to source anything manually.1415### Resolution order (first hit wins, per value)16171. **Variable already set in the caller's environment** — `ORFS_ROOT=... run_orfs.sh ...` wins unconditionally.182. **User env file** — path in `$R2G_ENV_FILE` (if set).193. **In-skill override file** — `references/env.local.sh` (copy from `references/env.local.sh.template`).204. **ORFS-provided env** — `$ORFS_ROOT/env.sh` (once `ORFS_ROOT` is known).215. **System-wide env** — `/opt/openroad_tools_env.sh` (if present).226. **Autodetect** — `command -v <tool>` on `$PATH`, then a list of well-known install paths (e.g. `$ORFS_ROOT/tools/install/OpenROAD/bin/openroad`, `$HOME/oss-cad-suite/bin/yosys`, `/usr/local/bin/klayout`).2324### Checking what the skill found2526```bash27bash scripts/flow/check_env.sh28```2930Prints the resolved `ORFS_ROOT`, every tool binary it picked, and the31platforms it can see. Exits non-zero if a required tool is missing.3233### Overriding just a few values3435```bash36# One-off override for a single run37ORFS_ROOT=/opt/ORFS OPENROAD_EXE=/opt/openroad/bin/openroad \38 bash scripts/flow/run_orfs.sh design_cases/my_design nangate453940# Or persist overrides in a file41cp references/env.local.sh.template references/env.local.sh42# ...then edit the exports you care about; every subsequent flow picks them up.43```4445### Available platforms4647`nangate45`, `sky130hd`, `sky130hs`, `asap7`, `gf180`, `ihp-sg13g2` (default: `nangate45`).4849## Workflow5051### 1. Normalize the Specification First5253- Convert free-form requirements into a structured specification before writing RTL.54- Read `references/spec-template.md` and produce `input/normalized-spec.yaml`.55- If clock/reset, IO, target flow, or timing targets are missing, stop and ask the user or record explicit assumptions.5657### 2. Initialize a Project Directory5859- Create a run folder under `design_cases/<design-name>/` using `scripts/project/init_project.py`.60- The layout follows `references/workflow.md`.61- Directories created: `input/`, `rtl/`, `tb/`, `constraints/`, `lint/`, `sim/`, `synth/`, `backend/`, `drc/`, `lvs/`, `rcx/`, `reports/`.6263### 3. Generate RTL and Testbench Separately6465- Write RTL to `rtl/design.v`.66- Write testbench to `tb/testbench.v`.67- Keep assumptions and design notes in `reports/rtl-notes.md`.6869### 4. Run Validation in Strict Order70711. Run `scripts/project/validate_config.py <project-dir>` before ORFS backend to catch config/RTL issues early.722. Run lint/syntax checks before simulation.733. Run simulation before synthesis.744. Run synthesis before backend (ORFS).755. Do not skip failed stages unless the user explicitly requests it.7677### 5. Run Backend with ORFS7879- Prepare `constraints/config.mk` and `constraints/constraint.sdc`.80- Use `scripts/flow/run_orfs.sh` to invoke the ORFS Makefile.81- ORFS runs place-and-route natively (no Docker required).82- Collect results from the ORFS results directory.8384### 5b. Check Timing Before Signoff (Tiered WNS + TNS)8586After ORFS completes, extract PPA and run the timing gate:87881. Run `scripts/extract/extract_ppa.py <project-dir> reports/ppa.json` to extract timing metrics.892. Run `scripts/reports/check_timing.py <project-dir>` to classify WNS and TNS and write `reports/timing_check.json`.903. The script independently classifies WNS and TNS, then takes the **worse** of the two as the combined tier. A design with small WNS but large TNS (many slightly-violating paths) is caught.914. Read `reports/timing_check.json` and act on the `tier`:9293| Tier | Criteria | Agent Action |94|------|----------|-------------|95| **clean** | WNS >= 0, TNS >= 0 | Proceed to signoff. |96| **minor** | WNS >= -2.0 AND TNS >= -10.0 | Auto-fix: update `clk_period` in constraint.sdc to `suggested_clock_period` from the JSON, then re-run backend. Report the fix to the user after the fact. |97| **moderate** | WNS >= -5.0 AND TNS >= -100.0 (but not clean/minor) | **Stop.** Present the numbered `options` from the JSON to the user. Wait for their choice. |98| **severe** | WNS < -5.0 OR TNS < -100.0 | **Stop.** Present options with strong warning. |99| **unconstrained** | WNS > 1e+30 | **Stop.** SDC clock port mismatch. Present options. Do NOT proceed. |1001015. The JSON includes `wns_tier` and `tns_tier` fields so the agent can explain which metric triggered the tier (e.g., "TNS escalated this from minor to moderate").1026. Only proceed to signoff checks (step 6) after timing is resolved.103104### 5a. (Optional) Fmax search — find the fastest closing period105106Before committing to a clock period, you can characterize the design's Fmax:107108 python3 scripts/reports/fmax_search.py <project-dir> [platform] [--verify]109110Loose-first search using cheap **placement-stage** timing (each probe runs only111`ORFS_STAGES="synth floorplan place"`). It reports a **predicted-signoff Fmax**112(`reports/fmax_search.json`), corrected by a learned per-family slack-deterioration113model. The number is a **proxy (UNVERIFIED)** — post-place timing is optimistic vs114signoff. Pass `--verify` to confirm the winner with one full flow (and feed the115result back to tighten the model). This does NOT replace the step-8 `check_timing`116gate, which still runs on the final backend.117118Knobs: `--probe-timeout`, `--place-fast` (whole-search conservative lower bound119for hang-prone designs), `--keep-variants`. The search is sequential; cross-design120parallelism is achieved by running multiple invocations concurrently.121122### 6. Run Signoff Checks (DRC, LVS, RCX)123124After a successful backend run, run signoff checks in order:125126#### DRC (Design Rule Check)127128Two tool options are available:1291301. **KLayout DRC** (default) — `scripts/flow/run_drc.sh <project-dir> [platform]`131 - Uses ORFS `make drc` target with platform `.lydrc` rules132 - Outputs: `drc/6_drc.lyrdb`, `drc/6_drc_count.rpt`, `drc/6_drc.log`1331342. **Magic DRC** (sky130 only) — `scripts/flow/run_magic_drc.sh <project-dir> [platform]`135 - Uses Magic's built-in DRC engine with sky130A tech file136 - Requires the sky130A PDK; the script reads `$PDK_ROOT/sky130A/libs.tech/magic/sky130A.tech`137 (set `PDK_ROOT` via `references/env.local.sh` — `/opt/pdks` is only the fallback default).138 - Outputs: `drc/magic_drc.rpt`, `drc/magic_drc_count.rpt`, `drc/magic_drc_result.json`139 - Supported platforms: sky130hd, sky130hs140141#### LVS (Layout vs Schematic)142143Two tool options are available:1441451. **KLayout LVS** (default) — `scripts/flow/run_lvs.sh <project-dir> [platform]`146 - Uses ORFS `make lvs` target with platform `.lylvs` rules + CDL netlist147 - **Gracefully skips** platforms without LVS rules (produces `lvs/lvs_result.json` with status "skipped")148 - Outputs: `lvs/6_lvs.lvsdb`, `lvs/6_lvs.log`, `lvs/6_final.cdl`149 - nangate45: uses adapted FreePDK45 rules with `connect_implicit("VDD"/"VSS")` for bulk merging and `schematic.purge` for unused cell pins (e.g., QN on DFFR_X1)150 - **Large design warning**: KLayout LVS on designs >100K cells (black_parrot, swerv) takes >60 minutes. Use `LVS_TIMEOUT=7200` for these designs. The default 3600s may not be enough.1511522. **Netgen LVS** (sky130 only) — `scripts/flow/run_netgen_lvs.sh <project-dir> [platform]`153 - Two-step flow: Magic extracts SPICE from GDS, then Netgen compares against Verilog netlist154 - Requires the sky130A PDK (Magic tech + `$PDK_ROOT/sky130A/libs.tech/netgen/sky130A_setup.tcl`).155 Set `PDK_ROOT` via `references/env.local.sh`; `/opt/pdks` is only the fallback default.156 - Outputs: `lvs/extracted.spice`, `lvs/netgen_lvs.rpt`, `lvs/netgen_lvs_result.json`157 - Supported platforms: sky130hd, sky130hs158 - **This is the production sky130 LVS path** — prefer it over KLayout LVS on sky130 (the159 ORFS KLayout sky130 rule deck is not production-grade; see `references/failure-patterns.md`,160 "sky130 LVS").161 - Antenna-diode designs are handled automatically: the script normalizes Magic's diode162 `X`-subcircuit instances to `D` devices (`perim=`→`pj=`) and runs netgen with163 `MAGIC_EXT_USE_GDS=1`, so `sky130_fd_sc_hd__diode_2` matches instead of flattening.164 - Designs with port-to-port feedthroughs (`assign out_port = in_port`) need165 `export POST_GLOBAL_PLACE_TCL = <skill>/scripts/flow/orfs_hooks/buffer_port_feedthroughs.tcl`166 in config.mk **before the backend run** — SPICE cannot express two top-level ports on one167 net, so without the hook LVS fails "Top level cell failed pin matching". The hook is a168 no-op for designs without feedthroughs (safe to set everywhere); a backend re-run is169 required when adding it. See `references/failure-patterns.md`, "sky130 LVS" cause 5.170171#### RCX (Parasitic Extraction)1721733. **RCX** — `scripts/flow/run_rcx.sh <project-dir> [platform]`174 - OpenRCX parasitic extraction via OpenROAD175 - Generates Tcl script (`rcx/run_rcx.tcl`) with `define_process_corner`, `extract_parasitics`, `write_spef`176 - Reads `6_final.odb` from ORFS results, writes SPEF output177 - Outputs: `rcx/6_final.spef`, `rcx/rcx.log`, `rcx/run_rcx.tcl`178179Extract results into JSON for reporting and dashboard:180- `scripts/extract/extract_drc.py <project-root> reports/drc.json`181- `scripts/extract/extract_lvs.py <project-root> reports/lvs.json`182- `scripts/extract/extract_rcx.py <project-root> reports/rcx.json`183- If DRC/LVS is `fail`, attempt automated real-layout fixes:184 `scripts/flow/fix_signoff.sh <project-dir> [platform] [--check drc|lvs|both]`185 (See `references/signoff-fixing.md`.)186- If the **backend aborted at `route`** (congestion / DRT timeout, exit 124 — `orfs_status=fail`,187 `orfs_fail_stage=route`), relieve it BEFORE signoff:188 `scripts/flow/fix_signoff.sh <project-dir> sky130hd --check route` (lowers `CORE_UTILIZATION` so189 DRT converges; learnable + A/B-validated `route_relief`). See `references/failure-patterns.md`190 "Routing Congestion".191192#### Fix-Learning Loop193194The skill learns from every fix attempt so candidate strategies are proposed in195evidence-ranked order on the next similar violation.196197- **Record.** `fix_signoff.sh` and `check_timing.py --journal` append lossless,198 session-keyed rows to `reports/fix_log.jsonl` (one per iteration: strategy, before/after199 counts, pre-fix violation class, verdict). `fix_signoff.sh` uses an adaptive budget (base200 3 iters, hard cap 8, early-stop after 2 non-improving iters past the base).201- **Ingest.** Step-10 ingest (`knowledge/ingest_run.py`) reads `fix_log.jsonl` into the202 Tier-1 `fix_events` table and writes a `run_violations` snapshot for **every** run — clean203 or not (the full violation landscape). It then auto-runs `fix_log_manager.manage()`204 (toggle `R2G_FIX_AUTOLEARN`, default on).205- **Learn.** `learn_heuristics.py` derives Tier-2 `fix_trajectories` (per-episode path,206 including *abandoned* episodes and failed strategies — negative learning) and folds them207 into Tier-3 `fix_recipes` inside `heuristics.json`.208- **Apply.** When a recipe exists for the design's family/platform/violation class,209 `diagnose_signoff_fix.py` reorders the strategy list by empirical clearance — there is **no210 hard gate**, all real-fix strategies are always proposed, priority-ordered.211 `diagnose_signoff_fix.py <proj> --check drc --list` prints the evidence-ranked candidate212 set as JSON. Hard safety clamps are unchanged.213- **Symptom index.** Learned repair experience is keyed by a **symptom signature**214 (`knowledge/symptom.py`: `{check, class, predicates}` → a stable `symptom_id`), NOT the215 design-family name. `learn_heuristics.py` emits a top-level `symptoms[symptom_id]`216 projection in `heuristics.json` (pooled across families/platforms, with `by_platform` +217 `evidence_designs` provenance); `diagnose_signoff_fix.py` looks recipes up by symptom and218 seeds an informed cross-platform prior for untried strategies (so a fix learned on219 nangate45 transfers to e.g. sky130hd). It also surfaces the matching active prose lesson220 (via `search_failures.lessons_for_symptom`) at the fix-decision point. `monitor_health.py`221 (degradation alerts) and `analyze_execution.py` (fix-proposal triage) are operator-invoked222 CLIs over the same store.223224See `references/signoff-fixing.md` ("Fix-Learning Loop") and `knowledge/README.md`.225226#### Engineer Loop (campaign mode)227228Use campaign mode when you need to run the full flow unattended across many designs — or229when you want the A/B-gated recipe-learning cycle to run autonomously. The campaign230orchestrator (`scripts/loop/engineer_loop.py`) drives the flow scripts, ingests results,231triggers learning, and manages A/B trials without human gates.232233```bash234# Add a project to the campaign ledger235python3 scripts/loop/engineer_loop.py add \236 --ledger design_cases/_batch/campaign.jsonl \237 --project design_cases/my_design [--platform nangate45]238239# Run the campaign (optionally limit to N designs)240python3 scripts/loop/engineer_loop.py run \241 --ledger design_cases/_batch/campaign.jsonl [--max N]242243# Inspect per-design state244python3 scripts/loop/engineer_loop.py status \245 --ledger design_cases/_batch/campaign.jsonl246```247248The ledger is JSONL (last-state-wins); kill/restart is safe — the campaign resumes where it249left off. States: `pending → flow → signoff → fixing → clean | escalated | abandoned`.250251**Hard rules for campaign mode:**252- Phase-1 runs workers=1 (single-process); do not run two campaigns sharing a `DESIGN_NAME`253 concurrently.254- Never run two configs with the same `DESIGN_NAME` + `FLOW_VARIANT` concurrently.255- Never run more than one LVS job concurrently for designs > 100 K cells.256- Only `promoted` recipes affect live strategy ranking; shadow and candidate recipes are257 inert until their A/B trial completes.258259When the loop opens an escalation (unknown symptom, exhausted catalog, unseen crash, or260repeated regression), drain it following the agent runbook in261`references/engineer-loop.md` ("Escalation Drain"). That document also covers provenance262queries (`trace_provenance.py`) and the full safety-invariant list.263264#### Platform Support Matrix265266| Platform | KLayout DRC | KLayout LVS | Magic DRC | Netgen LVS | RCX |267|----------|-------------|-------------|-----------|------------|-----|268| nangate45 | Yes | Yes | No | No | Yes |269| sky130hd | Yes | Yes | Yes | Yes | Yes |270| sky130hs | Yes | Yes | Yes | Yes | Yes |271| asap7 | Yes | No | No | No | Yes |272| gf180 | Yes | Yes | No | No | Yes |273| ihp-sg13g2 | Yes | Yes | No | No | Yes |274275### 7. Treat Artifacts as Source of Truth276277- Save logs, reports, VCD waveforms, netlists, SPEF, configurations, and summary files.278- Prefer file outputs over GUI tools. GUI viewers like GTKWave/KLayout are optional helpers.279280### 8. Diagnose Before Editing281282- For failures, read `references/failure-patterns.md`.283- Classify the failure: specification gap, RTL bug, testbench bug, synthesis issue, backend/configuration issue, DRC violation, LVS mismatch, or RCX extraction error.284- Fix the smallest plausible cause first.285286### 9. Summarize Each Stage Clearly287288- State pass/fail status.289- List key artifact paths.290- Record assumptions, blockers, and next recommended actions.291- For signoff: report DRC violation count, LVS match/skip status, RCX net count and total capacitance.292293### 10. Ingest the Run into the Knowledge Store294295After **every** flow — successful, failed, or partial — run:296297```bash298python3 r2g-rtl2gds/knowledge/ingest_run.py design_cases/<project>299```300301This reads the structured JSON artifacts produced by the extraction scripts302and appends one row to `r2g-rtl2gds/knowledge/knowledge.sqlite`. It never303parses raw ORFS logs.304305Then rebuild derived artifacts:306307```bash308python3 r2g-rtl2gds/knowledge/learn_heuristics.py309python3 r2g-rtl2gds/knowledge/mine_rules.py310```311312- `knowledge/heuristics.json` is consumed automatically by313 `suggest_config.py` on the next project — no CLI changes required.314- `knowledge/failure_candidates.json` is a **review queue**, not a rule315 source. Surface new signatures to the user and, if confirmed, edit316 `references/failure-patterns.md` by hand.317318A family/platform pair appears in `heuristics.json` only after at least319**3 successful runs** under that configuration.320321### 10b. Share / Transfer the Knowledge Store Across Users (git-friendly)322323`knowledge.sqlite` is the **tracked, committed store** — a fresh clone is pre-trained324immediately. A binary SQLite blob cannot be combined across operators (git only3253-way-merges text; two operators' campaigns would conflict and one would clobber the326other), so when you need to **share or merge** experience across operators,327`knowledge/knowledge_sync.py` is an **on-demand** tool: it exports a deterministic,328git-friendly text bundle (`knowledge/store/`, one NDJSON file per table — regenerable,329not committed by default) and performs a real honesty-gated cross-operator union:330331```bash332# After learning, re-export the committed text bundle (keeps it in sync with the DB):333python3 knowledge/knowledge_sync.py export334335# A NEW user folds another operator's experience into their local store. The merge is336# ADDITIVE (dedups by natural content key — run_id/symptom_id are portable; surrogate337# ids are re-assigned) and is REFUSED+rolled back if it would break an honesty gate:338python3 knowledge/knowledge_sync.py merge --bundle path/to/their/store339python3 knowledge/knowledge_sync.py merge --from-db path/to/their/knowledge.sqlite340341# Bootstrap a fresh store from a bundle only (rebuilds knowledge.sqlite):342python3 knowledge/knowledge_sync.py import --bundle knowledge/store --db knowledge/knowledge.sqlite343344# Honesty CI gate (the real gate — runs the 5 honesty gates over the committed store):345python3 knowledge/honesty.py --db knowledge/knowledge.sqlite346# On-demand drift check for an EXPORTED bundle you intend to share (reports347# "no committed bundle" by design when none exists — NOT a CI gate post-revert):348python3 knowledge/knowledge_sync.py status349```350351**Commit workflow:** `knowledge.sqlite` is the committed store — commit it (and352`heuristics.json`) after ingest/learn, as before. The `knowledge/store/` bundle is gitignored353and only produced on demand (`export`) when you want to hand experience to another operator or354review a diff; `status` confirms an exported bundle matches the DB. After any `merge`, run355`learn()` + `engineer_loop ab-drain` so imported recipes re-validate locally. See356`knowledge/README.md` ("Sharing the store across users").357358## Hard Rules359360- Do not start backend if simulation is failing.361- Do not start ORFS if synthesis failed or the top module is unclear.362- Do not start signoff checks (DRC/LVS/RCX) if backend did not produce a GDS/ODB.363- Run `check_timing.py` after every backend run. It checks both WNS and TNS. For minor violations (WNS >= -2.0 AND TNS >= -10.0), auto-fix by increasing clock period and re-running. For moderate/severe/unconstrained, stop and present numbered fix options — do not proceed without the user's decision.364- Do not silently invent missing interfaces, clocks, resets, or timing targets without documenting assumptions.365- Prefer single-clock MVP flows. Macro designs (fakeram45) are supported with proper config (see "Macro / Hard Memory Designs"). Escalate to the user before attempting CDC, multi-clock, or DFT.366- Use the scripts in `scripts/` for repeatable operations instead of re-inventing shell commands each time.367- Do not hand-source any system env file before running EDA tools — every flow script sources `scripts/flow/_env.sh`, which autodetects ORFS and tool paths (see "Environment Setup"). `/opt/openroad_tools_env.sh` is only one optional source in that chain and may be absent.368- When a batch produces a mix of pass/fail, diagnose with `references/failure-patterns.md` (see "Batch-Campaign Failure Patterns") and apply the repo-level batch fixer before any code changes. That fixer (`tools/fix_orfs_failures.py` in the agent-r2g repository — not shipped with the installed skill) handles the six dominant failure modes (memory inference, IO-pin perimeter overflow, place density >1, PDN straps, missing include dirs, stage timeouts) by rewriting `config.mk`. When running standalone, apply the same patterns by hand using `references/failure-patterns.md`. Do not hand-edit configs case-by-case in batch — extend the fix tool so future batches self-heal.369- Floorplan sizing policy (validated on 495-design batch):370 - Explicit DIE_AREA is only safe when pin count ≤ ~200 *and* RTL fits in the area. Prefer `CORE_UTILIZATION` when in doubt.371 - When PPL-0024 reports a required perimeter, derive `DIE_AREA = 0 0 S S` with `S = ceil((required_perim / 4) * 1.3)` rounded up to 10um.372 - For designs with memory inference, set `SYNTH_MEMORY_MAX_BITS = 131072` (default 4096 is too tight for register files and FIFOs).373374## Default Project Layout375376```text377design_cases/<design-name>/378├── input/379│ ├── raw-spec.md380│ └── normalized-spec.yaml381├── rtl/382│ └── design.v383├── tb/384│ └── testbench.v385├── constraints/386│ ├── config.mk387│ └── constraint.sdc388├── lint/389│ └── lint.log390├── sim/391│ ├── sim.log392│ └── output.vcd393├── synth/394│ ├── synth.ys395│ ├── synth.log396│ └── synth_output.v397├── backend/398│ └── RUN_<timestamp>/399│ ├── final/ # GDS, DEF, ODB400│ ├── logs/ # Per-stage logs401│ ├── reports/ # Timing, area, power402│ ├── drc/ # DRC results (copied)403│ ├── lvs/ # LVS results (copied)404│ └── rcx/ # RCX results (copied)405├── drc/406│ ├── 6_drc.lyrdb # KLayout DRC violation database (XML)407│ ├── 6_drc_count.rpt # Violation count408│ ├── 6_drc.log # DRC log409│ └── drc_run.log # Full make output410├── lvs/411│ ├── 6_lvs.lvsdb # KLayout LVS comparison database (XML)412│ ├── 6_lvs.log # LVS log413│ ├── 6_final.cdl # CDL netlist414│ ├── lvs_run.log # Full make output415│ └── lvs_result.json # Only if skipped (no rules)416├── rcx/417│ ├── 6_final.spef # SPEF parasitic data418│ ├── rcx.log # OpenRCX extraction log419│ └── run_rcx.tcl # Generated Tcl extraction script420├── labels/ # Dataset labels (Y): congestion/wirelength/timing/irdrop CSVs (run_labels.sh)421├── features/ # Dataset features (X): nodes/edges/metadata CSVs (run_features.sh)422├── reports/423│ ├── ppa.json # PPA metrics + geometry424│ ├── progress.json # ORFS stage completion425│ ├── run-history.json # Multi-run comparison426│ ├── run-compare.json # Baseline vs current delta427│ ├── diagnosis.json # Issue detection & suggestions428│ ├── drc.json # DRC summary (violations, categories)429│ ├── lvs.json # LVS summary (match/mismatch/skipped)430│ ├── rcx.json # RCX summary (net count, cap, res)431│ └── demo-summary.md # Human-readable summary432└── metadata.json433```434435## Resource Map436437- Read `references/spec-template.md` when the specification is incomplete or ambiguous.438- Read `references/workflow.md` when you need the phase-by-phase execution order.439- Read `references/orfs-playbook.md` before setting up or debugging the ORFS backend.440- Read `references/failure-patterns.md` when a run fails and you need a triage path.441- Read `references/ppa-report-guide.md` when summarizing synthesis/backend reports.442- Read `references/label-extraction.md` when building the physical-design dataset (per-cell/per-net labels + stats).443- Read `references/feature-extraction.md` when building the graph-feature (X) side of the dataset (per-node/per-edge/metadata CSVs + stats).444- Read `scripts/extract/techlib/` for the shared per-platform tech layer consumed by both stages: `profile.py` (supply voltage, tap patterns, cell-type strategy per ORFS platform), `resolve.py` (the Python backend for `resolve_platform_paths.sh` — same `KEY=VALUE` contract), `def_parse.py` (single DEF/SDC parser), `lef.py` (routing-layer names, pitch/direction, regex matcher), `liberty.py` (cell/pin/net classifiers), `cell_types.py` (`cell_type_id` map — curated for nangate45, runtime-built for all others).445- Use scripts in `scripts/` for initialization, spec normalization, environment checks, lint, simulation, synthesis, ORFS backend, DRC, LVS, RCX extraction, result collection, GDS preview rendering, dashboard generation, and run summaries.446- Use `scripts/flow/orfs_hooks/` for Tcl sourced into ORFS stages via the generic447 `PRE_<STAGE>_TCL` / `POST_<STAGE>_TCL` env hooks (set them in config.mk, not the shell —448 ORFS scrubs exported variables). Currently: `buffer_port_feedthroughs.tcl`449 (`POST_GLOBAL_PLACE_TCL`) splits port-to-port feedthrough nets behind real buffers so450 Netgen LVS top-level pins match; a no-op for designs without feedthroughs.451- Use `assets/examples/simple-arbiter/` as the first smoke-test case.452- Use `assets/config-template.mk` and `assets/constraint-template.sdc` as default backend configuration templates.453454## Quick Start455456### Prerequisites457458**Required Tools (all installed on this machine):**459- `python3` (3.13+)460- `yosys` (synthesis)461- `iverilog` + `vvp` (simulation)462- `openroad` (place & route, OpenRCX)463464**Optional Tools (also available):**465- `verilator` (faster lint/simulation)466- `klayout` (GDS visualization, DRC, LVS)467- `magic` (DRC, SPICE extraction for sky130)468- `netgen-lvs` (LVS comparison for sky130)469- `gtkwave` (waveform viewing)470- `sta` / `opensta` (static timing analysis)471472### Running a Full Flow4734741. No manual env setup needed — flow scripts autodetect ORFS/tools via `scripts/flow/_env.sh`. Run `scripts/flow/check_env.sh` to confirm what was found.4752. Initialize a run directory with `scripts/project/init_project.py <design-name>`.4763. Save user requirements to `input/raw-spec.md`.4774. Normalize them into `input/normalized-spec.yaml` using `scripts/project/normalize_spec.py`.4785. Write or copy `rtl/design.v` and `tb/testbench.v`.4796. Run `scripts/flow/check_env.sh` to verify tool availability.4807. Run `scripts/flow/run_lint.sh`, then `scripts/flow/run_sim.sh`, then `scripts/flow/run_synth.sh`.4818. After those pass, prepare `constraints/config.mk` and `constraints/constraint.sdc`.4829. Run `scripts/flow/run_orfs.sh <project-dir>` for the backend.48310. Extract PPA: `scripts/extract/extract_ppa.py <project-dir> reports/ppa.json`48411. Run timing gate: `scripts/reports/check_timing.py <project-dir>` — reads `reports/timing_check.json`:485 - `tier=clean`: proceed to step 12.486 - `tier=minor`: auto-fix clock period per `suggested_clock_period`, re-run step 9, then re-check.487 - `tier=moderate/severe/unconstrained`: **stop, present options to user, wait for decision**.488 - Check `wns_tier` and `tns_tier` to explain which metric drove the tier.48912. Run signoff checks (only after timing gate passes or user approves):490 - `scripts/flow/run_drc.sh <project-dir> [platform]` (KLayout DRC)491 - `scripts/flow/run_magic_drc.sh <project-dir> [platform]` (Magic DRC, sky130 only)492 - `scripts/flow/run_lvs.sh <project-dir> [platform]` (KLayout LVS)493 - `scripts/flow/run_netgen_lvs.sh <project-dir> [platform]` (Netgen LVS, sky130 only)494 - `scripts/flow/run_rcx.sh <project-dir> [platform]`49513. Extract remaining results:496 - `scripts/extract/extract_drc.py <project-root> reports/drc.json`497 - `scripts/extract/extract_lvs.py <project-root> reports/lvs.json`498 - `scripts/extract/extract_rcx.py <project-root> reports/rcx.json`499 - If DRC/LVS status is `fail`, attempt real layout fixes (antenna diode insertion +500 repair iters, route effort, density relief; LVS triage):501 `scripts/flow/fix_signoff.sh <project-dir> [platform] [--check drc|lvs|both] [--max-iters 3]`502 Real-fixes-only — never relaxes the rule deck. Residual stuck/timeout/KLayout-crash503 cases are reported honestly. See `references/signoff-fixing.md`.50413b. Extract dataset labels (optional, for dataset building):505 - `scripts/flow/run_labels.sh <project-dir> [platform]`506 - Emits per-cell/per-net label CSVs to `<project-dir>/labels/` (congestion,507 wirelength, timing, IR drop) and a per-design `reports/labels_stats.json`.508 - Fail-soft: a missing input or per-label tool error is recorded, not fatal.509 - Platform-agnostic: liberty/lef/supply-voltage are resolved from the ORFS510 platform config. See `references/label-extraction.md`.511 - Batch backfill across completed designs: `tools/run_labels_batch.sh`.51213c. Extract dataset features (optional, for dataset building — the X side of 13b's Y):513 - `scripts/flow/run_features.sh <project-dir> [platform]`514 - Emits graph-feature CSVs to `<project-dir>/features/`: `metadata.csv` (graph-level),515 `nodes_{gate,net,iopin,pin}.csv`, `edges_{gate_pin,pin_net,iopin_net}.csv`, plus a516 per-design `reports/features_stats.json`.517 - Reads the same `6_final.def` (+ optional `6_final.spef`) as the labels, so feature518 rows join the label rows on `graph_id`+`inst_name`/`net_name`. Fail-soft; SPEF519 absence degrades cap columns to 0.520 - Platform-agnostic: liberty/tech-lef are resolved from the ORFS platform config and521 cell-type/routing-layer vocabularies adapt per platform. See522 `references/feature-extraction.md`.523 - Batch backfill across completed designs: `tools/run_features_batch.sh`.52414. Diagnose issues: `scripts/reports/build_diagnosis.py <project-root> reports/diagnosis.json`52515. Get config suggestions: `knowledge/suggest_config.py <project-dir>` (optional, useful for tuning)52616. Collect artifacts with `scripts/reports/collect_reports.py` and summarize with `scripts/reports/summarize_run.py`.52717. Generate the dashboard with `scripts/dashboard/generate_multi_project_dashboard.py`.528 The index page carries two read-only knowledge-store panels at the top (above the529 project grid), computed by `scripts/reports/build_lineage_view.py`:530 - **Knowledge Store Health** — total runs, ORFS status distribution, % partial/unknown,531 learnable family/platform pairs (≥3 successes via `knowledge_db.is_success`), signoff532 positives, and whether `heuristics.json` is populated (the EMPTY case renders red — the533 screaming diagnostic that learning is inert).534 - **Config Tuning Provenance** — the `config_lineage` diff chain per design/platform535 (changed/added/removed config keys + orfs/drc/lvs outcome delta prev→cur).536537 INVARIANT: these panels are a strictly descriptive, READ-ONLY projection over538 `knowledge.sqlite` / `config_lineage` / `heuristics.json` (opened `mode=ro`; the projection539 writes only JSON). They are NEVER wired into `suggest_config` as an auto-tuner. The540 config-variant lineage is a loose single-parent diff chain, not a true DAG.54118. Serve it with `scripts/dashboard/serve_multi_project_dashboard.py 8765`.542543## MVP Scope544545Default to an MVP flow that supports:546- Single module or small design547- Single clock domain548- Simple reset behavior549- Generated or hand-authored Verilog RTL550- Testbench-driven simulation551- Yosys synthesis552- ORFS backend run with nangate45 platform553- DRC signoff check554- LVS signoff check (where platform supports it)555- OpenRCX parasitic extraction (SPEF)556- Report collection, signoff summary, and dashboard557558Escalate to the user before attempting CDC, multi-clock constraints, DFT, or signoff-quality closure.559560### Macro / Hard Memory Designs (Validated)561562Macro designs using fakeram45 on nangate45 are supported and validated (riscv32i, tinyRocket, swerv, bp_multi_top — all produce GDS + pass RCX). LVS passes for designs <150K cells; designs >150K cells may need extended LVS timeout.563564Some designs instantiate hard memory macros (fakeram45 on nangate45, SRAM on sky130). These require extra config:5655661. **Verilog blackbox stubs** — Provide module definitions for all macros referenced in the RTL. For designs using SYNTH_HIERARCHICAL=1, stubs must be actual module implementations (not `(* blackbox *)` attributes), because Yosys CELLMATCH pass needs cost info. Wrap the fakeram macros inside the BSG-style wrapper modules with real port connections.5675682. **ADDITIONAL_LEFS / ADDITIONAL_LIBS** — Point to the platform's LEF and LIB files for each macro type.5695703. **CDL_FILE for LVS** — The platform config.mk sets a default CDL_FILE that only includes standard cells. Macro designs need a combined CDL with both standard cells and fakeram subcircuit definitions. Use `override export CDL_FILE` (the `override` keyword is critical — without it, the platform config.mk, which is included after the design config, will silently overwrite your CDL_FILE).5715724. **MACRO_PLACEMENT_TCL** — Provide a Tcl script for macro placement. Use `find_macros` (not `all_macros`) to check for macros, and call `global_placement` before `macro_placement`:573 ```tcl574 if {[find_macros] != ""} {575 global_placement -density [place_density_with_lb_addon] -pad_left 2 -pad_right 2576 macro_placement -halo {10 10} -style corner_max_wl577 }578 ```5795805. **GDS_ALLOW_EMPTY** — Set `export GDS_ALLOW_EMPTY = fakeram.*` so ORFS allows empty GDS cells for the macro stubs.5815826. **Safety flags** — Large macro designs need `SKIP_CTS_REPAIR_TIMING=1` and `SKIP_LAST_GASP=1` to avoid OpenROAD crashes.583584### Behavioral SRAM Stubs (Alternative to Macro Mapping)585586When the design's SRAM macros are *undefined* in the RTL set (e.g., Chipyard587BOOM's `freepdk45_sram_*`, generic foundry stubs without LEF/LIB) AND the588total memory bits are modest (<~256K bits), substitute **behavioral589flop-array implementations** instead of mapping to fakeram45.590591Use `tools/gen_openram_behavioral_stubs.py <wrapper.v> <stubs.v>` (a repo-level helper in the agent-r2g repository — not bundled with the installed skill) to592auto-generate behavioral Verilog for every `freepdk45_sram_<ports>_<rows>x<cols>[_<gran>]`593referenced. The generator handles both `1rw0r` (single-port) and `1w1r`594(write-port + read-port, independent clocks) styles, with optional595write-mask granularity.596597Why behavioral instead of fakeram45:598- fakeram45 is single-port only — cannot represent BOOM's `1w1r` macros.599- fakeram45 widths (32/39/64/etc.) don't match arbitrary BOOM widths600 (40, 44, 52, 56, 124) without padding waste.601- Behavioral stubs let Yosys infer memories cleanly; ORFS handles them602 as plain logic with no macro placement needed.603604When NOT to use behavioral stubs:605- **Total memory bits > ~50K** — Yosys's `memory_map` pass turns each606 read port into a wide mux tree. At BOOM SmallSEBoom's 168K total bits,607 the post-mapping cell count exceeds ~1M gates and ABC's `speed`608 script grinds beyond the 4 h `ORFS_TIMEOUT`. The earlier guidance609 (512K) was too optimistic; lowered after a 2h28m ABC failure.610- Designs that need real silicon (taping out) — use real macros.611- The skill currently caps `SYNTH_MEMORY_MAX_BITS` per memory at 65536.612 Single memories larger than that should use real macros.613614When behavioral stubs hit the ABC ceiling but you still want to avoid615real macros, try **`SYNTH_HIERARCHICAL=1`** before switching to fakeram45.616With hierarchical synth, ABC is invoked separately per Yosys module —617each `freepdk45_sram_*` stub becomes its own small ABC run (≤32K gates618per memory) instead of one giant 1M-gate ABC pass.619620**Validated:**621- DMA-class designs (Faraday DMA, ff_ram flop array): pass behavioral.622- AES / ibex / CRC / iscas89 (no SRAM macros, total memory ≤ ~10K bits): pass.623- **Faraday RISC** (3 unique `tsyncram_*` sizes, 87K total memory bits,624 79 RTL files, dual SYSCLK/BUSCLK): synth passes in 213 s under625 `SYNTH_HIERARCHICAL=1` + `ABC_AREA=1`. Yosys peak 553 MB; ABC ran626 per kept module (5 ABC invocations, 57 s combined). Confirms627 hierarchical mode lifts the behavioral ceiling well past the 50K-bit628 flat-mode limit when single memories stay <16K bits each.629- BOOM SmallSEBoom (17 SRAM types, 168K total memory bits, ~360K-line top):630 flat-mode ABC fails (2h28m wall, 5.36 GB peak). Retry with631 `SYNTH_HIERARCHICAL=1` is the recommended next step; if that still632 fails, fall back to mapping the four `1rw0r` macros (61K bits total)633 to `fakeram45` and keep the thirteen `1w1r` macros behavioral.634- See `docs/faraday_viability.md` for the per-design SRAM scale audit.635636## ORFS Backend Details637638### config.mk Format639640```makefile641export DESIGN_NAME = <top_module>642export PLATFORM = nangate45643644export VERILOG_FILES = <absolute_path_to_rtl>645export SDC_FILE = <absolute_path_to_sdc>646647export CORE_UTILIZATION = 30648export PLACE_DENSITY_LB_ADDON = 0.20649```650651For macro designs, add (note the `override` on CDL_FILE):652```makefile653export ADDITIONAL_LEFS = $(PLATFORM_DIR)/lef/fakeram45_64x32.lef654export ADDITIONAL_LIBS = $(PLATFORM_DIR)/lib/fakeram45_64x32.lib655export GDS_ALLOW_EMPTY = fakeram.*656export MACRO_PLACEMENT_TCL = /absolute/path/to/macro_placement.tcl657override export CDL_FILE = /absolute/path/to/combined_with_fakerams.cdl658```659660The `override` keyword on CDL_FILE is essential: ORFS includes the platform config.mk *after* the design config.mk, so a bare `export CDL_FILE` gets silently overwritten by the platform default (which only has standard cells).661662For sky130 (and any design whose RTL contains port-to-port `assign out = in` feedthroughs),663also add the stage hook that keeps Netgen LVS top-level pins matchable:664```makefile665# Split port-to-port feedthrough nets so Netgen LVS top-level pins match666export POST_GLOBAL_PLACE_TCL = <skill>/scripts/flow/orfs_hooks/buffer_port_feedthroughs.tcl667```668Set it in config.mk (not the shell — ORFS scrubs exported variables). It is a no-op for669designs without feedthroughs, so it is safe to set unconditionally.670671### config.mk Validation Rules (Hard)672673Before running ORFS, validate every config.mk against these rules:6746751. **PLACE_DENSITY_LB_ADDON ≥ 0.10** — Values below 0.10 cause placement divergence (NesterovSolve stuck). Use 0.20+ for macro designs.6762. **Bus-heavy designs need CORE_UTILIZATION ≤ 15%** — Crossbars, interconnect fabrics, and bus arbiters have high routing demand.6773. **Large macro designs need safety flags** — Designs with >50K instances or SRAM macros (swerv, black_parrot, ibex) must include:678 ```makefile679 export SKIP_CTS_REPAIR_TIMING = 1680 export SKIP_LAST_GASP = 1681 ```682 Without these, OpenROAD may SIGSEGV during CTS timing repair.6834. **All VERILOG_FILES must be absolute paths** and point to existing files.6845. **DESIGN_NAME must exactly match the RTL top module name.**685686### constraint.sdc Format687688```tcl689current_design <top_module>690set clk_name core_clock691set clk_port_name clk692set clk_period 10.0693set clk_io_pct 0.2694695set clk_port [get_ports $clk_port_name]696create_clock -name $clk_name -period $clk_period $clk_port697698set non_clock_inputs [all_inputs -no_clocks]699set_input_delay [expr $clk_period * $clk_io_pct] -clock $clk_name $non_clock_inputs700set_output_delay [expr $clk_period * $clk_io_pct] -clock $clk_name [all_outputs]701```702703### Running ORFS704705The `scripts/flow/run_orfs.sh` script:7061. Copies RTL and constraints to an ORFS-compatible design directory7072. Derives a unique `FLOW_VARIANT` from the project directory name (prevents collisions)7083. Runs `make DESIGN_CONFIG=<config.mk> FLOW_VARIANT=<variant>` with optional timeout7094. Collects results back to the project directory710711Resource control via environment variables:712```bash713ORFS_TIMEOUT=7200 # Per-stage max runtime in seconds (default: 2 hours)714ORFS_MAX_CPUS=4 # Limit CPU cores via taskset (default: all)715PLACE_FAST=1 # Disable GPL_TIMING_DRIVEN/ROUTABILITY_DRIVEN — use for716 # BOOM-class designs (>1M nets) where the timing-repair717 # loop in gpl spins for hours after Nesterov has already718 # converged. CTS/route still apply timing closure.719ROUTE_FAS720721…(truncated)