Skip to content
Draft
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
1 change: 1 addition & 0 deletions lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export { SilkscreenGraphic } from "./primitive-components/SilkscreenGraphic"
export { SmtPad } from "./primitive-components/SmtPad"
export { Fiducial } from "./primitive-components/Fiducial"
export { Trace } from "./primitive-components/Trace/Trace"
export { Bus } from "./primitive-components/Bus"
export { DifferentialPair } from "./primitive-components/DifferentialPair"
export { PcbTrace } from "./primitive-components/PcbTrace"
export { PcbVia } from "./primitive-components/PcbVia"
Expand Down
17 changes: 17 additions & 0 deletions lib/components/primitive-components/Bus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { busProps } from "@tscircuit/props"
import {
type BaseComponentConfig,
PrimitiveComponent,
} from "../base-components/PrimitiveComponent"

/**
* Declares a group of connections that an autorouter should keep together.
*/
export class Bus extends PrimitiveComponent<typeof busProps> {
override get config(): BaseComponentConfig {
return {
componentName: "Bus",
zodProps: busProps,
}
}
}
1 change: 1 addition & 0 deletions lib/fiber/intrinsic-jsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface TscircuitElements {
cadassembly: Props.CadAssemblyProps
net: Props.NetProps
trace: Props.TraceProps
bus: Props.BusProps
differentialpair: Props.DifferentialPairProps
breakout: Props.BreakoutProps
breakoutpoint: Props.BreakoutPointProps
Expand Down
8 changes: 8 additions & 0 deletions lib/utils/autorouting/SimpleRouteJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ export type SimpleRouteDifferentialPair = {
lengthTolerance: number
}

/** A group of connections that an autorouter should keep together. */
export type SimpleRouteBus = {
name?: string
connectionNames: SrjConnectionName[]
}

export type SimpleRouteJson = Omit<
AutorouterSimpleRouteJson,
| "connections"
Expand All @@ -108,6 +114,7 @@ export type SimpleRouteJson = Omit<
| "allowJumpers"
| "availableJumperTypes"
| "differentialPairs"
| "buses"
> & {
layerCount: number
minTraceWidth: number
Expand Down Expand Up @@ -143,6 +150,7 @@ export type SimpleRouteJson = Omit<
allowJumpers?: boolean
availableJumperTypes?: Array<"1206x4" | "0603">
differentialPairs?: SimpleRouteDifferentialPair[]
buses?: SimpleRouteBus[]
}

// declare module "autorouting-dataset" {
Expand Down
156 changes: 156 additions & 0 deletions lib/utils/autorouting/getBusesForSimpleRouteJson.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import type { SourcePort, SourceTrace } from "circuit-json"
import type { Bus } from "lib/components/primitive-components/Bus"
import type { Port } from "lib/components/primitive-components/Port/Port"
import type {
SimpleRouteBus,
SimpleRouteConnection,
SrjConnectionName,
} from "./SimpleRouteJson"

type SourcePortId = NonNullable<SourcePort["source_port_id"]>
type SubcircuitId = NonNullable<SourceTrace["subcircuit_id"]>
type SubcircuitConnectivityMapKey = NonNullable<
SourceTrace["subcircuit_connectivity_map_key"]
>

type GetBusesParams = {
srjConnections: SimpleRouteConnection[]
buses: Bus[]
sourceTraces: SourceTrace[]
subcircuitId?: SubcircuitId | null
}

const getBusSourceTraceSubcircuitConnectivityMapKeyOrThrow = ({
bus,
busSourceTraces,
traceNameOrPortSelector,
}: {
bus: Bus
busSourceTraces: SourceTrace[]
traceNameOrPortSelector: string
}): SubcircuitConnectivityMapKey => {
const sourceTracesWithMatchingName = busSourceTraces.filter(
(sourceTrace) => sourceTrace.name === traceNameOrPortSelector,
)
const selectedPort =
sourceTracesWithMatchingName.length === 0
? bus.getSubcircuit().selectOne<Port>(traceNameOrPortSelector, {
type: "port",
})
: null
const selectedSourcePortId: SourcePortId | undefined =
selectedPort?.source_port_id ?? undefined
const matchingSourceTraces = selectedSourcePortId
? busSourceTraces.filter((sourceTrace) =>
sourceTrace.connected_source_port_ids.includes(selectedSourcePortId),
)
: sourceTracesWithMatchingName

if (matchingSourceTraces.length === 0) {
throw new Error(
`Could not find source trace for trace name or port selector "${traceNameOrPortSelector}" in bus "${bus.name}"`,
)
}
if (matchingSourceTraces.length > 1) {
throw new Error(
`Trace name or port selector "${traceNameOrPortSelector}" matches multiple source traces in bus "${bus.name}"`,
)
}

const sourceTrace = matchingSourceTraces[0]
if (!sourceTrace?.subcircuit_connectivity_map_key) {
throw new Error(
`Source trace for "${traceNameOrPortSelector}" does not have a subcircuit connectivity map key in bus "${bus.name}"`,
)
}

return sourceTrace.subcircuit_connectivity_map_key
}

const getBusSrjConnectionNameOrThrow = ({
srjConnections,
bus,
busSourceTraces,
traceSubcircuitConnectivityMapKey,
traceNameOrPortSelector,
}: {
srjConnections: SimpleRouteConnection[]
bus: Bus
busSourceTraces: SourceTrace[]
traceSubcircuitConnectivityMapKey: SubcircuitConnectivityMapKey
traceNameOrPortSelector: string
}): SrjConnectionName => {
const sourceTraceIds = busSourceTraces
.filter(
(sourceTrace) =>
sourceTrace.subcircuit_connectivity_map_key ===
traceSubcircuitConnectivityMapKey,
)
.map((sourceTrace) => sourceTrace.source_trace_id)
const matchingSrjConnections = srjConnections.filter(
(srjConnection) =>
srjConnection.source_trace_id &&
sourceTraceIds.includes(srjConnection.source_trace_id),
)

if (matchingSrjConnections.length === 0) {
throw new Error(
`Could not find an SRJ connection for "${traceNameOrPortSelector}" in bus "${bus.name}"`,
)
}
if (matchingSrjConnections.length > 1) {
throw new Error(
`Trace name or port selector "${traceNameOrPortSelector}" matches multiple SRJ connections in bus "${bus.name}"`,
)
}

return matchingSrjConnections[0]!.name
}

/** Converts bus trace names or port selectors into SRJ constraints. */
export const getBusesForSimpleRouteJson = ({
srjConnections,
buses,
sourceTraces,
subcircuitId,
}: GetBusesParams): SimpleRouteBus[] | undefined => {
const srjBuses: SimpleRouteBus[] = []
for (const bus of buses) {
const busSubcircuitId = bus.getSubcircuit().subcircuit_id
if (subcircuitId && busSubcircuitId !== subcircuitId) continue

const busSourceTraces = sourceTraces.filter(
(sourceTrace) => sourceTrace.subcircuit_id === busSubcircuitId,
)
const connectionNames = bus._parsedProps.connections.map(
(traceNameOrPortSelector) => {
const traceSubcircuitConnectivityMapKey =
getBusSourceTraceSubcircuitConnectivityMapKeyOrThrow({
bus,
busSourceTraces,
traceNameOrPortSelector,
})
return getBusSrjConnectionNameOrThrow({
srjConnections,
bus,
busSourceTraces,
traceSubcircuitConnectivityMapKey,
traceNameOrPortSelector,
})
},
)

if (new Set(connectionNames).size !== connectionNames.length) {
throw new Error(
`Bus "${bus.name}" resolves multiple entries to one trace`,
)
}

srjBuses.push({
name: bus.name,
connectionNames,
})
}

return srjBuses.length > 0 ? srjBuses : undefined
}
12 changes: 12 additions & 0 deletions lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ConnectivityMap,
getFullConnectivityMapFromCircuitJson,
} from "circuit-json-to-connectivity-map"
import { Bus } from "lib/components/primitive-components/Bus"
import { DifferentialPair } from "lib/components/primitive-components/DifferentialPair"
import type { ISubcircuit } from "lib/components/primitive-components/Group/Subcircuit/ISubcircuit"
import { getObstaclesFromCircuitJson } from "../obstacles/getObstaclesFromCircuitJson"
Expand All @@ -14,6 +15,7 @@ import type {
SimpleRouteJson,
} from "./SimpleRouteJson"
import { getDescendantSubcircuitIds } from "./getAncestorSubcircuitIds"
import { getBusesForSimpleRouteJson } from "./getBusesForSimpleRouteJson"
import { getDifferentialPairsForSimpleRouteJson } from "./getDifferentialPairsForSimpleRouteJson"
import { getPreservedRoutedSubcircuitTraces } from "./getPreservedRoutedSubcircuitTraces"
import { getUnbrokenCopperPourObstacles } from "./getUnbrokenCopperPourObstacles"
Expand Down Expand Up @@ -658,6 +660,8 @@ export const getSimpleRouteJsonFromCircuitJson = ({
const differentialPairs: DifferentialPair[] =
subcircuitComponent?.selectAll<DifferentialPair>("differentialpair") ?? []

const buses: Bus[] = subcircuitComponent?.selectAll<Bus>("bus") ?? []

const srjDifferentialPairs: SimpleRouteDifferentialPair[] | undefined =
getDifferentialPairsForSimpleRouteJson({
srjConnections: allConns,
Expand All @@ -666,6 +670,13 @@ export const getSimpleRouteJsonFromCircuitJson = ({
subcircuitId: subcircuit_id,
})

const srjBuses = getBusesForSimpleRouteJson({
srjConnections: allConns,
buses,
sourceTraces: db.source_trace.list(),
subcircuitId: subcircuit_id,
})

if (subcircuit_id) {
const pointIdToConn = new Map<string, SimpleRouteConnection>()
for (const conn of allConns) {
Expand Down Expand Up @@ -724,6 +735,7 @@ export const getSimpleRouteJsonFromCircuitJson = ({
obstacles,
connections: allConns,
differentialPairs: srjDifferentialPairs,
buses: srjBuses,
traces:
preservedRoutedSubcircuitTraces.length > 0
? preservedRoutedSubcircuitTraces
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"@tscircuit/math-utils": "^0.0.36",
"@tscircuit/miniflex": "^0.0.4",
"@tscircuit/ngspice-spice-engine": "^0.0.20",
"@tscircuit/props": "^0.0.592",
"@tscircuit/props": "^0.0.593",
"@tscircuit/schematic-match-adapt": "^0.0.18",
"@tscircuit/schematic-trace-solver": "^0.0.111",
"@tscircuit/solver-utils": "^0.0.16",
Expand Down
Loading
Loading