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-cap-vdds-cache.tsx

import { Circuit } from "@tscircuit/core"
import type { AnyCircuitElement } from "circuit-json"
import { mkdirSync, writeFileSync } from "node:fs"
import { Fragment } from "react"
import {
  CAP_VDDS_LINKS,
  CapVddsSubcircuit,
} from "../subcircuits/cap-vdds"
import { namespaceCachePcbTraceIds } from "./namespace-cache-pcb-trace-ids"

const CACHE_PATH = "subcircuits/cache/cap-vdds.circuit.json"
const INTERNAL_TRACE_COUNT = 18
const PARENT_LINK_COUNT = CAP_VDDS_LINKS.length

const BoardRules = ({
  children,
  placementDrcChecksDisabled = false,
}: {
  children: React.ReactNode
  placementDrcChecksDisabled?: boolean
}) => (
  <board
    width="140mm"
    height="70mm"
    layers={4}
    autorouter="default"
    schematicDisabled
    placementDrcChecksDisabled={placementDrcChecksDisabled}
    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 LinkPad = ({ name, pcbX, pcbY, parentLayer }: {
  name: string
  pcbX: number
  pcbY: number
  parentLayer: "top" | "inner1" | "inner2" | "bottom"
}) => (
  <chip
    name={name}
    pcbX={pcbX}
    pcbY={pcbY}
    noSchematicRepresentation
    footprint={
      <footprint>
        <smtpad
          portHints={["pin1"]}
          layer={parentLayer}
          shape="circle"
          radius="0.12mm"
        />
      </footprint>
    }
  />
)

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 !== "pcb_board" &&
      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, "cap-vdds")
}

const main = async () => {
  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"
      />
      <CapVddsSubcircuit />
    </BoardRules>,
  )

  await sourceCircuit.renderUntilSettled()
  const 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({ sourceTraceCount, sourceErrors }, null, 2),
    )
    process.exitCode = 1
    return
  }

  const parentCircuit = new Circuit()
  parentCircuit.on("autorouting:start", (event: any) => {
    console.log(
      `parent autorouting start: ${event.phaseName ?? "unphased"} (${event.simpleRouteJson.connections.length} connections)`,
    )
    writeFileSync(
      "/private/tmp/cap-vdds-parent-route-input.json",
      `${JSON.stringify(event.simpleRouteJson, null, 2)}\n`,
    )
  })
  parentCircuit.add(
    <BoardRules placementDrcChecksDisabled>
      <net name="GND" />
      <copperpour
        name="GND_PLANE"
        layer="inner1"
        connectsTo="net.GND"
        clearance="0.15mm"
        boardEdgeMargin="0.3mm"
      />
      <subcircuit
        name="CAP_VDDS_CACHE"
        circuitJson={cacheJson}
        pcbX={0}
        pcbY={0}
        exposedNets={["GND"]}
      />
      {CAP_VDDS_LINKS.map(({ ball }, index) => (
        <Fragment key={`CAP_VDDS_PARENT_PHASE_${ball}`}>
          <autoroutingphase
            name={`CAP_VDDS_PARENT_LINK_${ball}`}
            phaseIndex={index}
            autorouter="default"
          />
        </Fragment>
      ))}
      {CAP_VDDS_LINKS.map(
        ({ ball, exitX, exitY, parentLayer }, index) => (
          <Fragment key={`CAP_VDDS_PARENT_LINK_${ball}`}>
            <LinkPad
              name={`L_${ball}`}
              pcbX={exitX}
              pcbY={exitY}
              parentLayer={parentLayer}
            />
            <trace
              from={`.L_${ball} > .pin1`}
              to={`.CAP_VDDS_CACHE .CAP_VDDS .X_${ball} > .pin1`}
              routingPhaseIndex={index}
            />
          </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

  if (
    parentErrors.length > 0 ||
    parentTraceCount !== INTERNAL_TRACE_COUNT + PARENT_LINK_COUNT
  ) {
    console.error(
      JSON.stringify({ parentTraceCount, 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,
      parentTraceCount,
      sourceElementCount: sourceJson.length,
      cacheElementCount: cacheJson.length,
    }, null, 2),
  )
}

main().catch((error) => {
  console.error(error)
  process.exitCode = 1
})