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
77 changes: 77 additions & 0 deletions lib/solvers/ChipPartitionsSolver/ChipPartitionsSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class ChipPartitionsSolver extends BaseSolver {
const decapChipIdSet = new Set<ChipId>()
const decapGroupPartitions: ChipId[][] = []

// Use IdentifyDecouplingCapsSolver groups if available
if (this.decouplingCapGroups && this.decouplingCapGroups.length > 0) {
for (const group of this.decouplingCapGroups) {
const capsOnly: ChipId[] = []
Expand All @@ -70,6 +71,20 @@ export class ChipPartitionsSolver extends BaseSolver {
}
}

// Fallback: detect decoupling-cap-like chips not identified by the solver
const fallbackGroups = this.findDecouplingCapFallbackGroups(
inputProblem,
decapChipIdSet,
)
for (const capsOnly of fallbackGroups) {
if (capsOnly.length >= 2) {
decapGroupPartitions.push(capsOnly)
for (const capId of capsOnly) {
decapChipIdSet.add(capId)
}
}
}

// 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 Expand Up @@ -180,6 +195,68 @@ export class ChipPartitionsSolver extends BaseSolver {
return partition
}

/**
* Fallback detection for decoupling-cap-like chips when IdentifyDecouplingCapsSolver
* doesn't identify them (e.g. when availableRotations metadata is not set).
*
* Criteria: 2 pins, pins on y+/y- sides, strong connection to a chip with >2 pins
*/
private findDecouplingCapFallbackGroups(
inputProblem: InputProblem,
alreadyMarked: Set<ChipId>,
): ChipId[][] {
const chipIds = Object.keys(inputProblem.chipMap).filter(
(id) => !alreadyMarked.has(id),
)

// Find cap candidates: 2 pins, y+/y- sides, connected to a complex chip
const capToMainChip = new Map<ChipId, ChipId>()
for (const chipId of chipIds) {
const chip = inputProblem.chipMap[chipId]
if (!chip || chip.pins.length !== 2) continue

// Check for y+/y- pin sides
const sides = chip.pins
.map((p) => inputProblem.chipPinMap[p]?.side)
.filter(Boolean)
if (!sides.includes("y+") || !sides.includes("y-")) continue

// Find strong connections to complex chips (>2 pins)
for (const pinId of chip.pins) {
for (const [connKey, connected] of Object.entries(
inputProblem.pinStrongConnMap,
)) {
if (!connected) continue
const [a, b] = connKey.split("-")
const otherPinId = a === pinId ? b : b === pinId ? a : null
if (!otherPinId) continue

const otherOwner = this.findPinOwner(otherPinId, inputProblem)
if (
otherOwner &&
otherOwner !== chipId &&
!alreadyMarked.has(otherOwner)
) {
const otherChip = inputProblem.chipMap[otherOwner]
if (otherChip && otherChip.pins.length > 2) {
capToMainChip.set(chipId, otherOwner)
}
}
}
}
}

// Group caps by their main chip
const groups = new Map<ChipId, ChipId[]>()
for (const [capId, mainChipId] of capToMainChip) {
const group = groups.get(mainChipId) || []
group.push(capId)
groups.set(mainChipId, group)
}

return Array.from(groups.values())
}

/**
* Creates a new InputProblem containing only the components in the given partition
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver {
}

override _step() {
// Specialized layout for decoupling capacitors: clean horizontal row
if (this.partitionInputProblem.partitionType === "decoupling_caps") {
this.layout = this.createDecouplingCapsLayout()
this.solved = true
return
}

// Initialize PackSolver2 if not already created
if (!this.activeSubSolver) {
const packInput = this.createPackInput()
Expand All @@ -64,6 +71,38 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver {
}
}

private createDecouplingCapsLayout(): OutputLayout {
const chipPlacements: Record<string, Placement> = {}
const chips = Object.entries(this.partitionInputProblem.chipMap)
const gap =
this.partitionInputProblem.decouplingCapsGap ??
this.partitionInputProblem.chipGap ??
0.1

// Sort by chipId for deterministic ordering
chips.sort(([a], [b]) => a.localeCompare(b))

// Calculate total width for centering
let totalWidth = 0
for (const [, chip] of chips) {
totalWidth += chip.size.x
}
totalWidth += (chips.length - 1) * gap
const startX = -totalWidth / 2

let currentX = startX
for (const [chipId, chip] of chips) {
chipPlacements[chipId] = {
x: currentX + chip.size.x / 2,
y: 0,
ccwRotationDegrees: 0,
}
currentX += chip.size.x + gap
}

return { chipPlacements, groupPlacements: {} }
}

private createPackInput(): PackInput {
// Fall back to filtered mapping (weak + strong)
const pinToNetworkMap = createFilteredNetworkMapping({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ export class PartitionPackingSolver extends BaseSolver {
components: packComponents,
minGap: this.inputProblem.partitionGap, // Use partitionGap from input problem
packOrderStrategy: "largest_to_smallest",
packPlacementStrategy: "minimum_sum_squared_distance_to_network",
packPlacementStrategy: "shortest_connection_along_outline",
}
}

Expand Down
Loading