The fully automated PCB design pipeline: TOML board definition, Rust analytical placement, 3D visibility-graph routing, KiCad DRC validation, and rendering. No manual KiCad steps. See the product-facing Placer/Router Engine page for the higher-level story.
mise run kicad:build
runs the full pipeline end-to-end. Every step is scripted. The only manual interaction is reviewing renders.
The board definition lives in kehvm.toml (7 subcircuits),
parsed by the Rust designgraph crate.
TOML board definition, Python constraints, KiCad symbol libraries, board config
Routed .kicad_pcb, PNG renders, GLB 3D model, DRC report
6-layer board: three signal layers with GND pours, a dedicated GND plane, a +3V3 plane, and a +1V2 plane. Power nets (GND, +3V3, +1V2, +1V8, +2V5, +5V) are connected via copper planes, not routed traces. Per-GND-pad vias connect pads into the GND pours and plane.
Placement happens in three phases. Phase 1 anchors immovable components: module sockets flush to board edges, connectors distributed along edges using best-fit-decreasing, and near-constrained decoupling caps placed by topological sort.
Phase 2 runs the canonical Rust analytical placer — a Nesterov gradient descent optimizer that simultaneously minimizes wirelength (LSE-smoothed HPWL), density (ePlace electric field), BGA escape violations, and near-constraint distances. RUDY congestion feedback steers components away from routing bottlenecks. Gamma doubles every 200 iterations for coarse-to-fine refinement.
Phase 3 legalizes (resolve overlaps), places silkscreen labels, creates copper zones, generates the USGC cartouche, and verifies no edge/overlap violations remain.
WirelengthLSE, DensityField, BGAEscape, NearPenalty
Gamma x2 every 200 iters, RUDY every 50, density weight adaptive
Up to 5000 iterations, Nesterov momentum 0.9, LR 0.05um
Greedy sort-and-place, then iterative push-apart (up to 500 iters)
V2 replaces the old grid router and KiCadRoutingTools pipeline with a Rust visibility-graph router that runs in 2-3 seconds (down from 300-400s). The router builds a visibility graph from axis-aligned obstacle corners, then runs A* pathfinding with push-and-shove rip-up negotiation.
BGA fanout uses classify_net to identify differential pairs vs. single-ended signals, applies cumulative stagger offsets for clean escape routing, and preserves pair symmetry. Power vias are placed in Rust by add_power_vias.py before routing begins, connecting each GND pad to the In1.Cu ground plane.
Each successfully routed trace becomes an obstacle for subsequent nets. PathFinder-style congestion negotiation runs multiple iterations, re-ordering failed nets first. The router handles multi-pin nets via MST decomposition into 2-pin segments.
Visibility graph + A* + rstar R-tree spatial index, push-and-shove rip-up
CSI_* (camera), ETH_* (ethernet) — impedance-controlled, pair-aware BGA fanout
Benchmark-backed route closure with KiCad DRC feedback, not hand-routed geometry
Grid router (0.1mm cell arrays), continuous_router, trace_nudge post-processing, KiCadRoutingTools dependency, CBS conflict detection module. The grid approach was fundamentally limited: 300-400s route time, 199 shorts from net_excluded overriding trace_blocked in dense BGA regions.
Visibility-graph router with continuous coordinates (no grid quantization), rstar R-tree spatial index for O(log n) obstacle queries, push-and-shove rip-up negotiation, classify_net BGA fanout with cumulative stagger, per-GND-pad power vias in Rust, DesignGraph TOML-to-KiCad pipeline with PyO3 bindings.
Continuous geometry, 3D A* routing, and DRC-guided repair replaced the retired grid path. The improvement is measured by isolated pipeline runs, not by manual board editing.
| hardware/design/kehvm.toml | Hierarchical TOML board definition (7 subcircuits) |
| crates/designgraph/ | Rust: TOML to DesignGraph to KiCad export, PyO3 bindings |
| crates/router/src/router_engine.rs | Rust: VG router with A* pathfinding + push-and-shove |
| crates/router/src/bga_fanout.rs | Rust: BGA escape routing with classify_net + cumulative stagger |
| crates/router/src/power_vias.rs | Rust: Per-GND-pad vias + power plane via drops |
| scripts/kicad/gen_schematics.py | Generates .kicad_sch files + kvm_constraints() |
| crates/placer | Canonical Rust analytical placer used by pipeline:zero |
| crates/router | 3D VG router, Pathfinder negotiation, dense escape, repair, and via validation |
| scripts/kicad/convergence.py | Automatic placement/routing/DRC feedback loop |
| crates/pipeline | Canonical orchestration from TOML to DRC and bench artifacts |
The router emits debug SVGs for every routing run. These show the obstacle field, any clearance violations, and per-net route paths overlaid on the visibility-graph node cloud. Obstacles are color-coded by net ownership: orange for one net family, blue for another. Routed paths show the A* solution through VG corner nodes.
392 axis-aligned rectangle obstacles extracted from the placed PCB. Each pad, via, and keepout zone becomes a rectangle in the visibility graph. Orange = net family A, blue = net family B. The dashed border is the board outline (120 x 92mm).
Red crosshatch overlay marks where routed traces violate minimum clearance to obstacle boundaries. These violations drive the push-and-shove rip-up iterations. Reducing these to zero is the convergence target.
HDMICP — HDMI clock positive. 6-point path through 2,294 VG nodes. The colored path shows the A* solution; small circles are the VG node cloud at obstacle corners.
XTAL_IN — HDMI transmitter crystal input. Multi-segment path navigating dense BGA escape region with tight obstacle spacing.
CEC — HDMI Consumer Electronics Control bus. Single-ended signal routed through the connector region on F.Cu.
The same visibility-graph A* router that runs in the PCB pipeline, compiled to WebAssembly and running in your browser. Click to set a source point, shift-click to set a target point. The router computes the shortest obstacle-avoiding path in real time. The demo obstacles below are a simplified subset of the actual board.
All 392 obstacles from the actual KVM board loaded into the WASM router. Click and shift-click to route between any two points on the real board layout. The obstacle density in the BGA regions (center-left and center-right clusters) shows why escape routing is the hardest part of this design.
The same simulated annealing placer used in the PCB pipeline, compiled to WebAssembly. 12 components are randomly placed on a board with interconnecting nets. Click Optimize to run 50,000 SA iterations — the placer minimizes total wirelength (HPWL) while eliminating component overlaps.