Skip to content
Draft
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
1 change: 1 addition & 0 deletions lib/DuplicateCongestedPortSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ const createSingleRouteProblem = (
routeEndPort: Int32Array.from([problem.routeEndPort[routeId]]),
routeNet: Int32Array.from([problem.routeNet[routeId]]),
regionNetId: new Int32Array(problem.regionNetId),
portNetId: problem.portNetId && new Int32Array(problem.portNetId),
portPenalty:
problem.portPenalty === undefined
? undefined
Expand Down
26 changes: 26 additions & 0 deletions lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ export interface TinyHyperGraphProblem {
/** regionNetId[regionId] = reserved net id for the region, -1 means freely traversable */
regionNetId: Int32Array

/** Optional port net restrictions: -1 is free, -2 is blocked, otherwise the sole allowed net. */
portNetId?: Int32Array

/** portPenalty[portId] = extra cost paid when a route traverses the port */
portPenalty?: Float64Array

Expand Down Expand Up @@ -638,6 +641,11 @@ export class TinyHyperGraphSolver extends BaseSolver {
}
}

for (let portId = 0; portId < topology.portCount; portId++) {
const netId = problem.portNetId?.[portId] ?? -1
if (netId !== -1) recordEndpointNet(portId, netId)
}

for (let routeId = 0; routeId < problem.routeCount; routeId++) {
const routeNetId = problem.routeNet[routeId]!
recordEndpointNet(problem.routeStartPort[routeId]!, routeNetId)
Expand Down Expand Up @@ -667,6 +675,24 @@ export class TinyHyperGraphSolver extends BaseSolver {
override _setup() {
void this.problemSetup

if (this.problem.portNetId) {
for (let routeId = 0; routeId < this.problem.routeCount; routeId++) {
for (const portId of [
this.problem.routeStartPort[routeId]!,
this.problem.routeEndPort[routeId]!,
]) {
const requiredNetId = this.problem.portNetId[portId]!
if (
requiredNetId === -1 ||
requiredNetId === this.problem.routeNet[routeId]
) continue
this.failed = true
this.error = `Route ${routeId} endpoint ${portId} violates its port net restriction`
return
}
}
}

if (this.STATIC_REACHABILITY_PRECHECK) {
const staticallyUnroutableRoutes = getStaticallyUnroutableRoutes({
topology: this.topology,
Expand Down
1 change: 1 addition & 0 deletions lib/section-solver/TinyHyperGraphSectionPipelineSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ const createProblemWithPortSectionMask = (
routeEndPort: new Int32Array(problem.routeEndPort),
routeNet: new Int32Array(problem.routeNet),
regionNetId: new Int32Array(problem.regionNetId),
portNetId: problem.portNetId && new Int32Array(problem.portNetId),
portPenalty:
problem.portPenalty === undefined
? undefined
Expand Down
1 change: 1 addition & 0 deletions lib/section-solver/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ const createSectionRoutePlans = (
routeEndPort,
routeNet: new Int32Array(problem.routeNet),
regionNetId: new Int32Array(problem.regionNetId),
portNetId: problem.portNetId && new Int32Array(problem.portNetId),
portPenalty:
problem.portPenalty === undefined
? undefined
Expand Down
197 changes: 112 additions & 85 deletions lib/selective-rerip-tiny-hyper-graph-solver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ type RelaxedSearchState = {
nextRegionId: RegionId
}

type CommittedCrossingGeometry = {
ownerRouteId: RouteId
lesserAngle: number
greaterAngle: number
layerMask: number
}

type PortDistanceSearch = {
costs: Float64Array
settled: Uint8Array
Expand Down Expand Up @@ -428,6 +435,12 @@ export class SelectiveReripTinyHyperGraphSolver extends OutsideInPartialRipTinyH
}

const portOwners = this.getPortOwners()
// Committed segments stay unchanged throughout this synchronous search.
// Keep geometry local so the next search observes any intervening rerips.
const crossingGeometryByRegion = new Map<
RegionId,
CommittedCrossingGeometry[]
>()
return findResourceBlockerPath({
start: { portId: startPortId, nextRegionId: startRegionId },
getStateKey: ({ portId, nextRegionId }): number =>
Expand All @@ -440,15 +453,19 @@ export class SelectiveReripTinyHyperGraphSolver extends OutsideInPartialRipTinyH
routeNetId,
portOwners,
forbiddenOwnerRouteIds,
crossingGeometryByRegion,
}),
getBlockerCost: (hop): number =>
(hop.data?.resources ?? []).reduce((cost, resource) => {
getBlockerCost: (hop): number => {
let cost = 0
for (const resource of hop.data?.resources ?? []) {
const previousConflicts =
this.blockerResourceHistory.get(
this.getBlockerResourceKey(resource),
) ?? 0
return cost + resource.owners.length * (1 + previousConflicts)
}, 0),
cost += resource.owners.length * (1 + previousConflicts)
}
return cost
},
maxExpandedLabels: this.getRelaxedSearchExpansionLimit(),
})
}
Expand Down Expand Up @@ -498,6 +515,7 @@ export class SelectiveReripTinyHyperGraphSolver extends OutsideInPartialRipTinyH
routeNetId: number
portOwners: ReadonlyMap<PortId, ReadonlySet<RouteId>>
forbiddenOwnerRouteIds: ReadonlySet<RouteId>
crossingGeometryByRegion: Map<RegionId, CommittedCrossingGeometry[]>
}): Array<{
state: RelaxedSearchState
distance: number
Expand Down Expand Up @@ -525,16 +543,20 @@ export class SelectiveReripTinyHyperGraphSolver extends OutsideInPartialRipTinyH
continue
}

const resources = this.getHopBlockerResources({
regionId: state.nextRegionId,
fromPortId: state.portId,
toPortId: neighborPortId,
const resources = this.getHopBlockerResources(
state.nextRegionId,
state.portId,
neighborPortId,
routeNetId,
portOwners: params.portOwners,
})
const owners = [
...new Set(resources.flatMap((resource) => resource.owners)),
]
params.portOwners,
params.crossingGeometryByRegion,
)
const owners: RouteId[] = []
for (const resource of resources) {
for (const owner of resource.owners) {
if (!owners.includes(owner)) owners.push(owner)
}
}
if (
owners.some((ownerRouteId) =>
params.forbiddenOwnerRouteIds.has(ownerRouteId),
Expand Down Expand Up @@ -586,40 +608,46 @@ export class SelectiveReripTinyHyperGraphSolver extends OutsideInPartialRipTinyH
return hops
}

private getHopBlockerResources(params: {
regionId: RegionId
fromPortId: PortId
toPortId: PortId
routeNetId: number
portOwners: ReadonlyMap<PortId, ReadonlySet<RouteId>>
}): SelectiveReripBlockerResource[] {
private getHopBlockerResources(
regionId: RegionId,
fromPortId: PortId,
toPortId: PortId,
routeNetId: number,
portOwners: ReadonlyMap<PortId, ReadonlySet<RouteId>>,
crossingGeometryByRegion: Map<RegionId, CommittedCrossingGeometry[]>,
): SelectiveReripBlockerResource[] {
const resources: SelectiveReripBlockerResource[] = []
const assignedNetId = this.state.portAssignment[params.toPortId]!
if (assignedNetId !== -1 && assignedNetId !== params.routeNetId) {
const owners = [
...(params.portOwners.get(params.toPortId) ?? new Set<RouteId>()),
].filter(
(routeId) => this.problem.routeNet[routeId] !== params.routeNetId,
)
const assignedNetId = this.state.portAssignment[toPortId]!
if (assignedNetId !== -1 && assignedNetId !== routeNetId) {
const owners: RouteId[] = []
const toPortOwners = portOwners.get(toPortId)
if (toPortOwners) {
for (const routeId of toPortOwners) {
if (this.problem.routeNet[routeId] !== routeNetId) {
owners.push(routeId)
}
}
}
if (owners.length === 0) {
throw new Error(
`SelectiveReripTinyHyperGraphSolver: port ${params.toPortId} is assigned to foreign net ${assignedNetId} without a committed route owner`,
`SelectiveReripTinyHyperGraphSolver: port ${toPortId} is assigned to foreign net ${assignedNetId} without a committed route owner`,
)
}
resources.push({ kind: "port", portId: params.toPortId, owners })
resources.push({ kind: "port", portId: toPortId, owners })
}

const sameLayerIntersectionOwners = this.getHardBlockedCrossingOwners(
params.regionId,
params.fromPortId,
params.toPortId,
regionId,
fromPortId,
toPortId,
crossingGeometryByRegion,
)
if (sameLayerIntersectionOwners.length > 0) {
resources.push({
kind: "same_layer_intersection",
regionId: params.regionId,
fromPortId: params.fromPortId,
toPortId: params.toPortId,
regionId,
fromPortId,
toPortId,
owners: sameLayerIntersectionOwners,
})
}
Expand All @@ -646,6 +674,7 @@ export class SelectiveReripTinyHyperGraphSolver extends OutsideInPartialRipTinyH
regionId: RegionId,
fromPortId: PortId,
toPortId: PortId,
crossingGeometryByRegion: Map<RegionId, CommittedCrossingGeometry[]>,
): RouteId[] {
if (!this.isKnownSingleLayerRegion(regionId)) return []

Expand All @@ -655,64 +684,62 @@ export class SelectiveReripTinyHyperGraphSolver extends OutsideInPartialRipTinyH
"SelectiveReripTinyHyperGraphSolver: crossing ownership requires a current route net",
)
}
const owners = new Set<RouteId>()
for (const [ownerRouteId, ownerFromPortId, ownerToPortId] of this.state
.regionSegments[regionId] ?? []) {
if (this.problem.routeNet[ownerRouteId] === routeNetId) continue
if (
this.segmentsCrossOnSameLayer(
let committed = crossingGeometryByRegion.get(regionId)
if (!committed) {
committed = []
for (const [ownerRouteId, ownerFromPortId, ownerToPortId] of this.state
.regionSegments[regionId] ?? []) {
if (this.problem.routeNet[ownerRouteId] === routeNetId) continue
const geometry = this.populateSegmentGeometryScratch(
regionId,
fromPortId,
toPortId,
ownerFromPortId,
ownerToPortId,
)
) {
owners.add(ownerRouteId)
committed.push({
ownerRouteId,
lesserAngle: geometry.lesserAngle,
greaterAngle: geometry.greaterAngle,
layerMask: geometry.layerMask,
})
}
crossingGeometryByRegion.set(regionId, committed)
}

return [...owners]
}

private segmentsCrossOnSameLayer(
regionId: RegionId,
firstFromPortId: PortId,
firstToPortId: PortId,
secondFromPortId: PortId,
secondToPortId: PortId,
): boolean {
const first = {
...this.populateSegmentGeometryScratch(
regionId,
firstFromPortId,
firstToPortId,
),
}
const second = {
...this.populateSegmentGeometryScratch(
regionId,
secondFromPortId,
secondToPortId,
),
}
if ((first.layerMask & second.layerMask) === 0) return false
if (
first.lesserAngle === second.lesserAngle ||
first.lesserAngle === second.greaterAngle ||
first.greaterAngle === second.lesserAngle ||
first.greaterAngle === second.greaterAngle
) {
return false
const owners: RouteId[] = []
if (committed.length === 0) return owners
const first = this.populateSegmentGeometryScratch(
regionId,
fromPortId,
toPortId,
)
const firstLesserAngle = first.lesserAngle
const firstGreaterAngle = first.greaterAngle
const firstLayerMask = first.layerMask
for (const second of committed) {
const ownerRouteId = second.ownerRouteId
if ((firstLayerMask & second.layerMask) === 0) continue
if (
firstLesserAngle === second.lesserAngle ||
firstLesserAngle === second.greaterAngle ||
firstGreaterAngle === second.lesserAngle ||
firstGreaterAngle === second.greaterAngle
) {
continue
}
const secondLesserInsideFirst =
firstLesserAngle < second.lesserAngle &&
second.lesserAngle < firstGreaterAngle
const secondGreaterInsideFirst =
firstLesserAngle < second.greaterAngle &&
second.greaterAngle < firstGreaterAngle
if (
secondLesserInsideFirst !== secondGreaterInsideFirst &&
!owners.includes(ownerRouteId)
) {
owners.push(ownerRouteId)
}
}

const secondLesserInsideFirst =
first.lesserAngle < second.lesserAngle &&
second.lesserAngle < first.greaterAngle
const secondGreaterInsideFirst =
first.lesserAngle < second.greaterAngle &&
second.greaterAngle < first.greaterAngle
return secondLesserInsideFirst !== secondGreaterInsideFirst
return owners
}

private rebuildCommittedState(rippedRouteIds: ReadonlySet<RouteId>): void {
Expand Down
Loading
Loading