@tscircuit/fanout-solver 0.0.20 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -4
- package/lib/build-output.ts +30 -12
- package/lib/complete-original-endpoints.ts +1208 -0
- package/lib/fanout-solver.ts +150 -20
- package/lib/index.ts +15 -0
- package/lib/route-bus.ts +339 -87
- package/lib/route-single-layer-adaptive-exits.ts +1 -0
- package/lib/route-single-layer-push-shove.ts +1 -0
- package/lib/types.ts +50 -0
- package/lib/validate-fanout-solution.ts +152 -79
- package/lib/validate-original-endpoint-connectivity.ts +415 -0
- package/lib/validate-routed-copper-drc.ts +463 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -64,6 +64,9 @@ and treats each bus-layer decision atomically.
|
|
|
64
64
|
- `compactBusTracks` bends each bus into a trace/clearance-pitch routing
|
|
65
65
|
envelope, so a wide pad row does not consume a disproportionately wide
|
|
66
66
|
breakout corridor.
|
|
67
|
+
- `preferOriginalEndpointTracks` projects boundary tracks onto the original
|
|
68
|
+
downstream pad coordinates and prefers their layer when legal. This lets
|
|
69
|
+
ordered edge-pad buses make direct, visibly continuous pad connections.
|
|
67
70
|
- Chamfers orthogonal routing corners into 45° segments before validating and
|
|
68
71
|
emitting the fanout.
|
|
69
72
|
- Verifies oriented-pad, via, trace, and already-routed fanout clearance on
|
|
@@ -77,6 +80,13 @@ and treats each bus-layer decision atomically.
|
|
|
77
80
|
opt-in; different electrical nets remain hard obstacles.
|
|
78
81
|
- Audits route continuity, unique connection coverage, boundary exits, and
|
|
79
82
|
retained downstream endpoints before marking a solution complete.
|
|
83
|
+
- `completeOriginalEndpoints` adds a bounded fail-first completion stage after
|
|
84
|
+
fanout. It first places DRC-gated interstitial capacitor escapes, then tries
|
|
85
|
+
breakout-to-pad routes with layer transitions at interior points along the
|
|
86
|
+
existing fanout copper, and finally a bounded capacity-router fallback. Vias
|
|
87
|
+
at original or moved routing endpoints are rejected. A candidate is retained
|
|
88
|
+
only when it improves independently proven original endpoint connectivity
|
|
89
|
+
and the complete emitted copper remains DRC-clean.
|
|
80
90
|
- Emits supplied fanout traces, via obstacles, and moved breakout endpoints in a
|
|
81
91
|
new `SimpleRouteJson`. The returned problem is ready for a downstream
|
|
82
92
|
autorouter to finish.
|
|
@@ -115,6 +125,7 @@ const fanoutSolver = new FanoutSolver(simpleRouteJson, {
|
|
|
115
125
|
availableCornersAndSides: ["top_left", "top", "top_right"],
|
|
116
126
|
borderDistribution: "even",
|
|
117
127
|
compactBusTracks: true,
|
|
128
|
+
preferOriginalEndpointTracks: true,
|
|
118
129
|
buses: [
|
|
119
130
|
{
|
|
120
131
|
busId: "ground",
|
|
@@ -186,6 +197,10 @@ bus-layer combination search.
|
|
|
186
197
|
|
|
187
198
|
- `simpleRouteJson`: the downstream routing problem with fanout prefixes
|
|
188
199
|
- `fanoutTraces`: the newly supplied pad-to-breakout traces
|
|
200
|
+
- `completionTraces`: optional DRC-gated traces from breakouts to original
|
|
201
|
+
endpoints
|
|
202
|
+
- `endpointCompletion`: optional independent connectivity/DRC reports and
|
|
203
|
+
bounded-search diagnostics
|
|
189
204
|
- `planeTerminations`: the completed local-via connection, layer, and via data
|
|
190
205
|
- `busLayerAssignments`: the selected layer for every bus
|
|
191
206
|
- `busDirections`: the direction shared by each bus
|
|
@@ -239,10 +254,16 @@ samples in parallel, and `--sample-timeout-seconds 600` prevents a difficult
|
|
|
239
254
|
sample from blocking the remaining work. Each run writes the full ordered
|
|
240
255
|
results to `benchmark-results/srj29.json` and
|
|
241
256
|
`benchmark-results/srj29.md`. A row is marked solved only when every input
|
|
242
|
-
connection has a validated breakout
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
257
|
+
connection has a validated breakout and an independent physical-copper audit
|
|
258
|
+
proves that the emitted wires, vias, and same-net pads connect every original
|
|
259
|
+
endpoint on compatible layers. A second independent audit checks every emitted
|
|
260
|
+
trace and via against different-net pads, obstacles, traces, and vias on every
|
|
261
|
+
physical layer in its span. Reaching an arbitrary boundary point, retaining an
|
|
262
|
+
unrouted endpoint in the output JSON, or emitting copper with a DRC violation
|
|
263
|
+
does not count. The report separates fanout-prefix completion from physically
|
|
264
|
+
connected original connections so partial progress remains visible without
|
|
265
|
+
overstating it as a solution. Partial solutions are reported as benchmark
|
|
266
|
+
results instead of failing the command. `bun run benchmark:srj29` is an alias
|
|
246
267
|
for the same command.
|
|
247
268
|
|
|
248
269
|
The `SRJ29 Benchmark` GitHub Actions workflow runs the complete dataset on a
|
package/lib/build-output.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { Obstacle, SimpleRouteJson } from "@tscircuit/capacity-autorouter"
|
|
2
|
-
import type { FanoutRoutePlan } from "./types"
|
|
2
|
+
import type { FanoutRoutePlan, SimpleRouteJsonWithFanoutPlanes } from "./types"
|
|
3
3
|
|
|
4
4
|
function createViaObstacle(
|
|
5
5
|
plan: FanoutRoutePlan,
|
|
6
6
|
layerNames: string[],
|
|
7
|
+
endpoint = false,
|
|
7
8
|
): Obstacle | null {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const via = endpoint ? plan.planeEndpointVia : plan.via
|
|
10
|
+
if (!via) return null
|
|
11
|
+
const zLayers = via.spanLayers.map((layer) => {
|
|
10
12
|
const layerIndex = layerNames.indexOf(layer)
|
|
11
13
|
if (layerIndex < 0) {
|
|
12
14
|
throw new Error(
|
|
@@ -16,12 +18,12 @@ function createViaObstacle(
|
|
|
16
18
|
return layerIndex
|
|
17
19
|
})
|
|
18
20
|
return {
|
|
19
|
-
obstacleId:
|
|
21
|
+
obstacleId: `${endpoint ? "fanout-plane-endpoint-via" : "fanout-via"}:${plan.connectionName}`,
|
|
20
22
|
type: "rect",
|
|
21
|
-
center:
|
|
22
|
-
width:
|
|
23
|
-
height:
|
|
24
|
-
layers:
|
|
23
|
+
center: via.center,
|
|
24
|
+
width: via.diameter,
|
|
25
|
+
height: via.diameter,
|
|
26
|
+
layers: via.spanLayers,
|
|
25
27
|
zLayers,
|
|
26
28
|
__zLayers: zLayers,
|
|
27
29
|
connectedTo: [plan.connectionName, plan.trace.pcb_trace_id],
|
|
@@ -32,7 +34,7 @@ export function buildOutputSimpleRouteJson(params: {
|
|
|
32
34
|
inputSrj: SimpleRouteJson
|
|
33
35
|
plans: FanoutRoutePlan[]
|
|
34
36
|
layerNames: string[]
|
|
35
|
-
}):
|
|
37
|
+
}): SimpleRouteJsonWithFanoutPlanes {
|
|
36
38
|
const { inputSrj, plans, layerNames } = params
|
|
37
39
|
const outputConnections = inputSrj.connections.map((connection) => ({
|
|
38
40
|
...connection,
|
|
@@ -62,9 +64,15 @@ export function buildOutputSimpleRouteJson(params: {
|
|
|
62
64
|
}
|
|
63
65
|
const viaObstacle = createViaObstacle(plan, layerNames)
|
|
64
66
|
if (viaObstacle) viaObstacles.push(viaObstacle)
|
|
67
|
+
const endpointViaObstacle = createViaObstacle(plan, layerNames, true)
|
|
68
|
+
if (endpointViaObstacle) viaObstacles.push(endpointViaObstacle)
|
|
65
69
|
}
|
|
66
|
-
const
|
|
67
|
-
plan.trace
|
|
70
|
+
const planTraces = plans.flatMap((plan) => [
|
|
71
|
+
plan.trace,
|
|
72
|
+
...(plan.planeEndpointTrace ? [plan.planeEndpointTrace] : []),
|
|
73
|
+
])
|
|
74
|
+
const coordinateRoutePoints = planTraces.flatMap((trace) =>
|
|
75
|
+
trace.route.filter(
|
|
68
76
|
(
|
|
69
77
|
routePoint,
|
|
70
78
|
): routePoint is Extract<typeof routePoint, { x: number; y: number }> =>
|
|
@@ -107,6 +115,16 @@ export function buildOutputSimpleRouteJson(params: {
|
|
|
107
115
|
|
|
108
116
|
return {
|
|
109
117
|
...inputSrj,
|
|
118
|
+
fanoutPlaneConnectivity: plans.flatMap((plan) =>
|
|
119
|
+
plan.termination.type === "plane"
|
|
120
|
+
? [
|
|
121
|
+
{
|
|
122
|
+
connectionName: plan.connectionName,
|
|
123
|
+
layer: plan.termination.layer,
|
|
124
|
+
},
|
|
125
|
+
]
|
|
126
|
+
: [],
|
|
127
|
+
),
|
|
110
128
|
bounds: outputBounds,
|
|
111
129
|
connections: outputConnections.filter(
|
|
112
130
|
(connection) => !planeTerminatedConnectionNames.has(connection.name),
|
|
@@ -134,7 +152,7 @@ export function buildOutputSimpleRouteJson(params: {
|
|
|
134
152
|
...trace,
|
|
135
153
|
route: trace.route.map((routePoint) => ({ ...routePoint })),
|
|
136
154
|
})),
|
|
137
|
-
...
|
|
155
|
+
...planTraces,
|
|
138
156
|
],
|
|
139
157
|
}
|
|
140
158
|
}
|