@tscircuit/props 0.0.703 → 0.0.705
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -2
- package/dist/index.d.ts +471 -26
- package/dist/index.js +577 -461
- package/dist/index.js.map +1 -1
- package/lib/common/ibis.ts +60 -0
- package/lib/components/analogdigitalstimulus.ts +60 -0
- package/lib/components/analogeyediagram.ts +47 -0
- package/lib/components/analogsimulation.ts +5 -5
- package/lib/components/analogtransientsimulation.ts +11 -0
- package/lib/components/ibismodel.ts +13 -0
- package/lib/components/symbol.ts +31 -0
- package/lib/index.ts +4 -0
- package/lib/platformConfig.ts +4 -4
- package/package.json +1 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { asset } from "circuit-json"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
/** Direction is explicit per experiment. Only outputs accept an enable state. */
|
|
5
|
+
export const ibisPinRunState = z.discriminatedUnion("isOutput", [
|
|
6
|
+
z.object({ isOutput: z.literal(false) }).strict(),
|
|
7
|
+
z
|
|
8
|
+
.object({ isOutput: z.literal(true), isOutputEnabled: z.boolean() })
|
|
9
|
+
.strict(),
|
|
10
|
+
])
|
|
11
|
+
export type IbisPinRunState = z.input<typeof ibisPinRunState>
|
|
12
|
+
|
|
13
|
+
/** Reference values are labels on the same chip, never inferred supply rails. */
|
|
14
|
+
export const ibisPinReferences = z
|
|
15
|
+
.object({
|
|
16
|
+
pullup: z.string().min(1).optional(),
|
|
17
|
+
pulldown: z.string().min(1).optional(),
|
|
18
|
+
powerClamp: z.string().min(1).optional(),
|
|
19
|
+
groundClamp: z.string().min(1).optional(),
|
|
20
|
+
external: z.string().min(1).optional(),
|
|
21
|
+
})
|
|
22
|
+
.strict()
|
|
23
|
+
export type IbisPinReferences = z.input<typeof ibisPinReferences>
|
|
24
|
+
|
|
25
|
+
/** Same location rules as circuit-json's simulation_ibis_model asset. */
|
|
26
|
+
const ibisAssetPath = z
|
|
27
|
+
.string()
|
|
28
|
+
.min(1)
|
|
29
|
+
.regex(/^(?!\s|[a-z][a-z\d+.-]*:|[/\\])[^\\\u0000-\u001f\u007f]+$/i)
|
|
30
|
+
|
|
31
|
+
export const ibisModelAsset = asset.extend({
|
|
32
|
+
project_relative_path: ibisAssetPath,
|
|
33
|
+
url: z
|
|
34
|
+
.string()
|
|
35
|
+
.url()
|
|
36
|
+
.regex(/^https?:\/\//i)
|
|
37
|
+
.or(ibisAssetPath),
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
export const ibisModelDefinition = z.object({
|
|
41
|
+
ibisModelAsset,
|
|
42
|
+
ibisComponentName: z.string().min(1),
|
|
43
|
+
ibisPinNameToPortLabel: z
|
|
44
|
+
.record(z.string().min(1), z.string().min(1))
|
|
45
|
+
.refine((pins) => Object.keys(pins).length > 0),
|
|
46
|
+
ibisPinNameToModelName: z
|
|
47
|
+
.record(z.string().min(1), z.string().min(1))
|
|
48
|
+
.optional(),
|
|
49
|
+
ibisPinNameToReferencePortLabels: z
|
|
50
|
+
.record(z.string().min(1), ibisPinReferences)
|
|
51
|
+
.optional(),
|
|
52
|
+
modelValueCorner: z.union([
|
|
53
|
+
z.literal("typical"),
|
|
54
|
+
z.literal("minimum"),
|
|
55
|
+
z.literal("maximum"),
|
|
56
|
+
]),
|
|
57
|
+
includePackageParasitics: z.boolean(),
|
|
58
|
+
})
|
|
59
|
+
/** Vendor [Component] and [Pin] names are bound explicitly to this chip's ports. No corner or package defaults are inferred. */
|
|
60
|
+
export type IbisModelDefinition = z.input<typeof ibisModelDefinition>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ms } from "circuit-json"
|
|
2
|
+
import { expectTypesMatch } from "lib/typecheck"
|
|
3
|
+
import { z } from "zod"
|
|
4
|
+
|
|
5
|
+
/** Matches circuit-json's simulation_digital_stimulus pattern limit. */
|
|
6
|
+
const MAX_TRANSMITTED_BITS = 65536
|
|
7
|
+
|
|
8
|
+
/** Binary traffic for one external transient. Numeric times are milliseconds. */
|
|
9
|
+
export interface AnalogDigitalStimulusProps {
|
|
10
|
+
name: string
|
|
11
|
+
/** Selector for the external analog.transientsimulation experiment. */
|
|
12
|
+
simulationRef: string
|
|
13
|
+
/** Selector for the physical source pin driven by this stimulus. */
|
|
14
|
+
sourcePinRef: string
|
|
15
|
+
bitDuration: number | string
|
|
16
|
+
startTime: number | string
|
|
17
|
+
/** Initial bit before optional inversion. No traffic defaults are inferred. */
|
|
18
|
+
initialState: 0 | 1
|
|
19
|
+
inverted?: boolean
|
|
20
|
+
transmittedData: {
|
|
21
|
+
transmissionType: "bits"
|
|
22
|
+
bits: string | [0 | 1, ...(0 | 1)[]]
|
|
23
|
+
repeat: boolean
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export const analogDigitalStimulusProps = z
|
|
27
|
+
.object({
|
|
28
|
+
name: z.string().min(1),
|
|
29
|
+
simulationRef: z.string().min(1),
|
|
30
|
+
sourcePinRef: z.string().min(1),
|
|
31
|
+
bitDuration: ms.refine(
|
|
32
|
+
(milliseconds) => Number.isFinite(milliseconds) && milliseconds > 0,
|
|
33
|
+
),
|
|
34
|
+
startTime: ms.refine(
|
|
35
|
+
(milliseconds) => Number.isFinite(milliseconds) && milliseconds >= 0,
|
|
36
|
+
),
|
|
37
|
+
initialState: z.union([z.literal(0), z.literal(1)]),
|
|
38
|
+
inverted: z.boolean().default(false),
|
|
39
|
+
transmittedData: z
|
|
40
|
+
.object({
|
|
41
|
+
transmissionType: z.literal("bits"),
|
|
42
|
+
bits: z.union([
|
|
43
|
+
z
|
|
44
|
+
.string()
|
|
45
|
+
.regex(/^[01]+$/)
|
|
46
|
+
.max(MAX_TRANSMITTED_BITS),
|
|
47
|
+
z
|
|
48
|
+
.array(z.union([z.literal(0), z.literal(1)]))
|
|
49
|
+
.nonempty()
|
|
50
|
+
.max(MAX_TRANSMITTED_BITS),
|
|
51
|
+
]),
|
|
52
|
+
repeat: z.boolean(),
|
|
53
|
+
})
|
|
54
|
+
.strict(),
|
|
55
|
+
})
|
|
56
|
+
.strict()
|
|
57
|
+
expectTypesMatch<
|
|
58
|
+
AnalogDigitalStimulusProps,
|
|
59
|
+
z.input<typeof analogDigitalStimulusProps>
|
|
60
|
+
>(true)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ms } from "circuit-json"
|
|
2
|
+
import { expectTypesMatch } from "lib/typecheck"
|
|
3
|
+
import { z } from "zod"
|
|
4
|
+
|
|
5
|
+
/** Fixed-origin eye measurement. Numeric times are milliseconds; no compliance threshold is implied. */
|
|
6
|
+
export interface AnalogEyeDiagramProps {
|
|
7
|
+
name: string
|
|
8
|
+
simulationRef: string
|
|
9
|
+
probeRef: string
|
|
10
|
+
unitInterval: number | string
|
|
11
|
+
timeOrigin: number | string
|
|
12
|
+
/** Omitted gate endpoints use the experiment's recorded start/end times. */
|
|
13
|
+
startTime?: number | string
|
|
14
|
+
endTime?: number | string
|
|
15
|
+
}
|
|
16
|
+
const finiteMilliseconds = ms.refine(Number.isFinite)
|
|
17
|
+
export const analogEyeDiagramProps = z
|
|
18
|
+
.object({
|
|
19
|
+
name: z.string().min(1),
|
|
20
|
+
simulationRef: z.string().min(1),
|
|
21
|
+
probeRef: z.string().min(1),
|
|
22
|
+
unitInterval: finiteMilliseconds.refine((milliseconds) => milliseconds > 0),
|
|
23
|
+
timeOrigin: finiteMilliseconds,
|
|
24
|
+
startTime: finiteMilliseconds
|
|
25
|
+
.refine((milliseconds) => milliseconds >= 0)
|
|
26
|
+
.optional(),
|
|
27
|
+
endTime: finiteMilliseconds
|
|
28
|
+
.refine((milliseconds) => milliseconds > 0)
|
|
29
|
+
.optional(),
|
|
30
|
+
})
|
|
31
|
+
.strict()
|
|
32
|
+
.superRefine((eye, context) => {
|
|
33
|
+
if (
|
|
34
|
+
eye.startTime !== undefined &&
|
|
35
|
+
eye.endTime !== undefined &&
|
|
36
|
+
eye.startTime >= eye.endTime
|
|
37
|
+
) {
|
|
38
|
+
context.addIssue({
|
|
39
|
+
code: z.ZodIssueCode.custom,
|
|
40
|
+
path: ["endTime"],
|
|
41
|
+
message: "Eye gate end must follow its start",
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
expectTypesMatch<AnalogEyeDiagramProps, z.input<typeof analogEyeDiagramProps>>(
|
|
46
|
+
true,
|
|
47
|
+
)
|
|
@@ -10,14 +10,14 @@ export interface AnalogSimulationProps {
|
|
|
10
10
|
duration?: number | string
|
|
11
11
|
startTime?: number | string
|
|
12
12
|
timePerStep?: number | string
|
|
13
|
-
spiceEngine?: AutocompleteString<"spicey" | "ngspice">
|
|
13
|
+
spiceEngine?: AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
|
|
14
14
|
spiceOptions?: SpiceOptions
|
|
15
15
|
graphIndependentAxes?: boolean
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const spiceEngine = z.custom<
|
|
19
|
-
|
|
20
|
-
)
|
|
18
|
+
const spiceEngine = z.custom<
|
|
19
|
+
AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
|
|
20
|
+
>((value) => typeof value === "string")
|
|
21
21
|
|
|
22
22
|
export interface SpiceOptions {
|
|
23
23
|
method?: "trap" | "gear"
|
|
@@ -37,7 +37,7 @@ export interface AnalogAnalysisSimulationBaseProps {
|
|
|
37
37
|
/** Stable identity for the simulation experiment. */
|
|
38
38
|
name?: string
|
|
39
39
|
/** SPICE implementation used to run this analysis. */
|
|
40
|
-
spiceEngine?: AutocompleteString<"spicey" | "ngspice">
|
|
40
|
+
spiceEngine?: AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
|
|
41
41
|
/** Numerical solver settings forwarded to the selected SPICE engine. */
|
|
42
42
|
spiceOptions?: SpiceOptions
|
|
43
43
|
/** Render each probe with an independent vertical graph scale. */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ms } from "circuit-json"
|
|
2
2
|
import { expectTypesMatch } from "lib/typecheck"
|
|
3
3
|
import { z } from "zod"
|
|
4
|
+
import { ibisPinRunState, type IbisPinRunState } from "lib/common/ibis"
|
|
4
5
|
import {
|
|
5
6
|
analogAnalysisSimulationBaseProps,
|
|
6
7
|
type AnalogAnalysisSimulationBaseProps,
|
|
@@ -14,6 +15,8 @@ export interface AnalogTransientSimulationProps
|
|
|
14
15
|
startTime?: number | string
|
|
15
16
|
/** Maximum simulation timestep. Raw numbers are milliseconds. Defaults to 0.01ms. */
|
|
16
17
|
timePerStep?: number | string
|
|
18
|
+
/** Physical pin selectors and per-experiment direction/enable states. Requires spiceEngine="pcb_spice"; rendering only declares the experiment. */
|
|
19
|
+
ibisPinStates?: Record<string, IbisPinRunState>
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
const positiveMilliseconds = ms.refine(
|
|
@@ -27,8 +30,16 @@ export const analogTransientSimulationProps = z
|
|
|
27
30
|
duration: positiveMilliseconds.default("10ms"),
|
|
28
31
|
startTime: ms.default("0ms"),
|
|
29
32
|
timePerStep: positiveMilliseconds.default("0.01ms"),
|
|
33
|
+
ibisPinStates: z.record(z.string().min(1), ibisPinRunState).optional(),
|
|
30
34
|
})
|
|
31
35
|
.superRefine((simulation, context) => {
|
|
36
|
+
if (simulation.ibisPinStates && simulation.spiceEngine !== "pcb_spice") {
|
|
37
|
+
context.addIssue({
|
|
38
|
+
code: z.ZodIssueCode.custom,
|
|
39
|
+
path: ["ibisPinStates"],
|
|
40
|
+
message: "IBIS pin states require spiceEngine=pcb_spice",
|
|
41
|
+
})
|
|
42
|
+
}
|
|
32
43
|
if (
|
|
33
44
|
simulation.startTime < 0 ||
|
|
34
45
|
simulation.startTime > simulation.duration
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ibisModelDefinition, type IbisModelDefinition } from "lib/common/ibis"
|
|
2
|
+
import { expectTypesMatch } from "lib/typecheck"
|
|
3
|
+
import { z } from "zod"
|
|
4
|
+
|
|
5
|
+
/** Declares a model for an existing chip. Rendering never fetches or converts the source. */
|
|
6
|
+
export interface IbisModelProps extends IbisModelDefinition {
|
|
7
|
+
/** Selector for exactly one source component in this subcircuit. */
|
|
8
|
+
componentRef: string
|
|
9
|
+
}
|
|
10
|
+
export const ibisModelProps = ibisModelDefinition
|
|
11
|
+
.extend({ componentRef: z.string().min(1) })
|
|
12
|
+
.strict()
|
|
13
|
+
expectTypesMatch<IbisModelProps, z.input<typeof ibisModelProps>>(true)
|
package/lib/components/symbol.ts
CHANGED
|
@@ -12,6 +12,20 @@ export interface SymbolProps {
|
|
|
12
12
|
originalFacingDirection?: "up" | "down" | "left" | "right"
|
|
13
13
|
width?: string | number
|
|
14
14
|
height?: string | number
|
|
15
|
+
/** CSS-style fill (default) and stretch resize axes independently; contain preserves proportions. */
|
|
16
|
+
fit?: "fill" | "contain" | "stretch"
|
|
17
|
+
/**
|
|
18
|
+
* Source sizing bounds in the local symbol coordinate space (mm, +X right, +Y up).
|
|
19
|
+
* With width/height, maps the bounds center to the symbol position; all artwork
|
|
20
|
+
* and ports use the same transform. Omitted uses automatic bounds including ports.
|
|
21
|
+
* maxX must exceed minX and maxY must exceed minY. No aliases; no change to existing defaults.
|
|
22
|
+
*/
|
|
23
|
+
viewbox?: {
|
|
24
|
+
minX: number | string
|
|
25
|
+
maxX: number | string
|
|
26
|
+
minY: number | string
|
|
27
|
+
maxY: number | string
|
|
28
|
+
}
|
|
15
29
|
name?: string
|
|
16
30
|
}
|
|
17
31
|
|
|
@@ -22,6 +36,23 @@ export const symbolProps = z.object({
|
|
|
22
36
|
.optional(),
|
|
23
37
|
width: distance.optional(),
|
|
24
38
|
height: distance.optional(),
|
|
39
|
+
fit: z.enum(["fill", "contain", "stretch"]).optional(),
|
|
40
|
+
viewbox: z
|
|
41
|
+
.object({
|
|
42
|
+
minX: distance,
|
|
43
|
+
maxX: distance,
|
|
44
|
+
minY: distance,
|
|
45
|
+
maxY: distance,
|
|
46
|
+
})
|
|
47
|
+
.refine((bounds) => bounds.maxX > bounds.minX, {
|
|
48
|
+
message: "viewbox maxX must exceed minX",
|
|
49
|
+
path: ["maxX"],
|
|
50
|
+
})
|
|
51
|
+
.refine((bounds) => bounds.maxY > bounds.minY, {
|
|
52
|
+
message: "viewbox maxY must exceed minY",
|
|
53
|
+
path: ["maxY"],
|
|
54
|
+
})
|
|
55
|
+
.optional(),
|
|
25
56
|
name: z.string().optional(),
|
|
26
57
|
})
|
|
27
58
|
|
package/lib/index.ts
CHANGED
|
@@ -78,6 +78,10 @@ export * from "./components/push-button"
|
|
|
78
78
|
export * from "./components/subcircuit"
|
|
79
79
|
export * from "./components/analogsimulation"
|
|
80
80
|
export * from "./components/analogtransientsimulation"
|
|
81
|
+
export * from "./common/ibis"
|
|
82
|
+
export * from "./components/ibismodel"
|
|
83
|
+
export * from "./components/analogdigitalstimulus"
|
|
84
|
+
export * from "./components/analogeyediagram"
|
|
81
85
|
export * from "./components/analogdcoperatingpointsimulation"
|
|
82
86
|
export * from "./components/analogdcsweepsimulation"
|
|
83
87
|
export * from "./components/analogacsweepsimulation"
|
package/lib/platformConfig.ts
CHANGED
|
@@ -126,7 +126,7 @@ export interface PlatformConfig {
|
|
|
126
126
|
includeBoardFiles?: string[]
|
|
127
127
|
snapshotsDir?: string
|
|
128
128
|
|
|
129
|
-
defaultSpiceEngine?: AutocompleteString<"spicey" | "ngspice">
|
|
129
|
+
defaultSpiceEngine?: AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
|
|
130
130
|
|
|
131
131
|
unitPreference?: "mm" | "in" | "mil"
|
|
132
132
|
|
|
@@ -220,9 +220,9 @@ const spiceEngineZod = z.object({
|
|
|
220
220
|
),
|
|
221
221
|
})
|
|
222
222
|
|
|
223
|
-
const defaultSpiceEngine = z.custom<
|
|
224
|
-
|
|
225
|
-
)
|
|
223
|
+
const defaultSpiceEngine = z.custom<
|
|
224
|
+
AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
|
|
225
|
+
>((value) => typeof value === "string")
|
|
226
226
|
|
|
227
227
|
const autorouterInstance = z.object({
|
|
228
228
|
run: z
|