@celox-sim/celox 0.1.13 → 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 +23 -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 +1037 -742
- package/src/dut.ts +580 -528
- package/src/e2e.bench.ts +512 -509
- package/src/e2e.test.ts +1847 -1574
- 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/simulator.test.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { describe,
|
|
2
|
-
import {
|
|
1
|
+
import { describe, expect, test, vi } from "vitest";
|
|
2
|
+
import { type NativeCreateFn, Simulator } from "./simulator.js";
|
|
3
3
|
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
CreateResult,
|
|
5
|
+
ModuleDefinition,
|
|
6
|
+
NativeSimulatorHandle,
|
|
7
7
|
} from "./types.js";
|
|
8
8
|
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
@@ -11,62 +11,92 @@ import type {
|
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
12
12
|
|
|
13
13
|
interface AdderPorts {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
rst: bigint;
|
|
15
|
+
a: bigint;
|
|
16
|
+
b: bigint;
|
|
17
|
+
readonly sum: bigint;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const AdderModule: ModuleDefinition<AdderPorts> = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
__celox_module: true,
|
|
22
|
+
name: "Adder",
|
|
23
|
+
source: "module Adder ...",
|
|
24
|
+
ports: {
|
|
25
|
+
clk: { direction: "input", type: "clock", width: 1 },
|
|
26
|
+
rst: { direction: "input", type: "reset", width: 1 },
|
|
27
|
+
a: { direction: "input", type: "logic", width: 16 },
|
|
28
|
+
b: { direction: "input", type: "logic", width: 16 },
|
|
29
|
+
sum: { direction: "output", type: "logic", width: 17 },
|
|
30
|
+
},
|
|
31
|
+
events: ["clk"],
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
function createMockNative(): {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
create: NativeCreateFn;
|
|
36
|
+
handle: NativeSimulatorHandle;
|
|
37
|
+
buffer: SharedArrayBuffer;
|
|
38
38
|
} {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
39
|
+
const buffer = new SharedArrayBuffer(64);
|
|
40
|
+
const evalFn = () => {
|
|
41
|
+
const view = new DataView(buffer);
|
|
42
|
+
const a = view.getUint16(2, true);
|
|
43
|
+
const b = view.getUint16(4, true);
|
|
44
|
+
view.setUint32(8, a + b, true);
|
|
45
|
+
};
|
|
46
|
+
const handle: NativeSimulatorHandle = {
|
|
47
|
+
tick: vi.fn().mockImplementation(evalFn),
|
|
48
|
+
tickN: vi.fn().mockImplementation((_eventId: number, count: number) => {
|
|
49
|
+
for (let i = 0; i < count; i++) evalFn();
|
|
50
|
+
}),
|
|
51
|
+
evalComb: vi.fn().mockImplementation(evalFn),
|
|
52
|
+
dump: vi.fn(),
|
|
53
|
+
dispose: vi.fn(),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const create: NativeCreateFn = vi.fn().mockReturnValue({
|
|
57
|
+
buffer,
|
|
58
|
+
layout: {
|
|
59
|
+
clk: {
|
|
60
|
+
offset: 12,
|
|
61
|
+
width: 1,
|
|
62
|
+
byteSize: 1,
|
|
63
|
+
is4state: false,
|
|
64
|
+
direction: "input",
|
|
65
|
+
},
|
|
66
|
+
rst: {
|
|
67
|
+
offset: 0,
|
|
68
|
+
width: 1,
|
|
69
|
+
byteSize: 1,
|
|
70
|
+
is4state: false,
|
|
71
|
+
direction: "input",
|
|
72
|
+
},
|
|
73
|
+
a: {
|
|
74
|
+
offset: 2,
|
|
75
|
+
width: 16,
|
|
76
|
+
byteSize: 2,
|
|
77
|
+
is4state: false,
|
|
78
|
+
direction: "input",
|
|
79
|
+
},
|
|
80
|
+
b: {
|
|
81
|
+
offset: 4,
|
|
82
|
+
width: 16,
|
|
83
|
+
byteSize: 2,
|
|
84
|
+
is4state: false,
|
|
85
|
+
direction: "input",
|
|
86
|
+
},
|
|
87
|
+
sum: {
|
|
88
|
+
offset: 8,
|
|
89
|
+
width: 17,
|
|
90
|
+
byteSize: 4,
|
|
91
|
+
is4state: false,
|
|
92
|
+
direction: "output",
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
events: { clk: 0 },
|
|
96
|
+
handle,
|
|
97
|
+
} satisfies CreateResult<NativeSimulatorHandle>);
|
|
98
|
+
|
|
99
|
+
return { create, handle, buffer };
|
|
70
100
|
}
|
|
71
101
|
|
|
72
102
|
// ---------------------------------------------------------------------------
|
|
@@ -74,118 +104,121 @@ function createMockNative(): {
|
|
|
74
104
|
// ---------------------------------------------------------------------------
|
|
75
105
|
|
|
76
106
|
describe("Simulator", () => {
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
107
|
+
test("create and basic tick", () => {
|
|
108
|
+
const mock = createMockNative();
|
|
109
|
+
const sim = Simulator.create(AdderModule, {
|
|
110
|
+
__nativeCreate: mock.create,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
sim.dut.a = 100n;
|
|
114
|
+
sim.dut.b = 200n;
|
|
115
|
+
sim.tick();
|
|
116
|
+
|
|
117
|
+
expect(sim.dut.sum).toBe(300n);
|
|
118
|
+
expect(mock.handle.tick).toHaveBeenCalledTimes(1);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("tick with count", () => {
|
|
122
|
+
const mock = createMockNative();
|
|
123
|
+
const sim = Simulator.create(AdderModule, {
|
|
124
|
+
__nativeCreate: mock.create,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
sim.tick(3);
|
|
128
|
+
expect(mock.handle.tickN).toHaveBeenCalledWith(0, 3);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("tick with event handle", () => {
|
|
132
|
+
const mock = createMockNative();
|
|
133
|
+
const sim = Simulator.create(AdderModule, {
|
|
134
|
+
__nativeCreate: mock.create,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const clk = sim.event("clk");
|
|
138
|
+
expect(clk.name).toBe("clk");
|
|
139
|
+
expect(clk.id).toBe(0);
|
|
140
|
+
|
|
141
|
+
sim.tick(clk);
|
|
142
|
+
expect(mock.handle.tick).toHaveBeenCalledWith(0);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("tick with event handle and count", () => {
|
|
146
|
+
const mock = createMockNative();
|
|
147
|
+
const sim = Simulator.create(AdderModule, {
|
|
148
|
+
__nativeCreate: mock.create,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const clk = sim.event("clk");
|
|
152
|
+
sim.tick(clk, 5);
|
|
153
|
+
expect(mock.handle.tickN).toHaveBeenCalledWith(0, 5);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("event() throws for unknown event", () => {
|
|
157
|
+
const mock = createMockNative();
|
|
158
|
+
const sim = Simulator.create(AdderModule, {
|
|
159
|
+
__nativeCreate: mock.create,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
expect(() => sim.event("nonexistent")).toThrow("Unknown event");
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("dispose prevents further operations", () => {
|
|
166
|
+
const mock = createMockNative();
|
|
167
|
+
const sim = Simulator.create(AdderModule, {
|
|
168
|
+
__nativeCreate: mock.create,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
sim.dispose();
|
|
172
|
+
expect(() => sim.tick()).toThrow("disposed");
|
|
173
|
+
expect(mock.handle.dispose).toHaveBeenCalledTimes(1);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("double dispose is safe", () => {
|
|
177
|
+
const mock = createMockNative();
|
|
178
|
+
const sim = Simulator.create(AdderModule, {
|
|
179
|
+
__nativeCreate: mock.create,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
sim.dispose();
|
|
183
|
+
sim.dispose(); // no-op
|
|
184
|
+
expect(mock.handle.dispose).toHaveBeenCalledTimes(1);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("dump delegates to handle", () => {
|
|
188
|
+
const mock = createMockNative();
|
|
189
|
+
const sim = Simulator.create(AdderModule, {
|
|
190
|
+
__nativeCreate: mock.create,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
sim.dump(42);
|
|
194
|
+
expect(mock.handle.dump).toHaveBeenCalledWith(42);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("create throws without native binding", () => {
|
|
198
|
+
expect(() => {
|
|
199
|
+
Simulator.create(AdderModule);
|
|
200
|
+
}).toThrow("Native simulator binding not loaded");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("tick clears dirty flag", () => {
|
|
204
|
+
const mock = createMockNative();
|
|
205
|
+
const sim = Simulator.create(AdderModule, {
|
|
206
|
+
__nativeCreate: mock.create,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
sim.dut.a = 100n;
|
|
210
|
+
sim.tick();
|
|
211
|
+
|
|
212
|
+
// After tick, reading output should NOT trigger evalComb
|
|
213
|
+
// because tick already cleared dirty
|
|
214
|
+
void sim.dut.sum;
|
|
215
|
+
// evalComb might have been called by the first dut.sum read,
|
|
216
|
+
// but tick itself should have cleared dirty
|
|
217
|
+
const callsBefore = (mock.handle.evalComb as ReturnType<typeof vi.fn>).mock
|
|
218
|
+
.calls.length;
|
|
219
|
+
void sim.dut.sum;
|
|
220
|
+
expect(
|
|
221
|
+
(mock.handle.evalComb as ReturnType<typeof vi.fn>).mock.calls.length,
|
|
222
|
+
).toBe(callsBefore);
|
|
223
|
+
});
|
|
191
224
|
});
|