@tscircuit/fanout-solver 0.0.21 → 0.0.23

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 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
@@ -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
- if (!plan.via) return null
9
- const zLayers = plan.via.spanLayers.map((layer) => {
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: `fanout-via:${plan.connectionName}`,
21
+ obstacleId: `${endpoint ? "fanout-plane-endpoint-via" : "fanout-via"}:${plan.connectionName}`,
20
22
  type: "rect",
21
- center: plan.via.center,
22
- width: plan.via.diameter,
23
- height: plan.via.diameter,
24
- layers: plan.via.spanLayers,
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
- }): SimpleRouteJson {
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 coordinateRoutePoints = plans.flatMap((plan) =>
67
- plan.trace.route.filter(
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
- ...plans.map((plan) => plan.trace),
155
+ ...planTraces,
138
156
  ],
139
157
  }
140
158
  }