Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 29 additions & 19 deletions lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import {
applyInitialAssignments,
type TinyHyperGraphInitialAssignment,
} from "./initialAssignments"
import {
createLayerAwareRouteHeuristic,
getLayerAwarePortHeuristicCost,
type LayerAwareRouteHeuristic,
} from "./layer-aware-route-heuristic"
import { MinHeap } from "./MinHeap"
import { shuffle } from "./shuffle"
import type { StaticallyUnroutableRouteSummary } from "./static-reachability"
Expand Down Expand Up @@ -167,6 +172,7 @@ export interface TinyHyperGraphProblem {
export interface TinyHyperGraphProblemSetup {
// portHCostToEndOfRoute[portId * routeCount + routeId] = distance from port to end of route
portHCostToEndOfRoute: Float64Array
layerAwareRouteHeuristic: LayerAwareRouteHeuristic
portEndpointNetIds: Array<Set<NetId>>
/** -1 for no endpoint, -2 for endpoints from multiple nets, otherwise the sole endpoint net. */
portEndpointReservationNetId: Int32Array
Expand Down Expand Up @@ -458,13 +464,15 @@ export class TinyHyperGraphSolver extends BaseSolver {

computeProblemSetup(): TinyHyperGraphProblemSetup {
const { topology, problem } = this
const layerAwareRouteHeuristic = createLayerAwareRouteHeuristic({
topology,
problem,
distanceToCost: this.DISTANCE_TO_COST,
minViaPadDiameter: this.minViaPadDiameter,
})
const portHCostToEndOfRoute = this.USE_LAZY_ROUTE_HEURISTIC
? undefined
: new Float64Array(topology.portCount * problem.routeCount)
const portX = (topology.portRoutingCostX ??
topology.portX) as unknown as ArrayLike<number>
const portY = (topology.portRoutingCostY ??
topology.portY) as unknown as ArrayLike<number>
const portEndpointNetIds = Array.from(
{ length: topology.portCount },
() => new Set<NetId>(),
Expand All @@ -488,21 +496,23 @@ export class TinyHyperGraphSolver extends BaseSolver {
recordEndpointNet(problem.routeEndPort[routeId]!, routeNetId)

if (portHCostToEndOfRoute) {
const endPortId = problem.routeEndPort[routeId]
const endX = portX[endPortId]
const endY = portY[endPortId]

for (let portId = 0; portId < topology.portCount; portId++) {
const dx = portX[portId] - endX
const dy = portY[portId] - endY
portHCostToEndOfRoute[portId * problem.routeCount + routeId] =
Math.hypot(dx, dy) * this.DISTANCE_TO_COST
getLayerAwarePortHeuristicCost({
topology,
problem,
layerAwareRouteHeuristic,
distanceToCost: this.DISTANCE_TO_COST,
routeId,
portId,
})
}
}
}

return {
portHCostToEndOfRoute: portHCostToEndOfRoute as Float64Array,
layerAwareRouteHeuristic,
portEndpointNetIds,
portEndpointReservationNetId,
}
Expand Down Expand Up @@ -1537,14 +1547,14 @@ export class TinyHyperGraphSolver extends BaseSolver {
]
}

const endPortId = this.problem.routeEndPort[this.state.currentRouteId!]
const dx =
this.getPortRoutingCostX(neighborPortId) -
this.getPortRoutingCostX(endPortId)
const dy =
this.getPortRoutingCostY(neighborPortId) -
this.getPortRoutingCostY(endPortId)
return Math.hypot(dx, dy) * this.DISTANCE_TO_COST
return getLayerAwarePortHeuristicCost({
topology: this.topology,
problem: this.problem,
layerAwareRouteHeuristic: this.problemSetup.layerAwareRouteHeuristic,
distanceToCost: this.DISTANCE_TO_COST,
routeId: this.state.currentRouteId!,
portId: neighborPortId,
})
}

protected getPortRoutingCostX(portId: PortId): number {
Expand Down
187 changes: 187 additions & 0 deletions lib/layer-aware-route-heuristic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import type { TinyHyperGraphProblem, TinyHyperGraphTopology } from "./core"
import { computeRegionCost } from "./computeRegionCost"
import type { PortId, RegionId, RouteId } from "./types"

export interface LayerAwareRouteHeuristic {
layerTransitionRegionIdByRoute: Int32Array
layerTransitionCostByRoute: Float64Array
}

interface CreateLayerAwareRouteHeuristicContext {
topology: TinyHyperGraphTopology
problem: TinyHyperGraphProblem
distanceToCost: number
minViaPadDiameter: number
}

interface GetLayerAwarePortHeuristicCostContext {
topology: TinyHyperGraphTopology
problem: TinyHyperGraphProblem
layerAwareRouteHeuristic: LayerAwareRouteHeuristic
distanceToCost: number
routeId: RouteId
portId: PortId
}

const getPortRoutingCostX = (
topology: TinyHyperGraphTopology,
portId: PortId,
) => topology.portRoutingCostX?.[portId] ?? topology.portX[portId]!

const getPortRoutingCostY = (
topology: TinyHyperGraphTopology,
portId: PortId,
) => topology.portRoutingCostY?.[portId] ?? topology.portY[portId]!

const getRegionPortLayerMask = (
topology: TinyHyperGraphTopology,
regionId: RegionId,
) => {
let layerMask = 0

for (const portId of topology.regionIncidentPorts[regionId] ?? []) {
layerMask |= 1 << topology.portZ[portId]!
}

return layerMask
}

const getTraversableRegionLayerMask = (
topology: TinyHyperGraphTopology,
regionId: RegionId,
) => {
const portLayerMask = getRegionPortLayerMask(topology, regionId)
const availableLayerMask = topology.regionAvailableZMask?.[regionId] ?? 0

return availableLayerMask === 0
? portLayerMask
: portLayerMask & availableLayerMask
}

/**
* Selects one existing ordinary region per cross-layer route. The region must
* expose ports on both endpoint layers, and the score includes its normal via
* cost. This changes search order only; it does not change topology or routing
* legality.
*/
export const createLayerAwareRouteHeuristic = ({
topology,
problem,
distanceToCost,
minViaPadDiameter,
}: CreateLayerAwareRouteHeuristicContext): LayerAwareRouteHeuristic => {
const layerTransitionRegionIdByRoute = new Int32Array(
problem.routeCount,
).fill(-1)
const layerTransitionCostByRoute = new Float64Array(problem.routeCount)
const traversableLayerMaskByRegion = new Int32Array(topology.regionCount)
const layerTransitionCostByRegion = new Float64Array(topology.regionCount)

for (let regionId = 0; regionId < topology.regionCount; regionId++) {
const traversableLayerMask = getTraversableRegionLayerMask(
topology,
regionId,
)
traversableLayerMaskByRegion[regionId] = traversableLayerMask
layerTransitionCostByRegion[regionId] = computeRegionCost(
topology.regionWidth[regionId]!,
topology.regionHeight[regionId]!,
0,
0,
1,
1,
traversableLayerMask,
minViaPadDiameter,
)
}

for (let routeId = 0; routeId < problem.routeCount; routeId++) {
const startPortId = problem.routeStartPort[routeId]!
const endPortId = problem.routeEndPort[routeId]!
const startLayer = topology.portZ[startPortId]!
const endLayer = topology.portZ[endPortId]!

if (startLayer === endLayer) continue

const requiredLayerMask = (1 << startLayer) | (1 << endLayer)
const routeNetId = problem.routeNet[routeId]!
const startX = getPortRoutingCostX(topology, startPortId)
const startY = getPortRoutingCostY(topology, startPortId)
const endX = getPortRoutingCostX(topology, endPortId)
const endY = getPortRoutingCostY(topology, endPortId)
let bestTransitionScore = Number.POSITIVE_INFINITY

for (let regionId = 0; regionId < topology.regionCount; regionId++) {
if (
(traversableLayerMaskByRegion[regionId]! & requiredLayerMask) !==
requiredLayerMask
) {
continue
}

const reservedNetId = problem.regionNetId[regionId]!
if (reservedNetId !== -1 && reservedNetId !== routeNetId) continue

const transitionX = topology.regionCenterX[regionId]!
const transitionY = topology.regionCenterY[regionId]!
const layerTransitionCost = layerTransitionCostByRegion[regionId]!
const transitionScore =
(Math.hypot(transitionX - startX, transitionY - startY) +
Math.hypot(endX - transitionX, endY - transitionY)) *
distanceToCost +
layerTransitionCost

if (transitionScore >= bestTransitionScore) continue

bestTransitionScore = transitionScore
layerTransitionRegionIdByRoute[routeId] = regionId
layerTransitionCostByRoute[routeId] = layerTransitionCost
}
}

return {
layerTransitionRegionIdByRoute,
layerTransitionCostByRoute,
}
}

/**
* Guides ports that remain on the start layer through the selected transition
* region. After the route changes layer, the original direct-distance
* heuristic applies.
*/
export const getLayerAwarePortHeuristicCost = ({
topology,
problem,
layerAwareRouteHeuristic,
distanceToCost,
routeId,
portId,
}: GetLayerAwarePortHeuristicCostContext): number => {
const endPortId = problem.routeEndPort[routeId]!
const portX = getPortRoutingCostX(topology, portId)
const portY = getPortRoutingCostY(topology, portId)
const endX = getPortRoutingCostX(topology, endPortId)
const endY = getPortRoutingCostY(topology, endPortId)
const directCost = Math.hypot(portX - endX, portY - endY) * distanceToCost
const startPortId = problem.routeStartPort[routeId]!

if (topology.portZ[portId] !== topology.portZ[startPortId]) {
return directCost
}

const layerTransitionRegionId =
layerAwareRouteHeuristic.layerTransitionRegionIdByRoute[routeId]!

if (layerTransitionRegionId === -1) return directCost

const transitionX = topology.regionCenterX[layerTransitionRegionId]!
const transitionY = topology.regionCenterY[layerTransitionRegionId]!

return (
(Math.hypot(transitionX - portX, transitionY - portY) +
Math.hypot(endX - transitionX, endY - transitionY)) *
distanceToCost +
layerAwareRouteHeuristic.layerTransitionCostByRoute[routeId]!
)
}
Loading
Loading