astra/am3352-sbc
A 4-layer AM3352 single-board computer with 128‑MiB DDR3, PMIC power regulation, USB‑C 5‑V PD input, dual USB host ports, HDMI output with ESD protection, microSD/UART/JTAG interfaces, addressable RGB indicators, and a PWM-driven buzzer.
- Version
- 0.1.19
- License
- unset
- Stars
- 0
design/peripheral-router.ts
import { BusLanesPipelineSolver, pairLengthReports, exteriorPairSpacingReports, type SimpleRouteJson } from "@tscircuit/bus-lanes-solver";
import { compactRoutingInput } from "./compact-routing-input";
import { writeFileSync } from "node:fs";
/** Board-world points in mm, +X right and +Y up. Preserve fixed DDR copper;
* use inner signal layers with only local top-pad escapes for new pairs. */
export async function peripheralBusLanes(input: SimpleRouteJson) {
const prepared = compactRoutingInput(structuredClone(input));
prepared.obstacles = prepared.obstacles.filter(o => !(o as any).isCopperPour);
prepared.allowedLayers = ["inner1", "inner2"];
writeFileSync("output/peripheral-pairs.srj.json", JSON.stringify(prepared));
const solver = new BusLanesPipelineSolver(prepared, { maxSearchIterations: 2_000_000, maxLaneIterations: 1_000_000 });
const handlers: Record<string, ((event: any) => void)[]> = {};
const emit = (type: string, event: object) => handlers[type]?.forEach(fn => fn({ type, ...event }));
const finish = () => {
solver.tryFinalAcceptance();
if (!solver.solved) throw new Error(solver.error ?? "Peripheral pair routing did not complete");
const pairs = pairLengthReports(prepared, solver.traces);
const coupling = exteriorPairSpacingReports(prepared, solver.traces);
writeFileSync("output/peripheral-pairs.result.json", JSON.stringify({ solved: solver.solved, pairs, coupling, traces: solver.traces }, null, 2));
if (solver.traces.length !== prepared.connections.length || pairs.some(p => !p.matched) || coupling.some(p => p.applicable && !p.matched))
throw new Error("Peripheral pairs failed complete routing, skew, or coupling validation");
return solver.traces;
};
return {
input, isRouting: false,
on(type: string, fn: (event: any) => void) { (handlers[type] ??= []).push(fn); },
stop() { this.isRouting = false; solver.tryFinalAcceptance(); },
async start() {
this.isRouting = true;
const started = performance.now(); let nextLog = started + 15000;
try {
while (this.isRouting && !solver.solved && !solver.failed && performance.now() - started < 300000) {
const until = performance.now() + 30;
do { solver.step(); } while (!solver.solved && !solver.failed && performance.now() < until);
if (performance.now() > nextLog) { console.log(JSON.stringify({ router: "peripheral_bus_lanes", phase: solver.phase, iterations: solver.iterations, seconds: (performance.now() - started) / 1000 })); nextLog += 15000; }
await new Promise(resolve => setTimeout(resolve, 0));
}
if (!this.isRouting) return;
this.isRouting = false;
emit("complete", { traces: finish() });
} catch (error) { this.isRouting = false; emit("error", { error }); }
},
solveSync() { solver.solve(); return finish(); },
};
}