Replies: 3 comments
|
This is all very interesting and forward looking - thanks for the ideas and feedback. I have also had in the back of my mind since early on that placement should be also addressed to some degree here. After all, the routing DEPENDS on the placement. And doing the placement DEPENDS on what can be routed successfully. I did take a stab at placement, and played around with it, as you saw. And it resulted in a critical mini-win, the under-BGA cap placement optimizer. But as for how to go further with placement board-wide, I only have a placeholder issue filed... I suspect a promising avenue may be:
All this can be in the CLI and GUI, as they are intended to be two interfaces to the same tools. Even AI can be fun from the Claude tab in the GUI as just like it can from the terminal. So we would have a Placement tab in the GUI. I also know, by the way, that we have significant gains yet to achieve from just optimizing the routing settings. We have yet to reproduce the human 100% connectivity on the corpus boards (91 now, plus monsters!), on the same human placement input. But getting all the way there might be too challenging. And working on placement to make the routing easier might be lower hanging fruit. |
|
Thanks Andy, that answers the vision question directly: an engine with two interfaces, and AI as a user of either one rather than a separate thing. Useful to know, and it means I'm building with the grain instead of against it. Your steps 1 to 4 are close to the loop I already run headless, so rather than theorise here I've put the substantive follow-up in #110, where you said the work lives. It covers the two parts that were not obvious to me (a hard stop-loss, and accept-or-revert graded by the router rather than the proxy), plus three concrete, self-contained issues:
The last one is the one I'd most encourage, since I think it blocks #110 more than the algorithm does. |
|
Consolidating placement discussion: this thread and the discussion that had grown on issue #110 are now merged into #118, which is the master placement thread from here on. @edgehero — your post and the reply thread are reproduced there verbatim, with authorship and dates intact:
Nothing is lost — closing here so replies land in one place. Please continue in #118. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Important
📌 Merged into #118 — the master placement thread
This thread has been folded into #118 — 📌 Placement (master thread), so that placement discussion lives in one place instead of three.
Nothing was removed. The original post below is untouched, and it is also
reproduced verbatim in #118,
as is the reply thread,
with original authors and dates intact.
This thread is closed; please continue the conversation in #118.
— maintainer note, 2 Aug 2026
I don't use KRT as a plugin. I drive it headless, as the routing engine inside a pipeline that takes a board from a written spec to production ready fab outputs. KRT is load bearing in it, and it replaced FreeRouting as my primary router months ago.
The part that is not solved is placement, and specifically: knowing when to stop routing and go move something.
The goal
Not "autoroute this board." Make a PCB from nothing to production ready. Spec in, gerbers out, autonomously, with the human gating judgement instead of operating a mouse.
Routing is one stage of maybe fifteen. Every stage has to be machine drivable and machine checkable, which is why my setup looks the way it does, and it's the root of everything I want to ask you.
The board, in the only terms that matter here: 10 layers, ~290 parts, ~150x100 mm, five controlled impedance classes. A via-less 50 ohm coplanar waveguide feed, a 5 pair 100 ohm source synchronous camera class bus with a tight skew budget, PCIe Gen2 x1 (85 ohm, die terminated), USB3 Gen1, Gigabit Ethernet, and a pile of slower buses. Fine pitch QFN and connector escapes everywhere. No BGA, which is why I keep filing QFN escape issues rather than BGA ones. It's a real product so I'll keep the application out of it, but as a routing problem it's genuinely nasty, and that's the part relevant to you.
The stack, and why each piece is in it
Everything here is open source, and every piece was chosen because an agent can drive it and a gate can check it.
pcbCLI,diodeinc/pcb(MIT, Starlark based)pcb buildgates on 0 ERC.pcb layoutsyncs the netlist into.kicad_pcband has no autorouter. That hole is exactly where you come in.diodeinc/registry+pcb searchpcb scanpcb new component(LCSC/EasyEDA, Samacsys, DigiKey) +pcb embed-stepKiCad, three interfaces, three reasons:
kicad-clipcbnewSWIG Pythonkicad-clihas nospecctraexport, so DSN round trips need SWIG. Deprecated since KiCad 9 and removed in 11, so this is borrowed time.kipy(IPC API)Which of your entry points are actually load bearing for me:
route_diff--ac-couple-match(#196/#245) for the series-cap pairsroute.py--layer-costs -1forbidden layers (#206/#207)qfn_fanout --escape-method underpadroute_planesroute_disconnected_planes --repair-padsbga_fanout(There's a second, entirely separate mechanical stack for the enclosure: OpenSCAD and trimesh for the model, Gmsh with CalculiX and FEniCSx for structural and thermal FEA. The board never touches it. I mention it only so the scope is honest.)
The loop
flowchart TB spec["Spec + datasheets<br/>(pcb scan)"] --> zen["Capture: Zener .zen<br/>pcb build, 0 ERC gate"] zen --> sim["ngspice testbenches"] sim --> sync["pcb layout<br/>netlist to KiCad, no autorouter"] sync --> P0["P0 stackup + netclasses"] P0 --> P1["P1 placement<br/>scripted packer + refine"] P1 --> gate{"floorplan_health<br/>congestion / bus-crossings /<br/>displacement / cohesion"} gate -->|FAIL| P1 gate -->|PASS| review["HUMAN GATE: render sign-off"] review --> P2["P2 criticals<br/>KRT route_diff + escapes"] P2 --> diag{"route_diagnose<br/>one RESULT= line"} diag -->|"RETRY (max 3)"| P2 diag -->|"corridor_congestion OR<br/>stop-loss: 2 strategies burned"| repair["place_route_repair<br/>diagnose, move BLOCK, re-route,<br/>accept or revert"] repair -->|success| P2 repair -->|HARD_WALL| human["HUMAN: re-block"] human --> P1 diag -->|PASS| P3["P3 bulk: KRT route.py"] P3 --> P4["P4 planes: KRT route_planes"] P4 --> P5["P5 validate<br/>adversarial verifier panel"] P5 -->|FAIL| P1 P5 --> P6["P6 fab outputs"] style repair fill:#fff4cc,stroke:#cc9900,stroke-width:2px style human fill:#ffdddd,stroke:#cc0000,stroke-width:2pxTwo doctrines that came out of being burned, in case they're useful:
"Renders are for INTENT, the oracle is for LEGALITY." No agent may adjudicate clearance from pixels. Images tell an agent what the board is trying to be; a geometry oracle decides what's legal. When I let vision near legality it hallucinated confidently.
Connectivity is geometry, never DRC.
kicad-cli pcb drccapsunconnected_itemsat 499, so on a mid layout board that number is pinned, and a change that severs a net shows delta 0 and passes every green gate. I shipped 8 dead Ethernet nets through 3 commits exactly that way. Union-find over the copper is now the only connectivity authority I trust.Where KRT sits, honestly
"KRT is better than FreeRouting" isn't a claim I can defend, so here's the version I can:
That's n=1. Your 45 board stress test (#117) is the real evidence; mine is one vote.
What made 10 layers tractable was forbidden layers (
--layer-costs -1, #206/#207). Naive outer layer bulk routing gave me 30 via barrel shorts against inner layer copper. Mandatory in my flow now, not optional.The actual problem: placement, and when to rip up
#118 is the best writing on PCB placement I've found anywhere. I think you're mostly right and interestingly wrong.
Your corpus holds placement fixed
flowchart LR subgraph A["Your 45 boards (#117)"] direction TB a1["Shipped production board"] --> a2["STRIP: tracks, vias, pours"] a2 --> a3["<b>Placement KEPT</b><br/>a human already moved parts<br/>until it routed, for weeks"] a3 --> a4["KRT re-routes it"] end subgraph B["My board (n=1)"] direction TB b1["Spec + datasheets"] --> b2["AI places it"] b2 --> b3["<b>Placement NEVER<br/>router-validated</b><br/>there is no hand"] b3 --> b4["KRT routes it"] end style a3 fill:#ddffdd,stroke:#00aa00,stroke-width:2px style b3 fill:#ffdddd,stroke:#cc0000,stroke-width:2pxYou strip tracks, vias and pours. You never strip the placement. So a production placement isn't merely "hand made", it's a post routing artifact: the human moved parts until it routed, then shipped it. Both boards in #118 (
interf_u,kit-dev-coldfire) are finished, human routed designs. Read that way, your three headline findings look less like facts about placement and more like facts about the corpus:place_route_loop, by hand, for weeks. That's your loop's output, not its input. Some of the 500x is constraint capture. Some is the answer being in the seed.--max-target-pins 40None of it is wrong. It's fitted to boards where placement is solved before your tools ever see them, so the corpus can't contain the failure I keep hitting.
Where I think you might be wrong
Your blocker is constraint capture:
True of the board file. Not true of my pipeline. The same agent that places the board also parsed the datasheets into structured text, authored the schematic as source, chose the impedance classes, sized the hot loops, and knows which pins form a bus, because it wrote them. The intent isn't trapped in a human skull. It's upstream of the
.kicad_pcb. So your conclusion may be conditional on the input format, not on placement itself..kicad_pcbis constraint poor. That's a property of the file, not the universe.Where you're right, and my scars prove it
And yet it didn't save me. Twice.
A corridor error. A magnetics block sat ~80 mm from both of its own endpoints, so 8 of its traces cut straight through the camera bus corridor. I burned days hand routing the 5th pair. Root cause was a floorplan error, visible from move zero to anyone looking at the right number.
~22 residual nets that would not route, no matter which knob I turned. Floorplan bound, not routing bound. The fix was re-floorplanning an entire quadrant.
Every signal needed to catch both already existed in my toolchain, just wired non-blocking: congestion advisory, bus-crossings report-only, the probe a whole-board aggregate (a dead 5 net bus is noise under a 228 unrouted baseline), cohesion per-group and blind to a split block. They're per-bus blockers now.
The gap
place_optimizequenchplace_route_loop--max-target-pins 40Your scoping is obviously right for your corpus. But your own dose response says the gap isn't merely unimplemented: at a 10 mm cap the quench destroyed the Xilinx to MCU corridor, the macro structure the proxies can't see. The proxies get worse exactly where I need them to work. That smells less like "tune the weights" and more like block level moves being a constraint problem, not an optimization problem, which is where I think AI belongs and a quench doesn't.
An experiment you could run tomorrow
You already have the 45 boards, the harness, and the grader. You strip the routing and keep the placement. What if you also perturbed the placement?
Displace whole blocks by 10 to 80 mm, or shuffle a subsystem to the wrong side, then run
place_route_loopand grade the recovered placement against the original. The original is free ground truth, exactly the way the original routing already is.That gives you what the corpus lacks: boards whose floorplan is known-wrong by a known amount. My prediction, which I'd love to be wrong about:
--max-target-pins 40recovers none of them, because the part that needs to move is never a passive.It also answers your own #118 question ("which seed sources are worth refining?") with something better than my anecdote. My anecdote, for what it's worth: an AI seed is good locally (it read the datasheet, it knows the hot loop) and bad globally (it put the magnetics 80 mm from both endpoints). That's inverted from a human seed, which has good macro structure and sloppy local detail. If that generalises, an AI seed may need a larger cap than 3 mm, because its macro structure is exactly the thing you shouldn't preserve by construction.
Three questions
1. Where should KRT stop? Routing engine wearing a GUI, or the engine under a whole pipeline with KiCad as file format, DRC oracle and renderer? You already built a harness checking the GUI against the CLI, which reads like CLI is ground truth, GUI is a client. Is a headless agent driver a third client you want, or one you tolerate? Either answer helps me; I'd rather build with the grain than against it.
2. What tells you the floorplan is wrong? My stop-loss (2 strategies per critical net, then examine the corridor) is a heuristic I invented after losing days to not having one. You have router iteration counts across 45 boards. Is there a signal in there that separates "the router needs another knob" from "the placement is wrong"?
3. Would you emit the blocker analysis as JSON? Your loop already computes it: failed nets plus the blocker nets walling them off, from the frontier analysis. To a GUI user that's a progress detail. To an outer loop it's the whole ballgame, the difference between "it failed" and "it failed because that bus is in the way". That one output is what lets the layer above choose between re-route, move a part, move a block, or ask a human. (Related to #352.)
Thanks for the tool. It's load bearing in a pipeline you didn't design it for, which I mean as a compliment.
All reactions