@tscircuit/fanout-solver 0.0.66 → 0.0.67

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.
@@ -1811,6 +1811,49 @@ export class FanoutSolver extends BaseSolver {
1811
1811
  const wideBoundaryBuses = unsortedBoundaryBuses.filter(
1812
1812
  (bus) => bus.connections.length >= 8,
1813
1813
  )
1814
+ const hasForeignAllLayerObstaclesInComponent = wideBoundaryBuses.some(
1815
+ (bus) =>
1816
+ this.routingSrj.obstacles.some(
1817
+ (obstacle) =>
1818
+ obstacle.componentId !== bus.componentId &&
1819
+ this.config.layerNames.every((layer) =>
1820
+ obstacle.layers.includes(layer),
1821
+ ) &&
1822
+ obstacle.center.x >= bus.componentBounds.minX &&
1823
+ obstacle.center.x <= bus.componentBounds.maxX &&
1824
+ obstacle.center.y >= bus.componentBounds.minY &&
1825
+ obstacle.center.y <= bus.componentBounds.maxY,
1826
+ ),
1827
+ )
1828
+ const dogboneCandidateCountByConnectionIndex = new Map<number, number>()
1829
+ if (hasForeignAllLayerObstaclesInComponent) {
1830
+ for (const candidate of getComponentDogboneViaSiteCandidates(
1831
+ unsortedBoundaryBuses,
1832
+ {
1833
+ viaDiameter: this.config.viaDiameter,
1834
+ viaHoleDiameter: this.config.viaHoleDiameter,
1835
+ traceWidth: this.config.traceWidth,
1836
+ clearance: this.config.clearance,
1837
+ additionalObstacles: this.routingSrj.obstacles,
1838
+ },
1839
+ )) {
1840
+ dogboneCandidateCountByConnectionIndex.set(
1841
+ candidate.connectionIndex,
1842
+ (dogboneCandidateCountByConnectionIndex.get(
1843
+ candidate.connectionIndex,
1844
+ ) ?? 0) + 1,
1845
+ )
1846
+ }
1847
+ }
1848
+ const getBusDogboneCandidateCount = (bus: PreparedBus): number =>
1849
+ bus.connections.reduce(
1850
+ (total, connection) =>
1851
+ total +
1852
+ (dogboneCandidateCountByConnectionIndex.get(
1853
+ connection.connectionIndex,
1854
+ ) ?? 0),
1855
+ 0,
1856
+ )
1814
1857
  // A single-layer turning bus beside the end of a centered source field
1815
1858
  // has fewer escape choices than a corner bus farther behind it. Reserve
1816
1859
  // that turning channel before the farther bus fences its local via sites.
@@ -1953,6 +1996,18 @@ export class FanoutSolver extends BaseSolver {
1953
1996
  ? first.connections.length - second.connections.length
1954
1997
  : second.connections.length - first.connections.length
1955
1998
  if (connectionCountDifference !== 0) return connectionCountDifference
1999
+ if (
2000
+ hasForeignAllLayerObstaclesInComponent &&
2001
+ first.connections.length >= 8 &&
2002
+ second.connections.length >= 8
2003
+ ) {
2004
+ const dogboneCandidateCountDifference =
2005
+ getBusDogboneCandidateCount(first) -
2006
+ getBusDogboneCandidateCount(second)
2007
+ if (dogboneCandidateCountDifference !== 0) {
2008
+ return dogboneCandidateCountDifference
2009
+ }
2010
+ }
1956
2011
  }
1957
2012
  const firstLayer = params.busLayerAssignments[first.busId]
1958
2013
  const secondLayer = params.busLayerAssignments[second.busId]
@@ -2571,11 +2626,14 @@ export class FanoutSolver extends BaseSolver {
2571
2626
  yield
2572
2627
  if (seedViaPoints) {
2573
2628
  const denseBoundaryBusesInRoutingOrder = [
2574
- ...multiLayerLeadingSingletonBuses,
2629
+ ...(hasForeignAllLayerObstaclesInComponent
2630
+ ? []
2631
+ : multiLayerLeadingSingletonBuses),
2575
2632
  ...boundaryBuses
2576
2633
  .filter(
2577
2634
  (bus) =>
2578
- !multiLayerLeadingSingletonBuses.includes(bus) &&
2635
+ (hasForeignAllLayerObstaclesInComponent ||
2636
+ !multiLayerLeadingSingletonBuses.includes(bus)) &&
2579
2637
  !throughAllLeadingBuses.includes(bus),
2580
2638
  )
2581
2639
  .flatMap((bus) => [
@@ -4643,7 +4701,7 @@ export class FanoutSolver extends BaseSolver {
4643
4701
  debugDense("plane-route:start", bus.busId)
4644
4702
  const targetLayer = params.busLayerAssignments[bus.busId]
4645
4703
  const blockingBusCounts = new Map<string, number>()
4646
- const busPlans = targetLayer
4704
+ let busPlans = targetLayer
4647
4705
  ? routeBus({
4648
4706
  srj: this.routingSrj,
4649
4707
  bus,
@@ -4662,6 +4720,42 @@ export class FanoutSolver extends BaseSolver {
4662
4720
  fixedViaPointsByConnectionIndex,
4663
4721
  })
4664
4722
  : null
4723
+ if (
4724
+ !busPlans &&
4725
+ targetLayer &&
4726
+ hasForeignAllLayerObstaclesInComponent
4727
+ ) {
4728
+ // Plane dogbones are matched before their full routes exist. A
4729
+ // preceding plane escape can therefore consume copper clearance
4730
+ // that the site matcher could not account for. Re-select only the
4731
+ // failed dogbone against the routes that are actually committed.
4732
+ busPlans = routeBus({
4733
+ srj: this.routingSrj,
4734
+ bus,
4735
+ targetLayer,
4736
+ acceptedPlans: matchedPlans,
4737
+ layerNames: this.config.layerNames,
4738
+ traceWidth: this.config.traceWidth,
4739
+ viaDiameter: this.config.viaDiameter,
4740
+ viaHoleDiameter: this.config.viaHoleDiameter,
4741
+ clearance: this.config.clearance,
4742
+ compactBusTracks: this.config.compactBusTracks,
4743
+ allowBlindAndBuriedVias: false,
4744
+ allowSameNetMerges: this.config.allowSameNetMerges,
4745
+ staticClearanceCache: this.routeStaticClearanceCache,
4746
+ blockingBusCounts,
4747
+ })
4748
+ if (busPlans) {
4749
+ fixedViaPointsByConnectionIndex = new Map([
4750
+ ...fixedViaPointsByConnectionIndex,
4751
+ ...busPlans.flatMap((plan) =>
4752
+ plan.via
4753
+ ? [[plan.connectionIndex, plan.via.center] as const]
4754
+ : [],
4755
+ ),
4756
+ ])
4757
+ }
4758
+ }
4665
4759
  if (!busPlans) {
4666
4760
  debugDense(
4667
4761
  "plane-route:failed",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/fanout-solver",
3
- "version": "0.0.66",
3
+ "version": "0.0.67",
4
4
  "description": "BGA fanout solver with coordinated bus-layer escapes for SimpleRouteJson",
5
5
  "module": "lib/index.ts",
6
6
  "type": "module",