@celox-sim/celox 0.1.14 → 0.1.16
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/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/napi-helpers.d.ts +8 -2
- package/dist/napi-helpers.d.ts.map +1 -1
- package/dist/napi-helpers.js +18 -7
- package/dist/napi-helpers.js.map +1 -1
- package/dist/simulation.d.ts +5 -2
- package/dist/simulation.d.ts.map +1 -1
- package/dist/simulation.js +14 -6
- package/dist/simulation.js.map +1 -1
- package/dist/simulator.d.ts +5 -2
- package/dist/simulator.d.ts.map +1 -1
- package/dist/simulator.js +14 -6
- package/dist/simulator.js.map +1 -1
- package/dist/types.d.ts +8 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/src/e2e.bench.ts +1 -1
- package/src/e2e.test.ts +242 -33
- package/src/index.ts +1 -0
- package/src/napi-helpers.ts +37 -9
- package/src/simulation.test.ts +1 -1
- package/src/simulation.ts +40 -11
- package/src/simulator.test.ts +1 -1
- package/src/simulator.ts +47 -7
- package/src/types.ts +9 -1
package/src/e2e.test.ts
CHANGED
|
@@ -400,7 +400,7 @@ describe("E2E: Simulator.create (backward compat)", () => {
|
|
|
400
400
|
{
|
|
401
401
|
__celox_module: true,
|
|
402
402
|
name: "Adder",
|
|
403
|
-
|
|
403
|
+
sources: [{ path: "", content: ADDER_SOURCE }],
|
|
404
404
|
ports: {
|
|
405
405
|
clk: { direction: "input", type: "clock", width: 1 },
|
|
406
406
|
rst: { direction: "input", type: "reset", width: 1 },
|
|
@@ -499,9 +499,13 @@ module InitTest (
|
|
|
499
499
|
b: input bit<8>,
|
|
500
500
|
) {}
|
|
501
501
|
`;
|
|
502
|
-
raw = new addon.NativeSimulatorHandle(
|
|
503
|
-
|
|
504
|
-
|
|
502
|
+
raw = new addon.NativeSimulatorHandle(
|
|
503
|
+
[{ content: source, path: "" }],
|
|
504
|
+
"InitTest",
|
|
505
|
+
{
|
|
506
|
+
fourState: true,
|
|
507
|
+
},
|
|
508
|
+
);
|
|
505
509
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
506
510
|
const buf = raw.sharedMemory().buffer;
|
|
507
511
|
|
|
@@ -536,9 +540,13 @@ module InitTest (
|
|
|
536
540
|
});
|
|
537
541
|
|
|
538
542
|
test("AND: 0 & X = 0 (dominant zero)", () => {
|
|
539
|
-
raw = new addon.NativeSimulatorHandle(
|
|
540
|
-
|
|
541
|
-
|
|
543
|
+
raw = new addon.NativeSimulatorHandle(
|
|
544
|
+
[{ content: AND_OR_SOURCE, path: "" }],
|
|
545
|
+
"AndOr",
|
|
546
|
+
{
|
|
547
|
+
fourState: true,
|
|
548
|
+
},
|
|
549
|
+
);
|
|
542
550
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
543
551
|
const buf = raw.sharedMemory().buffer;
|
|
544
552
|
const view = new DataView(buf);
|
|
@@ -571,9 +579,13 @@ module InitTest (
|
|
|
571
579
|
});
|
|
572
580
|
|
|
573
581
|
test("OR: 1 | X = 1 (dominant one)", () => {
|
|
574
|
-
raw = new addon.NativeSimulatorHandle(
|
|
575
|
-
|
|
576
|
-
|
|
582
|
+
raw = new addon.NativeSimulatorHandle(
|
|
583
|
+
[{ content: AND_OR_SOURCE, path: "" }],
|
|
584
|
+
"AndOr",
|
|
585
|
+
{
|
|
586
|
+
fourState: true,
|
|
587
|
+
},
|
|
588
|
+
);
|
|
577
589
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
578
590
|
const buf = raw.sharedMemory().buffer;
|
|
579
591
|
const view = new DataView(buf);
|
|
@@ -599,9 +611,13 @@ module InitTest (
|
|
|
599
611
|
});
|
|
600
612
|
|
|
601
613
|
test("logic-to-bit assignment strips X mask", () => {
|
|
602
|
-
raw = new addon.NativeSimulatorHandle(
|
|
603
|
-
|
|
604
|
-
|
|
614
|
+
raw = new addon.NativeSimulatorHandle(
|
|
615
|
+
[{ content: LOGIC_BIT_MIX_SOURCE, path: "" }],
|
|
616
|
+
"LogicBitMix",
|
|
617
|
+
{
|
|
618
|
+
fourState: true,
|
|
619
|
+
},
|
|
620
|
+
);
|
|
605
621
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
606
622
|
const buf = raw.sharedMemory().buffer;
|
|
607
623
|
const view = new DataView(buf);
|
|
@@ -620,9 +636,13 @@ module InitTest (
|
|
|
620
636
|
});
|
|
621
637
|
|
|
622
638
|
test("bit-to-logic assignment has no X", () => {
|
|
623
|
-
raw = new addon.NativeSimulatorHandle(
|
|
624
|
-
|
|
625
|
-
|
|
639
|
+
raw = new addon.NativeSimulatorHandle(
|
|
640
|
+
[{ content: LOGIC_BIT_MIX_SOURCE, path: "" }],
|
|
641
|
+
"LogicBitMix",
|
|
642
|
+
{
|
|
643
|
+
fourState: true,
|
|
644
|
+
},
|
|
645
|
+
);
|
|
626
646
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
627
647
|
const buf = raw.sharedMemory().buffer;
|
|
628
648
|
const view = new DataView(buf);
|
|
@@ -642,9 +662,13 @@ module InitTest (
|
|
|
642
662
|
});
|
|
643
663
|
|
|
644
664
|
test("arithmetic with X produces all-X output", () => {
|
|
645
|
-
raw = new addon.NativeSimulatorHandle(
|
|
646
|
-
|
|
647
|
-
|
|
665
|
+
raw = new addon.NativeSimulatorHandle(
|
|
666
|
+
[{ content: ADDER_4STATE_SOURCE, path: "" }],
|
|
667
|
+
"Adder4S",
|
|
668
|
+
{
|
|
669
|
+
fourState: true,
|
|
670
|
+
},
|
|
671
|
+
);
|
|
648
672
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
649
673
|
const buf = raw.sharedMemory().buffer;
|
|
650
674
|
const view = new DataView(buf);
|
|
@@ -668,9 +692,13 @@ module InitTest (
|
|
|
668
692
|
});
|
|
669
693
|
|
|
670
694
|
test("defined inputs in 4-state mode behave like 2-state", () => {
|
|
671
|
-
raw = new addon.NativeSimulatorHandle(
|
|
672
|
-
|
|
673
|
-
|
|
695
|
+
raw = new addon.NativeSimulatorHandle(
|
|
696
|
+
[{ content: ADDER_4STATE_SOURCE, path: "" }],
|
|
697
|
+
"Adder4S",
|
|
698
|
+
{
|
|
699
|
+
fourState: true,
|
|
700
|
+
},
|
|
701
|
+
);
|
|
674
702
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
675
703
|
const buf = raw.sharedMemory().buffer;
|
|
676
704
|
const view = new DataView(buf);
|
|
@@ -694,7 +722,11 @@ module InitTest (
|
|
|
694
722
|
});
|
|
695
723
|
|
|
696
724
|
test("FF captures X from input, reset clears X", () => {
|
|
697
|
-
raw = new addon.NativeSimulatorHandle(
|
|
725
|
+
raw = new addon.NativeSimulatorHandle(
|
|
726
|
+
[{ content: FF_SOURCE, path: "" }],
|
|
727
|
+
"FF",
|
|
728
|
+
{ fourState: true },
|
|
729
|
+
);
|
|
698
730
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
699
731
|
const buf = raw.sharedMemory().buffer;
|
|
700
732
|
const view = new DataView(buf);
|
|
@@ -744,9 +776,13 @@ module InitTest (
|
|
|
744
776
|
});
|
|
745
777
|
|
|
746
778
|
test("FourState write through DUT sets value and mask", () => {
|
|
747
|
-
raw = new addon.NativeSimulatorHandle(
|
|
748
|
-
|
|
749
|
-
|
|
779
|
+
raw = new addon.NativeSimulatorHandle(
|
|
780
|
+
[{ content: ADDER_4STATE_SOURCE, path: "" }],
|
|
781
|
+
"Adder4S",
|
|
782
|
+
{
|
|
783
|
+
fourState: true,
|
|
784
|
+
},
|
|
785
|
+
);
|
|
750
786
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
751
787
|
const buf = raw.sharedMemory().buffer;
|
|
752
788
|
const view = new DataView(buf);
|
|
@@ -764,9 +800,13 @@ module InitTest (
|
|
|
764
800
|
});
|
|
765
801
|
|
|
766
802
|
test("setting defined value clears X mask", () => {
|
|
767
|
-
raw = new addon.NativeSimulatorHandle(
|
|
768
|
-
|
|
769
|
-
|
|
803
|
+
raw = new addon.NativeSimulatorHandle(
|
|
804
|
+
[{ content: ADDER_4STATE_SOURCE, path: "" }],
|
|
805
|
+
"Adder4S",
|
|
806
|
+
{
|
|
807
|
+
fourState: true,
|
|
808
|
+
},
|
|
809
|
+
);
|
|
770
810
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
771
811
|
const buf = raw.sharedMemory().buffer;
|
|
772
812
|
const view = new DataView(buf);
|
|
@@ -866,9 +906,13 @@ describe("E2E: 4-state high-level DUT API", () => {
|
|
|
866
906
|
|
|
867
907
|
test("multiplexer with X selector produces X output", () => {
|
|
868
908
|
const addon = loadNativeAddon();
|
|
869
|
-
const raw = new addon.NativeSimulatorHandle(
|
|
870
|
-
|
|
871
|
-
|
|
909
|
+
const raw = new addon.NativeSimulatorHandle(
|
|
910
|
+
[{ content: MULTIPLEXER_SOURCE, path: "" }],
|
|
911
|
+
"Mux4",
|
|
912
|
+
{
|
|
913
|
+
fourState: true,
|
|
914
|
+
},
|
|
915
|
+
);
|
|
872
916
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
873
917
|
const buf = raw.sharedMemory().buffer;
|
|
874
918
|
const view = new DataView(buf);
|
|
@@ -1676,7 +1720,7 @@ describe("E2E: parameter override — DUT correctness", () => {
|
|
|
1676
1720
|
{
|
|
1677
1721
|
__celox_module: true,
|
|
1678
1722
|
name: "ParamWidth",
|
|
1679
|
-
|
|
1723
|
+
sources: [{ path: "", content: PARAM_WIDTH_SOURCE }],
|
|
1680
1724
|
ports: {
|
|
1681
1725
|
// STALE: these say width=8, but we'll override to 16
|
|
1682
1726
|
a: { direction: "input", type: "logic", width: 8 },
|
|
@@ -2345,3 +2389,168 @@ describe("E2E: deadStorePolicy option", () => {
|
|
|
2345
2389
|
sim.dispose();
|
|
2346
2390
|
});
|
|
2347
2391
|
});
|
|
2392
|
+
|
|
2393
|
+
// ---------------------------------------------------------------------------
|
|
2394
|
+
// E2E: Proto package ordering (issue #22)
|
|
2395
|
+
// ---------------------------------------------------------------------------
|
|
2396
|
+
|
|
2397
|
+
const PROTO_PKG_SOURCE = `
|
|
2398
|
+
pub proto package ItemProto {
|
|
2399
|
+
type Item;
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
pub package ItemPlain::<WIDTH: u32 = 16> for ItemProto {
|
|
2403
|
+
type Item = logic<WIDTH>;
|
|
2404
|
+
}
|
|
2405
|
+
`;
|
|
2406
|
+
|
|
2407
|
+
const GENERIC_MODULE_SOURCE = `
|
|
2408
|
+
pub module GenericModule::<PKG: ItemProto> #(
|
|
2409
|
+
param DEPTH: u32 = 4,
|
|
2410
|
+
) (
|
|
2411
|
+
clk : input clock ,
|
|
2412
|
+
rst : input reset ,
|
|
2413
|
+
d_in : input PKG::Item ,
|
|
2414
|
+
d_out: output PKG::Item ,
|
|
2415
|
+
) {
|
|
2416
|
+
var store: PKG::Item;
|
|
2417
|
+
always_ff (clk, rst) {
|
|
2418
|
+
if_reset { store = '0; }
|
|
2419
|
+
else { store = d_in; }
|
|
2420
|
+
}
|
|
2421
|
+
assign d_out = store;
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
pub module ConcreteModule #(
|
|
2425
|
+
param DEPTH: u32 = 4,
|
|
2426
|
+
) (
|
|
2427
|
+
clk : input clock ,
|
|
2428
|
+
rst : input reset ,
|
|
2429
|
+
d_in : input logic<16> ,
|
|
2430
|
+
d_out: output logic<16> ,
|
|
2431
|
+
) {
|
|
2432
|
+
inst u_inner: GenericModule::<ItemPlain::<16>> #(DEPTH: DEPTH) (
|
|
2433
|
+
clk, rst, d_in, d_out,
|
|
2434
|
+
);
|
|
2435
|
+
}
|
|
2436
|
+
`;
|
|
2437
|
+
|
|
2438
|
+
const UNRELATED_MODULE_SOURCE = `
|
|
2439
|
+
pub module UnrelatedModule (
|
|
2440
|
+
clk : input clock ,
|
|
2441
|
+
rst : input reset ,
|
|
2442
|
+
d_in : input logic<8> ,
|
|
2443
|
+
d_out: output logic<8> ,
|
|
2444
|
+
) {
|
|
2445
|
+
var data_r: logic<8>;
|
|
2446
|
+
always_ff (clk, rst) {
|
|
2447
|
+
if_reset { data_r = 0; }
|
|
2448
|
+
else { data_r = d_in; }
|
|
2449
|
+
}
|
|
2450
|
+
assign d_out = data_r;
|
|
2451
|
+
}
|
|
2452
|
+
`;
|
|
2453
|
+
|
|
2454
|
+
describe("E2E: Proto package ordering (issue #22)", () => {
|
|
2455
|
+
test("single-file source fails when project has proto packages in wrong order", () => {
|
|
2456
|
+
// Reproduce the original bug: when proto_pkg definitions come after
|
|
2457
|
+
// the code that references them (as a single concatenated source),
|
|
2458
|
+
// the analyzer fails with "referred before it is defined".
|
|
2459
|
+
expect(() =>
|
|
2460
|
+
Simulator.fromSource(
|
|
2461
|
+
GENERIC_MODULE_SOURCE + PROTO_PKG_SOURCE + UNRELATED_MODULE_SOURCE,
|
|
2462
|
+
"ConcreteModule",
|
|
2463
|
+
),
|
|
2464
|
+
).toThrow();
|
|
2465
|
+
});
|
|
2466
|
+
|
|
2467
|
+
test("multi-source: unrelated module compiles with proto packages in project", () => {
|
|
2468
|
+
// New behavior: all source files are passed as separate entries.
|
|
2469
|
+
// The Rust from_sources() handles dependency ordering correctly.
|
|
2470
|
+
const sim = Simulator.fromSource<{
|
|
2471
|
+
d_in: bigint;
|
|
2472
|
+
readonly d_out: bigint;
|
|
2473
|
+
}>(
|
|
2474
|
+
PROTO_PKG_SOURCE + GENERIC_MODULE_SOURCE + UNRELATED_MODULE_SOURCE,
|
|
2475
|
+
"UnrelatedModule",
|
|
2476
|
+
);
|
|
2477
|
+
|
|
2478
|
+
// Reset sequence
|
|
2479
|
+
sim.dut.rst = 0n;
|
|
2480
|
+
sim.tick();
|
|
2481
|
+
sim.tick();
|
|
2482
|
+
sim.dut.rst = 1n;
|
|
2483
|
+
|
|
2484
|
+
sim.dut.d_in = 42n;
|
|
2485
|
+
sim.tick();
|
|
2486
|
+
sim.tick();
|
|
2487
|
+
|
|
2488
|
+
expect(sim.dut.d_out).toBe(42n);
|
|
2489
|
+
sim.dispose();
|
|
2490
|
+
});
|
|
2491
|
+
|
|
2492
|
+
test("multi-source: ConcreteModule using proto package works", () => {
|
|
2493
|
+
// The concrete module that actually uses the proto package should
|
|
2494
|
+
// also compile and simulate correctly.
|
|
2495
|
+
const sim = Simulator.fromSource<{
|
|
2496
|
+
d_in: bigint;
|
|
2497
|
+
readonly d_out: bigint;
|
|
2498
|
+
}>(
|
|
2499
|
+
PROTO_PKG_SOURCE + GENERIC_MODULE_SOURCE + UNRELATED_MODULE_SOURCE,
|
|
2500
|
+
"ConcreteModule",
|
|
2501
|
+
);
|
|
2502
|
+
|
|
2503
|
+
// Reset sequence
|
|
2504
|
+
sim.dut.rst = 0n;
|
|
2505
|
+
sim.tick();
|
|
2506
|
+
sim.tick();
|
|
2507
|
+
sim.dut.rst = 1n;
|
|
2508
|
+
|
|
2509
|
+
sim.dut.d_in = 0xabcdn;
|
|
2510
|
+
sim.tick();
|
|
2511
|
+
sim.tick();
|
|
2512
|
+
|
|
2513
|
+
expect(sim.dut.d_out).toBe(0xabcdn);
|
|
2514
|
+
sim.dispose();
|
|
2515
|
+
});
|
|
2516
|
+
|
|
2517
|
+
test("Simulator.create() with multi-source ModuleDefinition", () => {
|
|
2518
|
+
// Simulates what celox-ts-gen now generates: a ModuleDefinition with
|
|
2519
|
+
// sources[] containing all project files.
|
|
2520
|
+
const addon = loadNativeAddon();
|
|
2521
|
+
const nativeCreate = createSimulatorBridge(addon);
|
|
2522
|
+
|
|
2523
|
+
const sim = Simulator.create(
|
|
2524
|
+
{
|
|
2525
|
+
__celox_module: true,
|
|
2526
|
+
name: "UnrelatedModule",
|
|
2527
|
+
sources: [
|
|
2528
|
+
{ path: "proto_pkg.veryl", content: PROTO_PKG_SOURCE },
|
|
2529
|
+
{ path: "generic_module.veryl", content: GENERIC_MODULE_SOURCE },
|
|
2530
|
+
{ path: "unrelated_module.veryl", content: UNRELATED_MODULE_SOURCE },
|
|
2531
|
+
],
|
|
2532
|
+
ports: {
|
|
2533
|
+
clk: { direction: "input", type: "clock", width: 1 },
|
|
2534
|
+
rst: { direction: "input", type: "reset", width: 1 },
|
|
2535
|
+
d_in: { direction: "input", type: "logic", width: 8 },
|
|
2536
|
+
d_out: { direction: "output", type: "logic", width: 8 },
|
|
2537
|
+
},
|
|
2538
|
+
events: ["clk"],
|
|
2539
|
+
},
|
|
2540
|
+
{ __nativeCreate: nativeCreate },
|
|
2541
|
+
);
|
|
2542
|
+
|
|
2543
|
+
// Reset sequence
|
|
2544
|
+
sim.dut.rst = 0n;
|
|
2545
|
+
sim.tick();
|
|
2546
|
+
sim.tick();
|
|
2547
|
+
sim.dut.rst = 1n;
|
|
2548
|
+
|
|
2549
|
+
sim.dut.d_in = 99n;
|
|
2550
|
+
sim.tick();
|
|
2551
|
+
sim.tick();
|
|
2552
|
+
|
|
2553
|
+
expect(sim.dut.d_out).toBe(99n);
|
|
2554
|
+
sim.dispose();
|
|
2555
|
+
});
|
|
2556
|
+
});
|
package/src/index.ts
CHANGED
package/src/napi-helpers.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
PortInfo,
|
|
20
20
|
SignalLayout,
|
|
21
21
|
SimulatorOptions,
|
|
22
|
+
SourceFile,
|
|
22
23
|
TrueLoopSpec,
|
|
23
24
|
} from "./types.js";
|
|
24
25
|
|
|
@@ -30,6 +31,7 @@ export interface RawNapiSimulatorHandle {
|
|
|
30
31
|
readonly layoutJson: string;
|
|
31
32
|
readonly eventsJson: string;
|
|
32
33
|
readonly hierarchyJson: string;
|
|
34
|
+
readonly warningsJson: string;
|
|
33
35
|
readonly stableSize: number;
|
|
34
36
|
readonly totalSize: number;
|
|
35
37
|
tick(eventId: number): void;
|
|
@@ -44,6 +46,7 @@ export interface RawNapiSimulationHandle {
|
|
|
44
46
|
readonly layoutJson: string;
|
|
45
47
|
readonly eventsJson: string;
|
|
46
48
|
readonly hierarchyJson: string;
|
|
49
|
+
readonly warningsJson: string;
|
|
47
50
|
readonly stableSize: number;
|
|
48
51
|
readonly totalSize: number;
|
|
49
52
|
readonly defaultMaxSteps: number | null;
|
|
@@ -98,10 +101,15 @@ export interface NapiOptions {
|
|
|
98
101
|
deadStorePolicy?: string;
|
|
99
102
|
}
|
|
100
103
|
|
|
104
|
+
export interface NapiSourceFile {
|
|
105
|
+
content: string;
|
|
106
|
+
path: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
101
109
|
export interface RawNapiAddon {
|
|
102
110
|
NativeSimulatorHandle: {
|
|
103
111
|
new (
|
|
104
|
-
|
|
112
|
+
sources: NapiSourceFile[],
|
|
105
113
|
top: string,
|
|
106
114
|
options?: NapiOptions,
|
|
107
115
|
): RawNapiSimulatorHandle;
|
|
@@ -113,7 +121,7 @@ export interface RawNapiAddon {
|
|
|
113
121
|
};
|
|
114
122
|
NativeSimulationHandle: {
|
|
115
123
|
new (
|
|
116
|
-
|
|
124
|
+
sources: NapiSourceFile[],
|
|
117
125
|
top: string,
|
|
118
126
|
options?: NapiOptions,
|
|
119
127
|
): RawNapiSimulationHandle;
|
|
@@ -265,7 +273,8 @@ export function buildNapiOpts(
|
|
|
265
273
|
preserveTopPorts: "preserve_top_ports",
|
|
266
274
|
preserveAllPorts: "preserve_all_ports",
|
|
267
275
|
};
|
|
268
|
-
napiOpts.deadStorePolicy =
|
|
276
|
+
napiOpts.deadStorePolicy =
|
|
277
|
+
map[options.deadStorePolicy] ?? options.deadStorePolicy;
|
|
269
278
|
hasOpt = true;
|
|
270
279
|
}
|
|
271
280
|
|
|
@@ -611,12 +620,20 @@ function parseLegacyLayout(json: string): Record<string, SignalLayout> {
|
|
|
611
620
|
*/
|
|
612
621
|
export function createSimulatorBridge(addon: RawNapiAddon): NativeCreateFn {
|
|
613
622
|
return (
|
|
614
|
-
|
|
623
|
+
sources: ReadonlyArray<SourceFile>,
|
|
615
624
|
moduleName: string,
|
|
616
625
|
options: SimulatorOptions,
|
|
617
626
|
): CreateResult<NativeSimulatorHandle> => {
|
|
618
627
|
const napiOpts = buildNapiOpts(options);
|
|
619
|
-
const
|
|
628
|
+
const napiSources = sources.map((s) => ({
|
|
629
|
+
content: s.content,
|
|
630
|
+
path: s.path,
|
|
631
|
+
}));
|
|
632
|
+
const raw = new addon.NativeSimulatorHandle(
|
|
633
|
+
napiSources,
|
|
634
|
+
moduleName,
|
|
635
|
+
napiOpts,
|
|
636
|
+
);
|
|
620
637
|
|
|
621
638
|
const layout = parseLegacyLayout(raw.layoutJson);
|
|
622
639
|
const events: Record<string, number> = JSON.parse(raw.eventsJson);
|
|
@@ -625,7 +642,9 @@ export function createSimulatorBridge(addon: RawNapiAddon): NativeCreateFn {
|
|
|
625
642
|
const buf = raw.sharedMemory().buffer;
|
|
626
643
|
const handle = wrapDirectSimulatorHandle(raw);
|
|
627
644
|
|
|
628
|
-
|
|
645
|
+
const warnings: string[] = JSON.parse(raw.warningsJson ?? "[]");
|
|
646
|
+
|
|
647
|
+
return { buffer: buf, layout, events, handle, hierarchy, warnings };
|
|
629
648
|
};
|
|
630
649
|
}
|
|
631
650
|
|
|
@@ -637,12 +656,20 @@ export function createSimulationBridge(
|
|
|
637
656
|
addon: RawNapiAddon,
|
|
638
657
|
): NativeCreateSimulationFn {
|
|
639
658
|
return (
|
|
640
|
-
|
|
659
|
+
sources: ReadonlyArray<SourceFile>,
|
|
641
660
|
moduleName: string,
|
|
642
661
|
options: SimulatorOptions,
|
|
643
662
|
): CreateResult<NativeSimulationHandle> => {
|
|
644
663
|
const napiOpts = buildNapiOpts(options);
|
|
645
|
-
const
|
|
664
|
+
const napiSources = sources.map((s) => ({
|
|
665
|
+
content: s.content,
|
|
666
|
+
path: s.path,
|
|
667
|
+
}));
|
|
668
|
+
const raw = new addon.NativeSimulationHandle(
|
|
669
|
+
napiSources,
|
|
670
|
+
moduleName,
|
|
671
|
+
napiOpts,
|
|
672
|
+
);
|
|
646
673
|
|
|
647
674
|
const layout = parseLegacyLayout(raw.layoutJson);
|
|
648
675
|
const events: Record<string, number> = JSON.parse(raw.eventsJson);
|
|
@@ -650,7 +677,8 @@ export function createSimulationBridge(
|
|
|
650
677
|
|
|
651
678
|
const buf = raw.sharedMemory().buffer;
|
|
652
679
|
const handle = wrapDirectSimulationHandle(raw);
|
|
680
|
+
const warnings: string[] = JSON.parse(raw.warningsJson ?? "[]");
|
|
653
681
|
|
|
654
|
-
return { buffer: buf, layout, events, handle, hierarchy };
|
|
682
|
+
return { buffer: buf, layout, events, handle, hierarchy, warnings };
|
|
655
683
|
};
|
|
656
684
|
}
|
package/src/simulation.test.ts
CHANGED
|
@@ -20,7 +20,7 @@ interface TopPorts {
|
|
|
20
20
|
const TopModule: ModuleDefinition<TopPorts> = {
|
|
21
21
|
__celox_module: true,
|
|
22
22
|
name: "Top",
|
|
23
|
-
|
|
23
|
+
sources: [{ path: "", content: "module Top ..." }],
|
|
24
24
|
ports: {
|
|
25
25
|
clk: { direction: "input", type: "clock", width: 1 },
|
|
26
26
|
rst: { direction: "input", type: "reset", width: 1 },
|
package/src/simulation.ts
CHANGED
|
@@ -22,6 +22,7 @@ import type {
|
|
|
22
22
|
NativeSimulationHandle,
|
|
23
23
|
SignalLayout,
|
|
24
24
|
SimulatorOptions,
|
|
25
|
+
SourceFile,
|
|
25
26
|
} from "./types.js";
|
|
26
27
|
import { SimulationTimeoutError } from "./types.js";
|
|
27
28
|
|
|
@@ -31,7 +32,7 @@ import { SimulationTimeoutError } from "./types.js";
|
|
|
31
32
|
* @internal
|
|
32
33
|
*/
|
|
33
34
|
export type NativeCreateSimulationFn = (
|
|
34
|
-
|
|
35
|
+
sources: ReadonlyArray<SourceFile>,
|
|
35
36
|
moduleName: string,
|
|
36
37
|
options: SimulatorOptions,
|
|
37
38
|
) => CreateResult<NativeSimulationHandle>;
|
|
@@ -65,6 +66,7 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
65
66
|
{ period: number; eventId: number }
|
|
66
67
|
>();
|
|
67
68
|
private readonly _defaultMaxSteps: number | undefined;
|
|
69
|
+
private readonly _warnings: readonly string[];
|
|
68
70
|
private _disposed = false;
|
|
69
71
|
|
|
70
72
|
private constructor(
|
|
@@ -77,6 +79,7 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
77
79
|
string,
|
|
78
80
|
SignalLayout & { typeKind?: string; associatedClock?: string }
|
|
79
81
|
>,
|
|
82
|
+
warnings: string[],
|
|
80
83
|
defaultMaxSteps?: number,
|
|
81
84
|
) {
|
|
82
85
|
this._handle = handle;
|
|
@@ -85,6 +88,7 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
85
88
|
this._state = state;
|
|
86
89
|
this._buffer = buffer;
|
|
87
90
|
this._layout = layout;
|
|
91
|
+
this._warnings = warnings;
|
|
88
92
|
this._defaultMaxSteps = defaultMaxSteps;
|
|
89
93
|
}
|
|
90
94
|
|
|
@@ -107,11 +111,7 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
107
111
|
|
|
108
112
|
// When the module was produced by the Vite plugin, delegate to fromProject()
|
|
109
113
|
if (module.projectPath && !merged?.__nativeCreate) {
|
|
110
|
-
return Simulation.fromProject<P>(
|
|
111
|
-
module.projectPath,
|
|
112
|
-
module.name,
|
|
113
|
-
merged,
|
|
114
|
-
);
|
|
114
|
+
return Simulation.fromProject<P>(module.projectPath, module.name, merged);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
const createFn = merged?.__nativeCreate ?? _nativeCreate;
|
|
@@ -133,7 +133,7 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
133
133
|
parameters,
|
|
134
134
|
deadStorePolicy,
|
|
135
135
|
} = merged ?? {};
|
|
136
|
-
const result = createFn(module.
|
|
136
|
+
const result = createFn(module.sources, module.name, {
|
|
137
137
|
fourState,
|
|
138
138
|
vcd,
|
|
139
139
|
optimize,
|
|
@@ -167,6 +167,7 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
167
167
|
state,
|
|
168
168
|
result.buffer,
|
|
169
169
|
result.layout,
|
|
170
|
+
result.warnings ?? [],
|
|
170
171
|
);
|
|
171
172
|
}
|
|
172
173
|
|
|
@@ -189,12 +190,19 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
189
190
|
): Simulation<P> {
|
|
190
191
|
const addon = loadNativeAddon(options?.nativeAddonPath);
|
|
191
192
|
const napiOpts = buildNapiOpts(options);
|
|
192
|
-
const raw = new addon.NativeSimulationHandle(
|
|
193
|
+
const raw = new addon.NativeSimulationHandle(
|
|
194
|
+
[{ content: source, path: "" }],
|
|
195
|
+
top,
|
|
196
|
+
napiOpts,
|
|
197
|
+
);
|
|
193
198
|
|
|
194
199
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
195
200
|
const events: Record<string, number> = JSON.parse(raw.eventsJson);
|
|
196
201
|
const rawHierarchy = parseHierarchyLayout(raw.hierarchyJson, events);
|
|
197
|
-
const hierarchy = filterHierarchyForDse(
|
|
202
|
+
const hierarchy = filterHierarchyForDse(
|
|
203
|
+
rawHierarchy,
|
|
204
|
+
options?.deadStorePolicy,
|
|
205
|
+
);
|
|
198
206
|
|
|
199
207
|
const ports = buildPortsFromLayout(hierarchy.signals, events);
|
|
200
208
|
|
|
@@ -211,7 +219,17 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
211
219
|
hierarchy,
|
|
212
220
|
);
|
|
213
221
|
|
|
214
|
-
|
|
222
|
+
const warnings: string[] = JSON.parse(raw.warningsJson ?? "[]");
|
|
223
|
+
|
|
224
|
+
return new Simulation<P>(
|
|
225
|
+
handle,
|
|
226
|
+
dut,
|
|
227
|
+
events,
|
|
228
|
+
state,
|
|
229
|
+
buf,
|
|
230
|
+
layout.signals,
|
|
231
|
+
warnings,
|
|
232
|
+
);
|
|
215
233
|
}
|
|
216
234
|
|
|
217
235
|
/**
|
|
@@ -242,7 +260,10 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
242
260
|
const layout = parseNapiLayout(raw.layoutJson);
|
|
243
261
|
const events: Record<string, number> = JSON.parse(raw.eventsJson);
|
|
244
262
|
const rawHierarchy = parseHierarchyLayout(raw.hierarchyJson, events);
|
|
245
|
-
const hierarchy = filterHierarchyForDse(
|
|
263
|
+
const hierarchy = filterHierarchyForDse(
|
|
264
|
+
rawHierarchy,
|
|
265
|
+
options?.deadStorePolicy,
|
|
266
|
+
);
|
|
246
267
|
|
|
247
268
|
const ports = buildPortsFromLayout(hierarchy.signals, events);
|
|
248
269
|
|
|
@@ -260,6 +281,8 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
260
281
|
hierarchy,
|
|
261
282
|
);
|
|
262
283
|
|
|
284
|
+
const warnings: string[] = JSON.parse(raw.warningsJson ?? "[]");
|
|
285
|
+
|
|
263
286
|
return new Simulation<P>(
|
|
264
287
|
handle,
|
|
265
288
|
dut,
|
|
@@ -267,6 +290,7 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
267
290
|
state,
|
|
268
291
|
buf,
|
|
269
292
|
layout.signals,
|
|
293
|
+
warnings,
|
|
270
294
|
defaultMaxSteps,
|
|
271
295
|
);
|
|
272
296
|
}
|
|
@@ -276,6 +300,11 @@ export class Simulation<P = Record<string, unknown>> {
|
|
|
276
300
|
return this._dut;
|
|
277
301
|
}
|
|
278
302
|
|
|
303
|
+
/** Analyzer warnings emitted during compilation. */
|
|
304
|
+
get warnings(): readonly string[] {
|
|
305
|
+
return this._warnings;
|
|
306
|
+
}
|
|
307
|
+
|
|
279
308
|
/**
|
|
280
309
|
* Register a periodic clock.
|
|
281
310
|
*
|
package/src/simulator.test.ts
CHANGED
|
@@ -20,7 +20,7 @@ interface AdderPorts {
|
|
|
20
20
|
const AdderModule: ModuleDefinition<AdderPorts> = {
|
|
21
21
|
__celox_module: true,
|
|
22
22
|
name: "Adder",
|
|
23
|
-
|
|
23
|
+
sources: [{ path: "", content: "module Adder ..." }],
|
|
24
24
|
ports: {
|
|
25
25
|
clk: { direction: "input", type: "clock", width: 1 },
|
|
26
26
|
rst: { direction: "input", type: "reset", width: 1 },
|