@tscircuit/props 0.0.704 → 0.0.706
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 +69 -2
- package/dist/index.d.ts +415 -26
- package/dist/index.js +567 -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/index.ts +4 -0
- package/lib/platformConfig.ts +23 -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/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
|
@@ -81,6 +81,16 @@ export interface PlatformConfig {
|
|
|
81
81
|
|
|
82
82
|
autorouter?: AutorouterProp
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Requested local autorouting thread count: a positive safe integer. Hosts
|
|
86
|
+
* supporting Bun/Node routing workers may use values above 1; 1 requests
|
|
87
|
+
* inline solving. Browsers remain single-threaded and cloud routing is
|
|
88
|
+
* unaffected. Omitted leaves the host default unchanged. Parsed values are
|
|
89
|
+
* preserved; there are no aliases or conflicts with autorouter selection.
|
|
90
|
+
* Existing configurations require no migration.
|
|
91
|
+
*/
|
|
92
|
+
autorouterThreads?: number
|
|
93
|
+
|
|
84
94
|
autorouterMap?: Record<string, AutorouterDefinition>
|
|
85
95
|
|
|
86
96
|
/** Use networked Pipeline9 node solving at effort 1. Omitted or false keeps local routing.
|
|
@@ -126,7 +136,7 @@ export interface PlatformConfig {
|
|
|
126
136
|
includeBoardFiles?: string[]
|
|
127
137
|
snapshotsDir?: string
|
|
128
138
|
|
|
129
|
-
defaultSpiceEngine?: AutocompleteString<"spicey" | "ngspice">
|
|
139
|
+
defaultSpiceEngine?: AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
|
|
130
140
|
|
|
131
141
|
unitPreference?: "mm" | "in" | "mil"
|
|
132
142
|
|
|
@@ -220,9 +230,9 @@ const spiceEngineZod = z.object({
|
|
|
220
230
|
),
|
|
221
231
|
})
|
|
222
232
|
|
|
223
|
-
const defaultSpiceEngine = z.custom<
|
|
224
|
-
|
|
225
|
-
)
|
|
233
|
+
const defaultSpiceEngine = z.custom<
|
|
234
|
+
AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
|
|
235
|
+
>((value) => typeof value === "string")
|
|
226
236
|
|
|
227
237
|
const autorouterInstance = z.object({
|
|
228
238
|
run: z
|
|
@@ -291,6 +301,15 @@ export const platformConfig = z.object({
|
|
|
291
301
|
.optional(),
|
|
292
302
|
fabricatorEngine: fabricatorEngine.optional(),
|
|
293
303
|
autorouter: autorouterProp.optional(),
|
|
304
|
+
autorouterThreads: z
|
|
305
|
+
.number()
|
|
306
|
+
.int()
|
|
307
|
+
.positive()
|
|
308
|
+
.safe()
|
|
309
|
+
.describe(
|
|
310
|
+
"Requested local autorouting thread count for supporting hosts. 1 requests inline solving; omission preserves the host default. Browsers stay single-threaded and cloud routing is unaffected.",
|
|
311
|
+
)
|
|
312
|
+
.optional(),
|
|
294
313
|
autorouterMap: z.record(z.string(), autorouterDefinition).optional(),
|
|
295
314
|
allowLegacyAutorouters: z.boolean().optional(),
|
|
296
315
|
registryApiUrl: url.optional(),
|