Skip to content

RustSys / RustSTA integration and validation

RustROAD has a working, bounded logic and pre-layout timing integration on a small two-input, one-register circuit with both required baseline libraries. It does not yet implement routing, extraction, real-PDK stream-out, DRC or LVS. full_rtl_to_gds_status remains unverified. A placement-only DEF is a separate physical milestone, not a closed RTL-to-GDS flow.

Reproduced evidence

The tracked logic evidence contains executable version/hash pins, original Liberty hashes, native scope/diagnostics, every comparison, negative controls, and an index of 48 local process receipts. The full raw run is .work/logic-suite-v2/. This is an integration smoke test, not a chip-scale performance result.

Check Sky130 HD TT 1.80 V / 25 C GF180 MCU 7T5V0 TT 3.30 V / 25 C
RustSys mapped netlist 2 cells, native CEC equivalent 2 cells, native CEC equivalent
External Yosys CEC correct circuit proves; XOR→AND control rejects same
Verilator simulation all 4 input combinations agree in RTL and mapped model; wrong oracle rejects same
RustSTA full and independent checks agree agree
RustSTA no-op incremental update vs fresh full check agree, 0 ns difference agree, 0 ns difference
RustSTA vs OpenSTA setup/hold, 2 endpoints within the 0.001 ns tolerance within the 0.001 ns tolerance

The differential tolerance is 0.001 ns. Both tools use the same explicitly hashed verification-only ideal-wire library for this comparison. The Sky130 original has wireload_lumped; its wire-load metadata is removed only in a separate verification projection. Original functions/NLDM tables are unchanged; projection byte spans and hashes are recorded. The production Liberty is never modified. GF180's original already selects ideal wires. Both original-library native runs are also recorded.

The SDC has a 10 ns ideal clock, 0.2 ns input/output delays, 0.1 ns slew and 0.01 pF output load. Both endpoints are constrained. RustSTA explicitly reports unsupported min_pulse_width arcs (both PDKs) and minimum_period arcs (GF180). These warnings remain in the evidence. This is setup/hold calibration within the recorded scope, not complete Liberty support or signoff. The incremental test is deliberately a no-op update; it does not validate an ECO with changed timing arcs. Simulation samples after the first clock and does not establish arbitrary initial-state equivalence; CEC is a separate check without a reset sequence.

The tool probe also found KLayout 0.30.0, Magic 8.3.105, Netgen 1.5.133 and ngspice 45.2. Their startup/version checks do not establish a valid physical or analog flow. Icarus was absent from the checked PATH; the actual simulation uses Verilator 5.032. The probe pins entrypoints, not all shared libraries, container contents or children of wrapper scripts. No reference implementation source was inspected.

Running the logic verification

Python is a verification dependency, never a dependency of a Rust core crate. The harness adapts the Apache-2.0 RustLane black-box engine harness and adds RustROAD simulation, incremental no-op verification and explicit evidence workspace revision/lock handling. It neither rebuilds nor modifies sibling RustSys/RustSTA repositories. It creates a fresh dedicated evidence workspace; its simple HEAD is not a RustROAD physical workspace and cannot be reused by rustroad init.

Before the suite, inspect free -h. The upfront budget is one active child, 128 objects plus 256 arcs at a conservative 256 bytes each, 1 corner, 2 threads, 2–4 MiB graph/tag state, up to 640 MiB for parsed libraries, 256 MiB projection and 256 MiB runtime overhead. Paths are capped at 8, native SAT obligations at 10,000 conflicts and sweep candidates at 256. The external solver has a hard 30 second CPU/wall limit and 2 GiB address-space cap because its public command has no conflict-limit option. Files/logs are capped at 64 MiB; identities at 256 MiB. Processes run serially; libraries are not cloned into parallel workers.

free -h
ulimit -v 2097152
CARGO_BUILD_JOBS=2 RUST_TEST_THREADS=2 RAYON_NUM_THREADS=2 \
/usr/bin/time -v -o .work/logic-repeat.time timeout 180s \
python3 scripts/verify_logic.py \
  --workspace .work/logic-repeat --base-rev empty \
  --rustsys /absolute/path/to/rustsys \
  --rusteda /absolute/path/to/RustSTA/rusteda \
  --ruststa /absolute/path/to/ruststa \
  --sky130-lib /absolute/path/to/sky130_fd_sc_hd__tt_025C_1v80.lib \
  --gf180-lib /absolute/path/to/gf180mcu_fd_sc_mcu7t5v0__tt_025C_3v30.lib \
  --yosys /absolute/path/to/yosys --opensta /absolute/path/to/sta \
  --verilator /absolute/path/to/verilator --threads 2 --timeout-seconds 30

