@tscircuit/fanout-solver 0.0.23 → 0.0.25
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 +6 -7
- package/lib/fanout-solver.ts +23 -20
- package/lib/index.ts +1 -0
- package/lib/prepare-buses.ts +29 -8
- package/lib/route-bus.ts +38 -18
- package/lib/route-single-layer-push-shove.ts +5 -2
- package/lib/types.ts +11 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -61,12 +61,12 @@ and treats each bus-layer decision atomically.
|
|
|
61
61
|
- Uses a straight pad-pair escape when the via fits. Otherwise it uses a 45°
|
|
62
62
|
four-pad interstitial escape and nested side bands that spread deeper
|
|
63
63
|
two-layer buses around already-routed outer buses.
|
|
64
|
-
- `compactBusTracks`
|
|
65
|
-
|
|
66
|
-
breakout corridor.
|
|
67
|
-
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
- `compactBusTracks` provides a trace/clearance-pitch fallback envelope when
|
|
65
|
+
the original endpoint track cannot route, so a wide pad row does not consume
|
|
66
|
+
a disproportionately wide breakout corridor.
|
|
67
|
+
- Boundary tracks project onto the original downstream pad coordinates and
|
|
68
|
+
prefer their layer when legal. This lets ordered edge-pad buses make direct,
|
|
69
|
+
visibly continuous pad connections.
|
|
70
70
|
- Chamfers orthogonal routing corners into 45° segments before validating and
|
|
71
71
|
emitting the fanout.
|
|
72
72
|
- Verifies oriented-pad, via, trace, and already-routed fanout clearance on
|
|
@@ -125,7 +125,6 @@ const fanoutSolver = new FanoutSolver(simpleRouteJson, {
|
|
|
125
125
|
availableCornersAndSides: ["top_left", "top", "top_right"],
|
|
126
126
|
borderDistribution: "even",
|
|
127
127
|
compactBusTracks: true,
|
|
128
|
-
preferOriginalEndpointTracks: true,
|
|
129
128
|
buses: [
|
|
130
129
|
{
|
|
131
130
|
busId: "ground",
|
package/lib/fanout-solver.ts
CHANGED
|
@@ -40,7 +40,6 @@ interface ResolvedFanoutConfig {
|
|
|
40
40
|
viaHoleDiameter: number
|
|
41
41
|
clearance: number
|
|
42
42
|
compactBusTracks: boolean
|
|
43
|
-
preferOriginalEndpointTracks: boolean
|
|
44
43
|
allowSameNetMerges: boolean
|
|
45
44
|
singleLayerPushAndShove: boolean
|
|
46
45
|
singleLayerAdaptiveExits: boolean
|
|
@@ -132,7 +131,6 @@ function resolveConfig(
|
|
|
132
131
|
viaHoleDiameter,
|
|
133
132
|
clearance,
|
|
134
133
|
compactBusTracks: options.compactBusTracks ?? false,
|
|
135
|
-
preferOriginalEndpointTracks: options.preferOriginalEndpointTracks ?? false,
|
|
136
134
|
allowSameNetMerges: options.allowSameNetMerges ?? false,
|
|
137
135
|
singleLayerPushAndShove: options.singleLayerPushAndShove ?? false,
|
|
138
136
|
singleLayerAdaptiveExits: options.singleLayerAdaptiveExits ?? false,
|
|
@@ -210,6 +208,18 @@ function getBusDistanceToBoundary(bus: PreparedBus): number {
|
|
|
210
208
|
}
|
|
211
209
|
}
|
|
212
210
|
|
|
211
|
+
function busUsesDestinationGuidedTracks(bus: PreparedBus): boolean {
|
|
212
|
+
const isHorizontal = bus.direction === "left" || bus.direction === "right"
|
|
213
|
+
return bus.connections.some((connection) => {
|
|
214
|
+
const exitTargetPoint = connection.exitTargetPoint ?? connection.targetPoint
|
|
215
|
+
const sourceTrack = isHorizontal
|
|
216
|
+
? connection.sourcePoint.y
|
|
217
|
+
: connection.sourcePoint.x
|
|
218
|
+
const targetTrack = isHorizontal ? exitTargetPoint.y : exitTargetPoint.x
|
|
219
|
+
return Math.abs(sourceTrack - targetTrack) > 1e-6
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
|
|
213
223
|
function busIsOnOutwardComponentEdge(bus: PreparedBus): boolean {
|
|
214
224
|
const isHorizontal = bus.direction === "left" || bus.direction === "right"
|
|
215
225
|
const directionalCoordinates = isHorizontal
|
|
@@ -256,14 +266,8 @@ function createPreferredLayerAssignment(params: {
|
|
|
256
266
|
buses: PreparedBus[]
|
|
257
267
|
escapeLayers: string[]
|
|
258
268
|
escapeLayersByBusId: Readonly<Record<string, readonly string[]>>
|
|
259
|
-
preferOriginalEndpointTracks: boolean
|
|
260
269
|
}): Readonly<Record<string, string>> {
|
|
261
|
-
const {
|
|
262
|
-
buses,
|
|
263
|
-
escapeLayers,
|
|
264
|
-
escapeLayersByBusId,
|
|
265
|
-
preferOriginalEndpointTracks,
|
|
266
|
-
} = params
|
|
270
|
+
const { buses, escapeLayers, escapeLayersByBusId } = params
|
|
267
271
|
const assignment: Record<string, string> = {}
|
|
268
272
|
const directionsByComponent = new Map<string, Set<PreparedBus["direction"]>>()
|
|
269
273
|
let nextViaLayerIndex = 0
|
|
@@ -288,7 +292,7 @@ function createPreferredLayerAssignment(params: {
|
|
|
288
292
|
)
|
|
289
293
|
if (
|
|
290
294
|
routableEscapeLayers.includes(sourceLayer) &&
|
|
291
|
-
(
|
|
295
|
+
(busUsesDestinationGuidedTracks(bus) || busIsOnOutwardComponentEdge(bus))
|
|
292
296
|
) {
|
|
293
297
|
assignment[bus.busId] = sourceLayer
|
|
294
298
|
} else if (viaLayers.length > 0) {
|
|
@@ -347,7 +351,6 @@ function getCandidateEscapeLayersForBus(params: {
|
|
|
347
351
|
viaHoleDiameter: config.viaHoleDiameter,
|
|
348
352
|
clearance: config.clearance,
|
|
349
353
|
compactBusTracks: config.compactBusTracks,
|
|
350
|
-
preferOriginalEndpointTracks: config.preferOriginalEndpointTracks,
|
|
351
354
|
allowSameNetMerges: config.allowSameNetMerges,
|
|
352
355
|
staticClearanceCache,
|
|
353
356
|
}) !== null,
|
|
@@ -458,7 +461,6 @@ export class FanoutSolver extends BaseSolver {
|
|
|
458
461
|
buses: this.preparedBuses,
|
|
459
462
|
escapeLayers: this.config.escapeLayers,
|
|
460
463
|
escapeLayersByBusId,
|
|
461
|
-
preferOriginalEndpointTracks: this.config.preferOriginalEndpointTracks,
|
|
462
464
|
}),
|
|
463
465
|
generatedAssignments,
|
|
464
466
|
maxAssignments: this.config.maxLayerCombinations,
|
|
@@ -605,7 +607,6 @@ export class FanoutSolver extends BaseSolver {
|
|
|
605
607
|
viaHoleDiameter: this.config.viaHoleDiameter,
|
|
606
608
|
clearance: this.config.clearance,
|
|
607
609
|
compactBusTracks: this.config.compactBusTracks,
|
|
608
|
-
preferOriginalEndpointTracks: this.config.preferOriginalEndpointTracks,
|
|
609
610
|
allowSameNetMerges: this.config.allowSameNetMerges,
|
|
610
611
|
staticClearanceCache: this.routeStaticClearanceCache,
|
|
611
612
|
blockingBusCounts: currentBusBlockingCounts,
|
|
@@ -791,7 +792,12 @@ export class FanoutSolver extends BaseSolver {
|
|
|
791
792
|
const viaCount = getPlanViaCount(state.plans)
|
|
792
793
|
const offEndpointLayerConnectionCount = this.preparedBuses.reduce(
|
|
793
794
|
(count, bus) => {
|
|
794
|
-
if (
|
|
795
|
+
if (
|
|
796
|
+
bus.termination.type !== "boundary" ||
|
|
797
|
+
!busUsesDestinationGuidedTracks(bus)
|
|
798
|
+
) {
|
|
799
|
+
return count
|
|
800
|
+
}
|
|
795
801
|
const sourceLayer = bus.connections[0]?.sourceLayer
|
|
796
802
|
return state.assignment[bus.busId] === sourceLayer
|
|
797
803
|
? count
|
|
@@ -802,9 +808,7 @@ export class FanoutSolver extends BaseSolver {
|
|
|
802
808
|
return (
|
|
803
809
|
routeLength +
|
|
804
810
|
viaCount * 0.1 +
|
|
805
|
-
|
|
806
|
-
? offEndpointLayerConnectionCount * 10_000
|
|
807
|
-
: 0) +
|
|
811
|
+
offEndpointLayerConnectionCount * 10_000 +
|
|
808
812
|
assignmentLoadPenalty(
|
|
809
813
|
state.assignment,
|
|
810
814
|
this.preparedBuses,
|
|
@@ -835,10 +839,11 @@ export class FanoutSolver extends BaseSolver {
|
|
|
835
839
|
)
|
|
836
840
|
}
|
|
837
841
|
const sourceLayer = bus.connections[0]?.sourceLayer
|
|
842
|
+
const preferSourceLayer = busUsesDestinationGuidedTracks(bus)
|
|
838
843
|
const orderedLayers = candidateLayers.toSorted(
|
|
839
844
|
(first, second) =>
|
|
840
845
|
(layerLoads.get(first) ?? 0) - (layerLoads.get(second) ?? 0) ||
|
|
841
|
-
(
|
|
846
|
+
(preferSourceLayer
|
|
842
847
|
? Number(second === sourceLayer) - Number(first === sourceLayer)
|
|
843
848
|
: Number(first === sourceLayer) -
|
|
844
849
|
Number(second === sourceLayer)) ||
|
|
@@ -858,8 +863,6 @@ export class FanoutSolver extends BaseSolver {
|
|
|
858
863
|
viaHoleDiameter: this.config.viaHoleDiameter,
|
|
859
864
|
clearance: this.config.clearance,
|
|
860
865
|
compactBusTracks: this.config.compactBusTracks,
|
|
861
|
-
preferOriginalEndpointTracks:
|
|
862
|
-
this.config.preferOriginalEndpointTracks,
|
|
863
866
|
allowSameNetMerges: this.config.allowSameNetMerges,
|
|
864
867
|
staticClearanceCache: this.routeStaticClearanceCache,
|
|
865
868
|
},
|
package/lib/index.ts
CHANGED
package/lib/prepare-buses.ts
CHANGED
|
@@ -643,6 +643,7 @@ function prepareConnection(params: {
|
|
|
643
643
|
sourceGrid: ComponentGrid
|
|
644
644
|
componentGrids: ComponentGrid[]
|
|
645
645
|
termination: FanoutBusTermination
|
|
646
|
+
exitTargetPoint?: { x: number; y: number }
|
|
646
647
|
}): PreparedConnection {
|
|
647
648
|
const {
|
|
648
649
|
connection,
|
|
@@ -650,6 +651,7 @@ function prepareConnection(params: {
|
|
|
650
651
|
sourceGrid,
|
|
651
652
|
componentGrids,
|
|
652
653
|
termination,
|
|
654
|
+
exitTargetPoint,
|
|
653
655
|
} = params
|
|
654
656
|
for (
|
|
655
657
|
let sourcePointIndex = 0;
|
|
@@ -671,6 +673,12 @@ function prepareConnection(params: {
|
|
|
671
673
|
`FanoutSolver: connection "${connection.name}" has no source layer shared with its BGA pad`,
|
|
672
674
|
)
|
|
673
675
|
}
|
|
676
|
+
const targetPoint = chooseTargetPoint(
|
|
677
|
+
sourcePoint,
|
|
678
|
+
connection,
|
|
679
|
+
sourcePointIndex,
|
|
680
|
+
termination,
|
|
681
|
+
)
|
|
674
682
|
return {
|
|
675
683
|
connection,
|
|
676
684
|
connectionIndex,
|
|
@@ -678,12 +686,8 @@ function prepareConnection(params: {
|
|
|
678
686
|
sourcePointIndex,
|
|
679
687
|
sourceLayer,
|
|
680
688
|
sourceObstacle: sourceMatch.obstacle,
|
|
681
|
-
targetPoint
|
|
682
|
-
|
|
683
|
-
connection,
|
|
684
|
-
sourcePointIndex,
|
|
685
|
-
termination,
|
|
686
|
-
),
|
|
689
|
+
targetPoint,
|
|
690
|
+
exitTargetPoint: exitTargetPoint ?? targetPoint,
|
|
687
691
|
}
|
|
688
692
|
}
|
|
689
693
|
throw new Error(
|
|
@@ -698,8 +702,10 @@ function inferDirection(
|
|
|
698
702
|
let dx = 0
|
|
699
703
|
let dy = 0
|
|
700
704
|
for (const preparedConnection of connections) {
|
|
701
|
-
|
|
702
|
-
|
|
705
|
+
const exitTargetPoint =
|
|
706
|
+
preparedConnection.exitTargetPoint ?? preparedConnection.targetPoint
|
|
707
|
+
dx += exitTargetPoint.x - preparedConnection.sourcePoint.x
|
|
708
|
+
dy += exitTargetPoint.y - preparedConnection.sourcePoint.y
|
|
703
709
|
}
|
|
704
710
|
if (Math.abs(dx) < 1e-9 && Math.abs(dy) < 1e-9) {
|
|
705
711
|
throw new Error(
|
|
@@ -941,6 +947,20 @@ export function prepareFanoutBuses(
|
|
|
941
947
|
srj.connections.map((connection, index) => [connection.name, index]),
|
|
942
948
|
)
|
|
943
949
|
const resolvedBusInputs = resolveBusSpecs(srj, options).map((busSpec) => {
|
|
950
|
+
for (const [connectionName, point] of Object.entries(
|
|
951
|
+
busSpec.connectionExitTargets ?? {},
|
|
952
|
+
)) {
|
|
953
|
+
if (!busSpec.connectionNames.includes(connectionName)) {
|
|
954
|
+
throw new Error(
|
|
955
|
+
`FanoutSolver: connectionExitTargets contains connection "${connectionName}" outside bus "${busSpec.busId}"`,
|
|
956
|
+
)
|
|
957
|
+
}
|
|
958
|
+
if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) {
|
|
959
|
+
throw new Error(
|
|
960
|
+
`FanoutSolver: connectionExitTargets for connection "${connectionName}" must contain finite x and y coordinates`,
|
|
961
|
+
)
|
|
962
|
+
}
|
|
963
|
+
}
|
|
944
964
|
const connections = busSpec.connectionNames.map((connectionName) => {
|
|
945
965
|
const connectionIndex = connectionIndexByName.get(connectionName)
|
|
946
966
|
if (connectionIndex === undefined) {
|
|
@@ -962,6 +982,7 @@ export function prepareFanoutBuses(
|
|
|
962
982
|
sourceGrid,
|
|
963
983
|
componentGrids,
|
|
964
984
|
termination: busSpec.termination ?? { type: "boundary" },
|
|
985
|
+
exitTargetPoint: busSpec.connectionExitTargets?.[connection.name],
|
|
965
986
|
}),
|
|
966
987
|
)
|
|
967
988
|
return { busSpec, sourceGrid, preparedConnections }
|
package/lib/route-bus.ts
CHANGED
|
@@ -39,7 +39,6 @@ export interface RouteBusParams {
|
|
|
39
39
|
viaHoleDiameter: number
|
|
40
40
|
clearance: number
|
|
41
41
|
compactBusTracks: boolean
|
|
42
|
-
preferOriginalEndpointTracks?: boolean
|
|
43
42
|
allowSameNetMerges?: boolean
|
|
44
43
|
staticClearanceCache?: RouteBusStaticClearanceCache
|
|
45
44
|
blockingBusCounts?: Map<string, number>
|
|
@@ -293,10 +292,19 @@ function getTrackCandidates(params: {
|
|
|
293
292
|
function getPreferredTrack(params: {
|
|
294
293
|
bus: PreparedBus
|
|
295
294
|
connection: PreparedConnection
|
|
295
|
+
}): number {
|
|
296
|
+
return getPerpendicularAxis(
|
|
297
|
+
params.connection.exitTargetPoint ?? params.connection.targetPoint,
|
|
298
|
+
params.bus.direction,
|
|
299
|
+
)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function getLegacyPreferredTrack(params: {
|
|
303
|
+
bus: PreparedBus
|
|
304
|
+
connection: PreparedConnection
|
|
296
305
|
targetUsesVia: boolean
|
|
297
306
|
interstitialEscape: boolean
|
|
298
307
|
compactBusTracks: boolean
|
|
299
|
-
preferOriginalEndpointTracks: boolean
|
|
300
308
|
traceWidth: number
|
|
301
309
|
viaDiameter: number
|
|
302
310
|
clearance: number
|
|
@@ -307,7 +315,6 @@ function getPreferredTrack(params: {
|
|
|
307
315
|
targetUsesVia,
|
|
308
316
|
interstitialEscape,
|
|
309
317
|
compactBusTracks,
|
|
310
|
-
preferOriginalEndpointTracks,
|
|
311
318
|
traceWidth,
|
|
312
319
|
viaDiameter,
|
|
313
320
|
clearance,
|
|
@@ -319,9 +326,6 @@ function getPreferredTrack(params: {
|
|
|
319
326
|
connection.sourcePoint,
|
|
320
327
|
bus.direction,
|
|
321
328
|
)
|
|
322
|
-
if (preferOriginalEndpointTracks) {
|
|
323
|
-
return getPerpendicularAxis(connection.targetPoint, bus.direction)
|
|
324
|
-
}
|
|
325
329
|
if (compactBusTracks) {
|
|
326
330
|
const connectionRank = getConnectionRank(bus, connection)
|
|
327
331
|
const componentCenter =
|
|
@@ -332,11 +336,9 @@ function getPreferredTrack(params: {
|
|
|
332
336
|
(traceWidth + clearance)
|
|
333
337
|
)
|
|
334
338
|
}
|
|
335
|
-
if (!targetUsesVia) return sourceTrack
|
|
336
|
-
if (!interstitialEscape) return sourceTrack
|
|
339
|
+
if (!targetUsesVia || !interstitialEscape) return sourceTrack
|
|
337
340
|
|
|
338
341
|
const depthInRows = getDepthInRows(bus)
|
|
339
|
-
|
|
340
342
|
const trackPitch = traceWidth + clearance
|
|
341
343
|
const halfConnectionCount = Math.ceil(bus.connections.length / 2)
|
|
342
344
|
const sideBandWidth = (halfConnectionCount - 1) * trackPitch
|
|
@@ -1296,7 +1298,6 @@ export function routeBusAlternatives(
|
|
|
1296
1298
|
viaHoleDiameter,
|
|
1297
1299
|
clearance,
|
|
1298
1300
|
compactBusTracks,
|
|
1299
|
-
preferOriginalEndpointTracks = false,
|
|
1300
1301
|
staticClearanceCache,
|
|
1301
1302
|
blockingBusCounts,
|
|
1302
1303
|
allowSameNetMerges = false,
|
|
@@ -1359,23 +1360,42 @@ export function routeBusAlternatives(
|
|
|
1359
1360
|
|
|
1360
1361
|
const preparedConnection = connectionOrder[connectionIndex]!
|
|
1361
1362
|
const connectionRank = getConnectionRank(bus, preparedConnection)
|
|
1362
|
-
const
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1363
|
+
const preferredTracks = [
|
|
1364
|
+
getPreferredTrack({
|
|
1365
|
+
bus,
|
|
1366
|
+
connection: preparedConnection,
|
|
1367
|
+
}),
|
|
1368
|
+
getLegacyPreferredTrack({
|
|
1366
1369
|
bus,
|
|
1367
1370
|
connection: preparedConnection,
|
|
1368
1371
|
targetUsesVia,
|
|
1369
1372
|
interstitialEscape,
|
|
1370
1373
|
compactBusTracks,
|
|
1371
|
-
preferOriginalEndpointTracks,
|
|
1372
1374
|
traceWidth,
|
|
1373
1375
|
viaDiameter,
|
|
1374
1376
|
clearance,
|
|
1375
1377
|
}),
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1378
|
+
].filter(
|
|
1379
|
+
(track, index, tracks) =>
|
|
1380
|
+
tracks.findIndex((candidate) => Math.abs(candidate - track) < 1e-9) ===
|
|
1381
|
+
index,
|
|
1382
|
+
)
|
|
1383
|
+
const trackCandidates = preferredTracks
|
|
1384
|
+
.flatMap((preferredTrack) =>
|
|
1385
|
+
getTrackCandidates({
|
|
1386
|
+
bus,
|
|
1387
|
+
connection: preparedConnection,
|
|
1388
|
+
preferredTrack,
|
|
1389
|
+
traceWidth,
|
|
1390
|
+
clearance,
|
|
1391
|
+
}),
|
|
1392
|
+
)
|
|
1393
|
+
.filter(
|
|
1394
|
+
(track, index, tracks) =>
|
|
1395
|
+
tracks.findIndex(
|
|
1396
|
+
(candidate) => Math.abs(candidate.value - track.value) < 1e-9,
|
|
1397
|
+
) === index,
|
|
1398
|
+
)
|
|
1379
1399
|
for (
|
|
1380
1400
|
let trackIndex = 0;
|
|
1381
1401
|
trackIndex < trackCandidates.length;
|
|
@@ -197,7 +197,10 @@ function getCornerChannelPrefixes(params: {
|
|
|
197
197
|
maximum: bus.componentBounds.maxX,
|
|
198
198
|
}
|
|
199
199
|
const directionalDistance = sign * (componentExitAxis - sourceAxis)
|
|
200
|
-
const targetTrack = getPerpendicularAxis(
|
|
200
|
+
const targetTrack = getPerpendicularAxis(
|
|
201
|
+
connection.exitTargetPoint ?? connection.targetPoint,
|
|
202
|
+
direction,
|
|
203
|
+
)
|
|
201
204
|
const lanePitch = traceWidth + clearance
|
|
202
205
|
const exitAxis = getExitAxis(bus)
|
|
203
206
|
const candidates = ([-1, 1] as const)
|
|
@@ -280,7 +283,7 @@ function completeCornerChannelRoute(params: {
|
|
|
280
283
|
const minimumTrack = boundaryMinimum + traceWidth / 2
|
|
281
284
|
const maximumTrack = boundaryMaximum - traceWidth / 2
|
|
282
285
|
const targetTrack = getPerpendicularAxis(
|
|
283
|
-
item.connection.targetPoint,
|
|
286
|
+
item.connection.exitTargetPoint ?? item.connection.targetPoint,
|
|
284
287
|
direction,
|
|
285
288
|
)
|
|
286
289
|
const trackStep = lanePitch / 2
|
package/lib/types.ts
CHANGED
|
@@ -63,6 +63,15 @@ export interface FanoutBusSpec extends SimpleRouteBus {
|
|
|
63
63
|
sourceComponentId?: string
|
|
64
64
|
direction?: FanoutDirection
|
|
65
65
|
preferredExit?: FanoutBorderTarget
|
|
66
|
+
/**
|
|
67
|
+
* Preferred downstream routing point for each connection after it leaves the
|
|
68
|
+
* fanout boundary. This is routing guidance only and does not replace the
|
|
69
|
+
* connection's electrical endpoint in SimpleRouteJson.
|
|
70
|
+
*
|
|
71
|
+
* A caller coordinating two fanouts can pass the paired fanout's selected
|
|
72
|
+
* exit here so both sides aim toward the same track.
|
|
73
|
+
*/
|
|
74
|
+
connectionExitTargets?: Readonly<Record<string, Point2D>>
|
|
66
75
|
/**
|
|
67
76
|
* Defaults to `{ type: "boundary" }`.
|
|
68
77
|
*
|
|
@@ -102,13 +111,6 @@ export interface FanoutSolverOptions {
|
|
|
102
111
|
viaHoleDiameter?: number
|
|
103
112
|
clearance?: number
|
|
104
113
|
compactBusTracks?: boolean
|
|
105
|
-
/**
|
|
106
|
-
* Prefer the perpendicular coordinate of each original downstream endpoint
|
|
107
|
-
* when assigning boundary tracks. Ordered edge-pad buses can then enter
|
|
108
|
-
* same-layer pads directly instead of requiring a second global router to
|
|
109
|
-
* undo compacted fanout tracks.
|
|
110
|
-
*/
|
|
111
|
-
preferOriginalEndpointTracks?: boolean
|
|
112
114
|
/** Allow branches belonging to the same electrical net to share copper. */
|
|
113
115
|
allowSameNetMerges?: boolean
|
|
114
116
|
singleLayerPushAndShove?: boolean
|
|
@@ -216,6 +218,8 @@ export interface PreparedConnection {
|
|
|
216
218
|
sourceLayer: string
|
|
217
219
|
sourceObstacle: Obstacle
|
|
218
220
|
targetPoint: ConnectionPoint
|
|
221
|
+
/** Preferred downstream point used to choose the boundary exit track. */
|
|
222
|
+
exitTargetPoint?: Point2D
|
|
219
223
|
}
|
|
220
224
|
|
|
221
225
|
export interface PreparedBus {
|