@celox-sim/celox 0.1.13 → 0.1.15

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.
@@ -1,9 +1,9 @@
1
- import { describe, test, expect, vi } from "vitest";
2
- import { Simulator, type NativeCreateFn } from "./simulator.js";
1
+ import { describe, expect, test, vi } from "vitest";
2
+ import { type NativeCreateFn, Simulator } from "./simulator.js";
3
3
  import type {
4
- CreateResult,
5
- ModuleDefinition,
6
- NativeSimulatorHandle,
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
- rst: bigint;
15
- a: bigint;
16
- b: bigint;
17
- readonly sum: bigint;
14
+ rst: bigint;
15
+ a: bigint;
16
+ b: bigint;
17
+ readonly sum: bigint;
18
18
  }
19
19
 
20
20
  const AdderModule: ModuleDefinition<AdderPorts> = {
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"],
21
+ __celox_module: true,
22
+ name: "Adder",
23
+ sources: [{ path: "", content: "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
- create: NativeCreateFn;
36
- handle: NativeSimulatorHandle;
37
- buffer: SharedArrayBuffer;
35
+ create: NativeCreateFn;
36
+ handle: NativeSimulatorHandle;
37
+ buffer: SharedArrayBuffer;
38
38
  } {
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: { offset: 12, width: 1, byteSize: 1, is4state: false, direction: "input" },
60
- rst: { offset: 0, width: 1, byteSize: 1, is4state: false, direction: "input" },
61
- a: { offset: 2, width: 16, byteSize: 2, is4state: false, direction: "input" },
62
- b: { offset: 4, width: 16, byteSize: 2, is4state: false, direction: "input" },
63
- sum: { offset: 8, width: 17, byteSize: 4, is4state: false, direction: "output" },
64
- },
65
- events: { clk: 0 },
66
- handle,
67
- } satisfies CreateResult<NativeSimulatorHandle>);
68
-
69
- return { create, handle, buffer };
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
- test("create and basic tick", () => {
78
- const mock = createMockNative();
79
- const sim = Simulator.create(AdderModule, {
80
- __nativeCreate: mock.create,
81
- });
82
-
83
- sim.dut.a = 100n;
84
- sim.dut.b = 200n;
85
- sim.tick();
86
-
87
- expect(sim.dut.sum).toBe(300n);
88
- expect(mock.handle.tick).toHaveBeenCalledTimes(1);
89
- });
90
-
91
- test("tick with count", () => {
92
- const mock = createMockNative();
93
- const sim = Simulator.create(AdderModule, {
94
- __nativeCreate: mock.create,
95
- });
96
-
97
- sim.tick(3);
98
- expect(mock.handle.tickN).toHaveBeenCalledWith(0, 3);
99
- });
100
-
101
- test("tick with event handle", () => {
102
- const mock = createMockNative();
103
- const sim = Simulator.create(AdderModule, {
104
- __nativeCreate: mock.create,
105
- });
106
-
107
- const clk = sim.event("clk");
108
- expect(clk.name).toBe("clk");
109
- expect(clk.id).toBe(0);
110
-
111
- sim.tick(clk);
112
- expect(mock.handle.tick).toHaveBeenCalledWith(0);
113
- });
114
-
115
- test("tick with event handle and count", () => {
116
- const mock = createMockNative();
117
- const sim = Simulator.create(AdderModule, {
118
- __nativeCreate: mock.create,
119
- });
120
-
121
- const clk = sim.event("clk");
122
- sim.tick(clk, 5);
123
- expect(mock.handle.tickN).toHaveBeenCalledWith(0, 5);
124
- });
125
-
126
- test("event() throws for unknown event", () => {
127
- const mock = createMockNative();
128
- const sim = Simulator.create(AdderModule, {
129
- __nativeCreate: mock.create,
130
- });
131
-
132
- expect(() => sim.event("nonexistent")).toThrow("Unknown event");
133
- });
134
-
135
- test("dispose prevents further operations", () => {
136
- const mock = createMockNative();
137
- const sim = Simulator.create(AdderModule, {
138
- __nativeCreate: mock.create,
139
- });
140
-
141
- sim.dispose();
142
- expect(() => sim.tick()).toThrow("disposed");
143
- expect(mock.handle.dispose).toHaveBeenCalledTimes(1);
144
- });
145
-
146
- test("double dispose is safe", () => {
147
- const mock = createMockNative();
148
- const sim = Simulator.create(AdderModule, {
149
- __nativeCreate: mock.create,
150
- });
151
-
152
- sim.dispose();
153
- sim.dispose(); // no-op
154
- expect(mock.handle.dispose).toHaveBeenCalledTimes(1);
155
- });
156
-
157
- test("dump delegates to handle", () => {
158
- const mock = createMockNative();
159
- const sim = Simulator.create(AdderModule, {
160
- __nativeCreate: mock.create,
161
- });
162
-
163
- sim.dump(42);
164
- expect(mock.handle.dump).toHaveBeenCalledWith(42);
165
- });
166
-
167
- test("create throws without native binding", () => {
168
- expect(() => {
169
- Simulator.create(AdderModule);
170
- }).toThrow("Native simulator binding not loaded");
171
- });
172
-
173
- test("tick clears dirty flag", () => {
174
- const mock = createMockNative();
175
- const sim = Simulator.create(AdderModule, {
176
- __nativeCreate: mock.create,
177
- });
178
-
179
- sim.dut.a = 100n;
180
- sim.tick();
181
-
182
- // After tick, reading output should NOT trigger evalComb
183
- // because tick already cleared dirty
184
- void sim.dut.sum;
185
- // evalComb might have been called by the first dut.sum read,
186
- // but tick itself should have cleared dirty
187
- const callsBefore = (mock.handle.evalComb as ReturnType<typeof vi.fn>).mock.calls.length;
188
- void sim.dut.sum;
189
- expect((mock.handle.evalComb as ReturnType<typeof vi.fn>).mock.calls.length).toBe(callsBefore);
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
  });