@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/dut.test.ts
CHANGED
|
@@ -41,11 +41,11 @@ describe("createDut — scalar ports", () => {
|
|
|
41
41
|
const handle = mockHandle();
|
|
42
42
|
const state: DirtyState = { dirty: false };
|
|
43
43
|
|
|
44
|
-
const dut = createDut<{ a:
|
|
44
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
45
45
|
|
|
46
|
-
dut.a =
|
|
46
|
+
dut.a = 42n;
|
|
47
47
|
expect(state.dirty).toBe(true);
|
|
48
|
-
expect(dut.a).toBe(
|
|
48
|
+
expect(dut.a).toBe(42n);
|
|
49
49
|
// Reading an input doesn't trigger evalComb
|
|
50
50
|
expect(handle.evalComb).not.toHaveBeenCalled();
|
|
51
51
|
});
|
|
@@ -61,10 +61,10 @@ describe("createDut — scalar ports", () => {
|
|
|
61
61
|
const handle = mockHandle();
|
|
62
62
|
const state: DirtyState = { dirty: false };
|
|
63
63
|
|
|
64
|
-
const dut = createDut<{ a:
|
|
64
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
65
65
|
|
|
66
|
-
dut.a =
|
|
67
|
-
expect(dut.a).toBe(
|
|
66
|
+
dut.a = 0xABCDn;
|
|
67
|
+
expect(dut.a).toBe(0xABCDn);
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
test("write and read 32-bit input", () => {
|
|
@@ -78,13 +78,13 @@ describe("createDut — scalar ports", () => {
|
|
|
78
78
|
const handle = mockHandle();
|
|
79
79
|
const state: DirtyState = { dirty: false };
|
|
80
80
|
|
|
81
|
-
const dut = createDut<{ a:
|
|
81
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
82
82
|
|
|
83
|
-
dut.a =
|
|
84
|
-
expect(dut.a).toBe(
|
|
83
|
+
dut.a = 0xDEAD_BEEFn;
|
|
84
|
+
expect(dut.a).toBe(0xDEAD_BEEFn);
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
test("write and read 48-bit value
|
|
87
|
+
test("write and read 48-bit value", () => {
|
|
88
88
|
const buffer = makeBuffer(64);
|
|
89
89
|
const layout: Record<string, SignalLayout> = {
|
|
90
90
|
a: { offset: 0, width: 48, byteSize: 8, is4state: false, direction: "input" },
|
|
@@ -95,9 +95,9 @@ describe("createDut — scalar ports", () => {
|
|
|
95
95
|
const handle = mockHandle();
|
|
96
96
|
const state: DirtyState = { dirty: false };
|
|
97
97
|
|
|
98
|
-
const dut = createDut<{ a:
|
|
98
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
99
99
|
|
|
100
|
-
const val =
|
|
100
|
+
const val = 0x1234_5678_9ABCn;
|
|
101
101
|
dut.a = val;
|
|
102
102
|
expect(dut.a).toBe(val);
|
|
103
103
|
});
|
|
@@ -131,10 +131,10 @@ describe("createDut — scalar ports", () => {
|
|
|
131
131
|
const handle = mockHandle();
|
|
132
132
|
const state: DirtyState = { dirty: false };
|
|
133
133
|
|
|
134
|
-
const dut = createDut<{ a:
|
|
134
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
135
135
|
|
|
136
|
-
dut.a =
|
|
137
|
-
expect(dut.a).toBe(
|
|
136
|
+
dut.a = 0xFFn; // Only lower 4 bits should be stored
|
|
137
|
+
expect(dut.a).toBe(0x0Fn);
|
|
138
138
|
});
|
|
139
139
|
});
|
|
140
140
|
|
|
@@ -156,12 +156,12 @@ describe("createDut — dirty tracking", () => {
|
|
|
156
156
|
const handle = mockHandle();
|
|
157
157
|
const state: DirtyState = { dirty: false };
|
|
158
158
|
|
|
159
|
-
const dut = createDut<{ a:
|
|
159
|
+
const dut = createDut<{ a: bigint; readonly sum: bigint }>(
|
|
160
160
|
buffer, layout, ports, handle, state,
|
|
161
161
|
);
|
|
162
162
|
|
|
163
163
|
// Write input → dirty
|
|
164
|
-
dut.a =
|
|
164
|
+
dut.a = 100n;
|
|
165
165
|
expect(state.dirty).toBe(true);
|
|
166
166
|
|
|
167
167
|
// Read output → evalComb should be called
|
|
@@ -181,7 +181,7 @@ describe("createDut — dirty tracking", () => {
|
|
|
181
181
|
const handle = mockHandle();
|
|
182
182
|
const state: DirtyState = { dirty: false };
|
|
183
183
|
|
|
184
|
-
const dut = createDut<{ readonly sum:
|
|
184
|
+
const dut = createDut<{ readonly sum: bigint }>(
|
|
185
185
|
buffer, layout, ports, handle, state,
|
|
186
186
|
);
|
|
187
187
|
|
|
@@ -200,7 +200,7 @@ describe("createDut — dirty tracking", () => {
|
|
|
200
200
|
const handle = mockHandle();
|
|
201
201
|
const state: DirtyState = { dirty: true };
|
|
202
202
|
|
|
203
|
-
const dut = createDut<{ a:
|
|
203
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
204
204
|
|
|
205
205
|
void dut.a;
|
|
206
206
|
expect(handle.evalComb).not.toHaveBeenCalled();
|
|
@@ -217,10 +217,10 @@ describe("createDut — dirty tracking", () => {
|
|
|
217
217
|
const handle = mockHandle();
|
|
218
218
|
const state: DirtyState = { dirty: false };
|
|
219
219
|
|
|
220
|
-
const dut = createDut<{ sum:
|
|
220
|
+
const dut = createDut<{ sum: bigint }>(buffer, layout, ports, handle, state);
|
|
221
221
|
|
|
222
222
|
expect(() => {
|
|
223
|
-
dut.sum =
|
|
223
|
+
dut.sum = 42n;
|
|
224
224
|
}).toThrow("Cannot write to output port 'sum'");
|
|
225
225
|
});
|
|
226
226
|
});
|
|
@@ -243,7 +243,7 @@ describe("createDut — clock ports", () => {
|
|
|
243
243
|
const handle = mockHandle();
|
|
244
244
|
const state: DirtyState = { dirty: false };
|
|
245
245
|
|
|
246
|
-
const dut = createDut<{ a:
|
|
246
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
247
247
|
|
|
248
248
|
expect(Object.keys(dut as object)).toEqual(["a"]);
|
|
249
249
|
expect((dut as any).clk).toBeUndefined();
|
|
@@ -281,20 +281,20 @@ describe("createDut — multiple signals", () => {
|
|
|
281
281
|
|
|
282
282
|
const state: DirtyState = { dirty: false };
|
|
283
283
|
const dut = createDut<{
|
|
284
|
-
rst:
|
|
285
|
-
a:
|
|
286
|
-
b:
|
|
287
|
-
readonly sum:
|
|
284
|
+
rst: bigint;
|
|
285
|
+
a: bigint;
|
|
286
|
+
b: bigint;
|
|
287
|
+
readonly sum: bigint;
|
|
288
288
|
}>(buffer, layout, ports, handle, state);
|
|
289
289
|
|
|
290
|
-
dut.a =
|
|
291
|
-
dut.b =
|
|
290
|
+
dut.a = 100n;
|
|
291
|
+
dut.b = 200n;
|
|
292
292
|
// sum read triggers evalComb
|
|
293
|
-
expect(dut.sum).toBe(
|
|
293
|
+
expect(dut.sum).toBe(300n);
|
|
294
294
|
expect(handle.evalComb).toHaveBeenCalledTimes(1);
|
|
295
295
|
|
|
296
296
|
// second read without changes → no evalComb
|
|
297
|
-
expect(dut.sum).toBe(
|
|
297
|
+
expect(dut.sum).toBe(300n);
|
|
298
298
|
expect(handle.evalComb).toHaveBeenCalledTimes(1);
|
|
299
299
|
});
|
|
300
300
|
});
|
|
@@ -316,13 +316,13 @@ describe("createDut — 4-state", () => {
|
|
|
316
316
|
const handle = mockHandle();
|
|
317
317
|
const state: DirtyState = { dirty: false };
|
|
318
318
|
|
|
319
|
-
const dut = createDut<{ a:
|
|
319
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
320
320
|
|
|
321
321
|
(dut as any).a = X;
|
|
322
322
|
// Value should be 0, mask should be 0xFF
|
|
323
323
|
const [value, mask] = readFourState(buffer, layout.a);
|
|
324
|
-
expect(value).toBe(
|
|
325
|
-
expect(mask).toBe(
|
|
324
|
+
expect(value).toBe(0n);
|
|
325
|
+
expect(mask).toBe(0xFFn);
|
|
326
326
|
});
|
|
327
327
|
|
|
328
328
|
test("write FourState to a 4-state signal", () => {
|
|
@@ -336,12 +336,12 @@ describe("createDut — 4-state", () => {
|
|
|
336
336
|
const handle = mockHandle();
|
|
337
337
|
const state: DirtyState = { dirty: false };
|
|
338
338
|
|
|
339
|
-
const dut = createDut<{ a:
|
|
339
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
340
340
|
|
|
341
341
|
(dut as any).a = FourState(0b1010, 0b0100);
|
|
342
342
|
const [value, mask] = readFourState(buffer, layout.a);
|
|
343
|
-
expect(value).toBe(
|
|
344
|
-
expect(mask).toBe(
|
|
343
|
+
expect(value).toBe(0b1010n);
|
|
344
|
+
expect(mask).toBe(0b0100n);
|
|
345
345
|
});
|
|
346
346
|
|
|
347
347
|
test("writing X to non-4-state signal throws", () => {
|
|
@@ -355,7 +355,7 @@ describe("createDut — 4-state", () => {
|
|
|
355
355
|
const handle = mockHandle();
|
|
356
356
|
const state: DirtyState = { dirty: false };
|
|
357
357
|
|
|
358
|
-
const dut = createDut<{ a:
|
|
358
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
359
359
|
|
|
360
360
|
expect(() => {
|
|
361
361
|
(dut as any).a = X;
|
|
@@ -373,7 +373,7 @@ describe("createDut — 4-state", () => {
|
|
|
373
373
|
const handle = mockHandle();
|
|
374
374
|
const state: DirtyState = { dirty: false };
|
|
375
375
|
|
|
376
|
-
const dut = createDut<{ a:
|
|
376
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
377
377
|
|
|
378
378
|
expect(() => {
|
|
379
379
|
(dut as any).a = FourState(0xA5, 0x0F);
|
|
@@ -391,18 +391,18 @@ describe("createDut — 4-state", () => {
|
|
|
391
391
|
const handle = mockHandle();
|
|
392
392
|
const state: DirtyState = { dirty: false };
|
|
393
393
|
|
|
394
|
-
const dut = createDut<{ a:
|
|
394
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
395
395
|
|
|
396
396
|
// First write X
|
|
397
397
|
(dut as any).a = X;
|
|
398
398
|
const [, maskBefore] = readFourState(buffer, layout.a);
|
|
399
|
-
expect(maskBefore).toBe(
|
|
399
|
+
expect(maskBefore).toBe(0xFFn);
|
|
400
400
|
|
|
401
401
|
// Then write a defined value — mask should clear
|
|
402
|
-
dut.a =
|
|
402
|
+
dut.a = 42n;
|
|
403
403
|
const [value, maskAfter] = readFourState(buffer, layout.a);
|
|
404
|
-
expect(value).toBe(
|
|
405
|
-
expect(maskAfter).toBe(
|
|
404
|
+
expect(value).toBe(42n);
|
|
405
|
+
expect(maskAfter).toBe(0n);
|
|
406
406
|
});
|
|
407
407
|
|
|
408
408
|
test("reading 4-state output returns value part only", () => {
|
|
@@ -417,14 +417,14 @@ describe("createDut — 4-state", () => {
|
|
|
417
417
|
const handle = mockHandle();
|
|
418
418
|
const state: DirtyState = { dirty: false };
|
|
419
419
|
|
|
420
|
-
const dut = createDut<{ readonly y:
|
|
420
|
+
const dut = createDut<{ readonly y: bigint }>(buffer, layout, ports, handle, state);
|
|
421
421
|
|
|
422
422
|
// Set value=0xAB, mask=0x0F (lower 4 bits are X)
|
|
423
423
|
view.setUint8(0, 0xAB);
|
|
424
424
|
view.setUint8(1, 0x0F);
|
|
425
425
|
|
|
426
426
|
// DUT getter returns the value part
|
|
427
|
-
expect(dut.y).toBe(
|
|
427
|
+
expect(dut.y).toBe(0xABn);
|
|
428
428
|
});
|
|
429
429
|
|
|
430
430
|
test("write X sets dirty flag", () => {
|
|
@@ -438,7 +438,7 @@ describe("createDut — 4-state", () => {
|
|
|
438
438
|
const handle = mockHandle();
|
|
439
439
|
const state: DirtyState = { dirty: false };
|
|
440
440
|
|
|
441
|
-
const dut = createDut<{ a:
|
|
441
|
+
const dut = createDut<{ a: bigint }>(buffer, layout, ports, handle, state);
|
|
442
442
|
|
|
443
443
|
(dut as any).a = X;
|
|
444
444
|
expect(state.dirty).toBe(true);
|
|
@@ -462,20 +462,20 @@ describe("createDut — array ports", () => {
|
|
|
462
462
|
const handle = mockHandle();
|
|
463
463
|
const state: DirtyState = { dirty: false };
|
|
464
464
|
|
|
465
|
-
const dut = createDut<{ data: number
|
|
465
|
+
const dut = createDut<{ data: { at(i: number): bigint; set(i: number, v: bigint): void; length: number } }>(
|
|
466
466
|
buffer, layout, ports, handle, state,
|
|
467
467
|
);
|
|
468
468
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
469
|
+
dut.data.set(0, 0xAAn);
|
|
470
|
+
dut.data.set(1, 0xBBn);
|
|
471
|
+
dut.data.set(2, 0xCCn);
|
|
472
|
+
dut.data.set(3, 0xDDn);
|
|
473
473
|
|
|
474
|
-
expect(
|
|
475
|
-
expect(
|
|
476
|
-
expect(
|
|
477
|
-
expect(
|
|
478
|
-
expect(
|
|
474
|
+
expect(dut.data.at(0)).toBe(0xAAn);
|
|
475
|
+
expect(dut.data.at(1)).toBe(0xBBn);
|
|
476
|
+
expect(dut.data.at(2)).toBe(0xCCn);
|
|
477
|
+
expect(dut.data.at(3)).toBe(0xDDn);
|
|
478
|
+
expect(dut.data.length).toBe(4);
|
|
479
479
|
});
|
|
480
480
|
});
|
|
481
481
|
|
|
@@ -515,20 +515,20 @@ describe("createDut — interface ports", () => {
|
|
|
515
515
|
const state: DirtyState = { dirty: false };
|
|
516
516
|
const dut = createDut<{
|
|
517
517
|
bus: {
|
|
518
|
-
addr:
|
|
519
|
-
data:
|
|
520
|
-
valid:
|
|
521
|
-
readonly ready:
|
|
518
|
+
addr: bigint;
|
|
519
|
+
data: bigint;
|
|
520
|
+
valid: bigint;
|
|
521
|
+
readonly ready: bigint;
|
|
522
522
|
};
|
|
523
523
|
}>(buffer, layout, ports, handle, state);
|
|
524
524
|
|
|
525
|
-
dut.bus.addr =
|
|
526
|
-
dut.bus.data =
|
|
527
|
-
dut.bus.valid =
|
|
525
|
+
dut.bus.addr = 0x1000n;
|
|
526
|
+
dut.bus.data = 0xFFn;
|
|
527
|
+
dut.bus.valid = 1n;
|
|
528
528
|
|
|
529
|
-
expect(dut.bus.addr).toBe(
|
|
530
|
-
expect(dut.bus.data).toBe(
|
|
531
|
-
expect(dut.bus.ready).toBe(
|
|
529
|
+
expect(dut.bus.addr).toBe(0x1000n);
|
|
530
|
+
expect(dut.bus.data).toBe(0xFFn);
|
|
531
|
+
expect(dut.bus.ready).toBe(1n);
|
|
532
532
|
expect(handle.evalComb).toHaveBeenCalledTimes(1);
|
|
533
533
|
});
|
|
534
534
|
});
|
package/src/dut.ts
CHANGED
|
@@ -116,27 +116,27 @@ function writeBigInt(
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
/** Read a signal value from the DataView.
|
|
119
|
+
/** Read a signal value from the DataView. Always returns bigint. */
|
|
120
120
|
function readSignal(
|
|
121
121
|
view: DataView,
|
|
122
122
|
sig: SignalLayout,
|
|
123
|
-
):
|
|
123
|
+
): bigint {
|
|
124
124
|
if (sig.width <= 53) {
|
|
125
|
-
return readNumber(view, sig.offset, sig.width);
|
|
125
|
+
return BigInt(readNumber(view, sig.offset, sig.width));
|
|
126
126
|
}
|
|
127
127
|
return readBigInt(view, sig.offset, sig.byteSize);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
/** Write a signal value to the DataView. Accepts number
|
|
130
|
+
/** Write a signal value to the DataView. Accepts bigint (number accepted for compat). */
|
|
131
131
|
function writeSignal(
|
|
132
132
|
view: DataView,
|
|
133
133
|
sig: SignalLayout,
|
|
134
|
-
value:
|
|
134
|
+
value: bigint | number,
|
|
135
135
|
): void {
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
const bigVal = typeof value === "bigint" ? value : BigInt(value);
|
|
137
|
+
if (sig.width <= 53) {
|
|
138
|
+
writeNumber(view, sig.offset, sig.width, Number(bigVal));
|
|
138
139
|
} else {
|
|
139
|
-
const bigVal = typeof value === "bigint" ? value : BigInt(value);
|
|
140
140
|
writeBigInt(view, sig.offset, sig.byteSize, bigVal);
|
|
141
141
|
}
|
|
142
142
|
}
|
|
@@ -162,11 +162,8 @@ function writeFourState(
|
|
|
162
162
|
/** Write all-X mask for a signal. */
|
|
163
163
|
function writeAllX(view: DataView, sig: SignalLayout): void {
|
|
164
164
|
// Value = 0, mask = all 1s
|
|
165
|
-
writeSignal(view, sig,
|
|
166
|
-
const allOnes =
|
|
167
|
-
sig.width <= 53
|
|
168
|
-
? (sig.width === 53 ? Number.MAX_SAFE_INTEGER : (1 << sig.width) - 1)
|
|
169
|
-
: (1n << BigInt(sig.width)) - 1n;
|
|
165
|
+
writeSignal(view, sig, 0n);
|
|
166
|
+
const allOnes = (1n << BigInt(sig.width)) - 1n;
|
|
170
167
|
const maskLayout: SignalLayout = {
|
|
171
168
|
offset: sig.offset + sig.byteSize,
|
|
172
169
|
width: sig.width,
|
|
@@ -348,7 +345,7 @@ function defineSignalProperty(
|
|
|
348
345
|
const isInput = port?.direction === "input";
|
|
349
346
|
|
|
350
347
|
Object.defineProperty(target, name, {
|
|
351
|
-
get():
|
|
348
|
+
get(): bigint {
|
|
352
349
|
// Output reads: lazy evalComb if dirty
|
|
353
350
|
if (state.dirty && !isInput) {
|
|
354
351
|
handle.evalComb();
|
|
@@ -357,7 +354,7 @@ function defineSignalProperty(
|
|
|
357
354
|
return readSignal(view, sig);
|
|
358
355
|
},
|
|
359
356
|
|
|
360
|
-
set(value:
|
|
357
|
+
set(value: bigint | number | symbol | FourStateValue) {
|
|
361
358
|
if (isOutput) {
|
|
362
359
|
throw new Error(`Cannot write to output port '${name}'`);
|
|
363
360
|
}
|
|
@@ -373,7 +370,8 @@ function defineSignalProperty(
|
|
|
373
370
|
}
|
|
374
371
|
writeFourState(view, sig, value);
|
|
375
372
|
} else {
|
|
376
|
-
|
|
373
|
+
const bigVal = typeof value === "bigint" ? value : BigInt(value as number);
|
|
374
|
+
writeSignal(view, sig, bigVal);
|
|
377
375
|
// Clear mask when writing a defined value to a 4-state signal
|
|
378
376
|
if (sig.is4state) {
|
|
379
377
|
const maskLayout: SignalLayout = {
|
|
@@ -383,7 +381,7 @@ function defineSignalProperty(
|
|
|
383
381
|
is4state: false,
|
|
384
382
|
direction: sig.direction,
|
|
385
383
|
};
|
|
386
|
-
writeSignal(view, maskLayout,
|
|
384
|
+
writeSignal(view, maskLayout, 0n);
|
|
387
385
|
}
|
|
388
386
|
}
|
|
389
387
|
|
|
@@ -460,19 +458,19 @@ function createArrayDut(
|
|
|
460
458
|
return {
|
|
461
459
|
length: totalElements,
|
|
462
460
|
|
|
463
|
-
at(i: number):
|
|
461
|
+
at(i: number): bigint {
|
|
464
462
|
if (state.dirty && !isInput) {
|
|
465
463
|
handle.evalComb();
|
|
466
464
|
state.dirty = false;
|
|
467
465
|
}
|
|
468
466
|
const offset = baseOffset + i * elementByteSize;
|
|
469
467
|
if (elementWidth <= 53) {
|
|
470
|
-
return readNumber(view, offset, elementWidth);
|
|
468
|
+
return BigInt(readNumber(view, offset, elementWidth));
|
|
471
469
|
}
|
|
472
470
|
return readBigInt(view, offset, elementByteSize);
|
|
473
471
|
},
|
|
474
472
|
|
|
475
|
-
set(i: number, value:
|
|
473
|
+
set(i: number, value: bigint | number | symbol | FourStateValue): void {
|
|
476
474
|
if (isOutput) {
|
|
477
475
|
throw new Error("Cannot write to output array port");
|
|
478
476
|
}
|
|
@@ -495,13 +493,20 @@ function createArrayDut(
|
|
|
495
493
|
is4state, direction: baseSig.direction,
|
|
496
494
|
};
|
|
497
495
|
writeFourState(view, elemSig, value);
|
|
498
|
-
} else if (elementWidth <= 53 && typeof value === "number") {
|
|
499
|
-
writeNumber(view, offset, elementWidth, value);
|
|
500
|
-
if (is4state) writeNumber(view, offset + elementByteSize, elementWidth, 0);
|
|
501
496
|
} else {
|
|
502
497
|
const bigVal = typeof value === "bigint" ? value : BigInt(value as number);
|
|
503
|
-
|
|
504
|
-
|
|
498
|
+
const elemSig: SignalLayout = {
|
|
499
|
+
offset, width: elementWidth, byteSize: elementByteSize,
|
|
500
|
+
is4state, direction: baseSig.direction,
|
|
501
|
+
};
|
|
502
|
+
writeSignal(view, elemSig, bigVal);
|
|
503
|
+
if (is4state) {
|
|
504
|
+
const maskSig: SignalLayout = {
|
|
505
|
+
offset: offset + elementByteSize, width: elementWidth,
|
|
506
|
+
byteSize: elementByteSize, is4state: false, direction: baseSig.direction,
|
|
507
|
+
};
|
|
508
|
+
writeSignal(view, maskSig, 0n);
|
|
509
|
+
}
|
|
505
510
|
}
|
|
506
511
|
state.dirty = true;
|
|
507
512
|
},
|
|
@@ -519,7 +524,7 @@ function createArrayDut(
|
|
|
519
524
|
export function readFourState(
|
|
520
525
|
buffer: ArrayBuffer | SharedArrayBuffer,
|
|
521
526
|
sig: SignalLayout,
|
|
522
|
-
): [value:
|
|
527
|
+
): [value: bigint, mask: bigint] {
|
|
523
528
|
if (!sig.is4state) {
|
|
524
529
|
throw new Error("Signal is not 4-state");
|
|
525
530
|
}
|
package/src/e2e.bench.ts
CHANGED
|
@@ -39,8 +39,8 @@ const CODE = `
|
|
|
39
39
|
`;
|
|
40
40
|
|
|
41
41
|
interface TopPorts {
|
|
42
|
-
rst:
|
|
43
|
-
readonly cnt: { at(i: number):
|
|
42
|
+
rst: bigint;
|
|
43
|
+
readonly cnt: { at(i: number): bigint; readonly length: number };
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
describe("simulation", () => {
|
|
@@ -56,9 +56,9 @@ describe("simulation", () => {
|
|
|
56
56
|
const sim = Simulator.fromSource<TopPorts>(CODE, "Top");
|
|
57
57
|
|
|
58
58
|
// Reset sequence
|
|
59
|
-
sim.dut.rst =
|
|
59
|
+
sim.dut.rst = 1n;
|
|
60
60
|
sim.tick();
|
|
61
|
-
sim.dut.rst =
|
|
61
|
+
sim.dut.rst = 0n;
|
|
62
62
|
sim.tick();
|
|
63
63
|
|
|
64
64
|
afterAll(() => {
|
|
@@ -81,7 +81,7 @@ describe("simulation", () => {
|
|
|
81
81
|
|
|
82
82
|
// Testbench pattern: write input + tick + read back
|
|
83
83
|
bench("testbench_tick_top_n1000_x1", () => {
|
|
84
|
-
sim.dut.rst =
|
|
84
|
+
sim.dut.rst = 0n;
|
|
85
85
|
sim.tick();
|
|
86
86
|
// biome-ignore lint: read to measure full testbench cycle
|
|
87
87
|
sim.dut.rst;
|
|
@@ -91,7 +91,7 @@ describe("simulation", () => {
|
|
|
91
91
|
"testbench_tick_top_n1000_x1000000",
|
|
92
92
|
() => {
|
|
93
93
|
for (let i = 0; i < 1_000_000; i++) {
|
|
94
|
-
sim.dut.rst =
|
|
94
|
+
sim.dut.rst = 0n;
|
|
95
95
|
sim.tick();
|
|
96
96
|
// biome-ignore lint: read to measure full testbench cycle
|
|
97
97
|
sim.dut.rst;
|
|
@@ -116,9 +116,9 @@ describe("simulation", () => {
|
|
|
116
116
|
const simArr = Simulator.create<TopPorts>(TopModule, {
|
|
117
117
|
__nativeCreate: createSimulatorBridge(addon),
|
|
118
118
|
});
|
|
119
|
-
simArr.dut.rst =
|
|
119
|
+
simArr.dut.rst = 1n;
|
|
120
120
|
simArr.tick();
|
|
121
|
-
simArr.dut.rst =
|
|
121
|
+
simArr.dut.rst = 0n;
|
|
122
122
|
simArr.tick();
|
|
123
123
|
|
|
124
124
|
afterAll(() => {
|
|
@@ -126,7 +126,7 @@ describe("simulation", () => {
|
|
|
126
126
|
});
|
|
127
127
|
|
|
128
128
|
bench("testbench_array_tick_top_n1000_x1", () => {
|
|
129
|
-
simArr.dut.rst =
|
|
129
|
+
simArr.dut.rst = 0n;
|
|
130
130
|
simArr.tick();
|
|
131
131
|
// biome-ignore lint: read array element to measure .at() overhead
|
|
132
132
|
simArr.dut.cnt.at(0);
|
|
@@ -136,7 +136,7 @@ describe("simulation", () => {
|
|
|
136
136
|
"testbench_array_tick_top_n1000_x1000000",
|
|
137
137
|
() => {
|
|
138
138
|
for (let i = 0; i < 1_000_000; i++) {
|
|
139
|
-
simArr.dut.rst =
|
|
139
|
+
simArr.dut.rst = 0n;
|
|
140
140
|
simArr.tick();
|
|
141
141
|
// biome-ignore lint: read array element to measure .at() overhead
|
|
142
142
|
simArr.dut.cnt.at(0);
|
|
@@ -155,9 +155,9 @@ describe("simulation", () => {
|
|
|
155
155
|
describe("overhead", () => {
|
|
156
156
|
// Simulator.tick — same as Rust simulator_tick_x10000
|
|
157
157
|
const simTick = Simulator.fromSource<TopPorts>(CODE, "Top");
|
|
158
|
-
simTick.dut.rst =
|
|
158
|
+
simTick.dut.rst = 1n;
|
|
159
159
|
simTick.tick();
|
|
160
|
-
simTick.dut.rst =
|
|
160
|
+
simTick.dut.rst = 0n;
|
|
161
161
|
simTick.tick();
|
|
162
162
|
|
|
163
163
|
afterAll(() => {
|
|
@@ -270,18 +270,18 @@ describe("testbench-helpers", () => {
|
|
|
270
270
|
`;
|
|
271
271
|
|
|
272
272
|
interface CounterPorts {
|
|
273
|
-
rst:
|
|
274
|
-
en:
|
|
275
|
-
readonly count:
|
|
273
|
+
rst: bigint;
|
|
274
|
+
en: bigint;
|
|
275
|
+
readonly count: bigint;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
// waitForCycles benchmark
|
|
279
279
|
const simWait = Simulation.fromSource<CounterPorts>(COUNTER_CODE, "Counter");
|
|
280
280
|
simWait.addClock("clk", { period: 10 });
|
|
281
|
-
simWait.dut.rst =
|
|
281
|
+
simWait.dut.rst = 1n;
|
|
282
282
|
simWait.runUntil(20);
|
|
283
|
-
simWait.dut.rst =
|
|
284
|
-
simWait.dut.en =
|
|
283
|
+
simWait.dut.rst = 0n;
|
|
284
|
+
simWait.dut.en = 1n;
|
|
285
285
|
|
|
286
286
|
afterAll(() => {
|
|
287
287
|
simWait.dispose();
|
|
@@ -308,10 +308,10 @@ describe("testbench-helpers", () => {
|
|
|
308
308
|
// runUntil: fast Rust path vs guarded TS path
|
|
309
309
|
const simRun = Simulation.fromSource<CounterPorts>(COUNTER_CODE, "Counter");
|
|
310
310
|
simRun.addClock("clk", { period: 10 });
|
|
311
|
-
simRun.dut.rst =
|
|
311
|
+
simRun.dut.rst = 1n;
|
|
312
312
|
simRun.runUntil(20);
|
|
313
|
-
simRun.dut.rst =
|
|
314
|
-
simRun.dut.en =
|
|
313
|
+
simRun.dut.rst = 0n;
|
|
314
|
+
simRun.dut.en = 1n;
|
|
315
315
|
|
|
316
316
|
afterAll(() => {
|
|
317
317
|
simRun.dispose();
|
|
@@ -363,17 +363,17 @@ describe("optimize-flag", () => {
|
|
|
363
363
|
);
|
|
364
364
|
|
|
365
365
|
const simNoOpt = Simulator.fromSource<TopPorts>(CODE, "Top");
|
|
366
|
-
simNoOpt.dut.rst =
|
|
366
|
+
simNoOpt.dut.rst = 1n;
|
|
367
367
|
simNoOpt.tick();
|
|
368
|
-
simNoOpt.dut.rst =
|
|
368
|
+
simNoOpt.dut.rst = 0n;
|
|
369
369
|
simNoOpt.tick();
|
|
370
370
|
|
|
371
371
|
const simOpt = Simulator.fromSource<TopPorts>(CODE, "Top", {
|
|
372
372
|
optimize: true,
|
|
373
373
|
});
|
|
374
|
-
simOpt.dut.rst =
|
|
374
|
+
simOpt.dut.rst = 1n;
|
|
375
375
|
simOpt.tick();
|
|
376
|
-
simOpt.dut.rst =
|
|
376
|
+
simOpt.dut.rst = 0n;
|
|
377
377
|
simOpt.tick();
|
|
378
378
|
|
|
379
379
|
afterAll(() => {
|