ShiboSoftwareDev/am625sip-linux-board
This code defines the physical footprint and pin layout for an AM625 System-in-Package (SIP) component, detailing pad positions, pin labels, and package outline for hardware integration.
- Version
- 1.0.24
- License
- unset
- Stars
- 0
scripts/build-hdmi-cache.tsx
import { Circuit } from "@tscircuit/core"
import type { AnyCircuitElement } from "circuit-json"
import { Fragment } from "react"
import { namespaceCachePcbTraceIds } from "./namespace-cache-pcb-trace-ids"
import { mkdirSync, readFileSync, writeFileSync } from "node:fs"
import { HdmiSubcircuit } from "../subcircuits/hdmi"
const CACHE_PATH = "subcircuits/cache/hdmi.circuit.json"
const CANDIDATE_PATH = "/tmp/hdmi-cache-candidate.circuit.json"
const INTERNAL_TRACE_COUNT = 117
const VOUT_LINKS = [
{ suffix: "PCLK", pcbY: -13 },
{ suffix: "DE", pcbY: -11 },
{ suffix: "HSYNC", pcbY: 6.5 },
{ suffix: "DATA0", pcbY: 2.5 },
{ suffix: "DATA1", pcbY: 1.3 },
{ suffix: "DATA2", pcbY: 0.1 },
{ suffix: "DATA3", pcbY: -1.1 },
{ suffix: "DATA4", pcbY: -2.3 },
] as const
const LinkPad = ({ name, pcbY }: { name: string; pcbY: number }) => (
<chip
name={name}
pcbX={-10}
pcbY={pcbY}
noSchematicRepresentation
footprint={
<footprint>
<smtpad
portHints={["pin1"]}
shape="rect"
width="0.8mm"
height="0.8mm"
/>
</footprint>
}
/>
)
const BoardRules = ({ children }: { children: React.ReactNode }) => (
<board
width="140mm"
height="70mm"
layers={4}
autorouter="default"
schematicDisabled
defaultTraceWidth="0.08128mm"
minTraceWidth="0.08128mm"
minTraceToPadEdgeClearance="0.05mm"
minPadEdgeToPadEdgeClearance="0.08128mm"
minViaEdgeToPadEdgeClearance="0.08128mm"
minViaHoleEdgeToViaHoleEdgeClearance="0.1016mm"
minViaHoleDiameter="0.1mm"
minViaPadDiameter="0.24mm"
pcbStyle={{ viaHoleDiameter: "0.1mm", viaPadDiameter: "0.24mm" }}
>
{children}
</board>
)
const getErrors = (circuitJson: AnyCircuitElement[]) =>
circuitJson.filter(
(element) =>
element.type.endsWith("_error") || element.type === "pcb_placement_error",
)
const getCacheJson = (sourceJson: AnyCircuitElement[]) => {
let cacheJson = sourceJson.filter((element) => {
const type = element.type
return (
(!type.startsWith("schematic_") || type === "schematic_component") &&
!type.startsWith("cad_") &&
!type.endsWith("_warning") &&
type !== "pcb_debug_object" &&
type !== "source_project_metadata"
)
})
const schematicSourceComponentIds = new Set(
cacheJson.flatMap((element) =>
element.type === "schematic_component"
? [element.source_component_id]
: [],
),
)
const sourcePorts = cacheJson.filter(
(element) => element.type === "source_port",
)
for (const sourceComponent of cacheJson) {
if (
sourceComponent.type !== "source_component" ||
sourceComponent.ftype !== "simple_chip" ||
schematicSourceComponentIds.has(sourceComponent.source_component_id)
) {
continue
}
const portLabels = Object.fromEntries(
sourcePorts.flatMap((sourcePort) => {
if (
sourcePort.type !== "source_port" ||
sourcePort.source_component_id !==
sourceComponent.source_component_id ||
sourcePort.pin_number == null
) {
return []
}
return [[`pin${sourcePort.pin_number}`, sourcePort.name]]
}),
)
if (Object.keys(portLabels).length === 0) continue
cacheJson.push({
type: "schematic_component",
schematic_component_id: `schematic_component_cache_${sourceComponent.source_component_id}`,
source_component_id: sourceComponent.source_component_id,
center: { x: 0, y: 0 },
size: { width: 2, height: 2 },
is_box_with_pins: true,
pin_spacing: 0.2,
port_labels: portLabels,
})
}
const routedSourceTraceIds = new Set(
cacheJson.flatMap((element) =>
element.type === "pcb_trace" && element.source_trace_id
? [element.source_trace_id]
: [],
),
)
cacheJson = cacheJson.filter(
(element) =>
element.type !== "source_trace" ||
routedSourceTraceIds.has(element.source_trace_id),
)
for (const element of cacheJson) {
if (element.type === "pcb_component") {
element.rotation = 0
}
}
return namespaceCachePcbTraceIds(cacheJson, "hdmi")
}
const main = async () => {
let sourceJson: AnyCircuitElement[]
if (process.argv.includes("--validate-candidate")) {
sourceJson = JSON.parse(
readFileSync(CANDIDATE_PATH, "utf8"),
) as AnyCircuitElement[]
} else {
const sourceCircuit = new Circuit()
sourceCircuit.on("autorouting:start", (event: any) => {
console.log(
`source autorouting start: ${event.phaseName ?? "unphased"} (${event.simpleRouteJson.connections.length} connections)`,
)
})
sourceCircuit.on("autorouting:end", (event: any) => {
console.log(`source autorouting end: ${event.phaseName ?? "unphased"}`)
})
sourceCircuit.add(
<BoardRules>
<net name="GND" />
<copperpour
name="GND_PLANE"
layer="inner1"
connectsTo="net.GND"
clearance="0.15mm"
boardEdgeMargin="0.3mm"
/>
<HdmiSubcircuit />
</BoardRules>,
)
await sourceCircuit.renderUntilSettled()
sourceJson = sourceCircuit.getCircuitJson() as AnyCircuitElement[]
}
const sourceErrors = getErrors(sourceJson)
const sourceTraceCount = sourceJson.filter(
(element) => element.type === "pcb_trace",
).length
const cacheJson = getCacheJson(sourceJson)
if (sourceErrors.length > 0 || sourceTraceCount !== INTERNAL_TRACE_COUNT) {
console.error(
JSON.stringify(
{
error: "HDMI source-cache validation failed",
sourceTraceCount,
sourceErrors,
},
null,
2,
),
)
process.exitCode = 1
return
}
writeFileSync(CANDIDATE_PATH, `${JSON.stringify(cacheJson, null, 2)}\n`)
const parentCircuit = new Circuit()
let parentAutoroutingConnectionCount = 0
parentCircuit.on("autorouting:start", (event: any) => {
parentAutoroutingConnectionCount += event.simpleRouteJson.connections.length
console.log(
`parent autorouting start: ${event.phaseName ?? "unphased"} (${event.simpleRouteJson.connections.length} connections)`,
)
})
parentCircuit.on("autorouting:end", (event: any) => {
console.log(`parent autorouting end: ${event.phaseName ?? "unphased"}`)
})
parentCircuit.add(
<BoardRules>
<net name="GND" />
<copperpour
name="GND_PLANE"
layer="inner1"
connectsTo="net.GND"
clearance="0.15mm"
boardEdgeMargin="0.3mm"
/>
<subcircuit name="HDMI_CACHE" circuitJson={cacheJson} pcbX={0} pcbY={0} />
<LinkPad name="L_3V3" pcbY={13} />
<trace from=".L_3V3 > .pin1" to=".HDMI_CACHE .HDMI .X_3V3 > .pin1" />
{VOUT_LINKS.map(({ suffix, pcbY }) => (
<Fragment key={suffix}>
<LinkPad name={`L_${suffix}`} pcbY={pcbY} />
<trace
from={`.L_${suffix} > .pin1`}
to={`.HDMI_CACHE .HDMI .X_VOUT0_${suffix} > .pin1`}
/>
</Fragment>
))}
</BoardRules>,
)
await parentCircuit.renderUntilSettled()
const parentJson = parentCircuit.getCircuitJson() as AnyCircuitElement[]
const parentErrors = getErrors(parentJson)
const parentTraceCount = parentJson.filter(
(element) => element.type === "pcb_trace",
).length
const importedNames = [
"J3",
"X_3V3",
...VOUT_LINKS.map(({ suffix }) => `X_VOUT0_${suffix}`),
]
const importedCenters = importedNames.map((name) => {
const sourceComponent = parentJson.find(
(element) => element.type === "source_component" && element.name === name,
)
const pcbComponent = parentJson.find(
(element) =>
element.type === "pcb_component" &&
sourceComponent?.type === "source_component" &&
element.source_component_id === sourceComponent.source_component_id,
)
return {
name,
center:
pcbComponent?.type === "pcb_component" ? pcbComponent.center : null,
}
})
if (
parentErrors.length > 0 ||
parentTraceCount !== INTERNAL_TRACE_COUNT + 1 + VOUT_LINKS.length ||
parentAutoroutingConnectionCount !== 1 + VOUT_LINKS.length ||
importedCenters.some(({ center }) => center === null)
) {
console.error(
JSON.stringify(
{
error: "HDMI imported-cache validation failed",
parentTraceCount,
parentAutoroutingConnectionCount,
importedCenters,
parentErrors,
},
null,
2,
),
)
process.exitCode = 1
return
}
mkdirSync("subcircuits/cache", { recursive: true })
writeFileSync(CACHE_PATH, `${JSON.stringify(cacheJson, null, 2)}\n`)
console.log(
JSON.stringify(
{
cachePath: CACHE_PATH,
sourceTraceCount,
parentLinkTraceCount: 1 + VOUT_LINKS.length,
parentAutoroutingConnectionCount,
importedCenters,
sourceElementCount: sourceJson.length,
cacheElementCount: cacheJson.length,
},
null,
2,
),
)
}
main().catch((error) => {
console.error(error)
process.exitCode = 1
})