@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.
@@ -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<AutocompleteString<"spicey" | "ngspice">>(
19
- (value) => typeof value === "string",
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"
@@ -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<AutocompleteString<"spicey" | "ngspice">>(
224
- (value) => typeof value === "string",
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(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/props",
3
- "version": "0.0.704",
3
+ "version": "0.0.706",
4
4
  "description": "Props for tscircuit builtin component types",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",