From 0f4bc64a5f531ae600d193bc6725aab4967e4829 Mon Sep 17 00:00:00 2001 From: AgentGoose32 Date: Mon, 27 Apr 2026 21:15:17 -0400 Subject: [PATCH 1/2] Add specialized row packing for decoupling caps --- .../SingleInnerPartitionPackingSolver.ts | 62 ++++++++++++++++--- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver.ts b/lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver.ts index 88db103..51fcec9 100644 --- a/lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver.ts +++ b/lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver.ts @@ -3,22 +3,20 @@ * Uses a packing algorithm to arrange chips and their connections within the partition. */ -import type { GraphicsObject } from "graphics-debug" import { type PackInput, PackSolver2 } from "calculate-packing" -import { BaseSolver } from "../BaseSolver" -import type { OutputLayout, Placement } from "../../types/OutputLayout" +import type { GraphicsObject } from "graphics-debug" import type { - InputProblem, - PinId, - ChipId, - NetId, ChipPin, + InputProblem, PartitionInputProblem, + PinId, } from "../../types/InputProblem" -import { visualizeInputProblem } from "../LayoutPipelineSolver/visualizeInputProblem" +import type { OutputLayout, Placement } from "../../types/OutputLayout" import { createFilteredNetworkMapping } from "../../utils/networkFiltering" -import { getPadsBoundingBox } from "./getPadsBoundingBox" +import { BaseSolver } from "../BaseSolver" import { doBasicInputProblemLayout } from "../LayoutPipelineSolver/doBasicInputProblemLayout" +import { visualizeInputProblem } from "../LayoutPipelineSolver/visualizeInputProblem" +import { getPadsBoundingBox } from "./getPadsBoundingBox" const PIN_SIZE = 0.1 @@ -38,6 +36,12 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver { } override _step() { + if (this.partitionInputProblem.partitionType === "decoupling_caps") { + this.layout = this.createDecouplingCapLayout() + this.solved = true + return + } + // Initialize PackSolver2 if not already created if (!this.activeSubSolver) { const packInput = this.createPackInput() @@ -141,6 +145,46 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver { } } + private createDecouplingCapLayout(): OutputLayout { + const chipPlacements: Record = {} + const gap = + this.partitionInputProblem.decouplingCapsGap ?? + this.partitionInputProblem.chipGap + + const chipIds = Object.keys(this.partitionInputProblem.chipMap).sort( + (a, b) => + a.localeCompare(b, undefined, { + numeric: true, + sensitivity: "base", + }), + ) + + const widths = chipIds.map((chipId) => { + const chip = this.partitionInputProblem.chipMap[chipId]! + return chip.size.x + }) + const totalWidth = + widths.reduce((sum, width) => sum + width, 0) + + Math.max(0, chipIds.length - 1) * gap + + let cursorX = -totalWidth / 2 + for (let i = 0; i < chipIds.length; i++) { + const chipId = chipIds[i]! + const width = widths[i]! + chipPlacements[chipId] = { + x: cursorX + width / 2, + y: 0, + ccwRotationDegrees: 0, + } + cursorX += width + gap + } + + return { + chipPlacements, + groupPlacements: {}, + } + } + private createLayoutFromPackingResult( packedComponents: PackSolver2["packedComponents"], ): OutputLayout { From efb8b6f1312113a9f7641ab9ceb8d7a77f20553d Mon Sep 17 00:00:00 2001 From: AgentGoose32 Date: Mon, 27 Apr 2026 21:17:10 -0400 Subject: [PATCH 2/2] Create decoupling-caps-layout.test.ts --- .../decoupling-caps-layout.test.ts | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tests/PackInnerPartitionsSolver/decoupling-caps-layout.test.ts diff --git a/tests/PackInnerPartitionsSolver/decoupling-caps-layout.test.ts b/tests/PackInnerPartitionsSolver/decoupling-caps-layout.test.ts new file mode 100644 index 0000000..13aa7a3 --- /dev/null +++ b/tests/PackInnerPartitionsSolver/decoupling-caps-layout.test.ts @@ -0,0 +1,61 @@ +import { expect, test } from "bun:test" +import { SingleInnerPartitionPackingSolver } from "lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver" +import type { PartitionInputProblem } from "lib/types/InputProblem" + +const problem: PartitionInputProblem = { + isPartition: true, + partitionType: "decoupling_caps", + chipGap: 0.25, + partitionGap: 1, + decouplingCapsGap: 0.5, + chipMap: { + C10: { + chipId: "C10", + pins: ["C10.1", "C10.2"], + size: { x: 0.5, y: 1 }, + availableRotations: [0], + }, + C2: { + chipId: "C2", + pins: ["C2.1", "C2.2"], + size: { x: 0.5, y: 1 }, + availableRotations: [0], + }, + C1: { + chipId: "C1", + pins: ["C1.1", "C1.2"], + size: { x: 0.5, y: 1 }, + availableRotations: [0], + }, + }, + chipPinMap: { + "C1.1": { pinId: "C1.1", offset: { x: 0, y: 0.25 }, side: "y+" }, + "C1.2": { pinId: "C1.2", offset: { x: 0, y: -0.25 }, side: "y-" }, + "C2.1": { pinId: "C2.1", offset: { x: 0, y: 0.25 }, side: "y+" }, + "C2.2": { pinId: "C2.2", offset: { x: 0, y: -0.25 }, side: "y-" }, + "C10.1": { pinId: "C10.1", offset: { x: 0, y: 0.25 }, side: "y+" }, + "C10.2": { pinId: "C10.2", offset: { x: 0, y: -0.25 }, side: "y-" }, + }, + netMap: {}, + pinStrongConnMap: {}, + netConnMap: {}, +} + +test("decoupling capacitor partitions are packed into a clean horizontal row", () => { + const solver = new SingleInnerPartitionPackingSolver({ + partitionInputProblem: problem, + pinIdToStronglyConnectedPins: {}, + }) + solver.solve() + + expect(solver.solved).toBe(true) + const placements = solver.layout!.chipPlacements + expect(Object.keys(placements)).toHaveLength(3) + expect(placements.C1!.y).toBe(0) + expect(placements.C2!.y).toBe(0) + expect(placements.C10!.y).toBe(0) + expect(placements.C1!.x).toBeLessThan(placements.C2!.x) + expect(placements.C2!.x).toBeLessThan(placements.C10!.x) + expect(placements.C2!.x - placements.C1!.x).toBeCloseTo(1) + expect(placements.C10!.x - placements.C2!.x).toBeCloseTo(1) +})