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
})