@celox-sim/celox 0.1.6 → 0.1.7

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/src/e2e.test.ts CHANGED
@@ -97,117 +97,152 @@ module Mux4 (
97
97
  describe("E2E: Simulator.fromSource (event-based)", () => {
98
98
  test("combinational adder: a + b = sum", () => {
99
99
  interface AdderPorts {
100
- rst: number;
101
- a: number;
102
- b: number;
103
- readonly sum: number;
100
+ rst: bigint;
101
+ a: bigint;
102
+ b: bigint;
103
+ readonly sum: bigint;
104
104
  }
105
105
 
106
106
  const sim = Simulator.fromSource<AdderPorts>(ADDER_SOURCE, "Adder");
107
107
 
108
- sim.dut.a = 100;
109
- sim.dut.b = 200;
108
+ sim.dut.a = 100n;
109
+ sim.dut.b = 200n;
110
110
  sim.tick();
111
- expect(sim.dut.sum).toBe(300);
111
+ expect(sim.dut.sum).toBe(300n);
112
112
 
113
- sim.dut.a = 0xFFFF;
114
- sim.dut.b = 1;
113
+ sim.dut.a = 0xFFFFn;
114
+ sim.dut.b = 1n;
115
115
  sim.tick();
116
- expect(sim.dut.sum).toBe(0x10000);
116
+ expect(sim.dut.sum).toBe(0x10000n);
117
117
 
118
- sim.dut.a = 0;
119
- sim.dut.b = 0;
118
+ sim.dut.a = 0n;
119
+ sim.dut.b = 0n;
120
120
  sim.tick();
121
- expect(sim.dut.sum).toBe(0);
121
+ expect(sim.dut.sum).toBe(0n);
122
122
 
123
123
  sim.dispose();
124
124
  });
125
125
 
126
126
  test("combinational adder: lazy evalComb on output read", () => {
127
127
  interface AdderPorts {
128
- rst: number;
129
- a: number;
130
- b: number;
131
- readonly sum: number;
128
+ rst: bigint;
129
+ a: bigint;
130
+ b: bigint;
131
+ readonly sum: bigint;
132
132
  }
133
133
 
134
134
  const sim = Simulator.fromSource<AdderPorts>(ADDER_SOURCE, "Adder");
135
135
 
136
- sim.dut.a = 42;
137
- sim.dut.b = 58;
138
- expect(sim.dut.sum).toBe(100);
136
+ sim.dut.a = 42n;
137
+ sim.dut.b = 58n;
138
+ expect(sim.dut.sum).toBe(100n);
139
139
 
140
140
  sim.dispose();
141
141
  });
142
142
 
143
143
  test("sequential counter: counts on clock edges", () => {
144
144
  interface CounterPorts {
145
- rst: number;
146
- en: number;
147
- readonly count: number;
145
+ rst: bigint;
146
+ en: bigint;
147
+ readonly count: bigint;
148
148
  }
149
149
 
150
150
  const sim = Simulator.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter");
151
151
 
152
152
  // Reset the counter (default async_low: rst=0 is active)
153
- sim.dut.rst = 0;
153
+ sim.dut.rst = 0n;
154
154
  sim.tick();
155
- sim.dut.rst = 1;
155
+ sim.dut.rst = 1n;
156
156
  sim.tick();
157
- expect(sim.dut.count).toBe(0);
157
+ expect(sim.dut.count).toBe(0n);
158
158
 
159
159
  // Enable counting
160
- sim.dut.en = 1;
160
+ sim.dut.en = 1n;
161
161
  sim.tick();
162
- expect(sim.dut.count).toBe(1);
162
+ expect(sim.dut.count).toBe(1n);
163
163
 
164
164
  sim.tick();
165
- expect(sim.dut.count).toBe(2);
165
+ expect(sim.dut.count).toBe(2n);
166
166
 
167
167
  sim.tick();
168
- expect(sim.dut.count).toBe(3);
168
+ expect(sim.dut.count).toBe(3n);
169
169
 
170
170
  // Disable counting
171
- sim.dut.en = 0;
171
+ sim.dut.en = 0n;
172
172
  sim.tick();
173
- expect(sim.dut.count).toBe(3);
173
+ expect(sim.dut.count).toBe(3n);
174
174
 
175
175
  // Re-enable
176
- sim.dut.en = 1;
176
+ sim.dut.en = 1n;
177
177
  sim.tick(5);
178
- expect(sim.dut.count).toBe(8);
178
+ expect(sim.dut.count).toBe(8n);
179
+
180
+ sim.dispose();
181
+ });
182
+
183
+ test("always_comb evaluated before FF on tick (no prior output read)", () => {
184
+ interface CounterPorts {
185
+ rst: number;
186
+ en: number;
187
+ readonly count: number;
188
+ }
189
+
190
+ const sim = Simulator.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter");
191
+
192
+ // Reset (default async_low: rst=0 is active)
193
+ sim.dut.rst = 0;
194
+ sim.tick();
195
+ sim.dut.rst = 1;
196
+ sim.tick();
197
+
198
+ // Write input and tick WITHOUT reading any output first.
199
+ // This catches the stale-comb bug where always_ff reads stale
200
+ // combinational values because eval_comb was skipped before FF.
201
+ sim.dut.en = 1;
202
+ sim.tick();
203
+ expect(Number(sim.dut.count)).toBe(1);
204
+
205
+ // Again: set input, tick, verify — no intermediate reads
206
+ sim.dut.en = 1;
207
+ sim.tick();
208
+ expect(Number(sim.dut.count)).toBe(2);
209
+
210
+ // Disable, tick, verify
211
+ sim.dut.en = 0;
212
+ sim.tick();
213
+ expect(Number(sim.dut.count)).toBe(2);
179
214
 
180
215
  sim.dispose();
181
216
  });
182
217
 
183
218
  test("combinational multiplexer", () => {
184
219
  interface Mux4Ports {
185
- sel: number;
186
- d0: number;
187
- d1: number;
188
- d2: number;
189
- d3: number;
190
- readonly y: number;
220
+ sel: bigint;
221
+ d0: bigint;
222
+ d1: bigint;
223
+ d2: bigint;
224
+ d3: bigint;
225
+ readonly y: bigint;
191
226
  }
192
227
 
193
228
  const sim = Simulator.fromSource<Mux4Ports>(MULTIPLEXER_SOURCE, "Mux4");
194
229
 
195
- sim.dut.d0 = 0xAA;
196
- sim.dut.d1 = 0xBB;
197
- sim.dut.d2 = 0xCC;
198
- sim.dut.d3 = 0xDD;
230
+ sim.dut.d0 = 0xAAn;
231
+ sim.dut.d1 = 0xBBn;
232
+ sim.dut.d2 = 0xCCn;
233
+ sim.dut.d3 = 0xDDn;
199
234
 
200
- sim.dut.sel = 0;
201
- expect(sim.dut.y).toBe(0xAA);
235
+ sim.dut.sel = 0n;
236
+ expect(sim.dut.y).toBe(0xAAn);
202
237
 
203
- sim.dut.sel = 1;
204
- expect(sim.dut.y).toBe(0xBB);
238
+ sim.dut.sel = 1n;
239
+ expect(sim.dut.y).toBe(0xBBn);
205
240
 
206
- sim.dut.sel = 2;
207
- expect(sim.dut.y).toBe(0xCC);
241
+ sim.dut.sel = 2n;
242
+ expect(sim.dut.y).toBe(0xCCn);
208
243
 
209
- sim.dut.sel = 3;
210
- expect(sim.dut.y).toBe(0xDD);
244
+ sim.dut.sel = 3n;
245
+ expect(sim.dut.y).toBe(0xDDn);
211
246
 
212
247
  sim.dispose();
213
248
  });
@@ -220,9 +255,9 @@ describe("E2E: Simulator.fromSource (event-based)", () => {
220
255
  describe("E2E: Simulation.fromSource (time-based)", () => {
221
256
  test("counter with timed clock: step-by-step", () => {
222
257
  interface CounterPorts {
223
- rst: number;
224
- en: number;
225
- readonly count: number;
258
+ rst: bigint;
259
+ en: bigint;
260
+ readonly count: bigint;
226
261
  }
227
262
 
228
263
  const sim = Simulation.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter");
@@ -231,15 +266,15 @@ describe("E2E: Simulation.fromSource (time-based)", () => {
231
266
  expect(sim.time()).toBe(0);
232
267
 
233
268
  // Reset (default async_low: rst=0 is active)
234
- sim.dut.rst = 0;
269
+ sim.dut.rst = 0n;
235
270
  sim.runUntil(20);
236
- sim.dut.rst = 1;
237
- sim.dut.en = 1;
271
+ sim.dut.rst = 1n;
272
+ sim.dut.en = 1n;
238
273
 
239
274
  sim.runUntil(100);
240
275
 
241
276
  const count = sim.dut.count;
242
- expect(count).toBeGreaterThan(0);
277
+ expect(count).toBeGreaterThan(0n);
243
278
  expect(sim.time()).toBe(100);
244
279
 
245
280
  sim.dispose();
@@ -253,53 +288,53 @@ describe("E2E: Simulation.fromSource (time-based)", () => {
253
288
  describe("E2E: Simulator.fromProject (event-based)", () => {
254
289
  test("combinational adder from project directory", () => {
255
290
  interface AdderPorts {
256
- rst: number;
257
- a: number;
258
- b: number;
259
- readonly sum: number;
291
+ rst: bigint;
292
+ a: bigint;
293
+ b: bigint;
294
+ readonly sum: bigint;
260
295
  }
261
296
 
262
297
  const sim = Simulator.fromProject<AdderPorts>(ADDER_PROJECT, "Adder");
263
298
 
264
- sim.dut.a = 100;
265
- sim.dut.b = 200;
299
+ sim.dut.a = 100n;
300
+ sim.dut.b = 200n;
266
301
  sim.tick();
267
- expect(sim.dut.sum).toBe(300);
302
+ expect(sim.dut.sum).toBe(300n);
268
303
 
269
- sim.dut.a = 0xFFFF;
270
- sim.dut.b = 1;
304
+ sim.dut.a = 0xFFFFn;
305
+ sim.dut.b = 1n;
271
306
  sim.tick();
272
- expect(sim.dut.sum).toBe(0x10000);
307
+ expect(sim.dut.sum).toBe(0x10000n);
273
308
 
274
309
  sim.dispose();
275
310
  });
276
311
 
277
312
  test("sequential counter from project directory", () => {
278
313
  interface CounterPorts {
279
- rst: number;
280
- en: number;
281
- readonly count: number;
314
+ rst: bigint;
315
+ en: bigint;
316
+ readonly count: bigint;
282
317
  }
283
318
 
284
319
  const sim = Simulator.fromProject<CounterPorts>(COUNTER_PROJECT, "Counter");
285
320
 
286
321
  // Reset the counter (default async_low: rst=0 is active)
287
- sim.dut.rst = 0;
322
+ sim.dut.rst = 0n;
288
323
  sim.tick();
289
- sim.dut.rst = 1;
324
+ sim.dut.rst = 1n;
290
325
  sim.tick();
291
- expect(sim.dut.count).toBe(0);
326
+ expect(sim.dut.count).toBe(0n);
292
327
 
293
328
  // Enable counting
294
- sim.dut.en = 1;
329
+ sim.dut.en = 1n;
295
330
  sim.tick();
296
- expect(sim.dut.count).toBe(1);
331
+ expect(sim.dut.count).toBe(1n);
297
332
 
298
333
  sim.tick();
299
- expect(sim.dut.count).toBe(2);
334
+ expect(sim.dut.count).toBe(2n);
300
335
 
301
336
  sim.tick();
302
- expect(sim.dut.count).toBe(3);
337
+ expect(sim.dut.count).toBe(3n);
303
338
 
304
339
  sim.dispose();
305
340
  });
@@ -312,9 +347,9 @@ describe("E2E: Simulator.fromProject (event-based)", () => {
312
347
  describe("E2E: Simulation.fromProject (time-based)", () => {
313
348
  test("counter with timed clock from project directory", () => {
314
349
  interface CounterPorts {
315
- rst: number;
316
- en: number;
317
- readonly count: number;
350
+ rst: bigint;
351
+ en: bigint;
352
+ readonly count: bigint;
318
353
  }
319
354
 
320
355
  const sim = Simulation.fromProject<CounterPorts>(COUNTER_PROJECT, "Counter");
@@ -323,15 +358,15 @@ describe("E2E: Simulation.fromProject (time-based)", () => {
323
358
  expect(sim.time()).toBe(0);
324
359
 
325
360
  // Reset (default async_low: rst=0 is active)
326
- sim.dut.rst = 0;
361
+ sim.dut.rst = 0n;
327
362
  sim.runUntil(20);
328
- sim.dut.rst = 1;
329
- sim.dut.en = 1;
363
+ sim.dut.rst = 1n;
364
+ sim.dut.en = 1n;
330
365
 
331
366
  sim.runUntil(100);
332
367
 
333
368
  const count = sim.dut.count;
334
- expect(count).toBeGreaterThan(0);
369
+ expect(count).toBeGreaterThan(0n);
335
370
  expect(sim.time()).toBe(100);
336
371
 
337
372
  sim.dispose();
@@ -345,10 +380,10 @@ describe("E2E: Simulation.fromProject (time-based)", () => {
345
380
  describe("E2E: Simulator.create (backward compat)", () => {
346
381
  test("combinational adder via Simulator.create()", () => {
347
382
  interface AdderPorts {
348
- rst: number;
349
- a: number;
350
- b: number;
351
- readonly sum: number;
383
+ rst: bigint;
384
+ a: bigint;
385
+ b: bigint;
386
+ readonly sum: bigint;
352
387
  }
353
388
 
354
389
  const addon = loadNativeAddon();
@@ -371,10 +406,10 @@ describe("E2E: Simulator.create (backward compat)", () => {
371
406
  { __nativeCreate: nativeCreateSimulator },
372
407
  );
373
408
 
374
- sim.dut.a = 100;
375
- sim.dut.b = 200;
409
+ sim.dut.a = 100n;
410
+ sim.dut.b = 200n;
376
411
  sim.tick();
377
- expect(sim.dut.sum).toBe(300);
412
+ expect(sim.dut.sum).toBe(300n);
378
413
 
379
414
  sim.dispose();
380
415
  });
@@ -463,8 +498,8 @@ module InitTest (
463
498
 
464
499
  // logic port should have mask=0xFF (all X)
465
500
  const [valA, maskA] = readFourState(buf, layout.forDut.a);
466
- expect(valA).toBe(0);
467
- expect(maskA).toBe(0xFF);
501
+ expect(valA).toBe(0n);
502
+ expect(maskA).toBe(0xFFn);
468
503
 
469
504
  // bit port should have mask=0 (defined)
470
505
  // bit is not 4-state, so no mask — reading its value should be 0
@@ -473,8 +508,8 @@ module InitTest (
473
508
 
474
509
  test("writing X clears value and sets mask", () => {
475
510
  interface Ports {
476
- a: number;
477
- readonly y_and: number;
511
+ a: bigint;
512
+ readonly y_and: bigint;
478
513
  }
479
514
 
480
515
  const sim = Simulator.fromSource<Ports>(AND_OR_SOURCE, "AndOr", { fourState: true });
@@ -513,13 +548,13 @@ module InitTest (
513
548
 
514
549
  // 0 & X = 0 (mask should be 0 — dominant zero)
515
550
  const [vAnd, mAnd] = readFourState(buf, sigYAnd);
516
- expect(vAnd).toBe(0);
517
- expect(mAnd).toBe(0);
551
+ expect(vAnd).toBe(0n);
552
+ expect(mAnd).toBe(0n);
518
553
 
519
554
  // 0 | X = X (mask should be 1)
520
555
  const [vOr, mOr] = readFourState(buf, sigYOr);
521
- expect(vOr).toBe(0);
522
- expect(mOr).toBe(1);
556
+ expect(vOr).toBe(0n);
557
+ expect(mOr).toBe(1n);
523
558
  });
524
559
 
525
560
  test("OR: 1 | X = 1 (dominant one)", () => {
@@ -544,8 +579,8 @@ module InitTest (
544
579
 
545
580
  // 1 | X = 1 (mask should be 0 — dominant one)
546
581
  const [vOr, mOr] = readFourState(buf, sigYOr);
547
- expect(vOr).toBe(1);
548
- expect(mOr).toBe(0);
582
+ expect(vOr).toBe(1n);
583
+ expect(mOr).toBe(0n);
549
584
  });
550
585
 
551
586
  test("logic-to-bit assignment strips X mask", () => {
@@ -583,8 +618,8 @@ module InitTest (
583
618
 
584
619
  // y_logic_from_bit should be 0xAA with mask=0
585
620
  const [vLogic, mLogic] = readFourState(buf, sigYLogicFromBit);
586
- expect(vLogic).toBe(0xAA);
587
- expect(mLogic).toBe(0);
621
+ expect(vLogic).toBe(0xAAn);
622
+ expect(mLogic).toBe(0n);
588
623
  });
589
624
 
590
625
  test("arithmetic with X produces all-X output", () => {
@@ -608,7 +643,7 @@ module InitTest (
608
643
 
609
644
  // a + X = all-X
610
645
  const [, mY] = readFourState(buf, sigY);
611
- expect(mY).toBe(0xFF);
646
+ expect(mY).toBe(0xFFn);
612
647
  });
613
648
 
614
649
  test("defined inputs in 4-state mode behave like 2-state", () => {
@@ -631,8 +666,8 @@ module InitTest (
631
666
  raw.evalComb();
632
667
 
633
668
  const [vY, mY] = readFourState(buf, sigY);
634
- expect(vY).toBe(155);
635
- expect(mY).toBe(0);
669
+ expect(vY).toBe(155n);
670
+ expect(mY).toBe(0n);
636
671
  });
637
672
 
638
673
  test("FF captures X from input, reset clears X", () => {
@@ -658,8 +693,8 @@ module InitTest (
658
693
 
659
694
  // After reset, q should be 0 with mask=0
660
695
  const [vQ1, mQ1] = readFourState(buf, sigQ);
661
- expect(vQ1).toBe(0);
662
- expect(mQ1).toBe(0);
696
+ expect(vQ1).toBe(0n);
697
+ expect(mQ1).toBe(0n);
663
698
 
664
699
  // 2. Release reset (rst=1 is inactive), d = partial X (value=0xA5, mask=0x0F)
665
700
  view.setUint8(sigRst.offset, 1);
@@ -672,7 +707,7 @@ module InitTest (
672
707
 
673
708
  // FF should capture X mask from d
674
709
  const [, mQ2] = readFourState(buf, sigQ);
675
- expect(mQ2).toBe(0x0F);
710
+ expect(mQ2).toBe(0x0Fn);
676
711
 
677
712
  // 3. Assert reset again (rst=0): should clear X
678
713
  view.setUint8(sigRst.offset, 0);
@@ -681,8 +716,8 @@ module InitTest (
681
716
  raw.tick(clkEventId);
682
717
 
683
718
  const [vQ3, mQ3] = readFourState(buf, sigQ);
684
- expect(vQ3).toBe(0);
685
- expect(mQ3).toBe(0);
719
+ expect(vQ3).toBe(0n);
720
+ expect(mQ3).toBe(0n);
686
721
  });
687
722
 
688
723
  test("FourState write through DUT sets value and mask", () => {
@@ -699,8 +734,8 @@ module InitTest (
699
734
  view.setUint8(sigA.offset + sigA.byteSize, 0x0F);
700
735
 
701
736
  const [vA, mA] = readFourState(buf, sigA);
702
- expect(vA).toBe(0xA5);
703
- expect(mA).toBe(0x0F);
737
+ expect(vA).toBe(0xA5n);
738
+ expect(mA).toBe(0x0Fn);
704
739
  });
705
740
 
706
741
  test("setting defined value clears X mask", () => {
@@ -716,42 +751,42 @@ module InitTest (
716
751
  view.setUint8(sigA.offset + sigA.byteSize, 0xFF);
717
752
 
718
753
  const [, mBefore] = readFourState(buf, sigA);
719
- expect(mBefore).toBe(0xFF);
754
+ expect(mBefore).toBe(0xFFn);
720
755
 
721
756
  // Write a defined value (clear mask)
722
757
  view.setUint8(sigA.offset, 42);
723
758
  view.setUint8(sigA.offset + sigA.byteSize, 0);
724
759
 
725
760
  const [vAfter, mAfter] = readFourState(buf, sigA);
726
- expect(vAfter).toBe(42);
727
- expect(mAfter).toBe(0);
761
+ expect(vAfter).toBe(42n);
762
+ expect(mAfter).toBe(0n);
728
763
  });
729
764
 
730
765
  test("4-state through DUT high-level API (fromSource with fourState)", () => {
731
766
  interface Ports {
732
- a: number;
733
- b: number;
734
- readonly y: number;
767
+ a: bigint;
768
+ b: bigint;
769
+ readonly y: bigint;
735
770
  }
736
771
 
737
772
  const sim = Simulator.fromSource<Ports>(ADDER_4STATE_SOURCE, "Adder4S", { fourState: true });
738
773
 
739
774
  // Write defined values — should behave like 2-state
740
- sim.dut.a = 100;
741
- sim.dut.b = 55;
742
- expect(sim.dut.y).toBe(155);
775
+ sim.dut.a = 100n;
776
+ sim.dut.b = 55n;
777
+ expect(sim.dut.y).toBe(155n);
743
778
 
744
779
  // Write X to a — output should propagate X (value reads as 0)
745
780
  (sim.dut as any).a = X;
746
781
  // After writing X, the value part of 'y' is implementation-defined
747
782
  // but the read should not throw
748
783
  const _yVal = sim.dut.y;
749
- expect(typeof _yVal).toBe("number");
784
+ expect(typeof _yVal).toBe("bigint");
750
785
 
751
786
  // Write FourState with partial X
752
787
  (sim.dut as any).a = FourState(0xA0, 0x0F);
753
788
  const _yVal2 = sim.dut.y;
754
- expect(typeof _yVal2).toBe("number");
789
+ expect(typeof _yVal2).toBe("bigint");
755
790
 
756
791
  sim.dispose();
757
792
  });
@@ -764,9 +799,9 @@ module InitTest (
764
799
  describe("E2E: 4-state high-level DUT API", () => {
765
800
  test("counter in 4-state mode: reset clears X, counting works", () => {
766
801
  interface CounterPorts {
767
- rst: number;
768
- en: number;
769
- readonly count: number;
802
+ rst: bigint;
803
+ en: bigint;
804
+ readonly count: bigint;
770
805
  }
771
806
 
772
807
  const sim = Simulator.fromSource<CounterPorts>(
@@ -775,22 +810,22 @@ describe("E2E: 4-state high-level DUT API", () => {
775
810
 
776
811
  // In 4-state mode, count starts as X. Reset should clear it.
777
812
  // (default async_low: rst=0 is active)
778
- sim.dut.rst = 0;
813
+ sim.dut.rst = 0n;
779
814
  sim.tick();
780
- sim.dut.rst = 1;
815
+ sim.dut.rst = 1n;
781
816
  sim.tick();
782
- expect(sim.dut.count).toBe(0);
817
+ expect(sim.dut.count).toBe(0n);
783
818
 
784
819
  // Enable counting — should work exactly like 2-state
785
- sim.dut.en = 1;
820
+ sim.dut.en = 1n;
786
821
  sim.tick();
787
- expect(sim.dut.count).toBe(1);
822
+ expect(sim.dut.count).toBe(1n);
788
823
 
789
824
  sim.tick();
790
- expect(sim.dut.count).toBe(2);
825
+ expect(sim.dut.count).toBe(2n);
791
826
 
792
827
  sim.tick();
793
- expect(sim.dut.count).toBe(3);
828
+ expect(sim.dut.count).toBe(3n);
794
829
 
795
830
  sim.dispose();
796
831
  });
@@ -817,64 +852,64 @@ describe("E2E: 4-state high-level DUT API", () => {
817
852
  raw.evalComb();
818
853
 
819
854
  // With X selector, output should be all-X
820
- const [, mY] = readFourState(buf, sigY);
821
- expect(mY).toBe(0xFF);
855
+ const [, mY2] = readFourState(buf, sigY);
856
+ expect(mY2).toBe(0xFFn);
822
857
 
823
858
  raw.dispose();
824
859
  });
825
860
 
826
861
  test("FF via DUT API: write X input, tick, read output", () => {
827
862
  interface FFPorts {
828
- rst: number;
829
- d: number;
830
- readonly q: number;
863
+ rst: bigint;
864
+ d: bigint;
865
+ readonly q: bigint;
831
866
  }
832
867
 
833
868
  const sim = Simulator.fromSource<FFPorts>(FF_SOURCE, "FF", { fourState: true });
834
869
 
835
870
  // Reset to clear initial X (default async_low: rst=0 is active)
836
- sim.dut.rst = 0;
871
+ sim.dut.rst = 0n;
837
872
  sim.tick();
838
- sim.dut.rst = 1;
839
- expect(sim.dut.q).toBe(0);
873
+ sim.dut.rst = 1n;
874
+ expect(sim.dut.q).toBe(0n);
840
875
 
841
876
  // Write a defined value
842
- sim.dut.d = 0x42;
877
+ sim.dut.d = 0x42n;
843
878
  sim.tick();
844
- expect(sim.dut.q).toBe(0x42);
879
+ expect(sim.dut.q).toBe(0x42n);
845
880
 
846
- // Write X to d, tick — q should capture it (value read still returns a number)
881
+ // Write X to d, tick — q should capture it (value read still returns a bigint)
847
882
  (sim.dut as any).d = X;
848
883
  sim.tick();
849
- expect(typeof sim.dut.q).toBe("number");
884
+ expect(typeof sim.dut.q).toBe("bigint");
850
885
 
851
886
  // Write defined value again — q should recover
852
- sim.dut.d = 0x99;
887
+ sim.dut.d = 0x99n;
853
888
  sim.tick();
854
- expect(sim.dut.q).toBe(0x99);
889
+ expect(sim.dut.q).toBe(0x99n);
855
890
 
856
891
  sim.dispose();
857
892
  });
858
893
 
859
894
  test("X to defined transition: adder recovers from X", () => {
860
895
  interface Ports {
861
- a: number;
862
- b: number;
863
- readonly y: number;
896
+ a: bigint;
897
+ b: bigint;
898
+ readonly y: bigint;
864
899
  }
865
900
 
866
901
  const sim = Simulator.fromSource<Ports>(ADDER_4STATE_SOURCE, "Adder4S", { fourState: true });
867
902
 
868
903
  // Start with X
869
904
  (sim.dut as any).a = X;
870
- sim.dut.b = 10;
905
+ sim.dut.b = 10n;
871
906
  // Output has X — just verify it doesn't crash
872
- expect(typeof sim.dut.y).toBe("number");
907
+ expect(typeof sim.dut.y).toBe("bigint");
873
908
 
874
909
  // Clear X by writing defined values
875
- sim.dut.a = 20;
876
- sim.dut.b = 30;
877
- expect(sim.dut.y).toBe(50);
910
+ sim.dut.a = 20n;
911
+ sim.dut.b = 30n;
912
+ expect(sim.dut.y).toBe(50n);
878
913
 
879
914
  sim.dispose();
880
915
  });
@@ -887,9 +922,9 @@ describe("E2E: 4-state high-level DUT API", () => {
887
922
  describe("E2E: 4-state Simulation (time-based)", () => {
888
923
  test("FF with clock-driven 4-state: reset clears X, captures defined values", () => {
889
924
  interface FFPorts {
890
- rst: number;
891
- d: number;
892
- readonly q: number;
925
+ rst: bigint;
926
+ d: bigint;
927
+ readonly q: bigint;
893
928
  }
894
929
 
895
930
  const sim = Simulation.fromSource<FFPorts>(FF_SOURCE, "FF", { fourState: true });
@@ -898,29 +933,29 @@ describe("E2E: 4-state Simulation (time-based)", () => {
898
933
  expect(sim.time()).toBe(0);
899
934
 
900
935
  // Reset to clear initial X on q (default async_low: rst=0 is active)
901
- sim.dut.rst = 0;
936
+ sim.dut.rst = 0n;
902
937
  sim.runUntil(20);
903
- sim.dut.rst = 1;
904
- expect(sim.dut.q).toBe(0);
938
+ sim.dut.rst = 1n;
939
+ expect(sim.dut.q).toBe(0n);
905
940
 
906
941
  // Drive d with defined value
907
- sim.dut.d = 0x55;
942
+ sim.dut.d = 0x55n;
908
943
  sim.runUntil(40);
909
- expect(sim.dut.q).toBe(0x55);
944
+ expect(sim.dut.q).toBe(0x55n);
910
945
 
911
946
  // Drive d with different value
912
- sim.dut.d = 0xAA;
947
+ sim.dut.d = 0xAAn;
913
948
  sim.runUntil(60);
914
- expect(sim.dut.q).toBe(0xAA);
949
+ expect(sim.dut.q).toBe(0xAAn);
915
950
 
916
951
  sim.dispose();
917
952
  });
918
953
 
919
954
  test("counter in 4-state time-based mode", () => {
920
955
  interface CounterPorts {
921
- rst: number;
922
- en: number;
923
- readonly count: number;
956
+ rst: bigint;
957
+ en: bigint;
958
+ readonly count: bigint;
924
959
  }
925
960
 
926
961
  const sim = Simulation.fromSource<CounterPorts>(
@@ -930,15 +965,15 @@ describe("E2E: 4-state Simulation (time-based)", () => {
930
965
  sim.addClock("clk", { period: 10 });
931
966
 
932
967
  // Reset (default async_low: rst=0 is active)
933
- sim.dut.rst = 0;
968
+ sim.dut.rst = 0n;
934
969
  sim.runUntil(20);
935
- sim.dut.rst = 1;
936
- sim.dut.en = 1;
970
+ sim.dut.rst = 1n;
971
+ sim.dut.en = 1n;
937
972
 
938
973
  sim.runUntil(100);
939
974
 
940
975
  const count = sim.dut.count;
941
- expect(count).toBeGreaterThan(0);
976
+ expect(count).toBeGreaterThan(0n);
942
977
  expect(sim.time()).toBe(100);
943
978
 
944
979
  sim.dispose();
@@ -946,9 +981,9 @@ describe("E2E: 4-state Simulation (time-based)", () => {
946
981
 
947
982
  test("4-state combinational in time-based simulation", () => {
948
983
  interface Ports {
949
- a: number;
950
- b: number;
951
- readonly y: number;
984
+ a: bigint;
985
+ b: bigint;
986
+ readonly y: bigint;
952
987
  }
953
988
 
954
989
  const sim = Simulation.fromSource<Ports>(
@@ -956,11 +991,11 @@ describe("E2E: 4-state Simulation (time-based)", () => {
956
991
  );
957
992
 
958
993
  // No clock needed for pure combinational — just set values and read
959
- sim.dut.a = 100;
960
- sim.dut.b = 55;
994
+ sim.dut.a = 100n;
995
+ sim.dut.b = 55n;
961
996
  // runUntil(0) to force eval
962
997
  sim.runUntil(0);
963
- expect(sim.dut.y).toBe(155);
998
+ expect(sim.dut.y).toBe(155n);
964
999
 
965
1000
  sim.dispose();
966
1001
  });
@@ -973,19 +1008,19 @@ describe("E2E: 4-state Simulation (time-based)", () => {
973
1008
  describe("E2E: Simulation testbench helpers", () => {
974
1009
  test("waitForCycles: advances correct number of clock cycles", () => {
975
1010
  interface CounterPorts {
976
- rst: number;
977
- en: number;
978
- readonly count: number;
1011
+ rst: bigint;
1012
+ en: bigint;
1013
+ readonly count: bigint;
979
1014
  }
980
1015
 
981
1016
  const sim = Simulation.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter");
982
1017
  sim.addClock("clk", { period: 10 });
983
1018
 
984
1019
  // Reset (default async_low: rst=0 is active)
985
- sim.dut.rst = 0;
1020
+ sim.dut.rst = 0n;
986
1021
  sim.runUntil(20);
987
- sim.dut.rst = 1;
988
- sim.dut.en = 1;
1022
+ sim.dut.rst = 1n;
1023
+ sim.dut.en = 1n;
989
1024
 
990
1025
  const beforeTime = sim.time();
991
1026
  const afterTime = sim.waitForCycles("clk", 5);
@@ -999,22 +1034,22 @@ describe("E2E: Simulation testbench helpers", () => {
999
1034
 
1000
1035
  test("waitUntil: waits for condition to be met", () => {
1001
1036
  interface CounterPorts {
1002
- rst: number;
1003
- en: number;
1004
- readonly count: number;
1037
+ rst: bigint;
1038
+ en: bigint;
1039
+ readonly count: bigint;
1005
1040
  }
1006
1041
 
1007
1042
  const sim = Simulation.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter");
1008
1043
  sim.addClock("clk", { period: 10 });
1009
1044
 
1010
1045
  // Reset (default async_low: rst=0 is active)
1011
- sim.dut.rst = 0;
1046
+ sim.dut.rst = 0n;
1012
1047
  sim.runUntil(20);
1013
- sim.dut.rst = 1;
1014
- sim.dut.en = 1;
1048
+ sim.dut.rst = 1n;
1049
+ sim.dut.en = 1n;
1015
1050
 
1016
- const t = sim.waitUntil(() => sim.dut.count >= 3);
1017
- expect(sim.dut.count).toBeGreaterThanOrEqual(3);
1051
+ const t = sim.waitUntil(() => sim.dut.count >= 3n);
1052
+ expect(sim.dut.count).toBeGreaterThanOrEqual(3n);
1018
1053
  expect(t).toBeGreaterThan(20);
1019
1054
 
1020
1055
  sim.dispose();
@@ -1022,22 +1057,22 @@ describe("E2E: Simulation testbench helpers", () => {
1022
1057
 
1023
1058
  test("waitUntil: throws SimulationTimeoutError on timeout", () => {
1024
1059
  interface CounterPorts {
1025
- rst: number;
1026
- en: number;
1027
- readonly count: number;
1060
+ rst: bigint;
1061
+ en: bigint;
1062
+ readonly count: bigint;
1028
1063
  }
1029
1064
 
1030
1065
  const sim = Simulation.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter");
1031
1066
  sim.addClock("clk", { period: 10 });
1032
1067
 
1033
1068
  // Reset (default async_low: rst=0 is active)
1034
- sim.dut.rst = 0;
1069
+ sim.dut.rst = 0n;
1035
1070
  sim.runUntil(20);
1036
- sim.dut.rst = 1;
1037
- sim.dut.en = 0; // disabled — count won't increase
1071
+ sim.dut.rst = 1n;
1072
+ sim.dut.en = 0n; // disabled — count won't increase
1038
1073
 
1039
1074
  expect(() =>
1040
- sim.waitUntil(() => sim.dut.count >= 100, { maxSteps: 20 }),
1075
+ sim.waitUntil(() => sim.dut.count >= 100n, { maxSteps: 20 }),
1041
1076
  ).toThrow(SimulationTimeoutError);
1042
1077
 
1043
1078
  sim.dispose();
@@ -1045,34 +1080,34 @@ describe("E2E: Simulation testbench helpers", () => {
1045
1080
 
1046
1081
  test("reset: asserts and releases reset on counter", () => {
1047
1082
  interface CounterPorts {
1048
- rst: number;
1049
- en: number;
1050
- readonly count: number;
1083
+ rst: bigint;
1084
+ en: bigint;
1085
+ readonly count: bigint;
1051
1086
  }
1052
1087
 
1053
1088
  const sim = Simulation.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter");
1054
1089
  sim.addClock("clk", { period: 10 });
1055
1090
 
1056
1091
  // Count up a bit (default async_low: rst=0 is active)
1057
- sim.dut.rst = 0;
1092
+ sim.dut.rst = 0n;
1058
1093
  sim.runUntil(20);
1059
- sim.dut.rst = 1;
1060
- sim.dut.en = 1;
1094
+ sim.dut.rst = 1n;
1095
+ sim.dut.en = 1n;
1061
1096
  sim.runUntil(100);
1062
- expect(sim.dut.count).toBeGreaterThan(0);
1097
+ expect(sim.dut.count).toBeGreaterThan(0n);
1063
1098
 
1064
1099
  // Reset using the helper
1065
1100
  sim.reset("rst");
1066
- expect(sim.dut.count).toBe(0);
1101
+ expect(sim.dut.count).toBe(0n);
1067
1102
 
1068
1103
  sim.dispose();
1069
1104
  });
1070
1105
 
1071
1106
  test("reset: explicit async_low resetType activates with 0", () => {
1072
1107
  interface CounterPorts {
1073
- rst: number;
1074
- en: number;
1075
- readonly count: number;
1108
+ rst: bigint;
1109
+ en: bigint;
1110
+ readonly count: bigint;
1076
1111
  }
1077
1112
 
1078
1113
  const sim = Simulation.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter", {
@@ -1083,22 +1118,22 @@ describe("E2E: Simulation testbench helpers", () => {
1083
1118
  // With async_low, rst=0 is active, rst=1 is inactive
1084
1119
  sim.reset("rst");
1085
1120
 
1086
- sim.dut.en = 1;
1121
+ sim.dut.en = 1n;
1087
1122
  sim.runUntil(100);
1088
- expect(sim.dut.count).toBeGreaterThan(0);
1123
+ expect(sim.dut.count).toBeGreaterThan(0n);
1089
1124
 
1090
1125
  // Reset again using helper, verify it resets the counter
1091
1126
  sim.reset("rst");
1092
- expect(sim.dut.count).toBe(0);
1127
+ expect(sim.dut.count).toBe(0n);
1093
1128
 
1094
1129
  sim.dispose();
1095
1130
  });
1096
1131
 
1097
1132
  test("reset: explicit async_high resetType activates with 1", () => {
1098
1133
  interface CounterPorts {
1099
- rst: number;
1100
- en: number;
1101
- readonly count: number;
1134
+ rst: bigint;
1135
+ en: bigint;
1136
+ readonly count: bigint;
1102
1137
  }
1103
1138
 
1104
1139
  const sim = Simulation.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter", {
@@ -1109,22 +1144,22 @@ describe("E2E: Simulation testbench helpers", () => {
1109
1144
  // With async_high, rst=1 is active, rst=0 is inactive
1110
1145
  sim.reset("rst");
1111
1146
 
1112
- sim.dut.en = 1;
1147
+ sim.dut.en = 1n;
1113
1148
  sim.runUntil(100);
1114
- expect(sim.dut.count).toBeGreaterThan(0);
1149
+ expect(sim.dut.count).toBeGreaterThan(0n);
1115
1150
 
1116
1151
  // Reset again
1117
1152
  sim.reset("rst");
1118
- expect(sim.dut.count).toBe(0);
1153
+ expect(sim.dut.count).toBe(0n);
1119
1154
 
1120
1155
  sim.dispose();
1121
1156
  });
1122
1157
 
1123
1158
  test("Simulator.fromSource: resetType option works", () => {
1124
1159
  interface CounterPorts {
1125
- rst: number;
1126
- en: number;
1127
- readonly count: number;
1160
+ rst: bigint;
1161
+ en: bigint;
1162
+ readonly count: bigint;
1128
1163
  }
1129
1164
 
1130
1165
  const sim = Simulator.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter", {
@@ -1132,35 +1167,35 @@ describe("E2E: Simulation testbench helpers", () => {
1132
1167
  });
1133
1168
 
1134
1169
  // With async_high, assert reset with 1
1135
- sim.dut.rst = 1;
1170
+ sim.dut.rst = 1n;
1136
1171
  sim.tick();
1137
- sim.dut.rst = 0;
1172
+ sim.dut.rst = 0n;
1138
1173
  sim.tick();
1139
- expect(sim.dut.count).toBe(0);
1174
+ expect(sim.dut.count).toBe(0n);
1140
1175
 
1141
1176
  // Count up
1142
- sim.dut.en = 1;
1177
+ sim.dut.en = 1n;
1143
1178
  sim.tick();
1144
- expect(sim.dut.count).toBe(1);
1179
+ expect(sim.dut.count).toBe(1n);
1145
1180
 
1146
1181
  sim.dispose();
1147
1182
  });
1148
1183
 
1149
1184
  test("runUntil with maxSteps: succeeds within budget", () => {
1150
1185
  interface CounterPorts {
1151
- rst: number;
1152
- en: number;
1153
- readonly count: number;
1186
+ rst: bigint;
1187
+ en: bigint;
1188
+ readonly count: bigint;
1154
1189
  }
1155
1190
 
1156
1191
  const sim = Simulation.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter");
1157
1192
  sim.addClock("clk", { period: 10 });
1158
1193
 
1159
1194
  // Reset (default async_low: rst=0 is active)
1160
- sim.dut.rst = 0;
1195
+ sim.dut.rst = 0n;
1161
1196
  sim.runUntil(20);
1162
- sim.dut.rst = 1;
1163
- sim.dut.en = 1;
1197
+ sim.dut.rst = 1n;
1198
+ sim.dut.en = 1n;
1164
1199
 
1165
1200
  // 100 time units with period 10 = 10 events, should fit in 100 steps
1166
1201
  sim.runUntil(120, { maxSteps: 100 });
@@ -1171,17 +1206,17 @@ describe("E2E: Simulation testbench helpers", () => {
1171
1206
 
1172
1207
  test("runUntil with maxSteps: throws on exceeded budget", () => {
1173
1208
  interface CounterPorts {
1174
- rst: number;
1175
- en: number;
1176
- readonly count: number;
1209
+ rst: bigint;
1210
+ en: bigint;
1211
+ readonly count: bigint;
1177
1212
  }
1178
1213
 
1179
1214
  const sim = Simulation.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter");
1180
1215
  sim.addClock("clk", { period: 10 });
1181
1216
 
1182
1217
  // Release reset so counter can count (default async_low: rst=1 is inactive)
1183
- sim.dut.rst = 1;
1184
- sim.dut.en = 1;
1218
+ sim.dut.rst = 1n;
1219
+ sim.dut.en = 1n;
1185
1220
 
1186
1221
  // Very small budget for a long run
1187
1222
  expect(() => sim.runUntil(100000, { maxSteps: 5 })).toThrow(
@@ -1199,33 +1234,33 @@ describe("E2E: Simulation testbench helpers", () => {
1199
1234
  describe("E2E: fourState() method", () => {
1200
1235
  test("Simulator.fourState: reads 4-state value and mask", () => {
1201
1236
  interface Ports {
1202
- a: number;
1203
- b: number;
1204
- readonly y: number;
1237
+ a: bigint;
1238
+ b: bigint;
1239
+ readonly y: bigint;
1205
1240
  }
1206
1241
 
1207
1242
  const sim = Simulator.fromSource<Ports>(ADDER_4STATE_SOURCE, "Adder4S", {
1208
1243
  fourState: true,
1209
1244
  });
1210
1245
 
1211
- sim.dut.a = 100;
1212
- sim.dut.b = 55;
1246
+ sim.dut.a = 100n;
1247
+ sim.dut.b = 55n;
1213
1248
  // Trigger evalComb via output read (Adder4S is purely combinational)
1214
- expect(sim.dut.y).toBe(155);
1249
+ expect(sim.dut.y).toBe(155n);
1215
1250
 
1216
1251
  const fs = sim.fourState("y");
1217
1252
  expect(fs.__fourState).toBe(true);
1218
- expect(fs.value).toBe(155);
1219
- expect(fs.mask).toBe(0);
1253
+ expect(fs.value).toBe(155n);
1254
+ expect(fs.mask).toBe(0n);
1220
1255
 
1221
1256
  sim.dispose();
1222
1257
  });
1223
1258
 
1224
1259
  test("Simulator.fourState: reads X mask when input is X", () => {
1225
1260
  interface Ports {
1226
- a: number;
1227
- b: number;
1228
- readonly y: number;
1261
+ a: bigint;
1262
+ b: bigint;
1263
+ readonly y: bigint;
1229
1264
  }
1230
1265
 
1231
1266
  const sim = Simulator.fromSource<Ports>(ADDER_4STATE_SOURCE, "Adder4S", {
@@ -1233,43 +1268,43 @@ describe("E2E: fourState() method", () => {
1233
1268
  });
1234
1269
 
1235
1270
  (sim.dut as any).a = X;
1236
- sim.dut.b = 10;
1271
+ sim.dut.b = 10n;
1237
1272
  // Trigger evalComb via output read
1238
1273
  sim.dut.y;
1239
1274
 
1240
1275
  const fs = sim.fourState("y");
1241
- expect(fs.mask).toBe(0xFF); // all X from arithmetic propagation
1276
+ expect(fs.mask).toBe(0xFFn); // all X from arithmetic propagation
1242
1277
 
1243
1278
  sim.dispose();
1244
1279
  });
1245
1280
 
1246
1281
  test("Simulation.fourState: reads 4-state value", () => {
1247
1282
  interface Ports {
1248
- a: number;
1249
- b: number;
1250
- readonly y: number;
1283
+ a: bigint;
1284
+ b: bigint;
1285
+ readonly y: bigint;
1251
1286
  }
1252
1287
 
1253
1288
  const sim = Simulation.fromSource<Ports>(ADDER_4STATE_SOURCE, "Adder4S", {
1254
1289
  fourState: true,
1255
1290
  });
1256
1291
 
1257
- sim.dut.a = 50;
1258
- sim.dut.b = 25;
1292
+ sim.dut.a = 50n;
1293
+ sim.dut.b = 25n;
1259
1294
  sim.runUntil(0);
1260
1295
 
1261
1296
  const fs = sim.fourState("y");
1262
- expect(fs.value).toBe(75);
1263
- expect(fs.mask).toBe(0);
1297
+ expect(fs.value).toBe(75n);
1298
+ expect(fs.mask).toBe(0n);
1264
1299
 
1265
1300
  sim.dispose();
1266
1301
  });
1267
1302
 
1268
1303
  test("fourState: throws for unknown port", () => {
1269
1304
  interface Ports {
1270
- a: number;
1271
- b: number;
1272
- readonly y: number;
1305
+ a: bigint;
1306
+ b: bigint;
1307
+ readonly y: bigint;
1273
1308
  }
1274
1309
 
1275
1310
  const sim = Simulator.fromSource<Ports>(ADDER_4STATE_SOURCE, "Adder4S", {
@@ -1289,29 +1324,29 @@ describe("E2E: fourState() method", () => {
1289
1324
  describe("E2E: optimize flag", () => {
1290
1325
  test("Simulator.fromSource with optimize: true", () => {
1291
1326
  interface AdderPorts {
1292
- rst: number;
1293
- a: number;
1294
- b: number;
1295
- readonly sum: number;
1327
+ rst: bigint;
1328
+ a: bigint;
1329
+ b: bigint;
1330
+ readonly sum: bigint;
1296
1331
  }
1297
1332
 
1298
1333
  const sim = Simulator.fromSource<AdderPorts>(ADDER_SOURCE, "Adder", {
1299
1334
  optimize: true,
1300
1335
  });
1301
1336
 
1302
- sim.dut.a = 100;
1303
- sim.dut.b = 200;
1337
+ sim.dut.a = 100n;
1338
+ sim.dut.b = 200n;
1304
1339
  sim.tick();
1305
- expect(sim.dut.sum).toBe(300);
1340
+ expect(sim.dut.sum).toBe(300n);
1306
1341
 
1307
1342
  sim.dispose();
1308
1343
  });
1309
1344
 
1310
1345
  test("Simulation.fromSource with optimize: true", () => {
1311
1346
  interface CounterPorts {
1312
- rst: number;
1313
- en: number;
1314
- readonly count: number;
1347
+ rst: bigint;
1348
+ en: bigint;
1349
+ readonly count: bigint;
1315
1350
  }
1316
1351
 
1317
1352
  const sim = Simulation.fromSource<CounterPorts>(COUNTER_SOURCE, "Counter", {
@@ -1321,13 +1356,13 @@ describe("E2E: optimize flag", () => {
1321
1356
  sim.addClock("clk", { period: 10 });
1322
1357
 
1323
1358
  // Reset (default async_low: rst=0 is active)
1324
- sim.dut.rst = 0;
1359
+ sim.dut.rst = 0n;
1325
1360
  sim.runUntil(20);
1326
- sim.dut.rst = 1;
1327
- sim.dut.en = 1;
1361
+ sim.dut.rst = 1n;
1362
+ sim.dut.en = 1n;
1328
1363
  sim.runUntil(100);
1329
1364
 
1330
- expect(sim.dut.count).toBeGreaterThan(0);
1365
+ expect(sim.dut.count).toBeGreaterThan(0n);
1331
1366
 
1332
1367
  sim.dispose();
1333
1368
  });