The directory must not exist. Outputs include captured Verilog/SDC, synthesis and checker reports, independent reference scripts, stdout/stderr, full /usr/bin/time -v receipts, versions and hashes. Missing tools/libraries produce unverified (exit 3), failed evidence exit 1, successful scoped evidence exit 0. A process exit alone is never a proof: CEC verdicts, simulator markers, negative controls, timing scope, finite values and tolerance are all checked. Outer timeout bounds the whole suite; preserve evidence from interruption. Child limits are process limits, not a filesystem/network sandbox or an aggregate memory cgroup; use the parent AGENTS.md cgroup policy for larger campaigns.

Read-only readiness API

rustroad-flow::assess_path(&Path) reads a rustroad.flow.v1 manifest. The CLI runs it under the physical workspace's shared lock:

rustroad flow-check --workspace .work/design \
  --manifest fixtures/flow/local-pinned.json

local-pinned.json is the measured host's explicit profile, not a portable installer. unconfigured.json is a portable empty starting profile and keeps both required PDK rows visible. Each configured file requires an absolute path and lowercase SHA-256. The manifest is limited to 1 MiB, 16 tools, 8 PDKs and 64 file identities. Hashing streams a 64 KiB buffer, with a 256 MiB per-file cap; regular-file checks and nonblocking opens reject FIFOs. No subprocess is started by the Rust API. Expected RSS is below 16 MiB excluding runtime/CLI state; no per-node graphs, tag tables, cuts, clauses or paths are created.

A tool entry may carry "not_for_signoff": "<reason>". Such a tool's identity is reported as not_for_signoff and every stage that depends on it stays unverified with tool_<id>_not_for_signoff in missing. The host Magic 8.3.105, KLayout 0.30.0 and Netgen 1.5.133 in local-pinned.json are marked this way; foundry signoff uses the pinned image in fixtures/flow/signoff-pinned.json (see signoff.md).

ready_to_attempt only means required pinned files matched. Every stage still has verification_status: "not_run"; missing or mismatched inputs are unverified. Unknown timing scope fields are null, never invented zeroes. A missing routing implementation and absent extracted-parasitics adapter keep full-loop readiness unverified even if all executables are installed. The SPEF limitation is tied to the frozen binary/adapter used in this run, not a claim about future RustSTA revisions.

python3 scripts/flow_probe.py --workspace .work/design --manifest fixtures/flow/local-pinned.json executes allowlisted version commands under a shared lock, a 1 GiB address-space cap, a 3 second deadline per tool and a 64 KiB output cap, emitting only JSON to stdout. It does not mutate the workspace.

Independent placement legality

DEF control evidence validates the actual 24-cell, 6-row CLI export with an independent Python checker. It rejects injected cell overlap, off-grid placement, duplicate/missing cells, master changes and unsupported statements. This checker does not reproduce the row-packer: it uses an x-axis sweep with a Fenwick index to reject overlapping rows, a lattice lookup and sorted cell intervals to check each placement.

ulimit -v 1048576
/usr/bin/time -v -o .work/def-controls.time timeout 30s \
python3 scripts/verify_def.py --input fixtures/physical-small.json \
  --def .work/physical-small.def --workspace .work/def-controls-repeat --base-rev empty

Inputs are bounded to 16 MiB, 250,000 cells and 100,000 rows. The independent checker uses O((cells + rows) log(cells + rows)) work and bounded linear storage; no pairwise overlap matrix or path materialization. A conservative 1 GiB cap covers JSON objects, dictionaries, coordinate-compressed row events and sorting. The checker handles only the documented single-height, N-oriented, one-statement-per-line emitted DEF subset. DRC/LVS and connectivity remain unchecked.

Next implementation gate

Import real technology/cell LEF plus mapped-Verilog connectivity with explicit unsupported-construct diagnostics and consistent integer DBU. Join this with RustROAD placement, then add bounded net-aware placement and legal detailed routing. For both PDKs pin original LEF/GDS, extraction rules, DRC and LVS decks; stream out real referenced cell geometry and independently reopen the GDS. Run DRC and extracted-netlist LVS with positive/negative controls. Add a RustSTA extracted-parasitics adapter and changed-ECO incremental/full comparisons before calling any future end-to-end result signoff. Do not substitute rectangles, missing decks or ideal wires for these requirements.