0hmX/am62l-lpddr4-ti-pth-router
This code defines a hardware-oriented React/TypeScript setup for a PCB breakout circuit featuring an AM62L LPDDR4 interface, including detailed PCB component placement, routing algorithms, and validation scripts for DDR connections, via placement, and manufacturing constraints.
- Version
- 1.0.1
- License
- unset
- Stars
- 0
tests/am62l-free-space-fanout.test.ts
import { expect, test } from "bun:test"
import type { SimpleRouteJson } from "@tscircuit/core"
import { AM62L_FREE_SPACE_FANOUT_PHASES } from "../autorouting/am62l-free-space-fanout"
import { solveAm62lFreeSpaceFanout } from "../autorouting/solve-am62l-free-space-fanout"
const loadFixture = async (name: string) =>
(await Bun.file(
`${import.meta.dir}/fixtures/${name}`,
).json()) as SimpleRouteJson
const withManufacturableThroughVias = (input: SimpleRouteJson) => ({
...input,
minTraceToPadEdgeClearance: 0.08128,
minViaEdgeToPadEdgeClearance: 0.08128,
minViaPadDiameter: 0.4572,
min_via_pad_diameter: 0.4572,
minViaHoleDiameter: 0.2032,
min_via_hole_diameter: 0.2032,
})
const verifyFullFanout = async (
fixtureName: string,
expectedDirection: "left" | "right",
) => {
const input = withManufacturableThroughVias(await loadFixture(fixtureName))
const phases: string[] = []
const result = solveAm62lFreeSpaceFanout(input, (event) => {
phases.push(event.phase)
})
expect(input.connections).toHaveLength(33)
expect(input.differentialPairs ?? []).toEqual([])
expect(result.traces).toHaveLength(33)
expect(phases).toEqual([...AM62L_FREE_SPACE_FANOUT_PHASES])
const outputByName = new Map(
result.outputSimpleRouteJson.connections.map((connection) => [
connection.name,
connection,
]),
)
const traceByName = new Map(
result.traces.map((trace) => [trace.connection_name, trace]),
)
for (const inputConnection of input.connections) {
const source = inputConnection.pointsToConnect.find(
(point) => point.pcb_port_id !== undefined,
)!
const target = inputConnection.pointsToConnect.find((point) =>
point.pointId?.startsWith("pcb_breakout_point"),
)!
expect(
expectedDirection === "right" ? target.x > source.x : target.x < source.x,
).toBe(true)
const outputConnection = outputByName.get(inputConnection.name)!
expect(outputConnection.source_trace_id).toBe(
inputConnection.source_trace_id,
)
const outputTarget = outputConnection.pointsToConnect.find(
(point) => point.pointId === target.pointId,
)!
expect(outputTarget.pointId).toBe(target.pointId)
expect(outputTarget.layer).toBe(target.layer)
expect(outputTarget.x).toBeCloseTo(target.x, 6)
expect(outputTarget.y).toBeCloseTo(target.y, 6)
const trace = traceByName.get(inputConnection.name)!
expect(trace.connectsTo).toContain(target.pointId)
const vias = trace.route.filter((point) => point.route_type === "via")
expect(vias).toHaveLength(1)
expect(vias[0]).toMatchObject({
via_diameter: 0.4572,
via_hole_diameter: 0.2032,
from_layer: "top",
to_layer: "bottom",
})
for (const pad of input.obstacles.filter(
(obstacle) =>
Boolean(obstacle.componentId) && obstacle.layers.includes("top"),
)) {
const centerDistance = Math.hypot(
vias[0]!.x - pad.center.x,
vias[0]!.y - pad.center.y,
)
expect(centerDistance).toBeGreaterThanOrEqual(
Math.max(pad.width, pad.height) / 2 +
0.4572 / 2 +
(input.minViaEdgeToPadEdgeClearance ?? 0) -
1e-6,
)
}
const finalWire = [...trace.route]
.reverse()
.find((point) => point.route_type === "wire")!
expect(finalWire.layer).toBe(target.layer)
expect(finalWire.x).toBeCloseTo(target.x, 6)
expect(finalWire.y).toBeCloseTo(target.y, 6)
const wires = trace.route.filter((point) => point.route_type === "wire")
for (let index = 1; index < wires.length; index++) {
if (wires[index - 1]!.layer !== wires[index]!.layer) continue
const dx = Math.abs(wires[index]!.x - wires[index - 1]!.x)
const dy = Math.abs(wires[index]!.y - wires[index - 1]!.y)
expect(dx <= 1e-6 || dy <= 1e-6 || Math.abs(dx - dy) <= 1e-6).toBe(true)
}
for (let index = 1; index < wires.length - 1; index++) {
if (
wires[index - 1]!.layer !== wires[index]!.layer ||
wires[index]!.layer !== wires[index + 1]!.layer
) {
continue
}
const incoming = {
x: wires[index]!.x - wires[index - 1]!.x,
y: wires[index]!.y - wires[index - 1]!.y,
}
const outgoing = {
x: wires[index + 1]!.x - wires[index]!.x,
y: wires[index + 1]!.y - wires[index]!.y,
}
const dot = incoming.x * outgoing.x + incoming.y * outgoing.y
expect(Math.abs(dot)).toBeGreaterThan(1e-9)
}
}
expect(
result.outputSimpleRouteJson.buses?.map((bus) => ({
busId: bus.busId,
connectionNames: bus.connectionNames,
})),
).toEqual(
input.buses?.map((bus) => ({
busId: bus.busId,
connectionNames: bus.connectionNames,
})),
)
}
test(
"routes all 33 right-escape AM62L connections to exact ordered Core targets",
() => verifyFullFanout("am62l-soc-fanout.srj.json", "right"),
30_000,
)
test(
"routes all 33 left-escape LPDDR4 connections to exact ordered Core targets",
() => verifyFullFanout("lpddr4-ram-fanout.srj.json", "left"),
30_000,
)