Skip to content
Merged
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
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,20 @@ export interface AutoroutingPhaseProps extends RoutingTolerances {
* boundary where fanout traces terminate.
*/
fanoutBoundaryPadding?: FanoutBoundaryPadding;
/**
* Copper layers available to boundary-terminated fanout buses. Source-only
* traces whose nets are mapped by `fanoutPourNetMap` terminate on their
* mapped plane layer.
*/
fanoutRoutingLayers?: LayerRefInput[];
/**
* Maps copper layers to the net or nets poured on them. During fanout,
* source-only traces on those nets drop to the mapped layer instead of
* routing to the breakout boundary.
*
* This is inferred from `<copperpour>` components when omitted.
*/
fanoutPourNetMap?: FanoutPourNetMap;
}
```

Expand Down
51 changes: 47 additions & 4 deletions generated/COMPONENT_TYPES.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,35 @@ export const pcbCoordinate = calcString.or(baseDistance)
export { length }
```

### fanoutBoundaryPadding

```typescript
export interface DirectionalFanoutBoundaryPadding {
top?: Distance
right?: Distance
bottom?: Distance
left?: Distance
}
/**
* Padding between the union of the fanout source pads and the shared boundary
* where fanout traces terminate. Omitted directional values are treated as
* zero.
*/
export type FanoutBoundaryPadding = Distance | DirectionalFanoutBoundaryPadding

const nonnegativeDistance = distance.refine((value) => value >= 0, {
message: "Fanout boundary padding cannot be negative",
})
export const fanoutBoundaryPadding = z.union([
nonnegativeDistance,
z.object({
top: nonnegativeDistance.optional(),
right: nonnegativeDistance.optional(),
bottom: nonnegativeDistance.optional(),
left: nonnegativeDistance.optional(),
}),
```

### footprintProp

```typescript
Expand Down Expand Up @@ -1148,10 +1177,16 @@ export interface AutoroutingPhaseProps extends RoutingTolerances {
connections?: string[]
reroute?: boolean
busFanoutDirections?: Record<BusName, BusFanoutDirection>
fanoutBoundaryPadding?: FanoutBoundaryPadding
fanoutRoutingLayers?: LayerRefInput[]
fanoutPourNetMap?: FanoutPourNetMap
}
/**
* Fanout direction for each named bus in this phase. `center` leaves the
* direction unconstrained.
* Maps copper layers to the net or nets poured on them. During fanout,
* source-only traces on those nets drop to the mapped layer instead of
* routing to the breakout boundary.
*
* This is inferred from `<copperpour>` components when omitted.
*/
export const autoroutingPhaseProps = z
.object({
Expand All @@ -1173,6 +1208,11 @@ export const autoroutingPhaseProps = z
connections: z.array(z.string()).optional(),
reroute: z.boolean().optional(),
busFanoutDirections: z.record(busFanoutDirection).optional(),
fanoutBoundaryPadding: fanoutBoundaryPadding.optional(),
fanoutRoutingLayers: z.array(layer_ref).min(1).optional(),
fanoutPourNetMap: z
.record(layer_ref, z.union([z.string(), z.array(z.string()).min(1)]))
.optional(),
})
```

