@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/dist/dut.d.ts +1 -1
- package/dist/dut.d.ts.map +1 -1
- package/dist/dut.js +24 -21
- package/dist/dut.js.map +1 -1
- package/dist/simulation.js +2 -2
- package/dist/simulation.js.map +1 -1
- package/dist/simulator.d.ts.map +1 -1
- package/dist/simulator.js +4 -1
- package/dist/simulator.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/src/dut.test.ts +66 -66
- package/src/dut.ts +31 -26
- package/src/e2e.bench.ts +25 -25
- package/src/e2e.test.ts +313 -278
- package/src/matchers.ts +4 -7
- package/src/simulation.test.ts +8 -8
- package/src/simulation.ts +2 -2
- package/src/simulator.test.ts +8 -8
- package/src/simulator.ts +5 -1
- package/src/types.ts +3 -3
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:
|
|
101
|
-
a:
|
|
102
|
-
b:
|
|
103
|
-
readonly sum:
|
|
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 =
|
|
109
|
-
sim.dut.b =
|
|
108
|
+
sim.dut.a = 100n;
|
|
109
|
+
sim.dut.b = 200n;
|
|
110
110
|
sim.tick();
|
|
111
|
-
expect(sim.dut.sum).toBe(
|
|
111
|
+
expect(sim.dut.sum).toBe(300n);
|
|
112
112
|
|
|
113
|
-
sim.dut.a =
|
|
114
|
-
sim.dut.b =
|
|
113
|
+
sim.dut.a = 0xFFFFn;
|
|
114
|
+
sim.dut.b = 1n;
|
|
115
115
|
sim.tick();
|
|
116
|
-
expect(sim.dut.sum).toBe(
|
|
116
|
+
expect(sim.dut.sum).toBe(0x10000n);
|
|
117
117
|
|
|
118
|
-
sim.dut.a =
|
|
119
|
-
sim.dut.b =
|
|
118
|
+
sim.dut.a = 0n;
|
|
119
|
+
sim.dut.b = 0n;
|
|
120
120
|
sim.tick();
|
|
121
|
-
expect(sim.dut.sum).toBe(
|
|
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:
|
|
129
|
-
a:
|
|
130
|
-
b:
|
|
131
|
-
readonly sum:
|
|
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 =
|
|
137
|
-
sim.dut.b =
|
|
138
|
-
expect(sim.dut.sum).toBe(
|
|
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:
|
|
146
|
-
en:
|
|
147
|
-
readonly count:
|
|
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 =
|
|
153
|
+
sim.dut.rst = 0n;
|
|
154
154
|
sim.tick();
|
|
155
|
-
sim.dut.rst =
|
|
155
|
+
sim.dut.rst = 1n;
|
|
156
156
|
sim.tick();
|
|
157
|
-
expect(sim.dut.count).toBe(
|
|
157
|
+
expect(sim.dut.count).toBe(0n);
|
|
158
158
|
|
|
159
159
|
// Enable counting
|
|
160
|
-
sim.dut.en =
|
|
160
|
+
sim.dut.en = 1n;
|
|
161
161
|
sim.tick();
|
|
162
|
-
expect(sim.dut.count).toBe(
|
|
162
|
+
expect(sim.dut.count).toBe(1n);
|
|
163
163
|
|
|
164
164
|
sim.tick();
|
|
165
|
-
expect(sim.dut.count).toBe(
|
|
165
|
+
expect(sim.dut.count).toBe(2n);
|
|
166
166
|
|
|
167
167
|
sim.tick();
|
|
168
|
-
expect(sim.dut.count).toBe(
|
|
168
|
+
expect(sim.dut.count).toBe(3n);
|
|
169
169
|
|
|
170
170
|
// Disable counting
|
|
171
|
-
sim.dut.en =
|
|
171
|
+
sim.dut.en = 0n;
|
|
172
172
|
sim.tick();
|
|
173
|
-
expect(sim.dut.count).toBe(
|
|
173
|
+
expect(sim.dut.count).toBe(3n);
|
|
174
174
|
|
|
175
175
|
// Re-enable
|
|
176
|
-
sim.dut.en =
|
|
176
|
+
sim.dut.en = 1n;
|
|
177
177
|
sim.tick(5);
|
|
178
|
-
expect(sim.dut.count).toBe(
|
|
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:
|
|
186
|
-
d0:
|
|
187
|
-
d1:
|
|
188
|
-
d2:
|
|
189
|
-
d3:
|
|
190
|
-
readonly y:
|
|
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 =
|
|
196
|
-
sim.dut.d1 =
|
|
197
|
-
sim.dut.d2 =
|
|
198
|
-
sim.dut.d3 =
|
|
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 =
|
|
201
|
-
expect(sim.dut.y).toBe(
|
|
235
|
+
sim.dut.sel = 0n;
|
|
236
|
+
expect(sim.dut.y).toBe(0xAAn);
|
|
202
237
|
|
|
203
|
-
sim.dut.sel =
|
|
204
|
-
expect(sim.dut.y).toBe(
|
|
238
|
+
sim.dut.sel = 1n;
|
|
239
|
+
expect(sim.dut.y).toBe(0xBBn);
|
|
205
240
|
|
|
206
|
-
sim.dut.sel =
|
|
207
|
-
expect(sim.dut.y).toBe(
|
|
241
|
+
sim.dut.sel = 2n;
|
|
242
|
+
expect(sim.dut.y).toBe(0xCCn);
|
|
208
243
|
|
|
209
|
-
sim.dut.sel =
|
|
210
|
-
expect(sim.dut.y).toBe(
|
|
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:
|
|
224
|
-
en:
|
|
225
|
-
readonly count:
|
|
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 =
|
|
269
|
+
sim.dut.rst = 0n;
|
|
235
270
|
sim.runUntil(20);
|
|
236
|
-
sim.dut.rst =
|
|
237
|
-
sim.dut.en =
|
|
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(
|
|
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:
|
|
257
|
-
a:
|
|
258
|
-
b:
|
|
259
|
-
readonly sum:
|
|
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 =
|
|
265
|
-
sim.dut.b =
|
|
299
|
+
sim.dut.a = 100n;
|
|
300
|
+
sim.dut.b = 200n;
|
|
266
301
|
sim.tick();
|
|
267
|
-
expect(sim.dut.sum).toBe(
|
|
302
|
+
expect(sim.dut.sum).toBe(300n);
|
|
268
303
|
|
|
269
|
-
sim.dut.a =
|
|
270
|
-
sim.dut.b =
|
|
304
|
+
sim.dut.a = 0xFFFFn;
|
|
305
|
+
sim.dut.b = 1n;
|
|
271
306
|
sim.tick();
|
|
272
|
-
expect(sim.dut.sum).toBe(
|
|
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:
|
|
280
|
-
en:
|
|
281
|
-
readonly count:
|
|
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 =
|
|
322
|
+
sim.dut.rst = 0n;
|
|
288
323
|
sim.tick();
|
|
289
|
-
sim.dut.rst =
|
|
324
|
+
sim.dut.rst = 1n;
|
|
290
325
|
sim.tick();
|
|
291
|
-
expect(sim.dut.count).toBe(
|
|
326
|
+
expect(sim.dut.count).toBe(0n);
|
|
292
327
|
|
|
293
328
|
// Enable counting
|
|
294
|
-
sim.dut.en =
|
|
329
|
+
sim.dut.en = 1n;
|
|
295
330
|
sim.tick();
|
|
296
|
-
expect(sim.dut.count).toBe(
|
|
331
|
+
expect(sim.dut.count).toBe(1n);
|
|
297
332
|
|
|
298
333
|
sim.tick();
|
|
299
|
-
expect(sim.dut.count).toBe(
|
|
334
|
+
expect(sim.dut.count).toBe(2n);
|
|
300
335
|
|
|
301
336
|
sim.tick();
|
|
302
|
-
expect(sim.dut.count).toBe(
|
|
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:
|
|
316
|
-
en:
|
|
317
|
-
readonly count:
|
|
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 =
|
|
361
|
+
sim.dut.rst = 0n;
|
|
327
362
|
sim.runUntil(20);
|
|
328
|
-
sim.dut.rst =
|
|
329
|
-
sim.dut.en =
|
|
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(
|
|
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:
|
|
349
|
-
a:
|
|
350
|
-
b:
|
|
351
|
-
readonly sum:
|
|
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 =
|
|
375
|
-
sim.dut.b =
|
|
409
|
+
sim.dut.a = 100n;
|
|
410
|
+
sim.dut.b = 200n;
|
|
376
411
|
sim.tick();
|
|
377
|
-
expect(sim.dut.sum).toBe(
|
|
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(
|
|
467
|
-
expect(maskA).toBe(
|
|
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:
|
|
477
|
-
readonly y_and:
|
|
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(
|
|
517
|
-
expect(mAnd).toBe(
|
|
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(
|
|
522
|
-
expect(mOr).toBe(
|
|
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(
|
|
548
|
-
expect(mOr).toBe(
|
|
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(
|
|
587
|
-
expect(mLogic).toBe(
|
|
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(
|
|
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(
|
|
635
|
-
expect(mY).toBe(
|
|
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(
|
|
662
|
-
expect(mQ1).toBe(
|
|
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(
|
|
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(
|
|
685
|
-
expect(mQ3).toBe(
|
|
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(
|
|
703
|
-
expect(mA).toBe(
|
|
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(
|
|
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(
|
|
727
|
-
expect(mAfter).toBe(
|
|
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:
|
|
733
|
-
b:
|
|
734
|
-
readonly y:
|
|
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 =
|
|
741
|
-
sim.dut.b =
|
|
742
|
-
expect(sim.dut.y).toBe(
|
|
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("
|
|
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("
|
|
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:
|
|
768
|
-
en:
|
|
769
|
-
readonly count:
|
|
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 =
|
|
813
|
+
sim.dut.rst = 0n;
|
|
779
814
|
sim.tick();
|
|
780
|
-
sim.dut.rst =
|
|
815
|
+
sim.dut.rst = 1n;
|
|
781
816
|
sim.tick();
|
|
782
|
-
expect(sim.dut.count).toBe(
|
|
817
|
+
expect(sim.dut.count).toBe(0n);
|
|
783
818
|
|
|
784
819
|
// Enable counting — should work exactly like 2-state
|
|
785
|
-
sim.dut.en =
|
|
820
|
+
sim.dut.en = 1n;
|
|
786
821
|
sim.tick();
|
|
787
|
-
expect(sim.dut.count).toBe(
|
|
822
|
+
expect(sim.dut.count).toBe(1n);
|
|
788
823
|
|
|
789
824
|
sim.tick();
|
|
790
|
-
expect(sim.dut.count).toBe(
|
|
825
|
+
expect(sim.dut.count).toBe(2n);
|
|
791
826
|
|
|
792
827
|
sim.tick();
|
|
793
|
-
expect(sim.dut.count).toBe(
|
|
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 [,
|
|
821
|
-
expect(
|
|
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:
|
|
829
|
-
d:
|
|
830
|
-
readonly q:
|
|
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 =
|
|
871
|
+
sim.dut.rst = 0n;
|
|
837
872
|
sim.tick();
|
|
838
|
-
sim.dut.rst =
|
|
839
|
-
expect(sim.dut.q).toBe(
|
|
873
|
+
sim.dut.rst = 1n;
|
|
874
|
+
expect(sim.dut.q).toBe(0n);
|
|
840
875
|
|
|
841
876
|
// Write a defined value
|
|
842
|
-
sim.dut.d =
|
|
877
|
+
sim.dut.d = 0x42n;
|
|
843
878
|
sim.tick();
|
|
844
|
-
expect(sim.dut.q).toBe(
|
|
879
|
+
expect(sim.dut.q).toBe(0x42n);
|
|
845
880
|
|
|
846
|
-
// Write X to d, tick — q should capture it (value read still returns a
|
|
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("
|
|
884
|
+
expect(typeof sim.dut.q).toBe("bigint");
|
|
850
885
|
|
|
851
886
|
// Write defined value again — q should recover
|
|
852
|
-
sim.dut.d =
|
|
887
|
+
sim.dut.d = 0x99n;
|
|
853
888
|
sim.tick();
|
|
854
|
-
expect(sim.dut.q).toBe(
|
|
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:
|
|
862
|
-
b:
|
|
863
|
-
readonly y:
|
|
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 =
|
|
905
|
+
sim.dut.b = 10n;
|
|
871
906
|
// Output has X — just verify it doesn't crash
|
|
872
|
-
expect(typeof sim.dut.y).toBe("
|
|
907
|
+
expect(typeof sim.dut.y).toBe("bigint");
|
|
873
908
|
|
|
874
909
|
// Clear X by writing defined values
|
|
875
|
-
sim.dut.a =
|
|
876
|
-
sim.dut.b =
|
|
877
|
-
expect(sim.dut.y).toBe(
|
|
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:
|
|
891
|
-
d:
|
|
892
|
-
readonly q:
|
|
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 =
|
|
936
|
+
sim.dut.rst = 0n;
|
|
902
937
|
sim.runUntil(20);
|
|
903
|
-
sim.dut.rst =
|
|
904
|
-
expect(sim.dut.q).toBe(
|
|
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 =
|
|
942
|
+
sim.dut.d = 0x55n;
|
|
908
943
|
sim.runUntil(40);
|
|
909
|
-
expect(sim.dut.q).toBe(
|
|
944
|
+
expect(sim.dut.q).toBe(0x55n);
|
|
910
945
|
|
|
911
946
|
// Drive d with different value
|
|
912
|
-
sim.dut.d =
|
|
947
|
+
sim.dut.d = 0xAAn;
|
|
913
948
|
sim.runUntil(60);
|
|
914
|
-
expect(sim.dut.q).toBe(
|
|
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:
|
|
922
|
-
en:
|
|
923
|
-
readonly count:
|
|
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 =
|
|
968
|
+
sim.dut.rst = 0n;
|
|
934
969
|
sim.runUntil(20);
|
|
935
|
-
sim.dut.rst =
|
|
936
|
-
sim.dut.en =
|
|
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(
|
|
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:
|
|
950
|
-
b:
|
|
951
|
-
readonly y:
|
|
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 =
|
|
960
|
-
sim.dut.b =
|
|
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(
|
|
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:
|
|
977
|
-
en:
|
|
978
|
-
readonly count:
|
|
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 =
|
|
1020
|
+
sim.dut.rst = 0n;
|
|
986
1021
|
sim.runUntil(20);
|
|
987
|
-
sim.dut.rst =
|
|
988
|
-
sim.dut.en =
|
|
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:
|
|
1003
|
-
en:
|
|
1004
|
-
readonly count:
|
|
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 =
|
|
1046
|
+
sim.dut.rst = 0n;
|
|
1012
1047
|
sim.runUntil(20);
|
|
1013
|
-
sim.dut.rst =
|
|
1014
|
-
sim.dut.en =
|
|
1048
|
+
sim.dut.rst = 1n;
|
|
1049
|
+
sim.dut.en = 1n;
|
|
1015
1050
|
|
|
1016
|
-
const t = sim.waitUntil(() => sim.dut.count >=
|
|
1017
|
-
expect(sim.dut.count).toBeGreaterThanOrEqual(
|
|
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:
|
|
1026
|
-
en:
|
|
1027
|
-
readonly count:
|
|
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 =
|
|
1069
|
+
sim.dut.rst = 0n;
|
|
1035
1070
|
sim.runUntil(20);
|
|
1036
|
-
sim.dut.rst =
|
|
1037
|
-
sim.dut.en =
|
|
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 >=
|
|
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:
|
|
1049
|
-
en:
|
|
1050
|
-
readonly count:
|
|
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 =
|
|
1092
|
+
sim.dut.rst = 0n;
|
|
1058
1093
|
sim.runUntil(20);
|
|
1059
|
-
sim.dut.rst =
|
|
1060
|
-
sim.dut.en =
|
|
1094
|
+
sim.dut.rst = 1n;
|
|
1095
|
+
sim.dut.en = 1n;
|
|
1061
1096
|
sim.runUntil(100);
|
|
1062
|
-
expect(sim.dut.count).toBeGreaterThan(
|
|
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(
|
|
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:
|
|
1074
|
-
en:
|
|
1075
|
-
readonly count:
|
|
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 =
|
|
1121
|
+
sim.dut.en = 1n;
|
|
1087
1122
|
sim.runUntil(100);
|
|
1088
|
-
expect(sim.dut.count).toBeGreaterThan(
|
|
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(
|
|
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:
|
|
1100
|
-
en:
|
|
1101
|
-
readonly count:
|
|
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 =
|
|
1147
|
+
sim.dut.en = 1n;
|
|
1113
1148
|
sim.runUntil(100);
|
|
1114
|
-
expect(sim.dut.count).toBeGreaterThan(
|
|
1149
|
+
expect(sim.dut.count).toBeGreaterThan(0n);
|
|
1115
1150
|
|
|
1116
1151
|
// Reset again
|
|
1117
1152
|
sim.reset("rst");
|
|
1118
|
-
expect(sim.dut.count).toBe(
|
|
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:
|
|
1126
|
-
en:
|
|
1127
|
-
readonly count:
|
|
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 =
|
|
1170
|
+
sim.dut.rst = 1n;
|
|
1136
1171
|
sim.tick();
|
|
1137
|
-
sim.dut.rst =
|
|
1172
|
+
sim.dut.rst = 0n;
|
|
1138
1173
|
sim.tick();
|
|
1139
|
-
expect(sim.dut.count).toBe(
|
|
1174
|
+
expect(sim.dut.count).toBe(0n);
|
|
1140
1175
|
|
|
1141
1176
|
// Count up
|
|
1142
|
-
sim.dut.en =
|
|
1177
|
+
sim.dut.en = 1n;
|
|
1143
1178
|
sim.tick();
|
|
1144
|
-
expect(sim.dut.count).toBe(
|
|
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:
|
|
1152
|
-
en:
|
|
1153
|
-
readonly count:
|
|
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 =
|
|
1195
|
+
sim.dut.rst = 0n;
|
|
1161
1196
|
sim.runUntil(20);
|
|
1162
|
-
sim.dut.rst =
|
|
1163
|
-
sim.dut.en =
|
|
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:
|
|
1175
|
-
en:
|
|
1176
|
-
readonly count:
|
|
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 =
|
|
1184
|
-
sim.dut.en =
|
|
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:
|
|
1203
|
-
b:
|
|
1204
|
-
readonly y:
|
|
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 =
|
|
1212
|
-
sim.dut.b =
|
|
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(
|
|
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(
|
|
1219
|
-
expect(fs.mask).toBe(
|
|
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:
|
|
1227
|
-
b:
|
|
1228
|
-
readonly y:
|
|
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 =
|
|
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(
|
|
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:
|
|
1249
|
-
b:
|
|
1250
|
-
readonly y:
|
|
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 =
|
|
1258
|
-
sim.dut.b =
|
|
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(
|
|
1263
|
-
expect(fs.mask).toBe(
|
|
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:
|
|
1271
|
-
b:
|
|
1272
|
-
readonly y:
|
|
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:
|
|
1293
|
-
a:
|
|
1294
|
-
b:
|
|
1295
|
-
readonly sum:
|
|
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 =
|
|
1303
|
-
sim.dut.b =
|
|
1337
|
+
sim.dut.a = 100n;
|
|
1338
|
+
sim.dut.b = 200n;
|
|
1304
1339
|
sim.tick();
|
|
1305
|
-
expect(sim.dut.sum).toBe(
|
|
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:
|
|
1313
|
-
en:
|
|
1314
|
-
readonly count:
|
|
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 =
|
|
1359
|
+
sim.dut.rst = 0n;
|
|
1325
1360
|
sim.runUntil(20);
|
|
1326
|
-
sim.dut.rst =
|
|
1327
|
-
sim.dut.en =
|
|
1361
|
+
sim.dut.rst = 1n;
|
|
1362
|
+
sim.dut.en = 1n;
|
|
1328
1363
|
sim.runUntil(100);
|
|
1329
1364
|
|
|
1330
|
-
expect(sim.dut.count).toBeGreaterThan(
|
|
1365
|
+
expect(sim.dut.count).toBeGreaterThan(0n);
|
|
1331
1366
|
|
|
1332
1367
|
sim.dispose();
|
|
1333
1368
|
});
|