@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/index.ts
CHANGED
|
@@ -15,6 +15,8 @@ export type {
|
|
|
15
15
|
SimulatorOptions,
|
|
16
16
|
EventHandle,
|
|
17
17
|
FourStateValue,
|
|
18
|
+
LoopBreak,
|
|
19
|
+
TrueLoopSpec,
|
|
18
20
|
} from "./types.js";
|
|
19
21
|
|
|
20
22
|
/** @internal */
|
|
@@ -29,6 +31,9 @@ export type {
|
|
|
29
31
|
// 4-state helpers
|
|
30
32
|
export { X, FourState, isFourStateValue } from "./types.js";
|
|
31
33
|
|
|
34
|
+
// Error types
|
|
35
|
+
export { SimulationTimeoutError } from "./types.js";
|
|
36
|
+
|
|
32
37
|
// Simulator (event-based)
|
|
33
38
|
export { Simulator } from "./simulator.js";
|
|
34
39
|
|
|
@@ -36,7 +41,7 @@ export { Simulator } from "./simulator.js";
|
|
|
36
41
|
export { Simulation } from "./simulation.js";
|
|
37
42
|
|
|
38
43
|
/** @internal */
|
|
39
|
-
export { createDut, readFourState } from "./dut.js";
|
|
44
|
+
export { createDut, createChildDut, readFourState } from "./dut.js";
|
|
40
45
|
/** @internal */
|
|
41
46
|
export type { DirtyState } from "./dut.js";
|
|
42
47
|
|
|
@@ -44,14 +49,17 @@ export type { DirtyState } from "./dut.js";
|
|
|
44
49
|
export {
|
|
45
50
|
loadNativeAddon,
|
|
46
51
|
parseNapiLayout,
|
|
52
|
+
parseHierarchyLayout,
|
|
47
53
|
buildPortsFromLayout,
|
|
48
54
|
wrapDirectSimulatorHandle,
|
|
49
55
|
wrapDirectSimulationHandle,
|
|
50
56
|
createSimulatorBridge,
|
|
51
57
|
createSimulationBridge,
|
|
58
|
+
parseSignalPath,
|
|
59
|
+
buildNapiOpts,
|
|
52
60
|
} from "./napi-helpers.js";
|
|
53
61
|
/** @internal */
|
|
54
|
-
export type { RawNapiAddon, RawNapiSimulatorHandle, RawNapiSimulationHandle } from "./napi-helpers.js";
|
|
62
|
+
export type { HierarchyNode, RawNapiAddon, RawNapiSimulatorHandle, RawNapiSimulationHandle } from "./napi-helpers.js";
|
|
55
63
|
|
|
56
64
|
// NAPI bridge (backward compat — re-exports from napi-helpers)
|
|
57
65
|
// Consumers that import from "./napi-bridge.js" still work.
|
package/src/matchers.ts
CHANGED
|
@@ -70,7 +70,7 @@ function isFourStateRef(v: unknown): v is FourStateRef {
|
|
|
70
70
|
// Matcher implementations
|
|
71
71
|
// ---------------------------------------------------------------------------
|
|
72
72
|
|
|
73
|
-
function getMask(received: unknown):
|
|
73
|
+
function getMask(received: unknown): bigint {
|
|
74
74
|
if (!isFourStateRef(received)) {
|
|
75
75
|
throw new TypeError(
|
|
76
76
|
"toBeX/toBeAllX/toBeNotX matchers require a FourStateRef. " +
|
|
@@ -84,7 +84,7 @@ function getMask(received: unknown): number | bigint {
|
|
|
84
84
|
const customMatchers = {
|
|
85
85
|
toBeX(received: unknown) {
|
|
86
86
|
const mask = getMask(received);
|
|
87
|
-
const pass = mask !==
|
|
87
|
+
const pass = mask !== 0n;
|
|
88
88
|
return {
|
|
89
89
|
pass,
|
|
90
90
|
message: () =>
|
|
@@ -100,10 +100,7 @@ const customMatchers = {
|
|
|
100
100
|
}
|
|
101
101
|
const [, mask] = readFourState(received.buffer, received.layout);
|
|
102
102
|
const width = received.layout.width;
|
|
103
|
-
const allOnes =
|
|
104
|
-
width <= 53
|
|
105
|
-
? (width === 53 ? Number.MAX_SAFE_INTEGER : (1 << width) - 1)
|
|
106
|
-
: (1n << BigInt(width)) - 1n;
|
|
103
|
+
const allOnes = (1n << BigInt(width)) - 1n;
|
|
107
104
|
const pass = mask === allOnes;
|
|
108
105
|
return {
|
|
109
106
|
pass,
|
|
@@ -116,7 +113,7 @@ const customMatchers = {
|
|
|
116
113
|
|
|
117
114
|
toBeNotX(received: unknown) {
|
|
118
115
|
const mask = getMask(received);
|
|
119
|
-
const pass = mask ===
|
|
116
|
+
const pass = mask === 0n;
|
|
120
117
|
return {
|
|
121
118
|
pass,
|
|
122
119
|
message: () =>
|
package/src/napi-helpers.ts
CHANGED
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
|
|
12
12
|
import type {
|
|
13
13
|
CreateResult,
|
|
14
|
+
LoopBreak,
|
|
14
15
|
NativeSimulatorHandle,
|
|
15
16
|
NativeSimulationHandle,
|
|
16
17
|
PortInfo,
|
|
17
18
|
SignalLayout,
|
|
18
19
|
SimulatorOptions,
|
|
20
|
+
TrueLoopSpec,
|
|
19
21
|
} from "./types.js";
|
|
20
22
|
import type { NativeCreateFn } from "./simulator.js";
|
|
21
23
|
import type { NativeCreateSimulationFn } from "./simulation.js";
|
|
@@ -27,6 +29,7 @@ import type { NativeCreateSimulationFn } from "./simulation.js";
|
|
|
27
29
|
export interface RawNapiSimulatorHandle {
|
|
28
30
|
readonly layoutJson: string;
|
|
29
31
|
readonly eventsJson: string;
|
|
32
|
+
readonly hierarchyJson: string;
|
|
30
33
|
readonly stableSize: number;
|
|
31
34
|
readonly totalSize: number;
|
|
32
35
|
tick(eventId: number): void;
|
|
@@ -40,6 +43,7 @@ export interface RawNapiSimulatorHandle {
|
|
|
40
43
|
export interface RawNapiSimulationHandle {
|
|
41
44
|
readonly layoutJson: string;
|
|
42
45
|
readonly eventsJson: string;
|
|
46
|
+
readonly hierarchyJson: string;
|
|
43
47
|
readonly stableSize: number;
|
|
44
48
|
readonly totalSize: number;
|
|
45
49
|
addClock(eventId: number, period: number, initialDelay: number): void;
|
|
@@ -47,14 +51,42 @@ export interface RawNapiSimulationHandle {
|
|
|
47
51
|
runUntil(endTime: number): void;
|
|
48
52
|
step(): number | null;
|
|
49
53
|
time(): number;
|
|
54
|
+
nextEventTime(): number | null;
|
|
50
55
|
evalComb(): void;
|
|
51
56
|
dump(timestamp: number): void;
|
|
52
57
|
sharedMemory(): Uint8Array;
|
|
53
58
|
dispose(): void;
|
|
54
59
|
}
|
|
55
60
|
|
|
61
|
+
export interface NapiFalseLoop {
|
|
62
|
+
from: NapiSignalPath;
|
|
63
|
+
to: NapiSignalPath;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface NapiTrueLoop {
|
|
67
|
+
from: NapiSignalPath;
|
|
68
|
+
to: NapiSignalPath;
|
|
69
|
+
maxIter: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface NapiSignalPath {
|
|
73
|
+
instancePath: NapiInstanceSegment[];
|
|
74
|
+
varPath: string[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface NapiInstanceSegment {
|
|
78
|
+
name: string;
|
|
79
|
+
index: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
56
82
|
export interface NapiOptions {
|
|
57
83
|
fourState?: boolean;
|
|
84
|
+
vcd?: string;
|
|
85
|
+
optimize?: boolean;
|
|
86
|
+
falseLoops?: NapiFalseLoop[];
|
|
87
|
+
trueLoops?: NapiTrueLoop[];
|
|
88
|
+
clockType?: string;
|
|
89
|
+
resetType?: string;
|
|
58
90
|
}
|
|
59
91
|
|
|
60
92
|
export interface RawNapiAddon {
|
|
@@ -102,6 +134,98 @@ export function loadNativeAddon(addonPath?: string): RawNapiAddon {
|
|
|
102
134
|
}
|
|
103
135
|
}
|
|
104
136
|
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
// Signal path parsing
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Parse a signal path string into instance-path + var-path components.
|
|
143
|
+
*
|
|
144
|
+
* Format: `instanceSeg1.instanceSeg2:varSeg1.varSeg2`
|
|
145
|
+
* - `:` separates instance path from variable path
|
|
146
|
+
* - Without `:`, the whole string is the variable path
|
|
147
|
+
* - Instance segments may include `[N]` array indices
|
|
148
|
+
*
|
|
149
|
+
* Examples:
|
|
150
|
+
* - `"v"` → { instancePath: [], varPath: ["v"] }
|
|
151
|
+
* - `"p2:i"` → { instancePath: [{name:"p2",index:0}], varPath: ["i"] }
|
|
152
|
+
* - `"a.b[3]:x.y"` → { instancePath: [{name:"a",index:0},{name:"b",index:3}], varPath: ["x","y"] }
|
|
153
|
+
*/
|
|
154
|
+
export function parseSignalPath(path: string): NapiSignalPath {
|
|
155
|
+
const colonIdx = path.indexOf(":");
|
|
156
|
+
if (colonIdx < 0) {
|
|
157
|
+
return { instancePath: [], varPath: path.split(".") };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const instPart = path.slice(0, colonIdx);
|
|
161
|
+
const varPart = path.slice(colonIdx + 1);
|
|
162
|
+
|
|
163
|
+
const instancePath: NapiInstanceSegment[] = [];
|
|
164
|
+
if (instPart.length > 0) {
|
|
165
|
+
for (const seg of instPart.split(".")) {
|
|
166
|
+
const bracketIdx = seg.indexOf("[");
|
|
167
|
+
if (bracketIdx >= 0) {
|
|
168
|
+
const name = seg.slice(0, bracketIdx);
|
|
169
|
+
const index = Number.parseInt(seg.slice(bracketIdx + 1, -1), 10);
|
|
170
|
+
instancePath.push({ name, index });
|
|
171
|
+
} else {
|
|
172
|
+
instancePath.push({ name: seg, index: 0 });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return { instancePath, varPath: varPart.split(".") };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Build NapiOptions from SimulatorOptions.
|
|
182
|
+
* Returns `undefined` when no options are set (to skip the NAPI options arg).
|
|
183
|
+
*/
|
|
184
|
+
export function buildNapiOpts(options?: SimulatorOptions): NapiOptions | undefined {
|
|
185
|
+
if (!options) return undefined;
|
|
186
|
+
|
|
187
|
+
const napiOpts: NapiOptions = {};
|
|
188
|
+
let hasOpt = false;
|
|
189
|
+
|
|
190
|
+
if (options.fourState) {
|
|
191
|
+
napiOpts.fourState = options.fourState;
|
|
192
|
+
hasOpt = true;
|
|
193
|
+
}
|
|
194
|
+
if (options.vcd) {
|
|
195
|
+
napiOpts.vcd = options.vcd;
|
|
196
|
+
hasOpt = true;
|
|
197
|
+
}
|
|
198
|
+
if (options.optimize != null) {
|
|
199
|
+
napiOpts.optimize = options.optimize;
|
|
200
|
+
hasOpt = true;
|
|
201
|
+
}
|
|
202
|
+
if (options.falseLoops && options.falseLoops.length > 0) {
|
|
203
|
+
napiOpts.falseLoops = options.falseLoops.map((lb: LoopBreak) => ({
|
|
204
|
+
from: parseSignalPath(lb.from),
|
|
205
|
+
to: parseSignalPath(lb.to),
|
|
206
|
+
}));
|
|
207
|
+
hasOpt = true;
|
|
208
|
+
}
|
|
209
|
+
if (options.trueLoops && options.trueLoops.length > 0) {
|
|
210
|
+
napiOpts.trueLoops = options.trueLoops.map((tl: TrueLoopSpec) => ({
|
|
211
|
+
from: parseSignalPath(tl.from),
|
|
212
|
+
to: parseSignalPath(tl.to),
|
|
213
|
+
maxIter: tl.maxIter,
|
|
214
|
+
}));
|
|
215
|
+
hasOpt = true;
|
|
216
|
+
}
|
|
217
|
+
if (options.clockType) {
|
|
218
|
+
napiOpts.clockType = options.clockType;
|
|
219
|
+
hasOpt = true;
|
|
220
|
+
}
|
|
221
|
+
if (options.resetType) {
|
|
222
|
+
napiOpts.resetType = options.resetType;
|
|
223
|
+
hasOpt = true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return hasOpt ? napiOpts : undefined;
|
|
227
|
+
}
|
|
228
|
+
|
|
105
229
|
// ---------------------------------------------------------------------------
|
|
106
230
|
// Layout parsing helpers
|
|
107
231
|
// ---------------------------------------------------------------------------
|
|
@@ -114,6 +238,7 @@ interface RawSignalLayout {
|
|
|
114
238
|
direction: string;
|
|
115
239
|
type_kind: string;
|
|
116
240
|
array_dims?: number[];
|
|
241
|
+
associated_clock?: string;
|
|
117
242
|
}
|
|
118
243
|
|
|
119
244
|
/**
|
|
@@ -122,11 +247,11 @@ interface RawSignalLayout {
|
|
|
122
247
|
* the DUT-compatible layout (without type_kind).
|
|
123
248
|
*/
|
|
124
249
|
export function parseNapiLayout(json: string): {
|
|
125
|
-
signals: Record<string, SignalLayout & { typeKind: string; arrayDims?: number[] }>;
|
|
250
|
+
signals: Record<string, SignalLayout & { typeKind: string; arrayDims?: number[]; associatedClock?: string }>;
|
|
126
251
|
forDut: Record<string, SignalLayout>;
|
|
127
252
|
} {
|
|
128
253
|
const raw: Record<string, RawSignalLayout> = JSON.parse(json);
|
|
129
|
-
const signals: Record<string, SignalLayout & { typeKind: string; arrayDims?: number[] }> = {};
|
|
254
|
+
const signals: Record<string, SignalLayout & { typeKind: string; arrayDims?: number[]; associatedClock?: string }> = {};
|
|
130
255
|
const forDut: Record<string, SignalLayout> = {};
|
|
131
256
|
|
|
132
257
|
for (const [name, r] of Object.entries(raw)) {
|
|
@@ -137,13 +262,16 @@ export function parseNapiLayout(json: string): {
|
|
|
137
262
|
is4state: r.is_4state,
|
|
138
263
|
direction: r.direction as "input" | "output" | "inout",
|
|
139
264
|
};
|
|
140
|
-
const entry: SignalLayout & { typeKind: string; arrayDims?: number[] } = {
|
|
265
|
+
const entry: SignalLayout & { typeKind: string; arrayDims?: number[]; associatedClock?: string } = {
|
|
141
266
|
...sl,
|
|
142
267
|
typeKind: r.type_kind,
|
|
143
268
|
};
|
|
144
269
|
if (r.array_dims && r.array_dims.length > 0) {
|
|
145
270
|
entry.arrayDims = r.array_dims;
|
|
146
271
|
}
|
|
272
|
+
if (r.associated_clock) {
|
|
273
|
+
entry.associatedClock = r.associated_clock;
|
|
274
|
+
}
|
|
147
275
|
signals[name] = entry;
|
|
148
276
|
forDut[name] = sl;
|
|
149
277
|
}
|
|
@@ -164,19 +292,14 @@ export function buildPortsFromLayout(
|
|
|
164
292
|
for (const [name, sig] of Object.entries(signals)) {
|
|
165
293
|
const typeKind = sig.typeKind;
|
|
166
294
|
let portType: "clock" | "reset" | "logic" | "bit";
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
portType = "bit";
|
|
176
|
-
break;
|
|
177
|
-
default:
|
|
178
|
-
portType = "logic";
|
|
179
|
-
break;
|
|
295
|
+
if (typeKind === "clock") {
|
|
296
|
+
portType = "clock";
|
|
297
|
+
} else if (typeKind.startsWith("reset")) {
|
|
298
|
+
portType = "reset";
|
|
299
|
+
} else if (typeKind === "bit") {
|
|
300
|
+
portType = "bit";
|
|
301
|
+
} else {
|
|
302
|
+
portType = "logic";
|
|
180
303
|
}
|
|
181
304
|
|
|
182
305
|
const port: PortInfo = {
|
|
@@ -194,6 +317,78 @@ export function buildPortsFromLayout(
|
|
|
194
317
|
return ports;
|
|
195
318
|
}
|
|
196
319
|
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
// Hierarchy layout
|
|
322
|
+
// ---------------------------------------------------------------------------
|
|
323
|
+
|
|
324
|
+
export interface HierarchyNode {
|
|
325
|
+
moduleName: string;
|
|
326
|
+
signals: Record<string, SignalLayout & { typeKind: string; arrayDims?: number[] }>;
|
|
327
|
+
forDut: Record<string, SignalLayout>;
|
|
328
|
+
ports: Record<string, PortInfo>;
|
|
329
|
+
children: Record<string, HierarchyNode[]>;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
interface RawHierarchyNode {
|
|
333
|
+
module_name: string;
|
|
334
|
+
signals: Record<string, RawSignalLayout>;
|
|
335
|
+
children: Record<string, RawHierarchyNode[]>;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Parse the hierarchy JSON from NAPI into a HierarchyNode tree.
|
|
340
|
+
* Converts snake_case keys to camelCase and auto-detects ports.
|
|
341
|
+
*/
|
|
342
|
+
export function parseHierarchyLayout(
|
|
343
|
+
json: string,
|
|
344
|
+
events: Record<string, number>,
|
|
345
|
+
): HierarchyNode {
|
|
346
|
+
const raw: RawHierarchyNode = JSON.parse(json);
|
|
347
|
+
return convertHierarchyNode(raw, events);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function convertHierarchyNode(
|
|
351
|
+
raw: RawHierarchyNode,
|
|
352
|
+
events: Record<string, number>,
|
|
353
|
+
): HierarchyNode {
|
|
354
|
+
const signals: Record<string, SignalLayout & { typeKind: string; arrayDims?: number[] }> = {};
|
|
355
|
+
const forDut: Record<string, SignalLayout> = {};
|
|
356
|
+
|
|
357
|
+
for (const [name, r] of Object.entries(raw.signals)) {
|
|
358
|
+
const sl: SignalLayout = {
|
|
359
|
+
offset: r.offset,
|
|
360
|
+
width: r.width,
|
|
361
|
+
byteSize: r.byte_size > 0 ? r.byte_size : Math.ceil(r.width / 8),
|
|
362
|
+
is4state: r.is_4state,
|
|
363
|
+
direction: r.direction as "input" | "output" | "inout",
|
|
364
|
+
};
|
|
365
|
+
const entry: SignalLayout & { typeKind: string; arrayDims?: number[] } = {
|
|
366
|
+
...sl,
|
|
367
|
+
typeKind: r.type_kind,
|
|
368
|
+
};
|
|
369
|
+
if (r.array_dims && r.array_dims.length > 0) {
|
|
370
|
+
entry.arrayDims = r.array_dims;
|
|
371
|
+
}
|
|
372
|
+
signals[name] = entry;
|
|
373
|
+
forDut[name] = sl;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const ports = buildPortsFromLayout(signals, events);
|
|
377
|
+
|
|
378
|
+
const children: Record<string, HierarchyNode[]> = {};
|
|
379
|
+
for (const [name, instances] of Object.entries(raw.children)) {
|
|
380
|
+
children[name] = instances.map((inst) => convertHierarchyNode(inst, events));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return {
|
|
384
|
+
moduleName: raw.module_name,
|
|
385
|
+
signals,
|
|
386
|
+
forDut,
|
|
387
|
+
ports,
|
|
388
|
+
children,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
197
392
|
// ---------------------------------------------------------------------------
|
|
198
393
|
// Handle wrapping — zero-copy direct operations
|
|
199
394
|
// ---------------------------------------------------------------------------
|
|
@@ -246,6 +441,9 @@ export function wrapDirectSimulationHandle(
|
|
|
246
441
|
time(): number {
|
|
247
442
|
return raw.time();
|
|
248
443
|
},
|
|
444
|
+
nextEventTime(): number | null {
|
|
445
|
+
return raw.nextEventTime();
|
|
446
|
+
},
|
|
249
447
|
evalComb(): void {
|
|
250
448
|
raw.evalComb();
|
|
251
449
|
},
|
|
@@ -289,17 +487,19 @@ export function createSimulatorBridge(addon: RawNapiAddon): NativeCreateFn {
|
|
|
289
487
|
return (
|
|
290
488
|
source: string,
|
|
291
489
|
moduleName: string,
|
|
292
|
-
|
|
490
|
+
options: SimulatorOptions,
|
|
293
491
|
): CreateResult<NativeSimulatorHandle> => {
|
|
294
|
-
const
|
|
492
|
+
const napiOpts = buildNapiOpts(options);
|
|
493
|
+
const raw = new addon.NativeSimulatorHandle(source, moduleName, napiOpts);
|
|
295
494
|
|
|
296
495
|
const layout = parseLegacyLayout(raw.layoutJson);
|
|
297
496
|
const events: Record<string, number> = JSON.parse(raw.eventsJson);
|
|
497
|
+
const hierarchy = parseHierarchyLayout(raw.hierarchyJson, events);
|
|
298
498
|
|
|
299
499
|
const buf = raw.sharedMemory().buffer;
|
|
300
500
|
const handle = wrapDirectSimulatorHandle(raw);
|
|
301
501
|
|
|
302
|
-
return { buffer: buf, layout, events, handle };
|
|
502
|
+
return { buffer: buf, layout, events, handle, hierarchy };
|
|
303
503
|
};
|
|
304
504
|
}
|
|
305
505
|
|
|
@@ -311,16 +511,18 @@ export function createSimulationBridge(addon: RawNapiAddon): NativeCreateSimulat
|
|
|
311
511
|
return (
|
|
312
512
|
source: string,
|
|
313
513
|
moduleName: string,
|
|
314
|
-
|
|
514
|
+
options: SimulatorOptions,
|
|
315
515
|
): CreateResult<NativeSimulationHandle> => {
|
|
316
|
-
const
|
|
516
|
+
const napiOpts = buildNapiOpts(options);
|
|
517
|
+
const raw = new addon.NativeSimulationHandle(source, moduleName, napiOpts);
|
|
317
518
|
|
|
318
519
|
const layout = parseLegacyLayout(raw.layoutJson);
|
|
319
520
|
const events: Record<string, number> = JSON.parse(raw.eventsJson);
|
|
521
|
+
const hierarchy = parseHierarchyLayout(raw.hierarchyJson, events);
|
|
320
522
|
|
|
321
523
|
const buf = raw.sharedMemory().buffer;
|
|
322
524
|
const handle = wrapDirectSimulationHandle(raw);
|
|
323
525
|
|
|
324
|
-
return { buffer: buf, layout, events, handle };
|
|
526
|
+
return { buffer: buf, layout, events, handle, hierarchy };
|
|
325
527
|
};
|
|
326
528
|
}
|