@celox-sim/celox 0.1.5 → 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 +14 -7
- package/dist/dut.d.ts.map +1 -1
- package/dist/dut.js +103 -27
- package/dist/dut.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/napi-helpers.d.ts +62 -1
- package/dist/napi-helpers.d.ts.map +1 -1
- package/dist/napi-helpers.js +154 -19
- package/dist/napi-helpers.js.map +1 -1
- package/dist/simulation.d.ts +59 -3
- package/dist/simulation.d.ts.map +1 -1
- package/dist/simulation.js +162 -16
- package/dist/simulation.js.map +1 -1
- package/dist/simulator.d.ts +7 -1
- package/dist/simulator.d.ts.map +1 -1
- package/dist/simulator.js +35 -14
- package/dist/simulator.js.map +1 -1
- package/dist/types.d.ts +36 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +17 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/src/dut.test.ts +66 -66
- package/src/dut.ts +124 -31
- package/src/e2e.bench.ts +176 -13
- package/src/e2e.test.ts +632 -195
- package/src/index.ts +10 -2
- package/src/matchers.ts +4 -7
- package/src/napi-helpers.ts +224 -22
- package/src/simulation.test.ts +220 -12
- package/src/simulation.ts +198 -13
- package/src/simulator.test.ts +8 -8
- package/src/simulator.ts +43 -11
- package/src/types.ts +54 -3
package/src/dut.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
SignalLayout,
|
|
14
14
|
FourStateValue,
|
|
15
15
|
} from "./types.js";
|
|
16
|
+
import type { HierarchyNode } from "./napi-helpers.js";
|
|
16
17
|
import { isFourStateValue } from "./types.js";
|
|
17
18
|
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
@@ -115,27 +116,27 @@ function writeBigInt(
|
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
/** Read a signal value from the DataView.
|
|
119
|
+
/** Read a signal value from the DataView. Always returns bigint. */
|
|
119
120
|
function readSignal(
|
|
120
121
|
view: DataView,
|
|
121
122
|
sig: SignalLayout,
|
|
122
|
-
):
|
|
123
|
+
): bigint {
|
|
123
124
|
if (sig.width <= 53) {
|
|
124
|
-
return readNumber(view, sig.offset, sig.width);
|
|
125
|
+
return BigInt(readNumber(view, sig.offset, sig.width));
|
|
125
126
|
}
|
|
126
127
|
return readBigInt(view, sig.offset, sig.byteSize);
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
/** Write a signal value to the DataView. Accepts number
|
|
130
|
+
/** Write a signal value to the DataView. Accepts bigint (number accepted for compat). */
|
|
130
131
|
function writeSignal(
|
|
131
132
|
view: DataView,
|
|
132
133
|
sig: SignalLayout,
|
|
133
|
-
value:
|
|
134
|
+
value: bigint | number,
|
|
134
135
|
): void {
|
|
135
|
-
|
|
136
|
-
|
|
136
|
+
const bigVal = typeof value === "bigint" ? value : BigInt(value);
|
|
137
|
+
if (sig.width <= 53) {
|
|
138
|
+
writeNumber(view, sig.offset, sig.width, Number(bigVal));
|
|
137
139
|
} else {
|
|
138
|
-
const bigVal = typeof value === "bigint" ? value : BigInt(value);
|
|
139
140
|
writeBigInt(view, sig.offset, sig.byteSize, bigVal);
|
|
140
141
|
}
|
|
141
142
|
}
|
|
@@ -161,11 +162,8 @@ function writeFourState(
|
|
|
161
162
|
/** Write all-X mask for a signal. */
|
|
162
163
|
function writeAllX(view: DataView, sig: SignalLayout): void {
|
|
163
164
|
// Value = 0, mask = all 1s
|
|
164
|
-
writeSignal(view, sig,
|
|
165
|
-
const allOnes =
|
|
166
|
-
sig.width <= 53
|
|
167
|
-
? (sig.width === 53 ? Number.MAX_SAFE_INTEGER : (1 << sig.width) - 1)
|
|
168
|
-
: (1n << BigInt(sig.width)) - 1n;
|
|
165
|
+
writeSignal(view, sig, 0n);
|
|
166
|
+
const allOnes = (1n << BigInt(sig.width)) - 1n;
|
|
169
167
|
const maskLayout: SignalLayout = {
|
|
170
168
|
offset: sig.offset + sig.byteSize,
|
|
171
169
|
width: sig.width,
|
|
@@ -183,11 +181,12 @@ function writeAllX(view: DataView, sig: SignalLayout): void {
|
|
|
183
181
|
/**
|
|
184
182
|
* Create a DUT accessor object with defineProperty-based getters/setters.
|
|
185
183
|
*
|
|
186
|
-
* @param buffer
|
|
187
|
-
* @param layout
|
|
188
|
-
* @param portDefs
|
|
189
|
-
* @param handle
|
|
190
|
-
* @param state
|
|
184
|
+
* @param buffer SharedArrayBuffer from NAPI create()
|
|
185
|
+
* @param layout Per-signal byte layout within the buffer
|
|
186
|
+
* @param portDefs Port metadata from the ModuleDefinition
|
|
187
|
+
* @param handle Native handle (for evalComb calls)
|
|
188
|
+
* @param state Shared dirty-tracking state
|
|
189
|
+
* @param hierarchy Optional hierarchy node for child instance access
|
|
191
190
|
*/
|
|
192
191
|
export function createDut<P>(
|
|
193
192
|
buffer: ArrayBuffer | SharedArrayBuffer,
|
|
@@ -195,6 +194,7 @@ export function createDut<P>(
|
|
|
195
194
|
portDefs: Record<string, PortInfo>,
|
|
196
195
|
handle: NativeHandle,
|
|
197
196
|
state: DirtyState,
|
|
197
|
+
hierarchy?: HierarchyNode,
|
|
198
198
|
): P {
|
|
199
199
|
const view = new DataView(buffer);
|
|
200
200
|
const obj = Object.create(null) as P;
|
|
@@ -243,6 +243,91 @@ export function createDut<P>(
|
|
|
243
243
|
defineSignalProperty(obj as object, name, view, sig, port, handle, state);
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
// Attach child instance accessors from hierarchy
|
|
247
|
+
if (hierarchy) {
|
|
248
|
+
for (const [childName, instances] of Object.entries(hierarchy.children)) {
|
|
249
|
+
if (instances.length === 1) {
|
|
250
|
+
const childDut = createChildDut(buffer, instances[0]!, handle, state);
|
|
251
|
+
Object.defineProperty(obj, childName, {
|
|
252
|
+
value: childDut,
|
|
253
|
+
enumerable: true,
|
|
254
|
+
configurable: false,
|
|
255
|
+
writable: false,
|
|
256
|
+
});
|
|
257
|
+
} else if (instances.length > 1) {
|
|
258
|
+
const childDuts = instances.map((inst) =>
|
|
259
|
+
createChildDut(buffer, inst, handle, state),
|
|
260
|
+
);
|
|
261
|
+
Object.defineProperty(obj, childName, {
|
|
262
|
+
value: childDuts,
|
|
263
|
+
enumerable: true,
|
|
264
|
+
configurable: false,
|
|
265
|
+
writable: false,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return obj;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Create a child instance DUT accessor from a HierarchyNode.
|
|
276
|
+
* Recursively creates accessors for the child's signals and its own children.
|
|
277
|
+
*/
|
|
278
|
+
export function createChildDut(
|
|
279
|
+
buffer: ArrayBuffer | SharedArrayBuffer,
|
|
280
|
+
hierarchy: HierarchyNode,
|
|
281
|
+
handle: NativeHandle,
|
|
282
|
+
state: DirtyState,
|
|
283
|
+
): object {
|
|
284
|
+
const view = new DataView(buffer);
|
|
285
|
+
const obj = Object.create(null);
|
|
286
|
+
|
|
287
|
+
// Define signal properties for this child instance
|
|
288
|
+
for (const [name, port] of Object.entries(hierarchy.ports)) {
|
|
289
|
+
if (port.type === "clock") continue;
|
|
290
|
+
|
|
291
|
+
const sig = hierarchy.forDut[name];
|
|
292
|
+
if (!sig) continue;
|
|
293
|
+
|
|
294
|
+
if (port.arrayDims && port.arrayDims.length > 0) {
|
|
295
|
+
const arrayObj = createArrayDut(view, sig, port, handle, state);
|
|
296
|
+
Object.defineProperty(obj, name, {
|
|
297
|
+
value: arrayObj,
|
|
298
|
+
enumerable: true,
|
|
299
|
+
configurable: false,
|
|
300
|
+
writable: false,
|
|
301
|
+
});
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
defineSignalProperty(obj, name, view, sig, port, handle, state);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Recursively attach children
|
|
309
|
+
for (const [childName, instances] of Object.entries(hierarchy.children)) {
|
|
310
|
+
if (instances.length === 1) {
|
|
311
|
+
const childDut = createChildDut(buffer, instances[0]!, handle, state);
|
|
312
|
+
Object.defineProperty(obj, childName, {
|
|
313
|
+
value: childDut,
|
|
314
|
+
enumerable: true,
|
|
315
|
+
configurable: false,
|
|
316
|
+
writable: false,
|
|
317
|
+
});
|
|
318
|
+
} else if (instances.length > 1) {
|
|
319
|
+
const childDuts = instances.map((inst) =>
|
|
320
|
+
createChildDut(buffer, inst, handle, state),
|
|
321
|
+
);
|
|
322
|
+
Object.defineProperty(obj, childName, {
|
|
323
|
+
value: childDuts,
|
|
324
|
+
enumerable: true,
|
|
325
|
+
configurable: false,
|
|
326
|
+
writable: false,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
246
331
|
return obj;
|
|
247
332
|
}
|
|
248
333
|
|
|
@@ -260,7 +345,7 @@ function defineSignalProperty(
|
|
|
260
345
|
const isInput = port?.direction === "input";
|
|
261
346
|
|
|
262
347
|
Object.defineProperty(target, name, {
|
|
263
|
-
get():
|
|
348
|
+
get(): bigint {
|
|
264
349
|
// Output reads: lazy evalComb if dirty
|
|
265
350
|
if (state.dirty && !isInput) {
|
|
266
351
|
handle.evalComb();
|
|
@@ -269,7 +354,7 @@ function defineSignalProperty(
|
|
|
269
354
|
return readSignal(view, sig);
|
|
270
355
|
},
|
|
271
356
|
|
|
272
|
-
set(value:
|
|
357
|
+
set(value: bigint | number | symbol | FourStateValue) {
|
|
273
358
|
if (isOutput) {
|
|
274
359
|
throw new Error(`Cannot write to output port '${name}'`);
|
|
275
360
|
}
|
|
@@ -285,7 +370,8 @@ function defineSignalProperty(
|
|
|
285
370
|
}
|
|
286
371
|
writeFourState(view, sig, value);
|
|
287
372
|
} else {
|
|
288
|
-
|
|
373
|
+
const bigVal = typeof value === "bigint" ? value : BigInt(value as number);
|
|
374
|
+
writeSignal(view, sig, bigVal);
|
|
289
375
|
// Clear mask when writing a defined value to a 4-state signal
|
|
290
376
|
if (sig.is4state) {
|
|
291
377
|
const maskLayout: SignalLayout = {
|
|
@@ -295,7 +381,7 @@ function defineSignalProperty(
|
|
|
295
381
|
is4state: false,
|
|
296
382
|
direction: sig.direction,
|
|
297
383
|
};
|
|
298
|
-
writeSignal(view, maskLayout,
|
|
384
|
+
writeSignal(view, maskLayout, 0n);
|
|
299
385
|
}
|
|
300
386
|
}
|
|
301
387
|
|
|
@@ -372,19 +458,19 @@ function createArrayDut(
|
|
|
372
458
|
return {
|
|
373
459
|
length: totalElements,
|
|
374
460
|
|
|
375
|
-
at(i: number):
|
|
461
|
+
at(i: number): bigint {
|
|
376
462
|
if (state.dirty && !isInput) {
|
|
377
463
|
handle.evalComb();
|
|
378
464
|
state.dirty = false;
|
|
379
465
|
}
|
|
380
466
|
const offset = baseOffset + i * elementByteSize;
|
|
381
467
|
if (elementWidth <= 53) {
|
|
382
|
-
return readNumber(view, offset, elementWidth);
|
|
468
|
+
return BigInt(readNumber(view, offset, elementWidth));
|
|
383
469
|
}
|
|
384
470
|
return readBigInt(view, offset, elementByteSize);
|
|
385
471
|
},
|
|
386
472
|
|
|
387
|
-
set(i: number, value:
|
|
473
|
+
set(i: number, value: bigint | number | symbol | FourStateValue): void {
|
|
388
474
|
if (isOutput) {
|
|
389
475
|
throw new Error("Cannot write to output array port");
|
|
390
476
|
}
|
|
@@ -407,13 +493,20 @@ function createArrayDut(
|
|
|
407
493
|
is4state, direction: baseSig.direction,
|
|
408
494
|
};
|
|
409
495
|
writeFourState(view, elemSig, value);
|
|
410
|
-
} else if (elementWidth <= 53 && typeof value === "number") {
|
|
411
|
-
writeNumber(view, offset, elementWidth, value);
|
|
412
|
-
if (is4state) writeNumber(view, offset + elementByteSize, elementWidth, 0);
|
|
413
496
|
} else {
|
|
414
497
|
const bigVal = typeof value === "bigint" ? value : BigInt(value as number);
|
|
415
|
-
|
|
416
|
-
|
|
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
|
+
}
|
|
417
510
|
}
|
|
418
511
|
state.dirty = true;
|
|
419
512
|
},
|
|
@@ -431,7 +524,7 @@ function createArrayDut(
|
|
|
431
524
|
export function readFourState(
|
|
432
525
|
buffer: ArrayBuffer | SharedArrayBuffer,
|
|
433
526
|
sig: SignalLayout,
|
|
434
|
-
): [value:
|
|
527
|
+
): [value: bigint, mask: bigint] {
|
|
435
528
|
if (!sig.is4state) {
|
|
436
529
|
throw new Error("Signal is not 4-state");
|
|
437
530
|
}
|
package/src/e2e.bench.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { bench, describe, afterAll } from "vitest";
|
|
13
13
|
import { Simulator } from "./simulator.js";
|
|
14
14
|
import { Simulation } from "./simulation.js";
|
|
15
|
-
import type { ModuleDefinition } from "./types.js";
|
|
15
|
+
import type { ModuleDefinition, SimulationTimeoutError } from "./types.js";
|
|
16
16
|
import {
|
|
17
17
|
loadNativeAddon,
|
|
18
18
|
createSimulatorBridge,
|
|
@@ -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(() => {
|
|
@@ -238,3 +238,166 @@ describe("simulation-time-based", () => {
|
|
|
238
238
|
{ iterations: 3, time: 0 },
|
|
239
239
|
);
|
|
240
240
|
});
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Phase 3b: Testbench helpers benchmarks.
|
|
244
|
+
*
|
|
245
|
+
* Compares waitForCycles vs manual step loop, and runUntil with/without
|
|
246
|
+
* maxSteps guard to measure overhead.
|
|
247
|
+
*/
|
|
248
|
+
describe("testbench-helpers", () => {
|
|
249
|
+
const COUNTER_CODE = `
|
|
250
|
+
module Counter (
|
|
251
|
+
clk: input clock,
|
|
252
|
+
rst: input reset,
|
|
253
|
+
en: input logic,
|
|
254
|
+
count: output logic<8>,
|
|
255
|
+
) {
|
|
256
|
+
var count_r: logic<8>;
|
|
257
|
+
|
|
258
|
+
always_ff (clk, rst) {
|
|
259
|
+
if_reset {
|
|
260
|
+
count_r = 0;
|
|
261
|
+
} else if en {
|
|
262
|
+
count_r = count_r + 1;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
always_comb {
|
|
267
|
+
count = count_r;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
`;
|
|
271
|
+
|
|
272
|
+
interface CounterPorts {
|
|
273
|
+
rst: bigint;
|
|
274
|
+
en: bigint;
|
|
275
|
+
readonly count: bigint;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// waitForCycles benchmark
|
|
279
|
+
const simWait = Simulation.fromSource<CounterPorts>(COUNTER_CODE, "Counter");
|
|
280
|
+
simWait.addClock("clk", { period: 10 });
|
|
281
|
+
simWait.dut.rst = 1n;
|
|
282
|
+
simWait.runUntil(20);
|
|
283
|
+
simWait.dut.rst = 0n;
|
|
284
|
+
simWait.dut.en = 1n;
|
|
285
|
+
|
|
286
|
+
afterAll(() => {
|
|
287
|
+
simWait.dispose();
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
bench(
|
|
291
|
+
"waitForCycles_x1000",
|
|
292
|
+
() => {
|
|
293
|
+
simWait.waitForCycles("clk", 1000);
|
|
294
|
+
},
|
|
295
|
+
{ iterations: 3, time: 0 },
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
bench(
|
|
299
|
+
"manual_step_loop_x2000",
|
|
300
|
+
() => {
|
|
301
|
+
for (let i = 0; i < 2000; i++) {
|
|
302
|
+
simWait.step();
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
{ iterations: 3, time: 0 },
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
// runUntil: fast Rust path vs guarded TS path
|
|
309
|
+
const simRun = Simulation.fromSource<CounterPorts>(COUNTER_CODE, "Counter");
|
|
310
|
+
simRun.addClock("clk", { period: 10 });
|
|
311
|
+
simRun.dut.rst = 1n;
|
|
312
|
+
simRun.runUntil(20);
|
|
313
|
+
simRun.dut.rst = 0n;
|
|
314
|
+
simRun.dut.en = 1n;
|
|
315
|
+
|
|
316
|
+
afterAll(() => {
|
|
317
|
+
simRun.dispose();
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
bench(
|
|
321
|
+
"runUntil_fast_path_100000",
|
|
322
|
+
() => {
|
|
323
|
+
const base = simRun.time();
|
|
324
|
+
simRun.runUntil(base + 100_000);
|
|
325
|
+
},
|
|
326
|
+
{ iterations: 3, time: 0 },
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
bench(
|
|
330
|
+
"runUntil_guarded_100000",
|
|
331
|
+
() => {
|
|
332
|
+
const base = simRun.time();
|
|
333
|
+
simRun.runUntil(base + 100_000, { maxSteps: 1_000_000 });
|
|
334
|
+
},
|
|
335
|
+
{ iterations: 3, time: 0 },
|
|
336
|
+
);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Phase 3c: Optimize flag benchmarks.
|
|
341
|
+
*
|
|
342
|
+
* Compares build time and tick performance with and without optimization.
|
|
343
|
+
*/
|
|
344
|
+
describe("optimize-flag", () => {
|
|
345
|
+
bench(
|
|
346
|
+
"build_without_optimize",
|
|
347
|
+
() => {
|
|
348
|
+
const sim = Simulator.fromSource<TopPorts>(CODE, "Top");
|
|
349
|
+
sim.dispose();
|
|
350
|
+
},
|
|
351
|
+
{ iterations: 3, time: 0 },
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
bench(
|
|
355
|
+
"build_with_optimize",
|
|
356
|
+
() => {
|
|
357
|
+
const sim = Simulator.fromSource<TopPorts>(CODE, "Top", {
|
|
358
|
+
optimize: true,
|
|
359
|
+
});
|
|
360
|
+
sim.dispose();
|
|
361
|
+
},
|
|
362
|
+
{ iterations: 3, time: 0 },
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
const simNoOpt = Simulator.fromSource<TopPorts>(CODE, "Top");
|
|
366
|
+
simNoOpt.dut.rst = 1n;
|
|
367
|
+
simNoOpt.tick();
|
|
368
|
+
simNoOpt.dut.rst = 0n;
|
|
369
|
+
simNoOpt.tick();
|
|
370
|
+
|
|
371
|
+
const simOpt = Simulator.fromSource<TopPorts>(CODE, "Top", {
|
|
372
|
+
optimize: true,
|
|
373
|
+
});
|
|
374
|
+
simOpt.dut.rst = 1n;
|
|
375
|
+
simOpt.tick();
|
|
376
|
+
simOpt.dut.rst = 0n;
|
|
377
|
+
simOpt.tick();
|
|
378
|
+
|
|
379
|
+
afterAll(() => {
|
|
380
|
+
simNoOpt.dispose();
|
|
381
|
+
simOpt.dispose();
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
bench(
|
|
385
|
+
"tick_x10000_without_optimize",
|
|
386
|
+
() => {
|
|
387
|
+
for (let i = 0; i < 10_000; i++) {
|
|
388
|
+
simNoOpt.tick();
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
{ iterations: 3, time: 0 },
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
bench(
|
|
395
|
+
"tick_x10000_with_optimize",
|
|
396
|
+
() => {
|
|
397
|
+
for (let i = 0; i < 10_000; i++) {
|
|
398
|
+
simOpt.tick();
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
{ iterations: 3, time: 0 },
|
|
402
|
+
);
|
|
403
|
+
});
|