Expand Down Expand Up @@ -1263,10 +1303,12 @@ export interface BreakoutProps
paddingRight?: Distance
paddingTop?: Distance
paddingBottom?: Distance
fanoutBoundaryPadding?: FanoutBoundaryPadding
}
/**
* Autorouter used to escape the components inside the breakout boundary.
* Defaults to the multilayer fanout autorouter.
* Padding between the union of the fanout source pads and the shared
* boundary where fanout traces terminate. This is independent of the
* breakout group's layout padding.
*/
export const breakoutProps = subcircuitGroupProps.extend({
autorouter: autorouterProp.default("fanout"),
Expand All @@ -1275,6 +1317,7 @@ export const breakoutProps = subcircuitGroupProps.extend({
paddingRight: distance.optional(),
paddingTop: distance.optional(),
paddingBottom: distance.optional(),
fanoutBoundaryPadding: fanoutBoundaryPadding.optional(),
})
```

Expand Down
38 changes: 38 additions & 0 deletions generated/PROPS_OVERVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,25 @@ export interface AutoroutingPhaseProps extends RoutingTolerances {
* direction unconstrained.
*/
busFanoutDirections?: Record<BusName, BusFanoutDirection>
/**
* Padding between the union of the fanout source pads and the shared
* boundary where fanout traces terminate.
*/
fanoutBoundaryPadding?: FanoutBoundaryPadding
/**
* Copper layers available to boundary-terminated fanout buses. Source-only
* traces whose nets are mapped by `fanoutPourNetMap` terminate on their
* mapped plane layer.
*/
fanoutRoutingLayers?: LayerRefInput[]
/**
* Maps copper layers to the net or nets poured on them. During fanout,
* source-only traces on those nets drop to the mapped layer instead of
* routing to the breakout boundary.
*
* This is inferred from `<copperpour>` components when omitted.
*/
fanoutPourNetMap?: FanoutPourNetMap
}


Expand Down Expand Up @@ -408,11 +427,22 @@ export interface BreakoutPointProps

export interface BreakoutProps
extends Omit<SubcircuitGroupProps, "subcircuit"> {
/**
* Autorouter used to escape the components inside the breakout boundary.
* Defaults to the multilayer fanout autorouter.
*/
autorouter?: AutorouterProp
padding?: Distance
paddingLeft?: Distance
paddingRight?: Distance
paddingTop?: Distance
paddingBottom?: Distance
/**
* Padding between the union of the fanout source pads and the shared
* boundary where fanout traces terminate. This is independent of the
* breakout group's layout padding.
*/
fanoutBoundaryPadding?: FanoutBoundaryPadding
}


Expand Down Expand Up @@ -878,6 +908,14 @@ export interface DiodeProps<PinLabel extends string = string>
}


export interface DirectionalFanoutBoundaryPadding {
top?: Distance
right?: Distance
bottom?: Distance
left?: Distance
}


export interface DrcCheckProps {
name?: string
checkFn: CustomDrcCheckFn
Expand Down
23 changes: 23 additions & 0 deletions lib/components/autoroutingphase.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expectTypesMatch } from "lib/typecheck"
import { z } from "zod"
import { layer_ref, type LayerRef, type LayerRefInput } from "circuit-json"
import {
type FanoutBoundaryPadding,
fanoutBoundaryPadding,
Expand All @@ -22,6 +23,10 @@ export type BusFanoutDirection =
direction: NinePointAnchor
}

export type FanoutPourNetMap = Partial<
Record<Extract<LayerRef, string>, string | string[]>
>

export interface AutoroutingPhaseProps extends RoutingTolerances {
key?: any
name?: string
Expand All @@ -47,6 +52,20 @@ export interface AutoroutingPhaseProps extends RoutingTolerances {
* boundary where fanout traces terminate.
*/
fanoutBoundaryPadding?: FanoutBoundaryPadding
/**
* Copper layers available to boundary-terminated fanout buses. Source-only
* traces whose nets are mapped by `fanoutPourNetMap` terminate on their
* mapped plane layer.
*/
fanoutRoutingLayers?: LayerRefInput[]
/**
* Maps copper layers to the net or nets poured on them. During fanout,
* source-only traces on those nets drop to the mapped layer instead of
* routing to the breakout boundary.
*
* This is inferred from `<copperpour>` components when omitted.
*/
fanoutPourNetMap?: FanoutPourNetMap
}

const busFanoutDirection = z.union([
Expand Down Expand Up @@ -75,6 +94,10 @@ export const autoroutingPhaseProps = z
reroute: z.boolean().optional(),
busFanoutDirections: z.record(busFanoutDirection).optional(),
fanoutBoundaryPadding: fanoutBoundaryPadding.optional(),
fanoutRoutingLayers: z.array(layer_ref).min(1).optional(),
fanoutPourNetMap: z
.record(layer_ref, z.union([z.string(), z.array(z.string()).min(1)]))
.optional(),
})
.superRefine((value, ctx) => {
if (
Expand Down
21 changes: 21 additions & 0 deletions tests/autoroutingphase.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,27 @@ test("autorouting phase accepts per-bus fanout directions", () => {
expect(autoroutingPhaseProps.parse(raw)).toEqual(raw)
})

test("autorouting phase accepts fanout routing layers", () => {
const parsed = autoroutingPhaseProps.parse({
autorouter: "fanout",
fanoutRoutingLayers: ["top", { name: "inner3" }, "bottom"],
})

expect(parsed.fanoutRoutingLayers).toEqual(["top", "inner3", "bottom"])
})

test("autorouting phase accepts a fanout pour net map", () => {
const raw = {
autorouter: "fanout",
fanoutPourNetMap: {
inner1: "GND",
inner2: ["VCC_CORE", "VCC_IO"],
},
} satisfies AutoroutingPhaseProps

expect(autoroutingPhaseProps.parse(raw)).toEqual(raw)
})
Comment on lines +45 to +64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A *.test.ts file may have AT MOST one test(...). This file already had at least one test before these additions, and now two more test(...) calls are being added (lines 45 and 54), bringing the total well above one. Per the style guide, each test should be split into its own numbered file, e.g. autoroutingphase1.test.ts, autoroutingphase2.test.ts, autoroutingphase3.test.ts, etc.

Spotted by Graphite (based on custom rule: Custom rule)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.


test("autorouting phase accepts scalar fanout boundary padding", () => {
const raw = {
autorouter: "fanout",
Expand Down
13 changes: 2 additions & 11 deletions tests/bus.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,10 @@ import { expect, test } from "bun:test"
import { busProps, type BusProps } from "lib/components/bus"

test("busProps accepts two or more connection references", () => {
const rawProps: BusProps = {
const rawProps = {
name: "DATA",
connections: ["D0", ".U1 > .D1"],
}
} satisfies BusProps

expect(busProps.parse(rawProps)).toEqual(rawProps)
})

test("busProps rejects a single connection", () => {
expect(
busProps.safeParse({
name: "DATA",
connections: ["D0"],
}).success,
).toBe(false)
})
Loading