diff --git a/lib/solvers/ChipPartitionsSolver/ChipPartitionsSolver.ts b/lib/solvers/ChipPartitionsSolver/ChipPartitionsSolver.ts index 8335b60..5886066 100644 --- a/lib/solvers/ChipPartitionsSolver/ChipPartitionsSolver.ts +++ b/lib/solvers/ChipPartitionsSolver/ChipPartitionsSolver.ts @@ -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() { @@ -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() const decapGroupPartitions: ChipId[][] = [] @@ -59,10 +64,8 @@ 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) } @@ -70,6 +73,13 @@ export class ChipPartitionsSolver extends BaseSolver { } } + // 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>() diff --git a/lib/solvers/IdentifyPassivesSolver/IdentifyPassivesSolver.ts b/lib/solvers/IdentifyPassivesSolver/IdentifyPassivesSolver.ts new file mode 100644 index 0000000..acd194f --- /dev/null +++ b/lib/solvers/IdentifyPassivesSolver/IdentifyPassivesSolver.ts @@ -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() + + 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 { + const neighbors = new Set() + 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 + } +} diff --git a/lib/solvers/LayoutPipelineSolver/LayoutPipelineSolver.ts b/lib/solvers/LayoutPipelineSolver/LayoutPipelineSolver.ts index 33c7dd2..6078b75 100644 --- a/lib/solvers/LayoutPipelineSolver/LayoutPipelineSolver.ts +++ b/lib/solvers/LayoutPipelineSolver/LayoutPipelineSolver.ts @@ -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, @@ -50,6 +51,7 @@ function definePipelineStep< export class LayoutPipelineSolver extends BaseSolver { identifyDecouplingCapsSolver?: IdentifyDecouplingCapsSolver + identifyPassivesSolver?: IdentifyPassivesSolver chipPartitionsSolver?: ChipPartitionsSolver packInnerPartitionsSolver?: PackInnerPartitionsSolver partitionPackingSolver?: PartitionPackingSolver @@ -77,6 +79,16 @@ export class LayoutPipelineSolver extends BaseSolver { }, }, ), + definePipelineStep( + "identifyPassivesSolver", + IdentifyPassivesSolver, + () => [this.inputProblem], + { + onSolved: (_layoutSolver) => { + // Passives are identified + }, + }, + ), definePipelineStep( "chipPartitionsSolver", ChipPartitionsSolver, @@ -85,6 +97,7 @@ export class LayoutPipelineSolver extends BaseSolver { inputProblem: this.inputProblem, decouplingCapGroups: this.identifyDecouplingCapsSolver?.outputDecouplingCapGroups, + passiveGroups: this.identifyPassivesSolver?.outputPassiveGroups, }, ], { @@ -100,6 +113,7 @@ export class LayoutPipelineSolver extends BaseSolver { { partitions: this.chipPartitions!, pinIdToStronglyConnectedPins: this.pinIdToStronglyConnectedPins, + passiveGroups: this.identifyPassivesSolver?.outputPassiveGroups, }, ], { @@ -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() @@ -207,6 +222,7 @@ export class LayoutPipelineSolver extends BaseSolver { const visualizations = [ inputViz, identifyDecouplingCapsViz, + identifyPassivesViz, chipPartitionsViz, packInnerPartitionsViz, partitionPackingViz, diff --git a/lib/solvers/PackInnerPartitionsSolver/PackInnerPartitionsSolver.ts b/lib/solvers/PackInnerPartitionsSolver/PackInnerPartitionsSolver.ts index dd88906..2aacc5c 100644 --- a/lib/solvers/PackInnerPartitionsSolver/PackInnerPartitionsSolver.ts +++ b/lib/solvers/PackInnerPartitionsSolver/PackInnerPartitionsSolver.ts @@ -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 @@ -25,14 +26,17 @@ export class PackInnerPartitionsSolver extends BaseSolver { declare activeSubSolver: SingleInnerPartitionPackingSolver | null pinIdToStronglyConnectedPins: Record + passiveGroups?: PassiveGroup[] constructor(params: { partitions: InputProblem[] pinIdToStronglyConnectedPins: Record + passiveGroups?: PassiveGroup[] }) { super() this.partitions = params.partitions this.pinIdToStronglyConnectedPins = params.pinIdToStronglyConnectedPins + this.passiveGroups = params.passiveGroups } override _step() { @@ -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 } diff --git a/lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver.ts b/lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver.ts index 88db103..53de0dc 100644 --- a/lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver.ts +++ b/lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver.ts @@ -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 @@ -27,14 +28,17 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver { layout: OutputLayout | null = null declare activeSubSolver: PackSolver2 | null pinIdToStronglyConnectedPins: Record + passiveGroups?: PassiveGroup[] constructor(params: { partitionInputProblem: PartitionInputProblem pinIdToStronglyConnectedPins: Record + passiveGroups?: PassiveGroup[] }) { super() this.partitionInputProblem = params.partitionInputProblem this.pinIdToStronglyConnectedPins = params.pinIdToStronglyConnectedPins + this.passiveGroups = params.passiveGroups } override _step() { @@ -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 @@ -138,6 +178,7 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver { minGap, packOrderStrategy: "largest_to_smallest", packPlacementStrategy: "minimum_closest_sum_squared_distance", + relativeConstraints, } }