Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and output an array of arrays for any issues found.
| --- | --- |
| [`checkConnectorAccessibleOrientation`](./lib/check-connector-accessible-orientation.ts) | Returns `pcb_accessibility_error` for connectors whose orientation makes them inaccessible. |
| [`checkAllPinsInComponentAreUnderspecified`](./lib/check-all-pins-in-component-are-underspecified.ts) | Returns `source_component_pins_underspecified_warning` when every pin on a chip lacks pin attributes. |
| [`checkNoPowerPinDefinedForChip`](./lib/check-no-power-pin-defined-for-chip.ts) | Returns `source_chip_no_power_pin_defined_warning` when a chip has no pin with `requires_power=true`. |
| [`checkDifferentNetViaSpacing`](./lib/check-different-net-via-spacing.ts) | Returns `pcb_via_clearance_error` if vias on different nets are too close together. |
| [`checkEachPcbPortConnectedToPcbTraces`](./lib/check-each-pcb-port-connected-to-pcb-trace.ts) | Returns `pcb_trace_error` if any `source_port` is not connected to its corresponding PCB traces. |
| [`checkEachPcbTraceNonOverlapping`](./lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts) | Returns `pcb_trace_error` when `pcb_trace` segments overlap incompatible geometry on the same layer. |
Expand All @@ -28,7 +29,7 @@ and output an array of arrays for any issues found.
| Function | Description |
| --- | --- |
| [`runAllPlacementChecks`](./lib/run-all-checks.ts) | Runs all placement checks (`checkViasOffBoard`, `checkPcbComponentsOutOfBoard`, `checkPcbComponentOverlap`, and `checkConnectorAccessibleOrientation`). |
| [`runAllNetlistChecks`](./lib/run-all-checks.ts) | Runs all netlist checks (e.g. `checkPinMustBeConnected`, `checkAllPinsInComponentAreUnderspecified`). |
| [`runAllNetlistChecks`](./lib/run-all-checks.ts) | Runs all netlist checks (e.g. `checkPinMustBeConnected`, `checkAllPinsInComponentAreUnderspecified`, `checkNoPowerPinDefinedForChip`). |
| [`runAllRoutingChecks`](./lib/run-all-checks.ts) | Runs all routing checks currently enabled (`checkEachPcbPortConnectedToPcbTraces`, `checkSourceTracesHavePcbTraces`, `checkEachPcbTraceNonOverlapping`, same/different net via spacing, and `checkPcbTracesOutOfBoard`). |
| [`runAllChecks`](./lib/run-all-checks.ts) | Runs all placement, netlist, and routing checks and returns a combined list of errors. |

