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
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,21 @@ import type {
PartitionInputProblem,
} from "../../types/InputProblem"
import { visualizeInputProblem } from "../LayoutPipelineSolver/visualizeInputProblem"
import { createFilteredNetworkMapping } from "../../utils/networkFiltering"
import {
createFilteredNetworkMapping,
isPositiveVoltageNet,
} from "../../utils/networkFiltering"
import { getPadsBoundingBox } from "./getPadsBoundingBox"
import { doBasicInputProblemLayout } from "../LayoutPipelineSolver/doBasicInputProblemLayout"

const PIN_SIZE = 0.1

/**
* Y-axis bias applied to pins connected to positive voltage nets.
* Negative value pushes them upward in the schematic layout.
*/
const POSITIVE_VOLTAGE_Y_BIAS = -0.3

export class SingleInnerPartitionPackingSolver extends BaseSolver {
partitionInputProblem: PartitionInputProblem
layout: OutputLayout | null = null
Expand Down Expand Up @@ -65,7 +74,7 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver {
}

private createPackInput(): PackInput {
// Fall back to filtered mapping (weak + strong)
// Use filtered mapping (weak + strong)
const pinToNetworkMap = createFilteredNetworkMapping({
inputProblem: this.partitionInputProblem,
pinIdToStronglyConnectedPins: this.pinIdToStronglyConnectedPins,
Expand All @@ -75,7 +84,6 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver {
const packComponents = Object.entries(
this.partitionInputProblem.chipMap,
).map(([chipId, chip]) => {
// Create pads for all pins of this chip
const pads: Array<{
padId: string
networkId: string
Expand All @@ -89,15 +97,22 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver {
const pin = this.partitionInputProblem.chipPinMap[pinId]
if (!pin) continue

// Find network for this pin from our connectivity map
const networkId = pinToNetworkMap.get(pinId) || `${pinId}_isolated`

// Apply upward bias for positive voltage nets
const voltageBias = isPositiveVoltageNet(
networkId,
this.partitionInputProblem,
)
? POSITIVE_VOLTAGE_Y_BIAS
: 0

pads.push({
padId: pinId,
networkId: networkId,
type: "rect" as const,
offset: { x: pin.offset.x, y: pin.offset.y },
size: { x: PIN_SIZE, y: PIN_SIZE }, // Small size for pins
offset: { x: pin.offset.x, y: pin.offset.y + voltageBias },
size: { x: PIN_SIZE, y: PIN_SIZE },
})
}

Expand All @@ -107,9 +122,7 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver {
y: padsBoundingBox.maxY - padsBoundingBox.minY,
}

// Add chip body pad (disconnected from any network) but make sure
// it fully envelopes the "pads" (pins)

// Add chip body pad (disconnected) that envelopes all pins
pads.push({
padId: `${chipId}_body`,
networkId: `${chipId}_body_disconnected`,
Expand Down
59 changes: 23 additions & 36 deletions lib/solvers/PartitionPackingSolver/PartitionPackingSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@ import type { OutputLayout, Placement } from "../../types/OutputLayout"
import type { InputProblem } from "../../types/InputProblem"
import { visualizeInputProblem } from "../LayoutPipelineSolver/visualizeInputProblem"
import type { PackedPartition } from "../PackInnerPartitionsSolver/PackInnerPartitionsSolver"
import { isPositiveVoltageNet } from "../../utils/networkFiltering"

export interface PartitionPackingSolverInput {
packedPartitions: PackedPartition[]
inputProblem: InputProblem
}

/**
* Y-axis bias applied to partition-level pads connected to positive voltage nets.
* Negative value pushes them upward in the final schematic layout.
*/
const POSITIVE_VOLTAGE_Y_BIAS = -0.5

export class PartitionPackingSolver extends BaseSolver {
packedPartitions: PackedPartition[]
inputProblem: InputProblem
Expand All @@ -31,7 +38,6 @@ export class PartitionPackingSolver extends BaseSolver {
override _step() {
try {
if (this.packedPartitions.length === 0) {
// No partitions to pack, create empty layout
this.finalLayout = {
chipPlacements: {},
groupPlacements: {},
Expand All @@ -41,23 +47,19 @@ export class PartitionPackingSolver extends BaseSolver {
}

if (this.packedPartitions.length === 1) {
// Only one partition, use its layout directly
this.finalLayout = this.packedPartitions[0]!.layout
this.solved = true
return
}

// Create groups of components by partition for better organization
const partitionGroups = this.organizePackedPartitions()

// Initialize PackSolver2 if not already created
if (!this.packSolver2) {
const packInput = this.createPackInput(partitionGroups)
this.packSolver2 = new PackSolver2(packInput)
this.activeSubSolver = this.packSolver2
}

// Run one step of the PackSolver2
this.packSolver2.step()

if (this.packSolver2.failed) {
Expand All @@ -67,7 +69,6 @@ export class PartitionPackingSolver extends BaseSolver {
}

if (this.packSolver2.solved) {
// Apply the packing result to the layout
const packedLayout = this.applyPackingResult(
this.packSolver2.packedComponents,
partitionGroups,
Expand All @@ -92,7 +93,6 @@ export class PartitionPackingSolver extends BaseSolver {
maxY: number
}
}> {
// Group chips by partition based on packed partitions
const partitionGroups: Array<{
partitionIndex: number
chipIds: string[]
Expand All @@ -111,7 +111,6 @@ export class PartitionPackingSolver extends BaseSolver {
)

if (partitionChipIds.length > 0) {
// Calculate bounding box for this partition including chip sizes
let minX = Infinity
let maxX = -Infinity
let minY = Infinity
Expand All @@ -128,7 +127,6 @@ export class PartitionPackingSolver extends BaseSolver {
placement.ccwRotationDegrees === 90 ||
placement.ccwRotationDegrees === 270
) {
// Swap width and height for 90/270 degree rotations
;[chipWidth, chipHeight] = [chipHeight, chipWidth]
}

Expand All @@ -143,12 +141,10 @@ export class PartitionPackingSolver extends BaseSolver {
maxY = Math.max(maxY, chipMaxY)
}

const bounds = { minX, maxX, minY, maxY }

partitionGroups.push({
partitionIndex: i,
chipIds: partitionChipIds,
bounds,
bounds: { minX, maxX, minY, maxY },
})
}
}
Expand All @@ -168,12 +164,10 @@ export class PartitionPackingSolver extends BaseSolver {
}
}>,
): PackInput {
// Build a global connectivity map to properly assign networkIds
// Build a global connectivity map
const pinToNetworkMap = new Map<string, string>()

// First, process all partitions to build the connectivity map
for (const packedPartition of this.packedPartitions) {
// Process net connections
for (const [connKey, connected] of Object.entries(
packedPartition.inputProblem.netConnMap,
)) {
Expand All @@ -184,21 +178,18 @@ export class PartitionPackingSolver extends BaseSolver {
}
}

// Process strong connections - these form their own networks
for (const [connKey, connected] of Object.entries(
packedPartition.inputProblem.pinStrongConnMap,
)) {
if (!connected) continue
const pins = connKey.split("-")
if (pins.length === 2 && pins[0] && pins[1]) {
// If either pin already has a net connection, use that network for both
const existingNet =
pinToNetworkMap.get(pins[0]) || pinToNetworkMap.get(pins[1])
if (existingNet) {
pinToNetworkMap.set(pins[0], existingNet)
pinToNetworkMap.set(pins[1], existingNet)
} else {
// Otherwise, use the connection itself as the network
pinToNetworkMap.set(pins[0], connKey)
pinToNetworkMap.set(pins[1], connKey)
}
Expand All @@ -210,13 +201,11 @@ export class PartitionPackingSolver extends BaseSolver {
const packComponents = partitionGroups.map((group) => {
const packedPartition = this.packedPartitions[group.partitionIndex]!

// Calculate partition size from bounds
const partitionWidth = group.bounds.maxX - group.bounds.minX
const partitionHeight = group.bounds.maxY - group.bounds.minY
const centerX = (group.bounds.minX + group.bounds.maxX) / 2
const centerY = (group.bounds.minY + group.bounds.maxY) / 2

// Start with the partition body pad
const pads = [
{
padId: `partition_${group.partitionIndex}_body`,
Expand All @@ -230,11 +219,9 @@ export class PartitionPackingSolver extends BaseSolver {
},
]

// Add all pins from this partition as pads
const addedNetworks = new Set<string>()
const pinPositions = new Map<string, { x: number; y: number }>()

// Calculate pin positions for all chips in the partition
for (const chipId of group.chipIds) {
const chipPlacement = packedPartition.layout.chipPlacements[chipId]!
const chip = packedPartition.inputProblem.chipMap[chipId]!
Expand All @@ -255,31 +242,34 @@ export class PartitionPackingSolver extends BaseSolver {
transformedOffset = { x: chipPin.offset.y, y: -chipPin.offset.x }
}

// Calculate absolute pin position
const absolutePinX = chipPlacement.x + transformedOffset.x
const absolutePinY = chipPlacement.y + transformedOffset.y

// Store pin position for use in pad offset calculation
pinPositions.set(pinId, { x: absolutePinX, y: absolutePinY })

// Get the network ID for this pin
const networkId =
pinToNetworkMap.get(pinId) || `${pinId}_disconnected`

// Only add one pad per network to avoid overlapping
if (!addedNetworks.has(networkId)) {
addedNetworks.add(networkId)

// Calculate offset relative to partition center
const padOffsetX = absolutePinX - centerX
const padOffsetY = absolutePinY - centerY

// Apply upward bias for positive voltage nets
const voltageBias = isPositiveVoltageNet(
networkId,
this.inputProblem,
)
? POSITIVE_VOLTAGE_Y_BIAS
: 0

pads.push({
padId: `${group.partitionIndex}_pin_${pinId}`,
networkId: networkId,
type: "rect" as const,
offset: { x: padOffsetX, y: padOffsetY },
size: { x: 0.01, y: 0.01 }, // Small pin pad
offset: { x: padOffsetX, y: padOffsetY + voltageBias },
size: { x: 0.01, y: 0.01 },
})
}
}
Expand All @@ -288,15 +278,15 @@ export class PartitionPackingSolver extends BaseSolver {
return {
componentId: `partition_${group.partitionIndex}`,
pads,
availableRotationDegrees: [0] as Array<0 | 90 | 180 | 270>, // Keep partitions unrotated
availableRotationDegrees: [0] as Array<0 | 90 | 180 | 270>,
}
})

return {
components: packComponents,
minGap: this.inputProblem.partitionGap, // Use partitionGap from input problem
minGap: this.inputProblem.partitionGap,
packOrderStrategy: "largest_to_smallest",
packPlacementStrategy: "minimum_sum_squared_distance_to_network",
packPlacementStrategy: "minimum_closest_sum_squared_distance",
}
}

Expand All @@ -313,7 +303,6 @@ export class PartitionPackingSolver extends BaseSolver {
}
}>,
): OutputLayout {
// Apply the partition offsets to individual components
const newChipPlacements: Record<string, Placement> = {}

for (const packedComponent of packedComponents) {
Expand All @@ -326,7 +315,6 @@ export class PartitionPackingSolver extends BaseSolver {
const packedPartition = this.packedPartitions[partitionIndex]

if (group && packedPartition) {
// Calculate offset to apply to this partition's components
const currentCenterX = (group.bounds.minX + group.bounds.maxX) / 2
const currentCenterY = (group.bounds.minY + group.bounds.maxY) / 2
const newCenterX = packedComponent.center.x
Expand All @@ -335,7 +323,6 @@ export class PartitionPackingSolver extends BaseSolver {
const offsetX = newCenterX - currentCenterX
const offsetY = newCenterY - currentCenterY

// Apply offset to all chips in this partition
for (const chipId of group.chipIds) {
const originalPlacement =
packedPartition.layout.chipPlacements[chipId]!
Expand Down Expand Up @@ -374,7 +361,6 @@ export class PartitionPackingSolver extends BaseSolver {
partitionGap: this.inputProblem.partitionGap,
}

// Combine all packed partitions
for (const packedPartition of this.packedPartitions) {
Object.assign(
combinedProblem.chipMap,
Expand Down Expand Up @@ -405,3 +391,4 @@ export class PartitionPackingSolver extends BaseSolver {
}
}
}

Loading
Loading