Skip to content
Open
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
16 changes: 13 additions & 3 deletions lib/solvers/ChipPartitionsSolver/ChipPartitionsSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,27 @@ import { stackGraphicsHorizontally } from "graphics-debug"
import { visualizeInputProblem } from "lib/solvers/LayoutPipelineSolver/visualizeInputProblem"
import { doBasicInputProblemLayout } from "lib/solvers/LayoutPipelineSolver/doBasicInputProblemLayout"
import type { DecouplingCapGroup } from "../IdentifyDecouplingCapsSolver/IdentifyDecouplingCapsSolver"
import type { PassiveGroup } from "../IdentifyPassivesSolver/IdentifyPassivesSolver"

export class ChipPartitionsSolver extends BaseSolver {
inputProblem: InputProblem
partitions: PartitionInputProblem[] = []
decouplingCapGroups?: DecouplingCapGroup[]
passiveGroups?: PassiveGroup[]

constructor({
inputProblem,
decouplingCapGroups,
passiveGroups,
}: {
inputProblem: InputProblem
decouplingCapGroups?: DecouplingCapGroup[]
passiveGroups?: PassiveGroup[]
}) {
super()
this.inputProblem = inputProblem
this.decouplingCapGroups = decouplingCapGroups
this.passiveGroups = passiveGroups
}

override _step() {
Expand All @@ -47,7 +52,7 @@ export class ChipPartitionsSolver extends BaseSolver {
private createPartitions(inputProblem: InputProblem): InputProblem[] {
const chipIds = Object.keys(inputProblem.chipMap)

// 1) Build decoupling-cap-only partitions (exclude the main chip for each group)
// 1) Build decoupling-cap-only partitions
const decapChipIdSet = new Set<ChipId>()
const decapGroupPartitions: ChipId[][] = []

Expand All @@ -59,17 +64,22 @@ export class ChipPartitionsSolver extends BaseSolver {
capsOnly.push(capId)
}
}
// Only add a partition if there are at least two caps present in the inputProblem
if (capsOnly.length >= 2) {
decapGroupPartitions.push(capsOnly)
// Mark these caps as handled by decoupling-cap partitions
for (const capId of capsOnly) {
decapChipIdSet.add(capId)
}
}
}
}

// 1.5) Ensure passives are grouped with their main chip if not handled by decoupling caps
if (this.passiveGroups && this.passiveGroups.length > 0) {
// In this case, we don't need to do anything explicit here because
// passives are already strongly connected to the main chip.
// They will be picked up by the DFS in step 3 as long as they aren't in decapChipIdSet.
}

// 2) Build adjacency graph for NON-decap chips based on strong pin connections
const nonDecapChipIds = chipIds.filter((id) => !decapChipIdSet.has(id))
const adjacencyMap = new Map<ChipId, Set<ChipId>>()
Expand Down
86 changes: 86 additions & 0 deletions lib/solvers/IdentifyPassivesSolver/IdentifyPassivesSolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { BaseSolver } from "../BaseSolver"
import type {
InputProblem,
ChipId,
PinId,
Chip,
} from "lib/types/InputProblem"

export interface PassiveGroup {
passiveGroupId: string
mainChipId: ChipId
mainPinId: PinId
passiveChipId: ChipId
}

/**
* Identifies passive components (resistors, capacitors) that should be placed
* near specific chip pins.
*/
export class IdentifyPassivesSolver extends BaseSolver {
inputProblem: InputProblem
outputPassiveGroups: PassiveGroup[] = []

constructor(inputProblem: InputProblem) {
super()
this.inputProblem = inputProblem
}

override _step() {
this.outputPassiveGroups = this.identifyPassives()
this.solved = true
}

private identifyPassives(): PassiveGroup[] {
const groups: PassiveGroup[] = []
const handledPassives = new Set<ChipId>()

const chips = Object.values(this.inputProblem.chipMap)

// 1. Find all potential passives (2-pin components)
const passives = chips.filter(c => c.pins.length === 2)

for (const passive of passives) {
if (handledPassives.has(passive.chipId)) continue

// 2. Check if it's connected to a "main" chip (pin-to-pin strong connection)
for (const pinId of passive.pins) {
const strongNeighbors = this.getStronglyConnectedNeighborPins(pinId)

for (const neighborPinId of strongNeighbors) {
const neighborChipId = neighborPinId.split(".")[0]!
const neighborChip = this.inputProblem.chipMap[neighborChipId]

if (neighborChip && neighborChip.pins.length > 2) {
// Found a passive connected to a main chip pin!
groups.push({
passiveGroupId: `passive_${passive.chipId}_${neighborPinId}`,
mainChipId: neighborChipId,
mainPinId: neighborPinId,
passiveChipId: passive.chipId
})
handledPassives.add(passive.chipId)
break
}
}
if (handledPassives.has(passive.chipId)) break
}
}

return groups
}

private getStronglyConnectedNeighborPins(pinId: PinId): Set<PinId> {
const neighbors = new Set<PinId>()
for (const [connKey, connected] of Object.entries(this.inputProblem.pinStrongConnMap)) {
if (!connected) continue
const [a, b] = connKey.split("-") as [PinId, PinId]
if (a === pinId) {
neighbors.add(b)
} else if (b === pinId) {
neighbors.add(a)
}
}
return neighbors
}
}
16 changes: 16 additions & 0 deletions lib/solvers/LayoutPipelineSolver/LayoutPipelineSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { GraphicsObject } from "graphics-debug"
import { BaseSolver } from "lib/solvers/BaseSolver"
import { ChipPartitionsSolver } from "lib/solvers/ChipPartitionsSolver/ChipPartitionsSolver"
import { IdentifyDecouplingCapsSolver } from "lib/solvers/IdentifyDecouplingCapsSolver/IdentifyDecouplingCapsSolver"
import { IdentifyPassivesSolver } from "lib/solvers/IdentifyPassivesSolver/IdentifyPassivesSolver"
import {
PackInnerPartitionsSolver,
type PackedPartition,
Expand Down Expand Up @@ -50,6 +51,7 @@ function definePipelineStep<

export class LayoutPipelineSolver extends BaseSolver {
identifyDecouplingCapsSolver?: IdentifyDecouplingCapsSolver
identifyPassivesSolver?: IdentifyPassivesSolver
chipPartitionsSolver?: ChipPartitionsSolver
packInnerPartitionsSolver?: PackInnerPartitionsSolver
partitionPackingSolver?: PartitionPackingSolver
Expand Down Expand Up @@ -77,6 +79,16 @@ export class LayoutPipelineSolver extends BaseSolver {
},
},
),
definePipelineStep(
"identifyPassivesSolver",
IdentifyPassivesSolver,
() => [this.inputProblem],
{
onSolved: (_layoutSolver) => {
// Passives are identified
},
},
),
definePipelineStep(
"chipPartitionsSolver",
ChipPartitionsSolver,
Expand All @@ -85,6 +97,7 @@ export class LayoutPipelineSolver extends BaseSolver {
inputProblem: this.inputProblem,
decouplingCapGroups:
this.identifyDecouplingCapsSolver?.outputDecouplingCapGroups,
passiveGroups: this.identifyPassivesSolver?.outputPassiveGroups,
},
],
{
Expand All @@ -100,6 +113,7 @@ export class LayoutPipelineSolver extends BaseSolver {
{
partitions: this.chipPartitions!,
pinIdToStronglyConnectedPins: this.pinIdToStronglyConnectedPins,
passiveGroups: this.identifyPassivesSolver?.outputPassiveGroups,
},
],
{
Expand Down Expand Up @@ -196,6 +210,7 @@ export class LayoutPipelineSolver extends BaseSolver {

const identifyDecouplingCapsViz =
this.identifyDecouplingCapsSolver?.visualize()
const identifyPassivesViz = this.identifyPassivesSolver?.visualize()
const chipPartitionsViz = this.chipPartitionsSolver?.visualize()
const packInnerPartitionsViz = this.packInnerPartitionsSolver?.visualize()
const partitionPackingViz = this.partitionPackingSolver?.visualize()
Expand All @@ -207,6 +222,7 @@ export class LayoutPipelineSolver extends BaseSolver {
const visualizations = [
inputViz,
identifyDecouplingCapsViz,
identifyPassivesViz,
chipPartitionsViz,
packInnerPartitionsViz,
partitionPackingViz,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { ChipPin, InputProblem, PinId } from "../../types/InputProblem"
import type { OutputLayout } from "../../types/OutputLayout"
import { SingleInnerPartitionPackingSolver } from "./SingleInnerPartitionPackingSolver"
import { stackGraphicsHorizontally } from "graphics-debug"
import type { PassiveGroup } from "../IdentifyPassivesSolver/IdentifyPassivesSolver"

export type PackedPartition = {
inputProblem: InputProblem
Expand All @@ -25,14 +26,17 @@ export class PackInnerPartitionsSolver extends BaseSolver {

declare activeSubSolver: SingleInnerPartitionPackingSolver | null
pinIdToStronglyConnectedPins: Record<PinId, ChipPin[]>
passiveGroups?: PassiveGroup[]

constructor(params: {
partitions: InputProblem[]
pinIdToStronglyConnectedPins: Record<PinId, ChipPin[]>
passiveGroups?: PassiveGroup[]
}) {
super()
this.partitions = params.partitions
this.pinIdToStronglyConnectedPins = params.pinIdToStronglyConnectedPins
this.passiveGroups = params.passiveGroups
}

override _step() {
Expand All @@ -48,6 +52,7 @@ export class PackInnerPartitionsSolver extends BaseSolver {
this.activeSolver = new SingleInnerPartitionPackingSolver({
partitionInputProblem: currentPartition,
pinIdToStronglyConnectedPins: this.pinIdToStronglyConnectedPins,
passiveGroups: this.passiveGroups,
})
this.activeSubSolver = this.activeSolver
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { visualizeInputProblem } from "../LayoutPipelineSolver/visualizeInputPro
import { createFilteredNetworkMapping } from "../../utils/networkFiltering"
import { getPadsBoundingBox } from "./getPadsBoundingBox"
import { doBasicInputProblemLayout } from "../LayoutPipelineSolver/doBasicInputProblemLayout"
import type { PassiveGroup } from "../IdentifyPassivesSolver/IdentifyPassivesSolver"

const PIN_SIZE = 0.1

Expand All @@ -27,14 +28,17 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver {
layout: OutputLayout | null = null
declare activeSubSolver: PackSolver2 | null
pinIdToStronglyConnectedPins: Record<PinId, ChipPin[]>
passiveGroups?: PassiveGroup[]

constructor(params: {
partitionInputProblem: PartitionInputProblem
pinIdToStronglyConnectedPins: Record<PinId, ChipPin[]>
passiveGroups?: PassiveGroup[]
}) {
super()
this.partitionInputProblem = params.partitionInputProblem
this.pinIdToStronglyConnectedPins = params.pinIdToStronglyConnectedPins
this.passiveGroups = params.passiveGroups
}

override _step() {
Expand Down Expand Up @@ -128,6 +132,42 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver {
}
})

// Add relative constraints for passives
const relativeConstraints: PackInput["relativeConstraints"] = []
if (this.passiveGroups) {
for (const group of this.passiveGroups) {
// Only if both chips are in this partition
if (
this.partitionInputProblem.chipMap[group.mainChipId] &&
this.partitionInputProblem.chipMap[group.passiveChipId]
) {
const mainPin = this.partitionInputProblem.chipPinMap[group.mainPinId]
if (!mainPin) continue

// Suggest placement near the pin
// We want the passive's center to be near the pin offset
// Passive pins are usually at x= +/- something.
// Let's just suggest a small offset based on the pin side.
let dx = 0
let dy = 0
const gap = 0.5
if (mainPin.side === "left") dx = -gap
else if (mainPin.side === "right") dx = gap
else if (mainPin.side === "top" || mainPin.side === "y+") dy = gap
else if (mainPin.side === "bottom" || mainPin.side === "y-") dy = -gap

relativeConstraints.push({
componentId: group.passiveChipId,
toComponentId: group.mainChipId,
relativeOffset: {
x: mainPin.offset.x + dx,
y: mainPin.offset.y + dy,
},
})
}
}
}

let minGap = this.partitionInputProblem.chipGap
if (this.partitionInputProblem.partitionType === "decoupling_caps") {
minGap = this.partitionInputProblem.decouplingCapsGap ?? minGap
Expand All @@ -138,6 +178,7 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver {
minGap,
packOrderStrategy: "largest_to_smallest",
packPlacementStrategy: "minimum_closest_sum_squared_distance",
relativeConstraints,
}
}

Expand Down