@celox-sim/celox 0.1.12 → 0.1.14
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 +32 -10
- package/dist/dut.js.map +1 -1
- package/dist/index.d.ts +8 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -10
- package/dist/index.js.map +1 -1
- package/dist/napi-bridge.d.ts +1 -1
- package/dist/napi-bridge.d.ts.map +1 -1
- package/dist/napi-bridge.js +1 -1
- package/dist/napi-bridge.js.map +1 -1
- package/dist/napi-helpers.d.ts +11 -2
- package/dist/napi-helpers.d.ts.map +1 -1
- package/dist/napi-helpers.js +23 -0
- package/dist/napi-helpers.js.map +1 -1
- package/dist/simulation.d.ts.map +1 -1
- package/dist/simulation.js +29 -13
- package/dist/simulation.js.map +1 -1
- package/dist/simulator.d.ts.map +1 -1
- package/dist/simulator.js +28 -12
- package/dist/simulator.js.map +1 -1
- package/dist/types.d.ts +6 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/src/dut.test.ts +1040 -661
- package/src/dut.ts +580 -520
- package/src/e2e.bench.ts +627 -310
- package/src/e2e.test.ts +1872 -1550
- package/src/index.ts +46 -46
- package/src/matchers.ts +81 -81
- package/src/napi-bridge.ts +5 -5
- package/src/napi-helpers.ts +475 -400
- package/src/simulation.test.ts +395 -368
- package/src/simulation.ts +502 -430
- package/src/simulator.test.ts +201 -168
- package/src/simulator.ts +317 -267
- package/src/types.ts +102 -98
package/src/e2e.bench.ts
CHANGED
|
@@ -9,14 +9,23 @@
|
|
|
9
9
|
* 4. Simulator::tick vs Simulation::step overhead
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
12
|
+
import { readFileSync } from "node:fs";
|
|
13
|
+
import { dirname, resolve } from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
import { afterAll, bench, describe } from "vitest";
|
|
16
|
+
import { createSimulatorBridge, loadNativeAddon } from "./napi-helpers.js";
|
|
14
17
|
import { Simulation } from "./simulation.js";
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
import { Simulator } from "./simulator.js";
|
|
19
|
+
import type { ModuleDefinition } from "./types.js";
|
|
20
|
+
|
|
21
|
+
const __benchDir = dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
const VERYL_STD = resolve(
|
|
23
|
+
__benchDir,
|
|
24
|
+
"../../../deps/veryl/crates/std/veryl/src",
|
|
25
|
+
);
|
|
26
|
+
function readVeryl(...parts: string[]): string {
|
|
27
|
+
return readFileSync(resolve(VERYL_STD, ...parts), "utf8");
|
|
28
|
+
}
|
|
20
29
|
|
|
21
30
|
const CODE = `
|
|
22
31
|
module Top #(
|
|
@@ -39,111 +48,111 @@ const CODE = `
|
|
|
39
48
|
`;
|
|
40
49
|
|
|
41
50
|
interface TopPorts {
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
rst: bigint;
|
|
52
|
+
readonly cnt: { at(i: number): bigint; readonly length: number };
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
describe("simulation", () => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
56
|
+
bench(
|
|
57
|
+
"simulation_build_top_n1000",
|
|
58
|
+
() => {
|
|
59
|
+
const sim = Simulator.fromSource<TopPorts>(CODE, "Top");
|
|
60
|
+
sim.dispose();
|
|
61
|
+
},
|
|
62
|
+
{ iterations: 3, time: 0 },
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const sim = Simulator.fromSource<TopPorts>(CODE, "Top");
|
|
66
|
+
|
|
67
|
+
// Reset sequence
|
|
68
|
+
sim.dut.rst = 1n;
|
|
69
|
+
sim.tick();
|
|
70
|
+
sim.dut.rst = 0n;
|
|
71
|
+
sim.tick();
|
|
72
|
+
|
|
73
|
+
afterAll(() => {
|
|
74
|
+
sim.dispose();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
bench("simulation_tick_top_n1000_x1", () => {
|
|
78
|
+
sim.tick();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
bench(
|
|
82
|
+
"simulation_tick_top_n1000_x1000000",
|
|
83
|
+
() => {
|
|
84
|
+
for (let i = 0; i < 1_000_000; i++) {
|
|
85
|
+
sim.tick();
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{ iterations: 3, time: 0 },
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Testbench pattern: write input + tick + read back
|
|
92
|
+
bench("testbench_tick_top_n1000_x1", () => {
|
|
93
|
+
sim.dut.rst = 0n;
|
|
94
|
+
sim.tick();
|
|
95
|
+
//read to measure full testbench cycle
|
|
96
|
+
sim.dut.rst;
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
bench(
|
|
100
|
+
"testbench_tick_top_n1000_x1000000",
|
|
101
|
+
() => {
|
|
102
|
+
for (let i = 0; i < 1_000_000; i++) {
|
|
103
|
+
sim.dut.rst = 0n;
|
|
104
|
+
sim.tick();
|
|
105
|
+
//read to measure full testbench cycle
|
|
106
|
+
sim.dut.rst;
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{ iterations: 3, time: 0 },
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// Array access via .at() — use ModuleDefinition with arrayDims
|
|
113
|
+
const addon = loadNativeAddon();
|
|
114
|
+
const TopModule: ModuleDefinition<TopPorts> = {
|
|
115
|
+
__celox_module: true,
|
|
116
|
+
name: "Top",
|
|
117
|
+
source: CODE,
|
|
118
|
+
ports: {
|
|
119
|
+
clk: { direction: "input", type: "clock", width: 1 },
|
|
120
|
+
rst: { direction: "input", type: "reset", width: 1 },
|
|
121
|
+
cnt: { direction: "output", type: "logic", width: 32, arrayDims: [1000] },
|
|
122
|
+
},
|
|
123
|
+
events: ["clk"],
|
|
124
|
+
};
|
|
125
|
+
const simArr = Simulator.create<TopPorts>(TopModule, {
|
|
126
|
+
__nativeCreate: createSimulatorBridge(addon),
|
|
127
|
+
});
|
|
128
|
+
simArr.dut.rst = 1n;
|
|
129
|
+
simArr.tick();
|
|
130
|
+
simArr.dut.rst = 0n;
|
|
131
|
+
simArr.tick();
|
|
132
|
+
|
|
133
|
+
afterAll(() => {
|
|
134
|
+
simArr.dispose();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
bench("testbench_array_tick_top_n1000_x1", () => {
|
|
138
|
+
simArr.dut.rst = 0n;
|
|
139
|
+
simArr.tick();
|
|
140
|
+
//read array element to measure .at() overhead
|
|
141
|
+
simArr.dut.cnt.at(0);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
bench(
|
|
145
|
+
"testbench_array_tick_top_n1000_x1000000",
|
|
146
|
+
() => {
|
|
147
|
+
for (let i = 0; i < 1_000_000; i++) {
|
|
148
|
+
simArr.dut.rst = 0n;
|
|
149
|
+
simArr.tick();
|
|
150
|
+
//read array element to measure .at() overhead
|
|
151
|
+
simArr.dut.cnt.at(0);
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{ iterations: 3, time: 0 },
|
|
155
|
+
);
|
|
147
156
|
});
|
|
148
157
|
|
|
149
158
|
/**
|
|
@@ -153,45 +162,45 @@ describe("simulation", () => {
|
|
|
153
162
|
* scheduling overhead of the time-based API.
|
|
154
163
|
*/
|
|
155
164
|
describe("overhead", () => {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
165
|
+
// Simulator.tick — same as Rust simulator_tick_x10000
|
|
166
|
+
const simTick = Simulator.fromSource<TopPorts>(CODE, "Top");
|
|
167
|
+
simTick.dut.rst = 1n;
|
|
168
|
+
simTick.tick();
|
|
169
|
+
simTick.dut.rst = 0n;
|
|
170
|
+
simTick.tick();
|
|
171
|
+
|
|
172
|
+
afterAll(() => {
|
|
173
|
+
simTick.dispose();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
bench(
|
|
177
|
+
"simulator_tick_x10000",
|
|
178
|
+
() => {
|
|
179
|
+
for (let i = 0; i < 10_000; i++) {
|
|
180
|
+
simTick.tick();
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{ iterations: 3, time: 0 },
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
// Simulation.step — same as Rust simulation_step_x20000
|
|
187
|
+
const simStep = Simulation.fromSource<TopPorts>(CODE, "Top");
|
|
188
|
+
simStep.addClock("clk", { period: 10 });
|
|
189
|
+
|
|
190
|
+
afterAll(() => {
|
|
191
|
+
simStep.dispose();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
bench(
|
|
195
|
+
"simulation_step_x20000",
|
|
196
|
+
() => {
|
|
197
|
+
// 20000 steps = 10000 cycles (rising + falling)
|
|
198
|
+
for (let i = 0; i < 20_000; i++) {
|
|
199
|
+
simStep.step();
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
{ iterations: 3, time: 0 },
|
|
203
|
+
);
|
|
195
204
|
});
|
|
196
205
|
|
|
197
206
|
/**
|
|
@@ -199,44 +208,44 @@ describe("overhead", () => {
|
|
|
199
208
|
* above but uses the Simulation API instead of Simulator.
|
|
200
209
|
*/
|
|
201
210
|
describe("simulation-time-based", () => {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
211
|
+
bench(
|
|
212
|
+
"simulation_time_build_top_n1000",
|
|
213
|
+
() => {
|
|
214
|
+
const sim = Simulation.fromSource<TopPorts>(CODE, "Top");
|
|
215
|
+
sim.dispose();
|
|
216
|
+
},
|
|
217
|
+
{ iterations: 3, time: 0 },
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
const sim = Simulation.fromSource<TopPorts>(CODE, "Top");
|
|
221
|
+
sim.addClock("clk", { period: 10 });
|
|
222
|
+
|
|
223
|
+
afterAll(() => {
|
|
224
|
+
sim.dispose();
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
bench("simulation_time_step_x1", () => {
|
|
228
|
+
sim.step();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
bench(
|
|
232
|
+
"simulation_time_step_x1000000",
|
|
233
|
+
() => {
|
|
234
|
+
for (let i = 0; i < 1_000_000; i++) {
|
|
235
|
+
sim.step();
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
{ iterations: 3, time: 0 },
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
bench(
|
|
242
|
+
"simulation_time_runUntil_1000000",
|
|
243
|
+
() => {
|
|
244
|
+
const base = sim.time();
|
|
245
|
+
sim.runUntil(base + 1_000_000);
|
|
246
|
+
},
|
|
247
|
+
{ iterations: 3, time: 0 },
|
|
248
|
+
);
|
|
240
249
|
});
|
|
241
250
|
|
|
242
251
|
/**
|
|
@@ -246,7 +255,7 @@ describe("simulation-time-based", () => {
|
|
|
246
255
|
* maxSteps guard to measure overhead.
|
|
247
256
|
*/
|
|
248
257
|
describe("testbench-helpers", () => {
|
|
249
|
-
|
|
258
|
+
const COUNTER_CODE = `
|
|
250
259
|
module Counter (
|
|
251
260
|
clk: input clock,
|
|
252
261
|
rst: input reset,
|
|
@@ -269,71 +278,71 @@ describe("testbench-helpers", () => {
|
|
|
269
278
|
}
|
|
270
279
|
`;
|
|
271
280
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
281
|
+
interface CounterPorts {
|
|
282
|
+
rst: bigint;
|
|
283
|
+
en: bigint;
|
|
284
|
+
readonly count: bigint;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// waitForCycles benchmark
|
|
288
|
+
const simWait = Simulation.fromSource<CounterPorts>(COUNTER_CODE, "Counter");
|
|
289
|
+
simWait.addClock("clk", { period: 10 });
|
|
290
|
+
simWait.dut.rst = 1n;
|
|
291
|
+
simWait.runUntil(20);
|
|
292
|
+
simWait.dut.rst = 0n;
|
|
293
|
+
simWait.dut.en = 1n;
|
|
294
|
+
|
|
295
|
+
afterAll(() => {
|
|
296
|
+
simWait.dispose();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
bench(
|
|
300
|
+
"waitForCycles_x1000",
|
|
301
|
+
() => {
|
|
302
|
+
simWait.waitForCycles("clk", 1000);
|
|
303
|
+
},
|
|
304
|
+
{ iterations: 3, time: 0 },
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
bench(
|
|
308
|
+
"manual_step_loop_x2000",
|
|
309
|
+
() => {
|
|
310
|
+
for (let i = 0; i < 2000; i++) {
|
|
311
|
+
simWait.step();
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
{ iterations: 3, time: 0 },
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
// runUntil: fast Rust path vs guarded TS path
|
|
318
|
+
const simRun = Simulation.fromSource<CounterPorts>(COUNTER_CODE, "Counter");
|
|
319
|
+
simRun.addClock("clk", { period: 10 });
|
|
320
|
+
simRun.dut.rst = 1n;
|
|
321
|
+
simRun.runUntil(20);
|
|
322
|
+
simRun.dut.rst = 0n;
|
|
323
|
+
simRun.dut.en = 1n;
|
|
324
|
+
|
|
325
|
+
afterAll(() => {
|
|
326
|
+
simRun.dispose();
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
bench(
|
|
330
|
+
"runUntil_fast_path_100000",
|
|
331
|
+
() => {
|
|
332
|
+
const base = simRun.time();
|
|
333
|
+
simRun.runUntil(base + 100_000);
|
|
334
|
+
},
|
|
335
|
+
{ iterations: 3, time: 0 },
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
bench(
|
|
339
|
+
"runUntil_guarded_100000",
|
|
340
|
+
() => {
|
|
341
|
+
const base = simRun.time();
|
|
342
|
+
simRun.runUntil(base + 100_000, { maxSteps: 1_000_000 });
|
|
343
|
+
},
|
|
344
|
+
{ iterations: 3, time: 0 },
|
|
345
|
+
);
|
|
337
346
|
});
|
|
338
347
|
|
|
339
348
|
/**
|
|
@@ -342,62 +351,370 @@ describe("testbench-helpers", () => {
|
|
|
342
351
|
* Compares build time and tick performance with and without optimization.
|
|
343
352
|
*/
|
|
344
353
|
describe("optimize-flag", () => {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
354
|
+
bench(
|
|
355
|
+
"build_without_optimize",
|
|
356
|
+
() => {
|
|
357
|
+
const sim = Simulator.fromSource<TopPorts>(CODE, "Top");
|
|
358
|
+
sim.dispose();
|
|
359
|
+
},
|
|
360
|
+
{ iterations: 3, time: 0 },
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
bench(
|
|
364
|
+
"build_with_optimize",
|
|
365
|
+
() => {
|
|
366
|
+
const sim = Simulator.fromSource<TopPorts>(CODE, "Top", {
|
|
367
|
+
optimize: true,
|
|
368
|
+
});
|
|
369
|
+
sim.dispose();
|
|
370
|
+
},
|
|
371
|
+
{ iterations: 3, time: 0 },
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
const simNoOpt = Simulator.fromSource<TopPorts>(CODE, "Top");
|
|
375
|
+
simNoOpt.dut.rst = 1n;
|
|
376
|
+
simNoOpt.tick();
|
|
377
|
+
simNoOpt.dut.rst = 0n;
|
|
378
|
+
simNoOpt.tick();
|
|
379
|
+
|
|
380
|
+
const simOpt = Simulator.fromSource<TopPorts>(CODE, "Top", {
|
|
381
|
+
optimize: true,
|
|
382
|
+
});
|
|
383
|
+
simOpt.dut.rst = 1n;
|
|
384
|
+
simOpt.tick();
|
|
385
|
+
simOpt.dut.rst = 0n;
|
|
386
|
+
simOpt.tick();
|
|
387
|
+
|
|
388
|
+
afterAll(() => {
|
|
389
|
+
simNoOpt.dispose();
|
|
390
|
+
simOpt.dispose();
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
bench(
|
|
394
|
+
"tick_x10000_without_optimize",
|
|
395
|
+
() => {
|
|
396
|
+
for (let i = 0; i < 10_000; i++) {
|
|
397
|
+
simNoOpt.tick();
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
{ iterations: 3, time: 0 },
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
bench(
|
|
404
|
+
"tick_x10000_with_optimize",
|
|
405
|
+
() => {
|
|
406
|
+
for (let i = 0; i < 10_000; i++) {
|
|
407
|
+
simOpt.tick();
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
{ iterations: 3, time: 0 },
|
|
411
|
+
);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// ────────────────────────────────────────────────────────────
|
|
415
|
+
// Stdlib benchmarks — mirrors crates/celox/benches/simulation.rs
|
|
416
|
+
// ────────────────────────────────────────────────────────────
|
|
417
|
+
|
|
418
|
+
// --- Linear SEC (P=6): Hamming encoder/decoder, combinational ---
|
|
419
|
+
|
|
420
|
+
const LINEAR_SEC_SRC =
|
|
421
|
+
readVeryl("coding/linear_sec_encoder.veryl") +
|
|
422
|
+
readVeryl("coding/linear_sec_decoder.veryl") +
|
|
423
|
+
`
|
|
424
|
+
module Top #(
|
|
425
|
+
param P: u32 = 6,
|
|
426
|
+
const K: u32 = (1 << P) - 1,
|
|
427
|
+
const N: u32 = K - P,
|
|
428
|
+
)(
|
|
429
|
+
i_word : input logic<N>,
|
|
430
|
+
o_codeword : output logic<K>,
|
|
431
|
+
o_word : output logic<N>,
|
|
432
|
+
o_corrected: output logic,
|
|
433
|
+
) {
|
|
434
|
+
inst u_enc: linear_sec_encoder #(P: P) (i_word, o_codeword);
|
|
435
|
+
inst u_dec: linear_sec_decoder #(P: P) (
|
|
436
|
+
i_codeword: o_codeword,
|
|
437
|
+
o_word,
|
|
438
|
+
o_corrected,
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
`;
|
|
442
|
+
|
|
443
|
+
interface LinearSecPorts {
|
|
444
|
+
i_word: bigint;
|
|
445
|
+
readonly o_codeword: bigint;
|
|
446
|
+
readonly o_word: bigint;
|
|
447
|
+
readonly o_corrected: bigint;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
describe("stdlib-linear-sec", () => {
|
|
451
|
+
bench(
|
|
452
|
+
"simulation_build_linear_sec_p6",
|
|
453
|
+
() => {
|
|
454
|
+
const sim = Simulator.fromSource<LinearSecPorts>(LINEAR_SEC_SRC, "Top");
|
|
455
|
+
sim.dispose();
|
|
456
|
+
},
|
|
457
|
+
{ iterations: 3, time: 0 },
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
const sim = Simulator.fromSource<LinearSecPorts>(LINEAR_SEC_SRC, "Top");
|
|
461
|
+
|
|
462
|
+
afterAll(() => {
|
|
463
|
+
sim.dispose();
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
let linearSecInput = 0n;
|
|
467
|
+
bench("simulation_eval_linear_sec_p6_x1", () => {
|
|
468
|
+
sim.dut.i_word = linearSecInput++;
|
|
469
|
+
//read to measure eval
|
|
470
|
+
sim.dut.o_word;
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
bench(
|
|
474
|
+
"simulation_eval_linear_sec_p6_x1000000",
|
|
475
|
+
() => {
|
|
476
|
+
let input = 0n;
|
|
477
|
+
for (let i = 0; i < 1_000_000; i++) {
|
|
478
|
+
sim.dut.i_word = input++;
|
|
479
|
+
//read to measure eval
|
|
480
|
+
sim.dut.o_word;
|
|
481
|
+
}
|
|
482
|
+
},
|
|
483
|
+
{ iterations: 3, time: 0 },
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
bench(
|
|
487
|
+
"testbench_eval_linear_sec_p6_x1000000",
|
|
488
|
+
() => {
|
|
489
|
+
let input = 0n;
|
|
490
|
+
for (let i = 0; i < 1_000_000; i++) {
|
|
491
|
+
sim.dut.i_word = input++;
|
|
492
|
+
//read corrected flag
|
|
493
|
+
sim.dut.o_corrected;
|
|
494
|
+
}
|
|
495
|
+
},
|
|
496
|
+
{ iterations: 3, time: 0 },
|
|
497
|
+
);
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
// --- Countones (W=64): recursive combinational popcount tree ---
|
|
501
|
+
|
|
502
|
+
const COUNTONES_SRC =
|
|
503
|
+
readVeryl("countones/countones.veryl") +
|
|
504
|
+
`
|
|
505
|
+
module Top (
|
|
506
|
+
i_data: input logic<64>,
|
|
507
|
+
o_ones: output logic<7>,
|
|
508
|
+
) {
|
|
509
|
+
inst u: countones #(W: 64) (i_data, o_ones);
|
|
510
|
+
}
|
|
511
|
+
`;
|
|
512
|
+
|
|
513
|
+
interface CountonesPorts {
|
|
514
|
+
i_data: bigint;
|
|
515
|
+
readonly o_ones: bigint;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
describe("stdlib-countones", () => {
|
|
519
|
+
bench(
|
|
520
|
+
"simulation_build_countones_w64",
|
|
521
|
+
() => {
|
|
522
|
+
const sim = Simulator.fromSource<CountonesPorts>(COUNTONES_SRC, "Top");
|
|
523
|
+
sim.dispose();
|
|
524
|
+
},
|
|
525
|
+
{ iterations: 3, time: 0 },
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
const sim = Simulator.fromSource<CountonesPorts>(COUNTONES_SRC, "Top");
|
|
529
|
+
|
|
530
|
+
afterAll(() => {
|
|
531
|
+
sim.dispose();
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
let countonesInput = 0n;
|
|
535
|
+
bench("simulation_eval_countones_w64_x1", () => {
|
|
536
|
+
sim.dut.i_data = countonesInput++;
|
|
537
|
+
//read to measure eval
|
|
538
|
+
sim.dut.o_ones;
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
bench(
|
|
542
|
+
"simulation_eval_countones_w64_x1000000",
|
|
543
|
+
() => {
|
|
544
|
+
let input = 0n;
|
|
545
|
+
for (let i = 0; i < 1_000_000; i++) {
|
|
546
|
+
sim.dut.i_data = input++;
|
|
547
|
+
//read to measure eval
|
|
548
|
+
sim.dut.o_ones;
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
{ iterations: 3, time: 0 },
|
|
552
|
+
);
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
// --- std::counter (WIDTH=32): sequential up-counter ---
|
|
556
|
+
|
|
557
|
+
const STD_COUNTER_SRC =
|
|
558
|
+
readVeryl("counter/counter.veryl") +
|
|
559
|
+
`
|
|
560
|
+
module Top (
|
|
561
|
+
clk : input clock,
|
|
562
|
+
rst : input reset,
|
|
563
|
+
i_up : input logic,
|
|
564
|
+
o_count: output logic<32>,
|
|
565
|
+
) {
|
|
566
|
+
inst u: counter #(WIDTH: 32) (
|
|
567
|
+
i_clk : clk,
|
|
568
|
+
i_rst : rst,
|
|
569
|
+
i_clear : 1'b0,
|
|
570
|
+
i_set : 1'b0,
|
|
571
|
+
i_set_value : 32'b0,
|
|
572
|
+
i_up,
|
|
573
|
+
i_down : 1'b0,
|
|
574
|
+
o_count,
|
|
575
|
+
o_count_next: _,
|
|
576
|
+
o_wrap_around: _,
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
`;
|
|
580
|
+
|
|
581
|
+
interface StdCounterPorts {
|
|
582
|
+
rst: bigint;
|
|
583
|
+
i_up: bigint;
|
|
584
|
+
readonly o_count: bigint;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
describe("stdlib-counter", () => {
|
|
588
|
+
bench(
|
|
589
|
+
"simulation_build_std_counter_w32",
|
|
590
|
+
() => {
|
|
591
|
+
const sim = Simulator.fromSource<StdCounterPorts>(STD_COUNTER_SRC, "Top");
|
|
592
|
+
sim.dispose();
|
|
593
|
+
},
|
|
594
|
+
{ iterations: 3, time: 0 },
|
|
595
|
+
);
|
|
596
|
+
|
|
597
|
+
const sim = Simulator.fromSource<StdCounterPorts>(STD_COUNTER_SRC, "Top");
|
|
598
|
+
sim.dut.rst = 1n;
|
|
599
|
+
sim.dut.i_up = 0n;
|
|
600
|
+
sim.tick();
|
|
601
|
+
sim.dut.rst = 0n;
|
|
602
|
+
sim.dut.i_up = 1n;
|
|
603
|
+
sim.tick();
|
|
604
|
+
|
|
605
|
+
afterAll(() => {
|
|
606
|
+
sim.dispose();
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
bench("simulation_tick_std_counter_w32_x1", () => {
|
|
610
|
+
sim.tick();
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
bench(
|
|
614
|
+
"simulation_tick_std_counter_w32_x1000000",
|
|
615
|
+
() => {
|
|
616
|
+
for (let i = 0; i < 1_000_000; i++) {
|
|
617
|
+
sim.tick();
|
|
618
|
+
}
|
|
619
|
+
},
|
|
620
|
+
{ iterations: 3, time: 0 },
|
|
621
|
+
);
|
|
622
|
+
|
|
623
|
+
bench(
|
|
624
|
+
"testbench_tick_std_counter_w32_x1000000",
|
|
625
|
+
() => {
|
|
626
|
+
for (let i = 0; i < 1_000_000; i++) {
|
|
627
|
+
sim.tick();
|
|
628
|
+
//read to measure testbench cycle
|
|
629
|
+
sim.dut.o_count;
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
{ iterations: 3, time: 0 },
|
|
633
|
+
);
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
// --- std::gray_counter (WIDTH=32): Gray-encoded sequential counter ---
|
|
637
|
+
|
|
638
|
+
const GRAY_COUNTER_SRC =
|
|
639
|
+
readVeryl("counter/counter.veryl") +
|
|
640
|
+
readVeryl("gray/gray_encoder.veryl") +
|
|
641
|
+
readVeryl("gray/gray_counter.veryl") +
|
|
642
|
+
`
|
|
643
|
+
module Top (
|
|
644
|
+
clk : input clock,
|
|
645
|
+
rst : input reset,
|
|
646
|
+
i_up : input logic,
|
|
647
|
+
o_count: output logic<32>,
|
|
648
|
+
) {
|
|
649
|
+
inst u: gray_counter #(WIDTH: 32) (
|
|
650
|
+
i_clk : clk,
|
|
651
|
+
i_rst : rst,
|
|
652
|
+
i_clear : 1'b0,
|
|
653
|
+
i_set : 1'b0,
|
|
654
|
+
i_set_value : 32'b0,
|
|
655
|
+
i_up,
|
|
656
|
+
i_down : 1'b0,
|
|
657
|
+
o_count,
|
|
658
|
+
o_count_next: _,
|
|
659
|
+
o_wrap_around: _,
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
`;
|
|
663
|
+
|
|
664
|
+
interface GrayCounterPorts {
|
|
665
|
+
rst: bigint;
|
|
666
|
+
i_up: bigint;
|
|
667
|
+
readonly o_count: bigint;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
describe("stdlib-gray-counter", () => {
|
|
671
|
+
bench(
|
|
672
|
+
"simulation_build_gray_counter_w32",
|
|
673
|
+
() => {
|
|
674
|
+
const sim = Simulator.fromSource<GrayCounterPorts>(
|
|
675
|
+
GRAY_COUNTER_SRC,
|
|
676
|
+
"Top",
|
|
677
|
+
);
|
|
678
|
+
sim.dispose();
|
|
679
|
+
},
|
|
680
|
+
{ iterations: 3, time: 0 },
|
|
681
|
+
);
|
|
682
|
+
|
|
683
|
+
const sim = Simulator.fromSource<GrayCounterPorts>(GRAY_COUNTER_SRC, "Top");
|
|
684
|
+
sim.dut.rst = 1n;
|
|
685
|
+
sim.dut.i_up = 0n;
|
|
686
|
+
sim.tick();
|
|
687
|
+
sim.dut.rst = 0n;
|
|
688
|
+
sim.dut.i_up = 1n;
|
|
689
|
+
sim.tick();
|
|
690
|
+
|
|
691
|
+
afterAll(() => {
|
|
692
|
+
sim.dispose();
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
bench("simulation_tick_gray_counter_w32_x1", () => {
|
|
696
|
+
sim.tick();
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
bench(
|
|
700
|
+
"simulation_tick_gray_counter_w32_x1000000",
|
|
701
|
+
() => {
|
|
702
|
+
for (let i = 0; i < 1_000_000; i++) {
|
|
703
|
+
sim.tick();
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
{ iterations: 3, time: 0 },
|
|
707
|
+
);
|
|
708
|
+
|
|
709
|
+
bench(
|
|
710
|
+
"testbench_tick_gray_counter_w32_x1000000",
|
|
711
|
+
() => {
|
|
712
|
+
for (let i = 0; i < 1_000_000; i++) {
|
|
713
|
+
sim.tick();
|
|
714
|
+
//read to measure testbench cycle
|
|
715
|
+
sim.dut.o_count;
|
|
716
|
+
}
|
|
717
|
+
},
|
|
718
|
+
{ iterations: 3, time: 0 },
|
|
719
|
+
);
|
|
403
720
|
});
|