@tscircuit/core 0.0.2179 → 0.0.2181

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +290 -24
  2. package/dist/index.js +617 -13
  3. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -18,6 +18,8 @@ __export(components_exports, {
18
18
  AnalogAnalysisSimulation: () => AnalogAnalysisSimulation,
19
19
  AnalogDcOperatingPointSimulation: () => AnalogDcOperatingPointSimulation,
20
20
  AnalogDcSweepSimulation: () => AnalogDcSweepSimulation,
21
+ AnalogDigitalStimulus: () => AnalogDigitalStimulus,
22
+ AnalogEyeDiagram: () => AnalogEyeDiagram,
21
23
  AnalogSimulation: () => AnalogSimulation,
22
24
  AnalogSweepParameter: () => AnalogSweepParameter,
23
25
  AnalogTransientSimulation: () => AnalogTransientSimulation,
@@ -66,6 +68,7 @@ __export(components_exports, {
66
68
  Fuse: () => Fuse,
67
69
  Group: () => Group5,
68
70
  Hole: () => Hole,
71
+ IbisModel: () => IbisModel,
69
72
  Inductor: () => Inductor,
70
73
  Interconnect: () => Interconnect,
71
74
  Jumper: () => Jumper,
@@ -1751,6 +1754,11 @@ var renderPhaseIndexMap = new Map(
1751
1754
  var asyncPhaseDependencies = {
1752
1755
  InflateSubcircuitCircuitJson: ["RenderIsolatedSubcircuits"],
1753
1756
  ResolveFootprintPinLabels: ["PcbFootprintStringRender", "FetchPartFootprint"],
1757
+ SimulationRender: ["PcbFootprintStringRender", "FetchPartFootprint"],
1758
+ SimulationSpiceEngineRender: [
1759
+ "PcbFootprintStringRender",
1760
+ "FetchPartFootprint"
1761
+ ],
1754
1762
  SchematicComponentRender: ["PcbFootprintStringRender", "FetchPartFootprint"],
1755
1763
  SchematicPortRender: ["PcbFootprintStringRender", "FetchPartFootprint"],
1756
1764
  SymbolContainerRender: ["PcbFootprintStringRender", "FetchPartFootprint"],
@@ -20450,6 +20458,139 @@ function inflatePcbBoard(pcbBoard, inflatorContext) {
20450
20458
  return board;
20451
20459
  }
20452
20460
 
20461
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSimulation.ts
20462
+ import { getElementId } from "@tscircuit/circuit-json-util";
20463
+ var ibisSimulationTypes = [
20464
+ "simulation_ibis_model",
20465
+ "simulation_ibis_pin_state",
20466
+ "simulation_digital_stimulus",
20467
+ "simulation_eye_diagram"
20468
+ ];
20469
+ var simulationTypes = [
20470
+ "simulation_experiment",
20471
+ "simulation_voltage_probe",
20472
+ ...ibisSimulationTypes
20473
+ ];
20474
+ var InflatedSimulation = class extends PrimitiveComponent2 {
20475
+ constructor(inflationCtx) {
20476
+ super({});
20477
+ this.inflationCtx = inflationCtx;
20478
+ }
20479
+ inflationCtx;
20480
+ get config() {
20481
+ return { ...super.config, componentName: "InflatedSimulation" };
20482
+ }
20483
+ doInitialSimulationRender() {
20484
+ if (this.getInheritedProperty("analogSimulationDisabled")) return;
20485
+ restoreSimulationRecords(this.inflationCtx);
20486
+ }
20487
+ };
20488
+ function restoreSimulationRecords({
20489
+ injectionDb,
20490
+ subcircuit,
20491
+ groupsMap
20492
+ }) {
20493
+ const { db: db2 } = subcircuit.root;
20494
+ const eyes = injectionDb.simulation_eye_diagram.list();
20495
+ const experimentIds = new Set(
20496
+ [
20497
+ ...injectionDb.simulation_ibis_pin_state.list(),
20498
+ ...injectionDb.simulation_digital_stimulus.list(),
20499
+ ...eyes
20500
+ ].map((record) => record.simulation_experiment_id)
20501
+ );
20502
+ const probeIds = new Set(eyes.map((eye) => eye.simulation_voltage_probe_id));
20503
+ const restoredIds = /* @__PURE__ */ new Map();
20504
+ const remapId = (originalId, field) => {
20505
+ const restoredId = restoredIds.get(originalId);
20506
+ if (restoredId) return restoredId;
20507
+ let matchedId;
20508
+ if (field === "subcircuit_id") {
20509
+ const sourceGroup = injectionDb.source_group.list().find((group2) => group2.subcircuit_id === originalId);
20510
+ const group = sourceGroup && groupsMap?.get(sourceGroup.source_group_id);
20511
+ matchedId = group?.getSubcircuit().subcircuit_id ?? void 0;
20512
+ } else if (field === "source_component_id") {
20513
+ const original = injectionDb.source_component.get(originalId);
20514
+ const group = original?.source_group_id ? groupsMap?.get(original.source_group_id) : subcircuit;
20515
+ if (original && group?.source_group_id) {
20516
+ const components = db2.source_component.list({
20517
+ source_group_id: group.source_group_id,
20518
+ name: original.name
20519
+ });
20520
+ if (components.length === 1)
20521
+ matchedId = components[0].source_component_id;
20522
+ }
20523
+ } else if (field.endsWith("source_port_id")) {
20524
+ const original = injectionDb.source_port.get(originalId);
20525
+ if (original?.source_component_id) {
20526
+ const componentId = remapId(
20527
+ original.source_component_id,
20528
+ "source_component_id"
20529
+ );
20530
+ const ports = db2.source_port.list({ source_component_id: componentId }).filter(
20531
+ (port) => original.pin_number !== void 0 ? port.pin_number === original.pin_number : port.name === original.name
20532
+ );
20533
+ if (ports.length === 1) matchedId = ports[0].source_port_id;
20534
+ }
20535
+ } else if (field.endsWith("source_net_id")) {
20536
+ const original = injectionDb.source_net.get(originalId);
20537
+ if (original) {
20538
+ const nets = db2.source_net.list({
20539
+ name: original.name,
20540
+ subcircuit_id: original.subcircuit_id ? remapId(original.subcircuit_id, "subcircuit_id") : subcircuit.subcircuit_id
20541
+ });
20542
+ if (nets.length === 1) matchedId = nets[0].source_net_id;
20543
+ }
20544
+ }
20545
+ if (!matchedId) {
20546
+ throw new Error(
20547
+ `Cannot restore simulation records: unable to remap ${field} safely.`
20548
+ );
20549
+ }
20550
+ restoredIds.set(originalId, matchedId);
20551
+ return matchedId;
20552
+ };
20553
+ const remapReferences = (value, field) => {
20554
+ if (typeof value === "string" && field.endsWith("_id"))
20555
+ return remapId(value, field);
20556
+ if (Array.isArray(value))
20557
+ return value.map((entry) => remapReferences(entry, field));
20558
+ if (value && typeof value === "object") {
20559
+ return Object.fromEntries(
20560
+ Object.entries(value).map(([key, entry]) => [
20561
+ key,
20562
+ remapReferences(
20563
+ entry,
20564
+ field === "ibis_pin_name_to_source_port_id" ? "source_port_id" : key
20565
+ )
20566
+ ])
20567
+ );
20568
+ }
20569
+ return value;
20570
+ };
20571
+ for (const type of simulationTypes) {
20572
+ for (const record of injectionDb[type].list()) {
20573
+ if (record.type === "simulation_experiment" && !experimentIds.has(record.simulation_experiment_id) || record.type === "simulation_voltage_probe" && !probeIds.has(record.simulation_voltage_probe_id))
20574
+ continue;
20575
+ const primaryIdField = `${type}_id`;
20576
+ const fields = Object.fromEntries(
20577
+ Object.entries(record).filter(([key]) => key !== primaryIdField)
20578
+ );
20579
+ const restored = db2.insert(
20580
+ remapReferences(fields, "")
20581
+ );
20582
+ restoredIds.set(getElementId(record), getElementId(restored));
20583
+ }
20584
+ }
20585
+ }
20586
+ function inflateSimulation(inflationCtx) {
20587
+ if (!ibisSimulationTypes.some(
20588
+ (type) => inflationCtx.injectionDb[type].list().length > 0
20589
+ ))
20590
+ return;
20591
+ inflationCtx.subcircuit.add(new InflatedSimulation(inflationCtx));
20592
+ }
20593
+
20453
20594
  // lib/components/normal-components/Capacitor.ts
20454
20595
  import { capacitorProps, resolveManufacturerPartNumber as resolveManufacturerPartNumber4 } from "@tscircuit/props";
20455
20596
  import { formatSiUnit } from "format-si-unit";
@@ -85433,7 +85574,7 @@ var buildPowerPourPolygons = (problem) => {
85433
85574
  var getLayerColor = (layer) => layer === "top" ? "#c2453a" : layer === "bottom" ? "#5b7fd8" : "#c58b43";
85434
85575
 
85435
85576
  // node_modules/@tscircuit/implicit-copper-pour-solver/lib/prepare-circuit-json.ts
85436
- import { getElementId } from "@tscircuit/circuit-json-util";
85577
+ import { getElementId as getElementId2 } from "@tscircuit/circuit-json-util";
85437
85578
  import {
85438
85579
  getBoundFromCenteredRect,
85439
85580
  getBoundsFromPoints as getBoundsFromPoints8
@@ -85756,7 +85897,7 @@ var prepareCircuitJson = (input) => {
85756
85897
  );
85757
85898
  const netIndexByConnectivityNetwork = /* @__PURE__ */ new Map();
85758
85899
  const getConnectivityNetIndex = (element) => {
85759
- const elementId = getElementId(element);
85900
+ const elementId = getElementId2(element);
85760
85901
  const connectivityNetworkId = connectivityMap.getNetConnectedToId(elementId);
85761
85902
  if (connectivityNetworkId) {
85762
85903
  const connectedSourceNetIndexes = sourceNets.flatMap(
@@ -85797,7 +85938,7 @@ var prepareCircuitJson = (input) => {
85797
85938
  }
85798
85939
  const connectivityNetIndex = getConnectivityNetIndex(element);
85799
85940
  if (connectivityNetIndex !== void 0) return connectivityNetIndex;
85800
- const elementId = getElementId(element);
85941
+ const elementId = getElementId2(element);
85801
85942
  return getOrCreateImplicitNetIndex(
85802
85943
  `${element.type}:${elementId}`,
85803
85944
  elementId
@@ -110758,6 +110899,7 @@ var getSimpleRouteJsonFromCircuitJson = ({
110758
110899
  traces: preservedRoutedSubcircuitTraces.length > 0 ? preservedRoutedSubcircuitTraces : void 0,
110759
110900
  layerCount: board?.num_layers ?? 2,
110760
110901
  allowBlindAndBuriedVias: board?.allow_blind_and_buried_vias ?? false,
110902
+ allowViaInPad: board?.is_via_in_pad_allowed ?? false,
110761
110903
  minTraceWidth: Math.min(
110762
110904
  defaultTraceWidth,
110763
110905
  ...allConns.map((c2) => c2.width)
@@ -118478,6 +118620,10 @@ function Group_doInitialSimulationSpiceEngineRender(group) {
118478
118620
  debug12("No simulation experiment found, skipping simulation");
118479
118621
  continue;
118480
118622
  }
118623
+ if (simulationExperiment.spice_engine === "pcb_spice" && (!spiceEngineMap.pcb_spice || isExternalIbisExperiment(root.db, simulationExperimentId))) {
118624
+ debug12("Skipping external pcb_spice experiment during rendering");
118625
+ continue;
118626
+ }
118481
118627
  const simulationScope = analogSimulation.getGroup() ?? group;
118482
118628
  const voltageProbes = simulationScope.selectAll("voltageprobe");
118483
118629
  const ammeters = simulationScope.selectAll("ammeter");
@@ -118686,6 +118832,10 @@ ${simulationRuns.map((simulationRun) => simulationRun.spiceString).join("\n")}`
118686
118832
  });
118687
118833
  }
118688
118834
  }
118835
+ function isExternalIbisExperiment(db2, simulationExperimentId) {
118836
+ const belongsToExperiment = (record) => record.simulation_experiment_id === simulationExperimentId;
118837
+ return db2.simulation_ibis_pin_state.list().some(belongsToExperiment) || db2.simulation_digital_stimulus.list().some(belongsToExperiment) || db2.simulation_eye_diagram.list().some(belongsToExperiment);
118838
+ }
118689
118839
 
118690
118840
  // lib/components/primitive-components/Group/Group_doInitialSourceAddConnectivityMapKey.ts
118691
118841
  import { ConnectivityMap as ConnectivityMap5 } from "circuit-json-to-connectivity-map";
@@ -119559,7 +119709,7 @@ var RoutingPhasePreparationError = class extends Error {
119559
119709
  var package_default = {
119560
119710
  name: "@tscircuit/core",
119561
119711
  type: "module",
119562
- version: "0.0.2178",
119712
+ version: "0.0.2180",
119563
119713
  types: "dist/index.d.ts",
119564
119714
  main: "dist/index.js",
119565
119715
  module: "dist/index.js",
@@ -119618,7 +119768,7 @@ var package_default = {
119618
119768
  "@tscircuit/miniflex": "^0.0.4",
119619
119769
  "@tscircuit/modelprinter": "^0.0.18",
119620
119770
  "@tscircuit/ngspice-spice-engine": "^0.0.20",
119621
- "@tscircuit/props": "^0.0.704",
119771
+ "@tscircuit/props": "^0.0.705",
119622
119772
  "@tscircuit/schematic-match-adapt": "^0.0.18",
119623
119773
  "@tscircuit/schematic-trace-solver": "https://jscdn.tscircuit.com/@tscircuit/schematic-trace-solver/0.0.230.tgz",
119624
119774
  "@tscircuit/solver-utils": "^0.0.16",
@@ -119634,7 +119784,7 @@ var package_default = {
119634
119784
  "bun-match-svg": "0.0.12",
119635
119785
  "calculate-elbow": "^0.0.12",
119636
119786
  "chokidar-cli": "^3.0.0",
119637
- "circuit-json": "^0.0.528",
119787
+ "circuit-json": "^0.0.529",
119638
119788
  "circuit-json-to-bpc": "^0.0.13",
119639
119789
  "circuit-json-to-connectivity-map": "^0.0.33",
119640
119790
  "circuit-json-to-gltf": "^0.0.151",
@@ -119701,8 +119851,8 @@ var package_default = {
119701
119851
  "jscad-fiber": "^0.0.88"
119702
119852
  },
119703
119853
  overrides: {
119704
- "@tscircuit/props": "^0.0.704",
119705
- "circuit-json": "^0.0.528",
119854
+ "@tscircuit/props": "^0.0.705",
119855
+ "circuit-json": "^0.0.529",
119706
119856
  "@tscircuit/cableprinter": "^0.0.6"
119707
119857
  }
119708
119858
  };
@@ -121312,7 +121462,7 @@ var Group5 = class extends NormalComponent {
121312
121462
  subcircuit_id: this.subcircuit_id,
121313
121463
  subcircuitComponent: this
121314
121464
  });
121315
- simpleRouteJson.allowViaInPad = autorouterConfig.allowViaInPad;
121465
+ simpleRouteJson.allowViaInPad = autorouterConfig.allowViaInPad ?? simpleRouteJson.allowViaInPad;
121316
121466
  const { autorouting_result: autorouting_result2 } = await fetchWithDebug(
121317
121467
  `${serverUrl}/autorouting/solve`,
121318
121468
  {
@@ -121777,7 +121927,7 @@ var Group5 = class extends NormalComponent {
121777
121927
  simpleRouteJson,
121778
121928
  routingPhasePlan.drcTolerances
121779
121929
  );
121780
- simpleRouteJson.allowViaInPad = phaseAutorouterConfig.allowViaInPad;
121930
+ simpleRouteJson.allowViaInPad = phaseAutorouterConfig.allowViaInPad ?? simpleRouteJson.allowViaInPad;
121781
121931
  const getPrecomputedRoutingResult = usesPreviousStageOutput ? void 0 : routingPhasePlan.getPrecomputedRoutingResult;
121782
121932
  const preflightRoutingCheckPolicy = this.getInheritedProperty("preflightRoutingCheckPolicy") ?? "basic";
121783
121933
  if (routingPhasePlan.isImplicitRemainingPhase && phaseStageIndex === 0 && this.getInheritedProperty("routeRemaining") === void 0 && (preflightRoutingCheckPolicy === "basic" || preflightRoutingCheckPolicy === "conservative") && simpleRouteJson.connections.length > 50) {
@@ -124078,6 +124228,7 @@ var inflateCircuitJson = (target, circuitJson, children) => {
124078
124228
  inflateSourceTrace(sourceTrace, inflationCtx);
124079
124229
  }
124080
124230
  inflateStandalonePcbPrimitives(inflationCtx);
124231
+ inflateSimulation(inflationCtx);
124081
124232
  };
124082
124233
 
124083
124234
  // lib/components/primitive-components/resolve-board-motor-mount.ts
@@ -134096,6 +134247,80 @@ var AnalogAnalysisSimulation = class extends PrimitiveComponent2 {
134096
134247
 
134097
134248
  // lib/components/primitive-components/AnalogTransientSimulation.ts
134098
134249
  import { analogTransientSimulationProps } from "@tscircuit/props";
134250
+
134251
+ // lib/utils/simulation/resolveExternalSimulation.ts
134252
+ function resolveExternalSimulationPort({
134253
+ declaration,
134254
+ selector
134255
+ }) {
134256
+ const ports = declaration.getSubcircuit().selectAll(selector).filter((port2) => port2.componentName === "Port");
134257
+ if (ports.length !== 1 || !ports[0].source_port_id) {
134258
+ throw new Error(
134259
+ `Simulation pin selector "${selector}" must identify exactly one physical source pin.`
134260
+ );
134261
+ }
134262
+ const port = ports[0];
134263
+ if (port.getSubcircuit() !== declaration.getSubcircuit()) {
134264
+ throw new Error(
134265
+ `Simulation pin "${selector}" must belong to the same subcircuit as its declaration.`
134266
+ );
134267
+ }
134268
+ return port;
134269
+ }
134270
+ function resolveExternalTransientSimulation({
134271
+ declaration,
134272
+ selector
134273
+ }) {
134274
+ const simulations = declaration.getSubcircuit().selectAll(selector).filter(
134275
+ (simulation3) => simulation3.componentName === "AnalogTransientSimulation"
134276
+ );
134277
+ if (simulations.length !== 1 || simulations[0].getSubcircuit() !== declaration.getSubcircuit()) {
134278
+ throw new Error(
134279
+ `Simulation selector "${selector}" must identify one transient in the same subcircuit.`
134280
+ );
134281
+ }
134282
+ const simulation2 = simulations[0];
134283
+ if (simulation2.getSpiceEngineName() !== "pcb_spice") {
134284
+ throw new Error(
134285
+ `Simulation "${selector}" requires spiceEngine="pcb_spice" for IBIS declarations.`
134286
+ );
134287
+ }
134288
+ simulation2.getOrCreateSimulationExperiment();
134289
+ return simulation2;
134290
+ }
134291
+
134292
+ // lib/components/primitive-components/AnalogTransientSimulation_validateIbisBindings.ts
134293
+ function AnalogTransientSimulation_validateIbisBindings(simulation2) {
134294
+ if (simulation2.getSpiceEngineName() !== "pcb_spice") return;
134295
+ const subcircuit = simulation2.getSubcircuit();
134296
+ const models = subcircuit.selectAll("ibismodel").filter(
134297
+ (model) => !model.shouldBeRemoved && model.getSubcircuit() === subcircuit
134298
+ ).map(
134299
+ (model) => simulation2.root.db.simulation_ibis_model.get(
134300
+ model.simulation_ibis_model_id
134301
+ )
134302
+ );
134303
+ for (const selector of Object.keys(
134304
+ simulation2._parsedProps.ibisPinStates ?? {}
134305
+ )) {
134306
+ const port = resolveExternalSimulationPort({
134307
+ declaration: simulation2,
134308
+ selector
134309
+ });
134310
+ const bindings = models.filter(
134311
+ (model) => Object.values(model.ibis_pin_name_to_source_port_id).includes(
134312
+ port.source_port_id
134313
+ )
134314
+ );
134315
+ if (bindings.length !== 1) {
134316
+ throw new Error(
134317
+ `Simulation "${simulation2._parsedProps.name ?? "transient"}" pin "${selector}" requires exactly one IBIS model binding in this subcircuit.`
134318
+ );
134319
+ }
134320
+ }
134321
+ }
134322
+
134323
+ // lib/components/primitive-components/AnalogTransientSimulation.ts
134099
134324
  var AnalogTransientSimulation = class extends AnalogAnalysisSimulation {
134100
134325
  get config() {
134101
134326
  return {
@@ -134103,17 +134328,389 @@ var AnalogTransientSimulation = class extends AnalogAnalysisSimulation {
134103
134328
  zodProps: analogTransientSimulationProps
134104
134329
  };
134105
134330
  }
134331
+ doInitialSimulationSpiceEngineRender() {
134332
+ if (this.getInheritedProperty("analogSimulationDisabled")) return;
134333
+ AnalogTransientSimulation_validateIbisBindings(this);
134334
+ }
134335
+ updateSimulationSpiceEngineRender() {
134336
+ this.doInitialSimulationSpiceEngineRender();
134337
+ }
134338
+ onPropsChange() {
134339
+ this._markDirty("SimulationRender");
134340
+ if (!this.simulation_experiment_id) return;
134341
+ const subcircuit = this.getSubcircuit();
134342
+ for (const declaration of [
134343
+ ...subcircuit.selectAll("analogdigitalstimulus"),
134344
+ ...subcircuit.selectAll("analogeyediagram")
134345
+ ]) {
134346
+ if (declaration.getSubcircuit() === subcircuit)
134347
+ declaration._markDirty("SimulationSpiceEngineRender");
134348
+ }
134349
+ }
134350
+ updateSimulationRender() {
134351
+ this.insertSimulationExperiment();
134352
+ }
134353
+ removeIbisPinStates() {
134354
+ for (const state of this.root.db.simulation_ibis_pin_state.list({
134355
+ simulation_experiment_id: this.simulation_experiment_id
134356
+ })) {
134357
+ this.root.db.simulation_ibis_pin_state.delete(
134358
+ state.simulation_ibis_pin_state_id
134359
+ );
134360
+ }
134361
+ }
134362
+ removeSimulationRender() {
134363
+ if (!this.simulation_experiment_id) return;
134364
+ this.removeIbisPinStates();
134365
+ this.root.db.simulation_experiment.delete(this.simulation_experiment_id);
134366
+ this.simulation_experiment_id = null;
134367
+ }
134106
134368
  insertSimulationExperiment() {
134107
134369
  const { db: db2 } = this.root;
134108
134370
  const { duration, name, startTime, timePerStep, spiceOptions } = this._parsedProps;
134109
- return db2.simulation_experiment.insert({
134371
+ const ibisPinStates = this.getInheritedProperty("analogSimulationDisabled") ? {} : this._parsedProps.ibisPinStates;
134372
+ const pins = Object.entries(ibisPinStates ?? {}).map(
134373
+ ([selector, state]) => {
134374
+ const pin = {
134375
+ source_port_id: resolveExternalSimulationPort({
134376
+ declaration: this,
134377
+ selector
134378
+ }).source_port_id,
134379
+ is_output: state.isOutput
134380
+ };
134381
+ if (state.isOutput)
134382
+ return { ...pin, is_output_enabled: state.isOutputEnabled };
134383
+ return pin;
134384
+ }
134385
+ );
134386
+ if (new Set(pins.map((pin) => pin.source_port_id)).size !== pins.length) {
134387
+ throw new Error(
134388
+ `Simulation "${name ?? "transient"}" assigns multiple states to the same physical pin.`
134389
+ );
134390
+ }
134391
+ const experimentProps = {
134110
134392
  name: name ?? "spice_transient_analysis",
134111
134393
  experiment_type: "spice_transient_analysis",
134112
134394
  end_time_ms: duration,
134113
134395
  start_time_ms: startTime,
134114
134396
  time_per_step: timePerStep,
134115
- spice_options: spiceOptions
134116
- });
134397
+ spice_options: spiceOptions,
134398
+ spice_engine: this.getSpiceEngineName(),
134399
+ subcircuit_id: this.getSubcircuit().subcircuit_id
134400
+ };
134401
+ const experiment = this.simulation_experiment_id ? db2.simulation_experiment.update(
134402
+ this.simulation_experiment_id,
134403
+ experimentProps
134404
+ ) : db2.simulation_experiment.insert(experimentProps);
134405
+ if (this.simulation_experiment_id) this.removeIbisPinStates();
134406
+ for (const pin of pins) {
134407
+ db2.simulation_ibis_pin_state.insert({
134408
+ simulation_experiment_id: experiment.simulation_experiment_id,
134409
+ ...pin
134410
+ });
134411
+ }
134412
+ return experiment;
134413
+ }
134414
+ };
134415
+
134416
+ // lib/components/primitive-components/AnalogDigitalStimulus.ts
134417
+ import { analogDigitalStimulusProps } from "@tscircuit/props";
134418
+
134419
+ // lib/components/primitive-components/AnalogDigitalStimulus_getSimulationDigitalStimulus.ts
134420
+ function AnalogDigitalStimulus_getSimulationDigitalStimulus(declaration) {
134421
+ const props = declaration._parsedProps;
134422
+ const simulation2 = resolveExternalTransientSimulation({
134423
+ declaration,
134424
+ selector: props.simulationRef
134425
+ });
134426
+ const port = resolveExternalSimulationPort({
134427
+ declaration,
134428
+ selector: props.sourcePinRef
134429
+ });
134430
+ const experiment = simulation2.getOrCreateSimulationExperiment();
134431
+ if (props.startTime >= experiment.end_time_ms)
134432
+ throw new Error(`Stimulus "${props.name}" starts outside its simulation.`);
134433
+ const pinState = declaration.root.db.simulation_ibis_pin_state.list({
134434
+ simulation_experiment_id: experiment.simulation_experiment_id
134435
+ }).find((state) => state.source_port_id === port.source_port_id);
134436
+ if (pinState?.is_output !== true || pinState.is_output_enabled !== true) {
134437
+ throw new Error(
134438
+ `Stimulus "${props.name}" must drive a pin declared as an enabled output in its simulation.`
134439
+ );
134440
+ }
134441
+ if (declaration.root.db.simulation_digital_stimulus.list({
134442
+ simulation_experiment_id: experiment.simulation_experiment_id
134443
+ }).some(
134444
+ (stimulus) => stimulus.simulation_digital_stimulus_id !== declaration.simulation_digital_stimulus_id && (stimulus.source_port_id === port.source_port_id || stimulus.name === props.name)
134445
+ )) {
134446
+ throw new Error(
134447
+ `Stimulus "${props.name}" duplicates a driven pin or stimulus name in this simulation.`
134448
+ );
134449
+ }
134450
+ return {
134451
+ type: "simulation_digital_stimulus",
134452
+ name: props.name,
134453
+ simulation_experiment_id: experiment.simulation_experiment_id,
134454
+ source_port_id: port.source_port_id,
134455
+ bit_duration_ms: props.bitDuration,
134456
+ start_time_ms: props.startTime,
134457
+ initial_state: props.initialState,
134458
+ inverted: props.inverted,
134459
+ transmission_pattern: {
134460
+ transmission_type: props.transmittedData.transmissionType,
134461
+ bits: props.transmittedData.bits,
134462
+ repeat: props.transmittedData.repeat
134463
+ }
134464
+ };
134465
+ }
134466
+
134467
+ // lib/components/primitive-components/AnalogDigitalStimulus.ts
134468
+ var AnalogDigitalStimulus = class extends PrimitiveComponent2 {
134469
+ simulation_digital_stimulus_id = null;
134470
+ get config() {
134471
+ return {
134472
+ componentName: "AnalogDigitalStimulus",
134473
+ zodProps: analogDigitalStimulusProps
134474
+ };
134475
+ }
134476
+ doInitialSimulationRender() {
134477
+ if (this.getInheritedProperty("analogSimulationDisabled")) return;
134478
+ const stimulus = AnalogDigitalStimulus_getSimulationDigitalStimulus(this);
134479
+ if (this.simulation_digital_stimulus_id)
134480
+ this.root.db.simulation_digital_stimulus.update(
134481
+ this.simulation_digital_stimulus_id,
134482
+ stimulus
134483
+ );
134484
+ else
134485
+ this.simulation_digital_stimulus_id = this.root.db.simulation_digital_stimulus.insert(
134486
+ stimulus
134487
+ ).simulation_digital_stimulus_id;
134488
+ }
134489
+ onPropsChange() {
134490
+ this._markDirty("SimulationSpiceEngineRender");
134491
+ }
134492
+ // Refresh traffic after every experiment has updated its pin states.
134493
+ updateSimulationSpiceEngineRender() {
134494
+ this.doInitialSimulationRender();
134495
+ }
134496
+ removeSimulationRender() {
134497
+ if (this.simulation_digital_stimulus_id)
134498
+ this.root.db.simulation_digital_stimulus.delete(
134499
+ this.simulation_digital_stimulus_id
134500
+ );
134501
+ this.simulation_digital_stimulus_id = null;
134502
+ }
134503
+ };
134504
+
134505
+ // lib/components/primitive-components/AnalogEyeDiagram.ts
134506
+ import { analogEyeDiagramProps } from "@tscircuit/props";
134507
+
134508
+ // lib/components/primitive-components/AnalogEyeDiagram_getSimulationEyeDiagram.ts
134509
+ function AnalogEyeDiagram_getSimulationEyeDiagram(declaration) {
134510
+ const props = declaration._parsedProps;
134511
+ const simulation2 = resolveExternalTransientSimulation({
134512
+ declaration,
134513
+ selector: props.simulationRef
134514
+ });
134515
+ const experiment = simulation2.getOrCreateSimulationExperiment();
134516
+ const probes = declaration.getSubcircuit().selectAll(props.probeRef).filter((probe2) => probe2.componentName === "VoltageProbe");
134517
+ if (probes.length !== 1 || probes[0].getSubcircuit() !== declaration.getSubcircuit()) {
134518
+ throw new Error(
134519
+ `Eye probe selector "${props.probeRef}" must identify one voltage probe in this subcircuit.`
134520
+ );
134521
+ }
134522
+ const probe = probes[0];
134523
+ if (!probe.simulation_voltage_probe_id) {
134524
+ throw new Error(
134525
+ `Eye probe "${props.probeRef}" did not render a voltage probe.`
134526
+ );
134527
+ }
134528
+ const start = props.startTime ?? experiment.start_time_ms ?? 0, end = props.endTime ?? experiment.end_time_ms;
134529
+ const firstBoundary = (start - props.timeOrigin) / props.unitInterval + 0.5;
134530
+ const lastBoundary = (end - props.timeOrigin) / props.unitInterval - 1.5;
134531
+ const roundingTolerance = 8 * Number.EPSILON * Math.max(1, Math.abs(firstBoundary), Math.abs(lastBoundary));
134532
+ if (start < (experiment.start_time_ms ?? 0) || end > experiment.end_time_ms || end <= start || Math.ceil(firstBoundary - roundingTolerance) > Math.floor(lastBoundary + roundingTolerance)) {
134533
+ throw new Error(
134534
+ `Eye "${props.name}" needs a gate within its simulation containing at least two bit intervals forming a complete two-UI eye window aligned to timeOrigin after recording starts.`
134535
+ );
134536
+ }
134537
+ return {
134538
+ type: "simulation_eye_diagram",
134539
+ name: props.name,
134540
+ simulation_experiment_id: experiment.simulation_experiment_id,
134541
+ simulation_voltage_probe_id: probe.simulation_voltage_probe_id,
134542
+ unit_interval_ms: props.unitInterval,
134543
+ time_origin_ms: props.timeOrigin,
134544
+ start_time_ms: start,
134545
+ end_time_ms: end
134546
+ };
134547
+ }
134548
+
134549
+ // lib/components/primitive-components/AnalogEyeDiagram.ts
134550
+ var AnalogEyeDiagram = class extends PrimitiveComponent2 {
134551
+ simulation_eye_diagram_id = null;
134552
+ get config() {
134553
+ return {
134554
+ componentName: "AnalogEyeDiagram",
134555
+ zodProps: analogEyeDiagramProps
134556
+ };
134557
+ }
134558
+ // Probes have finished SimulationRender before this phase, independent of JSX order.
134559
+ doInitialSimulationSpiceEngineRender() {
134560
+ if (this.getInheritedProperty("analogSimulationDisabled")) return;
134561
+ const eye = AnalogEyeDiagram_getSimulationEyeDiagram(this);
134562
+ if (this.simulation_eye_diagram_id)
134563
+ this.root.db.simulation_eye_diagram.update(
134564
+ this.simulation_eye_diagram_id,
134565
+ eye
134566
+ );
134567
+ else
134568
+ this.simulation_eye_diagram_id = this.root.db.simulation_eye_diagram.insert(
134569
+ eye
134570
+ ).simulation_eye_diagram_id;
134571
+ }
134572
+ onPropsChange() {
134573
+ this._markDirty("SimulationSpiceEngineRender");
134574
+ }
134575
+ updateSimulationSpiceEngineRender() {
134576
+ this.doInitialSimulationSpiceEngineRender();
134577
+ }
134578
+ removeSimulationSpiceEngineRender() {
134579
+ if (this.simulation_eye_diagram_id)
134580
+ this.root.db.simulation_eye_diagram.delete(
134581
+ this.simulation_eye_diagram_id
134582
+ );
134583
+ this.simulation_eye_diagram_id = null;
134584
+ }
134585
+ };
134586
+
134587
+ // lib/components/primitive-components/IbisModel.ts
134588
+ import { ibisModelProps } from "@tscircuit/props";
134589
+
134590
+ // lib/components/primitive-components/IbisModel_getSimulationIbisModel.ts
134591
+ function IbisModel_getSimulationIbisModel(declaration) {
134592
+ const props = declaration._parsedProps;
134593
+ const chips = declaration.getSubcircuit().selectAll(props.componentRef).filter((chip2) => chip2.source_component_id);
134594
+ if (chips.length !== 1 || chips[0].getSubcircuit() !== declaration.getSubcircuit()) {
134595
+ throw new Error(
134596
+ `IBIS component selector "${props.componentRef}" must identify one component in this subcircuit.`
134597
+ );
134598
+ }
134599
+ const chip = chips[0];
134600
+ if (declaration.root.db.simulation_ibis_model.list({
134601
+ source_component_id: chip.source_component_id
134602
+ }).some(
134603
+ (model) => model.simulation_ibis_model_id !== declaration.simulation_ibis_model_id
134604
+ )) {
134605
+ throw new Error(
134606
+ `Component "${props.componentRef}" already has an IBIS model.`
134607
+ );
134608
+ }
134609
+ const pinMap = Object.fromEntries(
134610
+ Object.entries(props.ibisPinNameToPortLabel).map(([pin, label]) => [
134611
+ pin,
134612
+ resolveExternalSimulationPort({
134613
+ declaration,
134614
+ selector: `${props.componentRef} > .${label}`
134615
+ }).source_port_id
134616
+ ])
134617
+ );
134618
+ const ibisPinNameBySourcePortId = /* @__PURE__ */ new Map();
134619
+ for (const [pin, sourcePortId] of Object.entries(pinMap)) {
134620
+ const previousPin = ibisPinNameBySourcePortId.get(sourcePortId);
134621
+ if (previousPin !== void 0) {
134622
+ throw new Error(
134623
+ `IBIS pins "${previousPin}" and "${pin}" on "${props.componentRef}" resolve to the same physical pin.`
134624
+ );
134625
+ }
134626
+ ibisPinNameBySourcePortId.set(sourcePortId, pin);
134627
+ }
134628
+ for (const pin of [
134629
+ ...Object.keys(props.ibisPinNameToReferencePortLabels ?? {}),
134630
+ ...Object.keys(props.ibisPinNameToModelName ?? {})
134631
+ ]) {
134632
+ if (!Object.hasOwn(props.ibisPinNameToPortLabel, pin)) {
134633
+ throw new Error(
134634
+ `IBIS pin "${pin}" is referenced but not present in ibisPinNameToPortLabel.`
134635
+ );
134636
+ }
134637
+ }
134638
+ let references;
134639
+ if (props.ibisPinNameToReferencePortLabels) {
134640
+ references = {};
134641
+ for (const [pin, pinReferences] of Object.entries(
134642
+ props.ibisPinNameToReferencePortLabels
134643
+ )) {
134644
+ references[pin] = {};
134645
+ for (const [role, sourcePortIdField] of [
134646
+ ["pullup", "pullup_reference_source_port_id"],
134647
+ ["pulldown", "pulldown_reference_source_port_id"],
134648
+ ["powerClamp", "power_clamp_reference_source_port_id"],
134649
+ ["groundClamp", "ground_clamp_reference_source_port_id"],
134650
+ ["external", "external_reference_source_port_id"]
134651
+ ]) {
134652
+ const label = pinReferences[role];
134653
+ if (label === void 0) continue;
134654
+ references[pin][sourcePortIdField] = resolveExternalSimulationPort({
134655
+ declaration,
134656
+ selector: `${props.componentRef} > .${label}`
134657
+ }).source_port_id;
134658
+ }
134659
+ }
134660
+ }
134661
+ return {
134662
+ type: "simulation_ibis_model",
134663
+ source_component_id: chip.source_component_id,
134664
+ ibis_model_asset: props.ibisModelAsset,
134665
+ ibis_component_name: props.ibisComponentName,
134666
+ model_value_corner: props.modelValueCorner,
134667
+ include_package_parasitics: props.includePackageParasitics,
134668
+ ibis_pin_name_to_model_name: props.ibisPinNameToModelName,
134669
+ ibis_pin_name_to_source_port_id: pinMap,
134670
+ ibis_pin_name_to_reference_source_port_ids: references
134671
+ };
134672
+ }
134673
+
134674
+ // lib/components/primitive-components/IbisModel.ts
134675
+ var IbisModel = class extends PrimitiveComponent2 {
134676
+ simulation_ibis_model_id = null;
134677
+ get config() {
134678
+ return { componentName: "IbisModel", zodProps: ibisModelProps };
134679
+ }
134680
+ onPropsChange() {
134681
+ this._markDirty("SimulationRender");
134682
+ }
134683
+ markIbisBindingsDirty() {
134684
+ const subcircuit = this.getSubcircuit();
134685
+ for (const simulation2 of subcircuit.selectAll(
134686
+ "analogtransientsimulation"
134687
+ )) {
134688
+ if (simulation2.getSubcircuit() === subcircuit)
134689
+ simulation2._markDirty("SimulationSpiceEngineRender");
134690
+ }
134691
+ }
134692
+ doInitialSimulationRender() {
134693
+ if (this.getInheritedProperty("analogSimulationDisabled")) return;
134694
+ const model = IbisModel_getSimulationIbisModel(this);
134695
+ if (this.simulation_ibis_model_id)
134696
+ this.root.db.simulation_ibis_model.update(
134697
+ this.simulation_ibis_model_id,
134698
+ model
134699
+ );
134700
+ else
134701
+ this.simulation_ibis_model_id = this.root.db.simulation_ibis_model.insert(
134702
+ model
134703
+ ).simulation_ibis_model_id;
134704
+ this.markIbisBindingsDirty();
134705
+ }
134706
+ updateSimulationRender() {
134707
+ this.doInitialSimulationRender();
134708
+ }
134709
+ removeSimulationRender() {
134710
+ if (this.simulation_ibis_model_id)
134711
+ this.root.db.simulation_ibis_model.delete(this.simulation_ibis_model_id);
134712
+ this.simulation_ibis_model_id = null;
134713
+ this.markIbisBindingsDirty();
134117
134714
  }
134118
134715
  };
134119
134716
 
@@ -136049,6 +136646,10 @@ var createNamespacedElement = (hostType) => {
136049
136646
 
136050
136647
  // lib/namespaced-elements/analog.ts
136051
136648
  var analog = {
136649
+ digitalstimulus: createNamespacedElement(
136650
+ "analogdigitalstimulus"
136651
+ ),
136652
+ eyediagram: createNamespacedElement("analogeyediagram"),
136052
136653
  transientsimulation: createNamespacedElement(
136053
136654
  "analogtransientsimulation"
136054
136655
  ),
@@ -136358,6 +136959,8 @@ export {
136358
136959
  AnalogAnalysisSimulation,
136359
136960
  AnalogDcOperatingPointSimulation,
136360
136961
  AnalogDcSweepSimulation,
136962
+ AnalogDigitalStimulus,
136963
+ AnalogEyeDiagram,
136361
136964
  AnalogSimulation,
136362
136965
  AnalogSweepParameter,
136363
136966
  AnalogTransientSimulation,
@@ -136407,6 +137010,7 @@ export {
136407
137010
  Fuse,
136408
137011
  Group5 as Group,
136409
137012
  Hole,
137013
+ IbisModel,
136410
137014
  Inductor,
136411
137015
  Interconnect,
136412
137016
  IsolatedCircuit,