astra/f1c100s
This code defines and renders a four-layer, top-mounted F1C100S module with detailed pin assignments, schematic annotations, and layout profiles, facilitating design, validation, and routing of the hardware including support for decoupling capacitors, crystal oscillators, and external connectors.
- Version
- 0.11.0
- License
- unset
- Stars
- 0
tests/selective-breakouts.test.tsx
import { checkDecouplingPlacement } from "../scripts/check-decoupling-targets";
import { test, expect } from "bun:test";
import { Circuit } from "tscircuit";
import { F1C100SModule, getF1C100SCircuitJson, LAYOUT_PROFILES } from "../src";
import { selectBreakouts } from "../src/selective-breakouts";
import { EXTERNAL_NETS } from "../src/pin-map";
for (const profile of LAYOUT_PROFILES) {
for (const requested of [
[],
["GND", "VCC_IO", "UART0_TX"],
[...EXTERNAL_NETS],
]) {
test(`${profile}: ${requested.length} requested breakouts preserve support connectivity`, async () => {
const original: any[] = getF1C100SCircuitJson(profile);
expect(checkDecouplingPlacement(original)).toEqual([]);
const before = JSON.stringify(original);
const selected = new Set(requested);
const result = selectBreakouts(original, selected);
const components: any[] = result.circuitJson.filter(
(e) => e.type === "source_component",
);
expect(
components
.filter((c) => EXTERNAL_NETS.includes(c.name))
.map((c) => c.name)
.sort(),
).toEqual([...selected].sort());
expect(
components.filter((c) => !EXTERNAL_NETS.includes(c.name)).length,
).toBe(
original.filter(
(e) =>
e.type === "source_component" && !EXTERNAL_NETS.includes(e.name),
).length,
);
const originalPorts = new Map(
original
.filter((e) => e.type === "source_port")
.map((e) => [e.source_port_id, e]),
);
const originalComponents = new Map(
original
.filter((e) => e.type === "source_component")
.map((e) => [e.source_component_id, e]),
);
for (const trace of original.filter((e) => e.type === "source_trace")) {
const retained = trace.connected_source_port_ids.filter(
(id: string) => {
const name = originalComponents.get(
originalPorts.get(id).source_component_id,
).name;
return !EXTERNAL_NETS.includes(name) || selected.has(name);
},
);
const actual: any = result.circuitJson.find(
(e: any) => e.type === "source_trace" && e.name === trace.name,
);
expect(actual?.connected_source_port_ids ?? []).toEqual(
retained.length > 1 ? retained : [],
);
}
expect(JSON.stringify(original)).toBe(before);
const c = new Circuit();
c.add(
<board
width={28}
height={28}
layers={4}
minTraceWidth={0.12}
minViaPadDiameter={0.45}
minViaHoleDiameter={0.2}
>
<F1C100SModule
name="SOC"
layoutProfile={profile}
connections={Object.fromEntries(
requested.map((n) => [n, `net.${n}`]),
)}
/>
</board>,
);
await c.renderUntilSettled();
const json: any[] = c.getCircuitJson();
const processor = json.find(
(e) => e.type === "source_component" && e.name === "U1",
);
for (const cap of json.filter(
(e) => e.type === "source_component" && /^C_D\d+$/.test(e.name),
)) {
const cp = json.find(
(e) =>
e.type === "source_port" &&
e.source_component_id === cap.source_component_id &&
e.pin_number === 1,
);
const pp = json.find(
(e) =>
e.type === "source_port" &&
e.source_component_id === processor.source_component_id &&
e.pin_number === Number(cap.name.slice(3)),
);
const traces = json.filter(
(e) =>
e.type === "source_trace" &&
e.connected_source_port_ids.includes(cp.source_port_id),
);
expect(traces).toHaveLength(1);
expect(traces[0].connected_source_port_ids.slice().sort()).toEqual(
[cp.source_port_id, pp.source_port_id].sort(),
);
expect(traces[0].connected_source_net_ids).toEqual([]);
}
expect(json.filter((e) => e.type.endsWith("_error"))).toEqual([]);
expect(
json
.filter(
(e) =>
e.type === "source_component" && EXTERNAL_NETS.includes(e.name),
)
.map((e) => e.name)
.sort(),
).toEqual([...selected].sort());
if (!requested.length)
expect(
json.some((e) => e.type === "source_trace" && e.name === "N_LCD_D2"),
).toBe(false);
}, 60000);
}
}
test("empty targets do not create exits; instances do not leak selections", () => {
const a: any = F1C100SModule({
name: "A",
connections: { UART0_TX: "", PE2: "net.LED" },
});
const b: any = F1C100SModule({ name: "B" });
for (const [element, expected] of [
[a, ["PE2"]],
[b, []],
] as any[]) {
const json = element.props.children[0].props.circuitJson;
expect(
json
.filter(
(e: any) =>
e.type === "source_component" && EXTERNAL_NETS.includes(e.name),
)
.map((e: any) => e.name),
).toEqual(expected);
}
});