@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/simulator.ts
CHANGED
|
@@ -8,16 +8,20 @@
|
|
|
8
8
|
import type {
|
|
9
9
|
CreateResult,
|
|
10
10
|
EventHandle,
|
|
11
|
+
FourStateValue,
|
|
11
12
|
ModuleDefinition,
|
|
12
13
|
NativeSimulatorHandle,
|
|
14
|
+
SignalLayout,
|
|
13
15
|
SimulatorOptions,
|
|
14
16
|
} from "./types.js";
|
|
15
|
-
import { createDut, type DirtyState } from "./dut.js";
|
|
17
|
+
import { createDut, readFourState, type DirtyState } from "./dut.js";
|
|
16
18
|
import {
|
|
17
19
|
loadNativeAddon,
|
|
18
20
|
parseNapiLayout,
|
|
21
|
+
parseHierarchyLayout,
|
|
19
22
|
buildPortsFromLayout,
|
|
20
23
|
wrapDirectSimulatorHandle,
|
|
24
|
+
buildNapiOpts,
|
|
21
25
|
} from "./napi-helpers.js";
|
|
22
26
|
|
|
23
27
|
/**
|
|
@@ -54,6 +58,8 @@ export class Simulator<P = Record<string, unknown>> {
|
|
|
54
58
|
private readonly _events: Record<string, number>;
|
|
55
59
|
private readonly _defaultEventId: number;
|
|
56
60
|
private readonly _state: DirtyState;
|
|
61
|
+
private readonly _buffer: ArrayBuffer | SharedArrayBuffer;
|
|
62
|
+
private readonly _layout: Record<string, SignalLayout>;
|
|
57
63
|
private _disposed = false;
|
|
58
64
|
|
|
59
65
|
private constructor(
|
|
@@ -61,11 +67,15 @@ export class Simulator<P = Record<string, unknown>> {
|
|
|
61
67
|
dut: P,
|
|
62
68
|
events: Record<string, number>,
|
|
63
69
|
state: DirtyState,
|
|
70
|
+
buffer: ArrayBuffer | SharedArrayBuffer,
|
|
71
|
+
layout: Record<string, SignalLayout>,
|
|
64
72
|
) {
|
|
65
73
|
this._handle = handle;
|
|
66
74
|
this._dut = dut;
|
|
67
75
|
this._events = events;
|
|
68
76
|
this._state = state;
|
|
77
|
+
this._buffer = buffer;
|
|
78
|
+
this._layout = layout;
|
|
69
79
|
const keys = Object.keys(events);
|
|
70
80
|
this._defaultEventId = keys.length > 0 ? events[keys[0]!]! : -1;
|
|
71
81
|
}
|
|
@@ -98,8 +108,8 @@ export class Simulator<P = Record<string, unknown>> {
|
|
|
98
108
|
);
|
|
99
109
|
}
|
|
100
110
|
|
|
101
|
-
const { fourState, vcd } = options ?? {};
|
|
102
|
-
const result = createFn(module.source, module.name, { fourState, vcd });
|
|
111
|
+
const { fourState, vcd, optimize, falseLoops, trueLoops, clockType, resetType } = options ?? {};
|
|
112
|
+
const result = createFn(module.source, module.name, { fourState, vcd, optimize, falseLoops, trueLoops, clockType, resetType });
|
|
103
113
|
const state: DirtyState = { dirty: false };
|
|
104
114
|
|
|
105
115
|
const dut = createDut<P>(
|
|
@@ -108,9 +118,10 @@ export class Simulator<P = Record<string, unknown>> {
|
|
|
108
118
|
module.ports,
|
|
109
119
|
result.handle,
|
|
110
120
|
state,
|
|
121
|
+
result.hierarchy,
|
|
111
122
|
);
|
|
112
123
|
|
|
113
|
-
return new Simulator<P>(result.handle, dut, result.events, state);
|
|
124
|
+
return new Simulator<P>(result.handle, dut, result.events, state, result.buffer, result.layout);
|
|
114
125
|
}
|
|
115
126
|
|
|
116
127
|
/**
|
|
@@ -133,11 +144,12 @@ export class Simulator<P = Record<string, unknown>> {
|
|
|
133
144
|
options?: SimulatorOptions & { nativeAddonPath?: string },
|
|
134
145
|
): Simulator<P> {
|
|
135
146
|
const addon = loadNativeAddon(options?.nativeAddonPath);
|
|
136
|
-
const napiOpts = options
|
|
147
|
+
const napiOpts = buildNapiOpts(options);
|
|
137
148
|
const raw = new addon.NativeSimulatorHandle(source, top, napiOpts);
|
|
138
149
|
|
|
139
150
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
140
151
|
const events: Record<string, number> = JSON.parse(raw.eventsJson);
|
|
152
|
+
const hierarchy = parseHierarchyLayout(raw.hierarchyJson, events);
|
|
141
153
|
|
|
142
154
|
const ports = buildPortsFromLayout(layout.signals, events);
|
|
143
155
|
|
|
@@ -145,9 +157,9 @@ export class Simulator<P = Record<string, unknown>> {
|
|
|
145
157
|
|
|
146
158
|
const state: DirtyState = { dirty: false };
|
|
147
159
|
const handle = wrapDirectSimulatorHandle(raw);
|
|
148
|
-
const dut = createDut<P>(buf, layout.forDut, ports, handle, state);
|
|
160
|
+
const dut = createDut<P>(buf, layout.forDut, ports, handle, state, hierarchy);
|
|
149
161
|
|
|
150
|
-
return new Simulator<P>(handle, dut, events, state);
|
|
162
|
+
return new Simulator<P>(handle, dut, events, state, buf, layout.forDut);
|
|
151
163
|
}
|
|
152
164
|
|
|
153
165
|
/**
|
|
@@ -167,11 +179,12 @@ export class Simulator<P = Record<string, unknown>> {
|
|
|
167
179
|
options?: SimulatorOptions & { nativeAddonPath?: string },
|
|
168
180
|
): Simulator<P> {
|
|
169
181
|
const addon = loadNativeAddon(options?.nativeAddonPath);
|
|
170
|
-
const napiOpts = options
|
|
182
|
+
const napiOpts = buildNapiOpts(options);
|
|
171
183
|
const raw = addon.NativeSimulatorHandle.fromProject(projectPath, top, napiOpts);
|
|
172
184
|
|
|
173
185
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
174
186
|
const events: Record<string, number> = JSON.parse(raw.eventsJson);
|
|
187
|
+
const hierarchy = parseHierarchyLayout(raw.hierarchyJson, events);
|
|
175
188
|
|
|
176
189
|
const ports = buildPortsFromLayout(layout.signals, events);
|
|
177
190
|
|
|
@@ -179,9 +192,9 @@ export class Simulator<P = Record<string, unknown>> {
|
|
|
179
192
|
|
|
180
193
|
const state: DirtyState = { dirty: false };
|
|
181
194
|
const handle = wrapDirectSimulatorHandle(raw);
|
|
182
|
-
const dut = createDut<P>(buf, layout.forDut, ports, handle, state);
|
|
195
|
+
const dut = createDut<P>(buf, layout.forDut, ports, handle, state, hierarchy);
|
|
183
196
|
|
|
184
|
-
return new Simulator<P>(handle, dut, events, state);
|
|
197
|
+
return new Simulator<P>(handle, dut, events, state, buf, layout.forDut);
|
|
185
198
|
}
|
|
186
199
|
|
|
187
200
|
/** The DUT accessor object — read/write ports as plain properties. */
|
|
@@ -221,12 +234,16 @@ export class Simulator<P = Record<string, unknown>> {
|
|
|
221
234
|
ticks = 1;
|
|
222
235
|
}
|
|
223
236
|
|
|
237
|
+
if (this._state.dirty) {
|
|
238
|
+
this._handle.evalComb();
|
|
239
|
+
this._state.dirty = false;
|
|
240
|
+
}
|
|
241
|
+
|
|
224
242
|
if (ticks === 1) {
|
|
225
243
|
this._handle.tick(eventId);
|
|
226
244
|
} else if (ticks > 1) {
|
|
227
245
|
this._handle.tickN(eventId, ticks);
|
|
228
246
|
}
|
|
229
|
-
this._state.dirty = false;
|
|
230
247
|
}
|
|
231
248
|
|
|
232
249
|
/** Resolve an event name to a handle for use with `tick()`. */
|
|
@@ -240,6 +257,21 @@ export class Simulator<P = Record<string, unknown>> {
|
|
|
240
257
|
return { name, id };
|
|
241
258
|
}
|
|
242
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Read the raw 4-state (value + mask) pair for the named port.
|
|
262
|
+
*/
|
|
263
|
+
fourState(portName: string): FourStateValue {
|
|
264
|
+
this.ensureAlive();
|
|
265
|
+
const sig = this._layout[portName];
|
|
266
|
+
if (!sig) {
|
|
267
|
+
throw new Error(
|
|
268
|
+
`Unknown port '${portName}'. Available: ${Object.keys(this._layout).join(", ")}`,
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
const [value, mask] = readFourState(this._buffer, sig);
|
|
272
|
+
return { __fourState: true, value, mask };
|
|
273
|
+
}
|
|
274
|
+
|
|
243
275
|
/** Write current signal values to VCD at the given timestamp. */
|
|
244
276
|
dump(timestamp: number): void {
|
|
245
277
|
this.ensureAlive();
|
package/src/types.ts
CHANGED
|
@@ -58,6 +58,10 @@ export interface SignalLayout {
|
|
|
58
58
|
/** If true, an equal-sized mask follows immediately after the value. */
|
|
59
59
|
readonly is4state: boolean;
|
|
60
60
|
readonly direction: "input" | "output" | "inout";
|
|
61
|
+
/** The Veryl type kind (e.g. "clock", "reset_async_high", "logic"). */
|
|
62
|
+
readonly typeKind?: string;
|
|
63
|
+
/** For reset signals, the name of the associated clock (from FfDeclaration). */
|
|
64
|
+
readonly associatedClock?: string;
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
// ---------------------------------------------------------------------------
|
|
@@ -86,6 +90,7 @@ export interface NativeSimulationHandle {
|
|
|
86
90
|
runUntil(endTime: number): void;
|
|
87
91
|
step(): number | null;
|
|
88
92
|
time(): number;
|
|
93
|
+
nextEventTime(): number | null;
|
|
89
94
|
evalComb(): void;
|
|
90
95
|
dump(timestamp: number): void;
|
|
91
96
|
dispose(): void;
|
|
@@ -110,6 +115,8 @@ export interface CreateResult<H extends NativeHandle = NativeHandle> {
|
|
|
110
115
|
readonly events: Record<string, number>;
|
|
111
116
|
/** Native control handle. */
|
|
112
117
|
readonly handle: H;
|
|
118
|
+
/** Full instance hierarchy (optional — present when NAPI provides it). */
|
|
119
|
+
readonly hierarchy?: import("./napi-helpers.js").HierarchyNode;
|
|
113
120
|
}
|
|
114
121
|
|
|
115
122
|
// ---------------------------------------------------------------------------
|
|
@@ -121,6 +128,16 @@ export interface SimulatorOptions {
|
|
|
121
128
|
fourState?: boolean;
|
|
122
129
|
/** Path to write VCD waveform output. */
|
|
123
130
|
vcd?: string;
|
|
131
|
+
/** Enable Cranelift optimization passes. */
|
|
132
|
+
optimize?: boolean;
|
|
133
|
+
/** False-loop declarations to ignore during compilation. */
|
|
134
|
+
falseLoops?: LoopBreak[];
|
|
135
|
+
/** True-loop declarations with convergence limits. */
|
|
136
|
+
trueLoops?: TrueLoopSpec[];
|
|
137
|
+
/** Clock polarity. Default: "posedge". */
|
|
138
|
+
clockType?: "posedge" | "negedge";
|
|
139
|
+
/** Reset type. Default: "async_low". */
|
|
140
|
+
resetType?: "async_high" | "async_low" | "sync_high" | "sync_low";
|
|
124
141
|
}
|
|
125
142
|
|
|
126
143
|
// ---------------------------------------------------------------------------
|
|
@@ -143,8 +160,8 @@ export const X = Symbol.for("veryl:X");
|
|
|
143
160
|
/** A 4-state value with explicit bit-level mask. */
|
|
144
161
|
export interface FourStateValue {
|
|
145
162
|
readonly __fourState: true;
|
|
146
|
-
readonly value:
|
|
147
|
-
readonly mask:
|
|
163
|
+
readonly value: bigint;
|
|
164
|
+
readonly mask: bigint;
|
|
148
165
|
}
|
|
149
166
|
|
|
150
167
|
/** Construct a 4-state value. Mask bits set to 1 indicate X. */
|
|
@@ -152,7 +169,7 @@ export function FourState(
|
|
|
152
169
|
value: number | bigint,
|
|
153
170
|
mask: number | bigint,
|
|
154
171
|
): FourStateValue {
|
|
155
|
-
return { __fourState: true, value, mask };
|
|
172
|
+
return { __fourState: true, value: BigInt(value), mask: BigInt(mask) };
|
|
156
173
|
}
|
|
157
174
|
|
|
158
175
|
export function isFourStateValue(v: unknown): v is FourStateValue {
|
|
@@ -162,3 +179,37 @@ export function isFourStateValue(v: unknown): v is FourStateValue {
|
|
|
162
179
|
(v as FourStateValue).__fourState === true
|
|
163
180
|
);
|
|
164
181
|
}
|
|
182
|
+
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
// Simulation timeout error
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Thrown when a simulation helper exceeds its step budget.
|
|
189
|
+
*/
|
|
190
|
+
export class SimulationTimeoutError extends Error {
|
|
191
|
+
readonly time: number;
|
|
192
|
+
readonly steps: number;
|
|
193
|
+
|
|
194
|
+
constructor(message: string, time: number, steps: number) {
|
|
195
|
+
super(message);
|
|
196
|
+
this.name = "SimulationTimeoutError";
|
|
197
|
+
this.time = time;
|
|
198
|
+
this.steps = steps;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
// Loop-break types (for Phase 3c)
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
/** Specifies a false-loop to ignore during compilation. */
|
|
207
|
+
export interface LoopBreak {
|
|
208
|
+
from: string;
|
|
209
|
+
to: string;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** Specifies a true-loop with a convergence iteration limit. */
|
|
213
|
+
export interface TrueLoopSpec extends LoopBreak {
|
|
214
|
+
maxIter: number;
|
|
215
|
+
}
|