Expand Down
1 change: 1 addition & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export { checkPcbTracesOutOfBoard } from "./lib/check-trace-out-of-board/checkTr
export { checkPcbComponentOverlap } from "./lib/check-pcb-components-overlap/checkPcbComponentOverlap"
export { checkPinMustBeConnected } from "./lib/check-pin-must-be-connected"
export { checkAllPinsInComponentAreUnderspecified } from "./lib/check-all-pins-in-component-are-underspecified"
export { checkNoPowerPinDefinedForChip } from "./lib/check-no-power-pin-defined-for-chip"
export {
runAllChecks,
runAllNetlistChecks,
Expand Down
63 changes: 63 additions & 0 deletions lib/check-no-power-pin-defined-for-chip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { cju } from "@tscircuit/circuit-json-util"
import type {
AnyCircuitElement,
SourceComponentBase,
SourcePort,
} from "circuit-json"

type SourceChipNoPowerPinDefinedWarning = {
type: "source_chip_no_power_pin_defined_warning"
source_chip_no_power_pin_defined_warning_id: string
warning_type: "source_chip_no_power_pin_defined_warning"
message: string
source_component_id: string
source_port_ids: string[]
subcircuit_id?: string
}

/**
* Check that each chip has at least one pin marked as requires_power=true.
* Returns warnings for chips where no pin declares requires_power.
*/
export function checkNoPowerPinDefinedForChip(
circuitJson: AnyCircuitElement[],
): SourceChipNoPowerPinDefinedWarning[] {
const warnings: SourceChipNoPowerPinDefinedWarning[] = []
const db = cju(circuitJson)

const sourceComponents = db.source_component.list() as SourceComponentBase[]
const sourcePorts = db.source_port.list() as SourcePort[]

const portsByComponent = new Map<string, SourcePort[]>()
for (const port of sourcePorts) {
if (!port.source_component_id) continue
const existing = portsByComponent.get(port.source_component_id) ?? []
existing.push(port)
portsByComponent.set(port.source_component_id, existing)
}

for (const component of sourceComponents) {
if (component.ftype !== "simple_chip") continue

const componentPorts =
portsByComponent.get(component.source_component_id) ?? []
if (componentPorts.length === 0) continue

const hasRequiredPowerPin = componentPorts.some(
(port) => port.requires_power === true,
)
if (hasRequiredPowerPin) continue

warnings.push({
type: "source_chip_no_power_pin_defined_warning",
source_chip_no_power_pin_defined_warning_id: `source_chip_no_power_pin_defined_warning_${component.source_component_id}`,
warning_type: "source_chip_no_power_pin_defined_warning",
message: `${component.name} has no pin with requires_power=true`,
source_component_id: component.source_component_id,
source_port_ids: componentPorts.map((port) => port.source_port_id),
subcircuit_id: componentPorts[0]?.subcircuit_id,
})
}

return warnings
}
2 changes: 2 additions & 0 deletions lib/run-all-checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { checkViasOffBoard } from "./check-pcb-components-out-of-board/checkVias
import { checkPcbComponentOverlap } from "./check-pcb-components-overlap/checkPcbComponentOverlap"
import { checkConnectorAccessibleOrientation } from "./check-connector-accessible-orientation"
import { checkPinMustBeConnected } from "./check-pin-must-be-connected"
import { checkNoPowerPinDefinedForChip } from "./check-no-power-pin-defined-for-chip"
import { checkSameNetViaSpacing } from "./check-same-net-via-spacing"
import { checkSourceTracesHavePcbTraces } from "./check-source-traces-have-pcb-traces"
import { checkPcbTracesOutOfBoard } from "./check-trace-out-of-board/checkTraceOutOfBoard"
Expand All @@ -26,6 +27,7 @@ export async function runAllNetlistChecks(circuitJson: AnyCircuitElement[]) {
return [
...checkPinMustBeConnected(circuitJson),
...checkAllPinsInComponentAreUnderspecified(circuitJson),
...checkNoPowerPinDefinedForChip(circuitJson),
]
}

Expand Down
87 changes: 87 additions & 0 deletions tests/lib/check-no-power-pin-defined-for-chip.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { describe, expect, test } from "bun:test"
import type { AnyCircuitElement } from "circuit-json"
import { checkNoPowerPinDefinedForChip } from "lib/check-no-power-pin-defined-for-chip"

describe("checkNoPowerPinDefinedForChip", () => {
test("returns warning when chip has no requires_power pin", () => {
const circuitJson: AnyCircuitElement[] = [
{
type: "source_component",
source_component_id: "component_1",
name: "U1",
ftype: "simple_chip",
},
{
type: "source_port",
source_port_id: "port_1",
source_component_id: "component_1",
name: "IO1",
},
{
type: "source_port",
source_port_id: "port_2",
source_component_id: "component_1",
name: "IO2",
},
]

const warnings = checkNoPowerPinDefinedForChip(circuitJson)
expect(warnings).toHaveLength(1)
expect(warnings[0].type).toBe("source_chip_no_power_pin_defined_warning")
expect(warnings[0].source_component_id).toBe("component_1")
})

test("returns no warning when at least one pin has requires_power=true", () => {
const circuitJson: AnyCircuitElement[] = [
{
type: "source_component",
source_component_id: "component_1",
name: "U1",
ftype: "simple_chip",
},
{
type: "source_port",
source_port_id: "port_1",
source_component_id: "component_1",
name: "VCC",
requires_power: true,
},
{
type: "source_port",
source_port_id: "port_2",
source_component_id: "component_1",
name: "IO2",
},
]

const warnings = checkNoPowerPinDefinedForChip(circuitJson)
expect(warnings).toHaveLength(0)
})

test("ignores non-chip components", () => {
const circuitJson: AnyCircuitElement[] = [
{
type: "source_component",
source_component_id: "component_1",
name: "R1",
ftype: "simple_resistor",
resistance: 1000,
},
{
type: "source_port",
source_port_id: "port_1",
source_component_id: "component_1",
name: "pos",
},
{
type: "source_port",
source_port_id: "port_2",
source_component_id: "component_1",
name: "neg",
},
]

const warnings = checkNoPowerPinDefinedForChip(circuitJson)
expect(warnings).toHaveLength(0)
})
})
5 changes: 4 additions & 1 deletion tests/lib/user-circuit-netlist.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ test("test.tsx builds and has no netlist errors", async () => {
name="USBC"
pinAttributes={{
GND1: { mustBeConnected: false },
VBUS1: { requiresPower: true },
A4: { requiresPower: true },
}}
connections={{
GND1: "net.GND",
Expand All @@ -90,6 +92,7 @@ test("test.tsx builds and has no netlist errors", async () => {

const circuitJson = circuit.getCircuitJson()

const netlistErrors = await runAllNetlistChecks(circuitJson as any)
const netlistIssues = await runAllNetlistChecks(circuitJson)
const netlistErrors = netlistIssues.filter((issue) => "error_type" in issue)
expect(netlistErrors).toEqual([])
})