@celox-sim/celox 0.1.5 → 0.1.6
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 +13 -6
- package/dist/dut.d.ts.map +1 -1
- package/dist/dut.js +79 -6
- 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 +31 -13
- package/dist/simulator.js.map +1 -1
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/src/dut.ts +93 -5
- package/src/e2e.bench.ts +164 -1
- package/src/e2e.test.ts +432 -30
- package/src/index.ts +10 -2
- package/src/napi-helpers.ts +224 -22
- package/src/simulation.test.ts +213 -5
- package/src/simulation.ts +198 -13
- package/src/simulator.ts +38 -10
- package/src/types.ts +51 -0
package/dist/types.d.ts
CHANGED
|
@@ -47,6 +47,10 @@ export interface SignalLayout {
|
|
|
47
47
|
/** If true, an equal-sized mask follows immediately after the value. */
|
|
48
48
|
readonly is4state: boolean;
|
|
49
49
|
readonly direction: "input" | "output" | "inout";
|
|
50
|
+
/** The Veryl type kind (e.g. "clock", "reset_async_high", "logic"). */
|
|
51
|
+
readonly typeKind?: string;
|
|
52
|
+
/** For reset signals, the name of the associated clock (from FfDeclaration). */
|
|
53
|
+
readonly associatedClock?: string;
|
|
50
54
|
}
|
|
51
55
|
/**
|
|
52
56
|
* Opaque handle returned by NAPI for event-based simulation.
|
|
@@ -69,6 +73,7 @@ export interface NativeSimulationHandle {
|
|
|
69
73
|
runUntil(endTime: number): void;
|
|
70
74
|
step(): number | null;
|
|
71
75
|
time(): number;
|
|
76
|
+
nextEventTime(): number | null;
|
|
72
77
|
evalComb(): void;
|
|
73
78
|
dump(timestamp: number): void;
|
|
74
79
|
dispose(): void;
|
|
@@ -91,12 +96,24 @@ export interface CreateResult<H extends NativeHandle = NativeHandle> {
|
|
|
91
96
|
readonly events: Record<string, number>;
|
|
92
97
|
/** Native control handle. */
|
|
93
98
|
readonly handle: H;
|
|
99
|
+
/** Full instance hierarchy (optional — present when NAPI provides it). */
|
|
100
|
+
readonly hierarchy?: import("./napi-helpers.js").HierarchyNode;
|
|
94
101
|
}
|
|
95
102
|
export interface SimulatorOptions {
|
|
96
103
|
/** Enable 4-state (X/Z) simulation. Default: false. */
|
|
97
104
|
fourState?: boolean;
|
|
98
105
|
/** Path to write VCD waveform output. */
|
|
99
106
|
vcd?: string;
|
|
107
|
+
/** Enable Cranelift optimization passes. */
|
|
108
|
+
optimize?: boolean;
|
|
109
|
+
/** False-loop declarations to ignore during compilation. */
|
|
110
|
+
falseLoops?: LoopBreak[];
|
|
111
|
+
/** True-loop declarations with convergence limits. */
|
|
112
|
+
trueLoops?: TrueLoopSpec[];
|
|
113
|
+
/** Clock polarity. Default: "posedge". */
|
|
114
|
+
clockType?: "posedge" | "negedge";
|
|
115
|
+
/** Reset type. Default: "async_low". */
|
|
116
|
+
resetType?: "async_high" | "async_low" | "sync_high" | "sync_low";
|
|
100
117
|
}
|
|
101
118
|
/** A resolved event reference for use with `tick()`. */
|
|
102
119
|
export interface EventHandle {
|
|
@@ -114,4 +131,21 @@ export interface FourStateValue {
|
|
|
114
131
|
/** Construct a 4-state value. Mask bits set to 1 indicate X. */
|
|
115
132
|
export declare function FourState(value: number | bigint, mask: number | bigint): FourStateValue;
|
|
116
133
|
export declare function isFourStateValue(v: unknown): v is FourStateValue;
|
|
134
|
+
/**
|
|
135
|
+
* Thrown when a simulation helper exceeds its step budget.
|
|
136
|
+
*/
|
|
137
|
+
export declare class SimulationTimeoutError extends Error {
|
|
138
|
+
readonly time: number;
|
|
139
|
+
readonly steps: number;
|
|
140
|
+
constructor(message: string, time: number, steps: number);
|
|
141
|
+
}
|
|
142
|
+
/** Specifies a false-loop to ignore during compilation. */
|
|
143
|
+
export interface LoopBreak {
|
|
144
|
+
from: string;
|
|
145
|
+
to: string;
|
|
146
|
+
}
|
|
147
|
+
/** Specifies a true-loop with a convergence iteration limit. */
|
|
148
|
+
export interface TrueLoopSpec extends LoopBreak {
|
|
149
|
+
maxIter: number;
|
|
150
|
+
}
|
|
117
151
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/D,QAAQ,CAAC,cAAc,EAAE,IAAI,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC;CAC1B;AAED,qDAAqD;AACrD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACjD,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CAC/C;AAMD;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -20,4 +20,20 @@ export function isFourStateValue(v) {
|
|
|
20
20
|
v !== null &&
|
|
21
21
|
v.__fourState === true);
|
|
22
22
|
}
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Simulation timeout error
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
/**
|
|
27
|
+
* Thrown when a simulation helper exceeds its step budget.
|
|
28
|
+
*/
|
|
29
|
+
export class SimulationTimeoutError extends Error {
|
|
30
|
+
time;
|
|
31
|
+
steps;
|
|
32
|
+
constructor(message, time, steps) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.name = "SimulationTimeoutError";
|
|
35
|
+
this.time = time;
|
|
36
|
+
this.steps = steps;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
23
39
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiJH,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,mCAAmC;AACnC,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AASvC,gEAAgE;AAChE,MAAM,UAAU,SAAS,CACvB,KAAsB,EACtB,IAAqB;IAErB,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,CAAU;IACzC,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACT,CAAoB,CAAC,WAAW,KAAK,IAAI,CAC3C,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,2BAA2B;AAC3B,8EAA8E;AAE9E;;GAEG;AACH,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IACtC,IAAI,CAAS;IACb,KAAK,CAAS;IAEvB,YAAY,OAAe,EAAE,IAAY,EAAE,KAAa;QACtD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@celox-sim/celox",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "TypeScript runtime for Celox HDL simulation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@celox-sim/celox-napi": "0.1.
|
|
32
|
+
"@celox-sim/celox-napi": "0.1.6"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"vitest": ">=1.0.0"
|
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
|
// ---------------------------------------------------------------------------
|
|
@@ -183,11 +184,12 @@ function writeAllX(view: DataView, sig: SignalLayout): void {
|
|
|
183
184
|
/**
|
|
184
185
|
* Create a DUT accessor object with defineProperty-based getters/setters.
|
|
185
186
|
*
|
|
186
|
-
* @param buffer
|
|
187
|
-
* @param layout
|
|
188
|
-
* @param portDefs
|
|
189
|
-
* @param handle
|
|
190
|
-
* @param state
|
|
187
|
+
* @param buffer SharedArrayBuffer from NAPI create()
|
|
188
|
+
* @param layout Per-signal byte layout within the buffer
|
|
189
|
+
* @param portDefs Port metadata from the ModuleDefinition
|
|
190
|
+
* @param handle Native handle (for evalComb calls)
|
|
191
|
+
* @param state Shared dirty-tracking state
|
|
192
|
+
* @param hierarchy Optional hierarchy node for child instance access
|
|
191
193
|
*/
|
|
192
194
|
export function createDut<P>(
|
|
193
195
|
buffer: ArrayBuffer | SharedArrayBuffer,
|
|
@@ -195,6 +197,7 @@ export function createDut<P>(
|
|
|
195
197
|
portDefs: Record<string, PortInfo>,
|
|
196
198
|
handle: NativeHandle,
|
|
197
199
|
state: DirtyState,
|
|
200
|
+
hierarchy?: HierarchyNode,
|
|
198
201
|
): P {
|
|
199
202
|
const view = new DataView(buffer);
|
|
200
203
|
const obj = Object.create(null) as P;
|
|
@@ -243,6 +246,91 @@ export function createDut<P>(
|
|
|
243
246
|
defineSignalProperty(obj as object, name, view, sig, port, handle, state);
|
|
244
247
|
}
|
|
245
248
|
|
|
249
|
+
// Attach child instance accessors from hierarchy
|
|
250
|
+
if (hierarchy) {
|
|
251
|
+
for (const [childName, instances] of Object.entries(hierarchy.children)) {
|
|
252
|
+
if (instances.length === 1) {
|
|
253
|
+
const childDut = createChildDut(buffer, instances[0]!, handle, state);
|
|
254
|
+
Object.defineProperty(obj, childName, {
|
|
255
|
+
value: childDut,
|
|
256
|
+
enumerable: true,
|
|
257
|
+
configurable: false,
|
|
258
|
+
writable: false,
|
|
259
|
+
});
|
|
260
|
+
} else if (instances.length > 1) {
|
|
261
|
+
const childDuts = instances.map((inst) =>
|
|
262
|
+
createChildDut(buffer, inst, handle, state),
|
|
263
|
+
);
|
|
264
|
+
Object.defineProperty(obj, childName, {
|
|
265
|
+
value: childDuts,
|
|
266
|
+
enumerable: true,
|
|
267
|
+
configurable: false,
|
|
268
|
+
writable: false,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return obj;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Create a child instance DUT accessor from a HierarchyNode.
|
|
279
|
+
* Recursively creates accessors for the child's signals and its own children.
|
|
280
|
+
*/
|
|
281
|
+
export function createChildDut(
|
|
282
|
+
buffer: ArrayBuffer | SharedArrayBuffer,
|
|
283
|
+
hierarchy: HierarchyNode,
|
|
284
|
+
handle: NativeHandle,
|
|
285
|
+
state: DirtyState,
|
|
286
|
+
): object {
|
|
287
|
+
const view = new DataView(buffer);
|
|
288
|
+
const obj = Object.create(null);
|
|
289
|
+
|
|
290
|
+
// Define signal properties for this child instance
|
|
291
|
+
for (const [name, port] of Object.entries(hierarchy.ports)) {
|
|
292
|
+
if (port.type === "clock") continue;
|
|
293
|
+
|
|
294
|
+
const sig = hierarchy.forDut[name];
|
|
295
|
+
if (!sig) continue;
|
|
296
|
+
|
|
297
|
+
if (port.arrayDims && port.arrayDims.length > 0) {
|
|
298
|
+
const arrayObj = createArrayDut(view, sig, port, handle, state);
|
|
299
|
+
Object.defineProperty(obj, name, {
|
|
300
|
+
value: arrayObj,
|
|
301
|
+
enumerable: true,
|
|
302
|
+
configurable: false,
|
|
303
|
+
writable: false,
|
|
304
|
+
});
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
defineSignalProperty(obj, name, view, sig, port, handle, state);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Recursively attach children
|
|
312
|
+
for (const [childName, instances] of Object.entries(hierarchy.children)) {
|
|
313
|
+
if (instances.length === 1) {
|
|
314
|
+
const childDut = createChildDut(buffer, instances[0]!, handle, state);
|
|
315
|
+
Object.defineProperty(obj, childName, {
|
|
316
|
+
value: childDut,
|
|
317
|
+
enumerable: true,
|
|
318
|
+
configurable: false,
|
|
319
|
+
writable: false,
|
|
320
|
+
});
|
|
321
|
+
} else if (instances.length > 1) {
|
|
322
|
+
const childDuts = instances.map((inst) =>
|
|
323
|
+
createChildDut(buffer, inst, handle, state),
|
|
324
|
+
);
|
|
325
|
+
Object.defineProperty(obj, childName, {
|
|
326
|
+
value: childDuts,
|
|
327
|
+
enumerable: true,
|
|
328
|
+
configurable: false,
|
|
329
|
+
writable: false,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
246
334
|
return obj;
|
|
247
335
|
}
|
|
248
336
|
|
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,
|
|
@@ -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: number;
|
|
274
|
+
en: number;
|
|
275
|
+
readonly count: number;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// waitForCycles benchmark
|
|
279
|
+
const simWait = Simulation.fromSource<CounterPorts>(COUNTER_CODE, "Counter");
|
|
280
|
+
simWait.addClock("clk", { period: 10 });
|
|
281
|
+
simWait.dut.rst = 1;
|
|
282
|
+
simWait.runUntil(20);
|
|
283
|
+
simWait.dut.rst = 0;
|
|
284
|
+
simWait.dut.en = 1;
|
|
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 = 1;
|
|
312
|
+
simRun.runUntil(20);
|
|
313
|
+
simRun.dut.rst = 0;
|
|
314
|
+
simRun.dut.en = 1;
|
|
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 = 1;
|
|
367
|
+
simNoOpt.tick();
|
|
368
|
+
simNoOpt.dut.rst = 0;
|
|
369
|
+
simNoOpt.tick();
|
|
370
|
+
|
|
371
|
+
const simOpt = Simulator.fromSource<TopPorts>(CODE, "Top", {
|
|
372
|
+
optimize: true,
|
|
373
|
+
});
|
|
374
|
+
simOpt.dut.rst = 1;
|
|
375
|
+
simOpt.tick();
|
|
376
|
+
simOpt.dut.rst = 0;
|
|
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
|
+
});
|