⏱️ v0.19.3 — the router stops giving up early (+29 nets), plane repair 4.6× faster, and the diff-pair tab fix we promised #557
drandyhaas
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Hey everyone! 👋
v0.19.3 is out. (There's no public 0.19.2 — that number went to an internal Rust-crate bump; you're not missing a release.) Where 0.19.1 was about copper we shouldn't have been shipping, 0.19.3 is about nets we were giving up on too early. The router's search budget is now dynamic — a net that is measurably closing in on its target keeps searching instead of hitting a fixed iteration wall — and across the 150-board stress corpus that alone completes 29 more previously-unrouted nets. Also in here: the worst plane-repair board in the corpus went from 57 minutes to 12 at about a third of the memory, the Differential Pairs tab finally honors every routing knob (the #511 gap we told you about in the 0.19.1 notes — fixed as promised), and chain steps stop ripping up work an earlier step deliberately protected.
📦 How to get it: download KiCadRoutingTools-0.19.3.zip from the Releases page, then in KiCad open Plugin and Content Manager → Install from File… and pick that zip. Prebuilt router binaries for Linux/macOS/Windows are attached —
python build_router.pyfetches them automatically, no Rust toolchain needed.⏱️ The router stops giving up early (#529)
Every A* search used to run under a fixed iteration cap. A net 90% of the way to its target got cut off exactly like a hopeless one — and our own routing chains had been quietly papering over that by passing
--max-iterations 1000000everywhere, paying for it in time and memory on every board.The Rust core now tracks each search's best remaining distance-to-target in tranches: a search that improved meaningfully during its last tranche earns another one; a search that plateaus is cut off. It's fully deterministic (pure search state, no clocks), it's on by default, and the planning skills no longer tune iteration budgets at all — the old
--max-iterationshacks are simply unnecessary.What it bought on the corpus: 29 fewer unrouted nets across 150 boards. The standouts are the boards that had been quietly starving:
duodyne_z80went 17 → 1 unrouted (99.6% routed — its long-standing "signal congestion" failures turned out to be iteration starvation),zynq7020_som29 → 19,zynq_ad936416 → 8,butterstick16 → 10,cparti_fpga9 → 3,crkbd6 → 3, and a run of tail boards (hhkb,quickfeather,ch32v203,rp2040_motorctrl, …) reached 100% for the first time.Two dials if you want them:
KICAD_DYNAMIC_ITERATIONS=0is the kill switch, andKICAD_DYNAMIC_ITERATIONS_CLAMP=200000is the speed dial — it caps the base budget so tranches do the deep searching, which measured speed-neutral-to-faster while keeping most of the completion wins.🚿 Plane repair: 4.6× faster on the worst board, smarter by default (#546, #517, #540)
crkbd— a 277×107 mm split keyboard — was our worst plane-repair board: 57 minutes and a 13.3 GB peak. Profiling showed 71% of that was board-edge clearance stamping: dense cells×edges kernels recomputed on every obstacle rebuild. Those are now scanline/banded kernels with a perimeter clearance walk and vectorized drill discs — bit-exact (we verified byte-identical outputs) — and the same board now repairs in 12.4 minutes at a 4.9 GB peak (#546).The repair strategy also changed, and it's on by default (#517): most-constrained nets first, free-space plane taps before pad rips, immediate reconnection when rip pressure is low, and casualties get their original copper restored first when the corridor is still free. Across sets 1–5 of the corpus: rip-ups −58%, restore refusals −49%, ~15% faster, DRC −7, completion flat. On top of that sits a bus-coupling-aware gate (#540): a freshly ripped net that's name-coupled to a still-pending bus (think DDR corridors) defers its reconnect so the whole bus lands together —
allwinner_h3picked up 3 more nets on its repair step.KICAD_PLANE_REPAIR_ORDERING=offrestores the old flow if you want to compare.🔀 Differential Pairs tab: fixed as promised (#511) — and matching got honest (#520, #501)
The 0.19.1 notes disclosed that 25 Basic-tab controls (including length- and time-match tolerance) were silently ignored when routing from the Differential Pairs tab, because that tab maintained its own config builder that had fallen behind. That's fixed the right way: the tab now delegates to the same config builder as everything else, so every routing knob applies — and the sweep that fixed it also audited the repair and fanout engine call sites and closed two more gaps it found there.
Length matching itself got two real upgrades:
--meander-spacingis in multiples of the width (default 2W), so wide low-impedance traces get proportionate serpentines instead of a fixed pitch tuned for thin signals, and a meander that doesn't fit in one segment spills across runs.🛡️ Chain steps stop undoing earlier work (#521) — and a flag for when you want that (#515)
A retry step once ripped up a fully-matched DDR group and re-routed it unmatched. Never again: matched groups and routed diff pairs are now recorded as protected in the project file, and later chain steps refuse to rip them —
--rip-existing-netsglobs skip them (with a printed exclusion), and plane repair never picks them as rip candidates. Naming a net exactly (no glob) is the deliberate override. Copper you lock in KiCad (Lockedon a track/via) is never rip-eligible, full stop. And impedance declarations persist the same way: a later step touching an impedance net recomputes the same stackup-derived widths instead of silently routing it at defaults.The complement is the new
--force-reroute(#515): rip the selected nets and re-route them from scratch, with the original copper held in custody and restored if the re-route comes back empty.🌊 Planes: pour-first, with vias placed where the pour will be (#424, #485)
We spent a while studying why BGA-under-plane boards end up with so many repair welds, and the answer changed our recommended workflow:
--plane-drop, default auto): every BGA/QFN ball on a plane net gets its via placed during fanout — dogbone into a gap site where one exists, exact-clearance-checked via-in-pad where it doesn't — so the pour picks it up at fill time instead of a repair pass welding it later.On our BGA testbed (
ottercast), the combination connected GND and both power planes fully for the first time, cut repair welds 3075 → 1063, and 63 of 70 BGA balls are picked up by the pour itself rather than welded to it.Separately,
create_planecan now sow a proper stitching-via lattice with a board-edge via fence (#485), with pitch derived from your highest frequency of concern (--stitch-max-freq, λ/20 rule). Stitch sites are gated on the net-anchored exact fill — a floating-pour pathology on one corpus board taught us not to trust the zone outline.🌡️ Power & thermal (#487)
Exposed pads of heat-generating parts get thermal via arrays by default (
--thermal-viasto control it),--thermal-reliefnow actually reaches the zone writer, and the JSON summary reports plane resistance and IPC-2221 trace ampacity for power nets, so you can see current margins without leaving the report.🪵 Hand-routed and older boards: now parsed, and now used (PR #534, #545)
Two classes of boards used to be second-class citizens:
tstampdialect — and any uuid-less copper — could parse as having zero existing copper. All six copper patterns now accept both dialects. If you ever pointed the tool at an older board and it acted like the board was empty, this was why.🤖 AI features without an Anthropic account (#503)
All the AI features (the planning tab, the analysis skills) now run on a configurable backend, and opencode is supported out of the box — its free tier needs zero auth setup. The GUI naming changed from Claude-specific to "AI" accordingly.
🧩 Placement toolkit progress (community)
A big thank-you to @edgehero, who landed three PRs on the experimental placement tools (
place_optimize.py/place_route_loop.py): a real clearance model (actual courtyards, board outline, front/back awareness), reproducible quench across processes, ratsnest metrics export with a pre-route screen so hopeless placements are rejected before you pay for a route, and placement blocks with rigid block translation (#459 step 1) so grouped sections move as units. The place→route loop also now consumes the router's structured blocker output instead of scraping logs.🖥️ GUI quality of life
The long-silent phases — rescue, reconciliation, cleanup, plane reconnect — now report per-net progress and honor Cancel (#527; cancel skips remaining re-routes but never abandons copper custody). Obstacle-map builds on big boards show progress instead of appearing hung (#556). And the fanout options Reset button, which had been silently doing nothing, now resets.
😬 The honesty section
Dynamic iterations has real costs, and we shipped it anyway — eyes open. Corpus-wide it added +3 DRC (two boards went 0 → 2) and +83
connection_widthwarnings — but 61 of those are a single board (duet2_3dp, which is 100% connected and whose warning explosion turned out to be insensitive to the budget mechanism; we're root-causing it separately). CPU is class-dependent: boards with many deep-but-winnable searches get faster (hackrf−16%), boards dominated by genuinely hopeless searches spend more time proving it (neo6502+42%; ~+15% summed CPU on our calibration set). If speed matters more than the last few nets,KICAD_DYNAMIC_ITERATIONS_CLAMP=200000is the trade — measured speed-neutral-to-faster, keeps most of the wins.The pour-first plane defaults were validated deeply on one board, not the corpus. The ottercast numbers above are real and the mechanism is sound, but the corpus-wide A/B is deliberately still ahead of us. Full revert is two env vars:
KICAD_FANOUT_PLANE_DROP=0andKICAD_PLANE_FRAGILITY_COST=0. Known gap: diff pairs still route pour-blind — fragility pricing doesn't reach them yet.The anchor fixes traded a warning tier for hard metrics. Landing routes on thin QFN escape stubs added ~10
connection_widthwarnings on set 1 (all in the warnings tier, no DRC) in exchange for the speed and connectivity wins above. Tracked as #547; zone copper as a route anchor is #544.Full commit-level detail in the v0.19.1…v0.19.3 compare (130 commits) and the Rust changelog in
rust_router/README.md.Bug reports and feedback hugely welcome — open an issue or reply here. Happy routing! 🎉
All reactions