— true if any line starts with "PASS"
@@ -63,7 +63,7 @@ has_pass() { echo "$1" | grep -q "^PASS"; }
# ─── main loop ────────────────────────────────────────────────────────────────
-printf '\n%s\n' "$(dim "circt: $CIRCT_VERILOG")"
+printf '\n%s\n' "$(dim "mox: $MOX_VERILOG")"
printf '%s\n\n' "$(dim "lessons: $LESSONS_DIR")"
for lesson_dir in "$LESSONS_DIR"/*/; do
diff --git a/scripts/toolchain.lock.sh b/scripts/toolchain.lock.sh
index 0c8d3d5..39fe1df 100755
--- a/scripts/toolchain.lock.sh
+++ b/scripts/toolchain.lock.sh
@@ -6,9 +6,15 @@
readonly NODE_MAJOR_VERSION_LOCKED="22"
readonly EMSDK_VERSION_LOCKED="4.0.21"
-readonly CIRCT_REPO_LOCKED="https://github.com/thomasnormal/circt.git"
-readonly CIRCT_REF_LOCKED="a10b92ffd771fd458184278d26f6b980f71aa970"
-readonly CIRCT_LLVM_SUBMODULE_REF_LOCKED="aa3d6b37c7945bfb4c261dd994689de2a2de25bf"
+readonly MOX_REPO_LOCKED="https://github.com/normal-computing/mox.git"
+readonly MOX_REF_LOCKED="805b42d2d2a95c98e954bddd2071bd52f1ced0b4"
+readonly MOX_LLVM_SUBMODULE_REF_LOCKED="aa3d6b37c7945bfb4c261dd994689de2a2de25bf"
-readonly SURFER_ARTIFACT_URL_LOCKED="https://gitlab.com/surfer-project/surfer/-/jobs/artifacts/main/download?job=pages_build"
-readonly SURFER_ARTIFACT_SHA256_LOCKED="abf8d4c3415d445bf86edb39dda9ec9f37d20ccddf4069ec925acb608dcb661b"
+# Mirrored from gitlab.com/surfer-project/surfer pages_build (main pipeline
+# 2625476633, job 15008633862, commit 98287107b9, 2026-06-24). We host our own
+# copy because GitLab only keeps the *latest* pipeline's artifacts, so the
+# upstream "latest main" URL is a moving target that breaks the pinned SHA, and
+# job-ID URLs 404 once the artifacts expire. To refresh: download the new
+# pages_build zip, upload it to the 'surfer-web' release, and update both lines.
+readonly SURFER_ARTIFACT_URL_LOCKED="https://github.com/thomasnormal/sv-tutorial/releases/download/surfer-web/surfer-pages_build.zip"
+readonly SURFER_ARTIFACT_SHA256_LOCKED="8ab484d373120ac3a49592ebe87eaa8a9dc22714eb6c9dded0de495314a1df44"
diff --git a/src/app.html b/src/app.html
index ed2fa00..e9b660a 100644
--- a/src/app.html
+++ b/src/app.html
@@ -5,7 +5,7 @@
SV Tutorial
-
+
diff --git a/src/lessons/index.js b/src/lessons/index.js
index d024481..b11cbba 100644
--- a/src/lessons/index.js
+++ b/src/lessons/index.js
@@ -127,7 +127,7 @@ export const parts = [
],
},
{
- title: 'MLIR & CIRCT',
+ title: 'MLIR & MOX',
chapters: [
{
title: 'Inside the Compiler',
diff --git a/src/lessons/meta.js b/src/lessons/meta.js
index 661bd32..5ee7bc5 100644
--- a/src/lessons/meta.js
+++ b/src/lessons/meta.js
@@ -75,7 +75,7 @@ export default {
'rtl/rtl-to-gates': { title: 'RTL to Gates', focus: '/src/mux_reg.sv' },
'rtl/synthesis-gotchas': { title: 'Synthesis Gotchas', focus: '/src/decoder.sv' },
- // ── MLIR & CIRCT ──────────────────────────────────────────────────────────
+ // ── MLIR & MOX ──────────────────────────────────────────────────────────
'mlir/intro': { title: 'What is MLIR?', focus: '/src/adder.mlir' },
'mlir/comb': { title: 'The comb Dialect', focus: '/src/priority_enc.mlir' },
'mlir/seq': { title: 'The seq Dialect: Registers', focus: '/src/sram_core.mlir' },
diff --git a/src/lessons/mlir/comb/description.html b/src/lessons/mlir/comb/description.html
index abc1dd7..d4fb668 100644
--- a/src/lessons/mlir/comb/description.html
+++ b/src/lessons/mlir/comb/description.html
@@ -1,4 +1,4 @@
-The comb dialect represents purely combinational logic — stateless operations where the same inputs always produce the same output. There is no clock and no side effects.
+The comb dialect represents purely combinational logic — stateless operations where the same inputs always produce the same output. There is no clock and no side effects.
Key operations
@@ -20,4 +20,4 @@ No implicit conversions
Every operand and result has an explicit type and all operands must match. There are no implicit zero-extensions or sign-extensions. This strictness makes the IR unambiguous — a tool can rely on the types without guessing.
comb is language-neutral
-The same comb.mux might originate from a SystemVerilog ternary a ? b : c, a Chisel Mux(), or an HLS tool. CIRCT analyses and optimises the comb IR before it knows — or cares — which language produced it.
+The same comb.mux might originate from a SystemVerilog ternary a ? b : c, a Chisel Mux(), or an HLS tool. MOX analyses and optimises the comb IR before it knows — or cares — which language produced it.
diff --git a/src/lessons/mlir/comb/priority_enc.mlir b/src/lessons/mlir/comb/priority_enc.mlir
index a288e26..c5fdc98 100644
--- a/src/lessons/mlir/comb/priority_enc.mlir
+++ b/src/lessons/mlir/comb/priority_enc.mlir
@@ -1,4 +1,4 @@
-// priority_enc.sv — rewritten as CIRCT MLIR.
+// priority_enc.sv — rewritten as MOX MLIR.
//
// The comb dialect represents purely combinational logic:
// no state, no clock, no side effects.
diff --git a/src/lessons/mlir/comb/priority_enc_tb.mlir b/src/lessons/mlir/comb/priority_enc_tb.mlir
index ec05040..e210205 100644
--- a/src/lessons/mlir/comb/priority_enc_tb.mlir
+++ b/src/lessons/mlir/comb/priority_enc_tb.mlir
@@ -1,6 +1,6 @@
// Testbench: instantiate @priority_enc with req=0b0010; verify grant==1, valid==1.
//
-// Uses LLHD dialect for signal-driven simulation compatible with circt-sim.
+// Uses LLHD dialect for signal-driven simulation compatible with mox-sim.
hw.module @tb() {
%c0_i2 = hw.constant 0 : i2
%c0_i1 = hw.constant false
diff --git a/src/lessons/mlir/intro/adder.mlir b/src/lessons/mlir/intro/adder.mlir
index 187759e..53042f1 100644
--- a/src/lessons/mlir/intro/adder.mlir
+++ b/src/lessons/mlir/intro/adder.mlir
@@ -1,4 +1,4 @@
-// The adder from Part 1 — expressed as CIRCT MLIR.
+// The adder from Part 1 — expressed as MOX MLIR.
//
// Every MLIR file is a sequence of operations.
// Here there is one top-level operation: hw.module.
diff --git a/src/lessons/mlir/intro/adder_tb.mlir b/src/lessons/mlir/intro/adder_tb.mlir
index 43a7167..e6d425e 100644
--- a/src/lessons/mlir/intro/adder_tb.mlir
+++ b/src/lessons/mlir/intro/adder_tb.mlir
@@ -1,6 +1,6 @@
// Testbench: instantiate @adder with a=5, b=3 and verify sum==8.
//
-// Uses LLHD dialect for signal-driven simulation compatible with circt-sim.
+// Uses LLHD dialect for signal-driven simulation compatible with mox-sim.
// The hw.instance output is driven onto a signal so the check process can
// probe it after epsilon time, then print PASS or FAIL.
hw.module @tb() {
diff --git a/src/lessons/mlir/intro/description.html b/src/lessons/mlir/intro/description.html
index 9a7dec9..0618f76 100644
--- a/src/lessons/mlir/intro/description.html
+++ b/src/lessons/mlir/intro/description.html
@@ -1,4 +1,4 @@
-Every time you clicked Run or Verify in this tutorial, your SystemVerilog was parsed by CIRCT and converted into MLIR before anything else happened. This part lifts the lid on that representation.
+Every time you clicked Run or Verify in this tutorial, your SystemVerilog was parsed by MOX and converted into MLIR before anything else happened. This part lifts the lid on that representation.
What is an IR?
An Intermediate Representation is the compiler's internal language — somewhere between your source code and the final output. You never write it by hand in normal use, but reading it is a superpower for understanding what tools actually do with your design.
@@ -17,9 +17,9 @@ Operations, values, and types
Operation — a named computation: dialect.opname operands : type
Value — the result of an operation, written %name. Each value is produced exactly once (SSA form ) but can be used as many times as needed.
- Type — attached to every value. CIRCT uses i1, i8, i32 etc. for signless integers of N bits.
+ Type — attached to every value. MOX uses i1, i8, i32 etc. for signless integers of N bits.
-Open adder.mlir — it is the 8-bit adder from Part 1 written in CIRCT's textual format. Every line is annotated. The entire module is one hw.module operation containing two inner operations: comb.add and hw.output.
+Open adder.mlir — it is the 8-bit adder from Part 1 written in MOX's textual format. Every line is annotated. The entire module is one hw.module operation containing two inner operations: comb.add and hw.output.
Dialects
The prefix before the dot — hw, comb, seq — is the dialect . Think of it as a namespace for a coherent set of operations at one abstraction level:
diff --git a/src/lessons/mlir/lowering/description.html b/src/lessons/mlir/lowering/description.html
index 9ddcb13..5acdd60 100644
--- a/src/lessons/mlir/lowering/description.html
+++ b/src/lessons/mlir/lowering/description.html
@@ -1,4 +1,4 @@
-CIRCT does not convert SystemVerilog to its output in one step. It runs a pipeline of lowering passes , each transforming the IR one level closer to the target. Open lowering.mlir — it shows the same D flip-flop at each stage.
+MOX does not convert SystemVerilog to its output in one step. It runs a pipeline of lowering passes , each transforming the IR one level closer to the target. Open lowering.mlir — it shows the same D flip-flop at each stage.
The two output paths
@@ -15,7 +15,7 @@ The two output paths
The left branch is used when you click Run . The right branch is used when you click Verify . Both start from the same hw/comb/seq IR.
The sv dialect: one step from text
-The sv dialect is an AST-level mirror of SystemVerilog. Each operation maps directly onto a SV construct:
+The sv dialect is an AST-level mirror of SystemVerilog. Each operation maps directly onto a SV construct:
sv.reg name "q" : !hw.inout<i8> → reg [7:0] q;
sv.always posedge %clk { … } → always @(posedge clk) begin … end
@@ -25,8 +25,8 @@ The sv dialect: one step from text
The LowerSeqToSV pass converts every seq.compreg into an sv.reg plus an sv.always block. After that, ExportVerilog is essentially a pretty-printer.
The formal path: SMTLIB and Z3
-For bounded model checking, CIRCT takes a different route. The LowerHWtoBMC pass unrolls the design for N clock cycles and encodes it as a SAT/SMT formula. If any input sequence in those N cycles can violate a verif.assert, Z3 finds it and returns a counterexample. If Z3 proves no such sequence exists, the assertion is proved for that bound.
+For bounded model checking, MOX takes a different route. The LowerHWtoBMC pass unrolls the design for N clock cycles and encodes it as a SAT/SMT formula. If any input sequence in those N cycles can violate a verif.assert, Z3 finds it and returns a counterexample. If Z3 proves no such sequence exists, the assertion is proved for that bound.
This is why formal verification is stronger than simulation: instead of checking the testbench inputs you wrote, it checks every possible input sequence up to the bound.
Passes are composable
-A CIRCT pipeline is just a list of pass names. You can run only some passes, inspect the IR in between, or insert your own custom passes. This is MLIR's core promise: the framework handles the plumbing so tool builders can focus on the transformations.
+A MOX pipeline is just a list of pass names. You can run only some passes, inspect the IR in between, or insert your own custom passes. This is MLIR's core promise: the framework handles the plumbing so tool builders can focus on the transformations.
diff --git a/src/lessons/mlir/lowering/lowering.mlir b/src/lessons/mlir/lowering/lowering.mlir
index 4e5320d..19252e7 100644
--- a/src/lessons/mlir/lowering/lowering.mlir
+++ b/src/lessons/mlir/lowering/lowering.mlir
@@ -1,6 +1,6 @@
// The lowering pipeline — before and after.
//
-// CIRCT transforms hardware IR through a sequence of passes.
+// MOX transforms hardware IR through a sequence of passes.
// Each pass lowers one dialect level closer to SystemVerilog text.
//
// ─────────────────────────────────────────────────────────────────────────
@@ -51,9 +51,9 @@ hw.module @dff_after(in %d : i8, in %clk : i1, out q : i8) {
// ─────────────────────────────────────────────────────────────────────────
-// BONUS: the formal verification path (what circt-bmc does)
+// BONUS: the formal verification path (what mox-bmc does)
//
-// Instead of going to sv + ExportVerilog, circt-bmc takes the
+// Instead of going to sv + ExportVerilog, mox-bmc takes the
// hw + comb + seq IR and lowers it to SMT (Satisfiability Modulo Theories):
//
// hw.module + verif.assert
@@ -64,6 +64,6 @@ hw.module @dff_after(in %d : i8, in %clk : i1, out q : i8) {
// ↓ ExportSMTLIB
// SMTLIB text → Z3 solver → sat / unsat
//
-// This is why circt-bmc can exhaustively check all input combinations
+// This is why mox-bmc can exhaustively check all input combinations
// rather than just the ones your testbench happened to try.
// ─────────────────────────────────────────────────────────────────────────
diff --git a/src/lessons/mlir/lowering/lowering_tb.mlir b/src/lessons/mlir/lowering/lowering_tb.mlir
index 5bad311..c92b1e7 100644
--- a/src/lessons/mlir/lowering/lowering_tb.mlir
+++ b/src/lessons/mlir/lowering/lowering_tb.mlir
@@ -2,7 +2,7 @@
// Drive D=0xAA, apply one posedge, confirm Q==0xAA.
//
// Note: @dff_after uses sv.reg + sv.always posedge which requires SV-to-LLHD
-// lowering passes not run by circt-sim in standalone mode. The testbench
+// lowering passes not run by mox-sim in standalone mode. The testbench
// therefore exercises only @dff_before (which uses seq.compreg directly).
hw.module @tb() {
%false = hw.constant false
diff --git a/src/lessons/mlir/seq/description.html b/src/lessons/mlir/seq/description.html
index 624e68a..d822cdf 100644
--- a/src/lessons/mlir/seq/description.html
+++ b/src/lessons/mlir/seq/description.html
@@ -1,4 +1,4 @@
-The seq dialect adds state . Where comb operations are timeless, seq operations have memory — they remember values across clock cycles.
+The seq dialect adds state . Where comb operations are timeless, seq operations have memory — they remember values across clock cycles.
seq.compreg — the D flip-flop
The core operation is seq.compreg:
diff --git a/src/lessons/mlir/seq/sram_core.mlir b/src/lessons/mlir/seq/sram_core.mlir
index b3d50ae..dd04f97 100644
--- a/src/lessons/mlir/seq/sram_core.mlir
+++ b/src/lessons/mlir/seq/sram_core.mlir
@@ -1,4 +1,4 @@
-// sram_core.sv — rewritten as CIRCT MLIR.
+// sram_core.sv — rewritten as MOX MLIR.
//
// The seq dialect represents sequential (stateful) logic.
// Its key operation is seq.compreg — an abstract D flip-flop:
diff --git a/src/lessons/mlir/seq/sram_core_tb.mlir b/src/lessons/mlir/seq/sram_core_tb.mlir
index 0a6eb67..8bf8e6d 100644
--- a/src/lessons/mlir/seq/sram_core_tb.mlir
+++ b/src/lessons/mlir/seq/sram_core_tb.mlir
@@ -3,7 +3,7 @@
// confirm Q==0x42 on the output.
//
// Note: @sram_core uses seq.hlmem which requires lowering passes not run by
-// circt-sim in standalone mode, so we test the simpler @dff example here.
+// mox-sim in standalone mode, so we test the simpler @dff example here.
//
// Uses LLHD dialect for clock generation and time-driven simulation:
// llhd.sig / llhd.prb / llhd.drv — signals and drives
diff --git a/src/lessons/sv/events/event_sync.sol.sv b/src/lessons/sv/events/event_sync.sol.sv
index 8777f63..2527557 100644
--- a/src/lessons/sv/events/event_sync.sol.sv
+++ b/src/lessons/sv/events/event_sync.sol.sv
@@ -5,6 +5,7 @@ module event_sync;
logic [7:0] mem [0:3];
int errors = 0;
+ bit reader_ran = 0;
initial begin
#10;
@@ -17,13 +18,14 @@ module event_sync;
@(write_done);
if (mem[0] !== 8'd10 || mem[1] !== 8'd20) errors++;
if (mem[2] !== 8'd30 || mem[3] !== 8'd40) errors++;
+ reader_ran = 1;
$display("reader: %0d error(s)", errors);
-> read_done;
end
initial begin
@(read_done);
- if (errors == 0) $display("PASS");
+ if (reader_ran && errors == 0) $display("PASS");
$finish;
end
diff --git a/src/lessons/sv/events/event_sync.sv b/src/lessons/sv/events/event_sync.sv
index 8b2eecd..70e2eb9 100644
--- a/src/lessons/sv/events/event_sync.sv
+++ b/src/lessons/sv/events/event_sync.sv
@@ -7,6 +7,7 @@ module event_sync;
logic [7:0] mem [0:3];
int errors = 0;
+ bit reader_ran = 0; // set by the reader; checker must observe
// ── Writer ────────────────────────────────────────────────────────────────
// Fills the array after 10 time units, then signals it is done.
@@ -23,6 +24,7 @@ module event_sync;
// TODO: wait for write_done before reading
if (mem[0] !== 8'd10 || mem[1] !== 8'd20) errors++;
if (mem[2] !== 8'd30 || mem[3] !== 8'd40) errors++;
+ reader_ran = 1;
$display("reader: %0d error(s)", errors);
// TODO: post read_done so the checker can report
end
@@ -31,7 +33,7 @@ module event_sync;
// Must wait for the reader before declaring the result.
initial begin
// TODO: wait for read_done before reporting
- if (errors == 0) $display("PASS");
+ if (reader_ran && errors == 0) $display("PASS");
$finish;
end
diff --git a/src/lessons/sva/immediate-assert/description.html b/src/lessons/sva/immediate-assert/description.html
index a095d22..4804c51 100644
--- a/src/lessons/sva/immediate-assert/description.html
+++ b/src/lessons/sva/immediate-assert/description.html
@@ -24,7 +24,7 @@
The else $error("...") clause prints an automatic timestamp, file name, and line number — far more useful than a bare $display.
Formal verification with BMC
-Immediate assertions inside always blocks are also recognized by CIRCT's bounded model checker . Instead of running a testbench, BMC exhaustively searches all possible input combinations. If an assertion can be violated, BMC produces a counterexample — without you having to write a single test vector.
+Immediate assertions inside always blocks are also recognized by MOX's bounded model checker . Instead of running a testbench, BMC exhaustively searches all possible input combinations. If an assertion can be violated, BMC produces a counterexample — without you having to write a single test vector.
Exercise
Open fifo_checker.sv. The module receives four FIFO status signals and must prevent four illegal conditions. Inside the always @(posedge clk) block, add four immediate assertions:
diff --git a/src/lessons/uvm/ral/description.html b/src/lessons/uvm/ral/description.html
index 276471d..73622d4 100644
--- a/src/lessons/uvm/ral/description.html
+++ b/src/lessons/uvm/ral/description.html
@@ -51,7 +51,7 @@ UVM RAL hierarchy
The starter model
- This lesson ships a hand-rolled register model that already compiles and simulates in CIRCT. Study how it maps to the skeleton above before converting it:
+ This lesson ships a hand-rolled register model that already compiles and simulates in MOX. Study how it maps to the skeleton above before converting it:
Fields as class members — logic enable and logic [1:0] mode are plain variables; uvm_reg_field replaces them
to_data() — packs fields by hand: {5'b0, mode, enable}; uvm_reg::get() does this automatically using the lsb_pos from configure()
diff --git a/src/lib/circt.js b/src/lib/circt.js
deleted file mode 100644
index 07de4df..0000000
--- a/src/lib/circt.js
+++ /dev/null
@@ -1 +0,0 @@
-export { getCirctWasmAdapter, createCirctWasmAdapter } from '../runtime/circt-adapter.js';
diff --git a/src/lib/mox.js b/src/lib/mox.js
new file mode 100644
index 0000000..bd170e5
--- /dev/null
+++ b/src/lib/mox.js
@@ -0,0 +1 @@
+export { getMoxWasmAdapter, createMoxWasmAdapter } from '../runtime/mox-adapter.js';
diff --git a/src/lib/offline-cache.js b/src/lib/offline-cache.js
index 9fa93b3..781b330 100644
--- a/src/lib/offline-cache.js
+++ b/src/lib/offline-cache.js
@@ -3,7 +3,7 @@ export const OFFLINE_RUNTIME_CACHE = 'svt-runtime-v1';
export const OFFLINE_STATE_KEY = 'svt:offline-ready-v1';
export const OFFLINE_READY_SENTINEL_RELATIVE_PATH = '__offline__/ready';
-export const HEAVY_STATIC_PREFIXES = ['circt/', 'surfer/', 'z3/', 'pyodide/'];
+export const HEAVY_STATIC_PREFIXES = ['mox/', 'surfer/', 'z3/', 'pyodide/'];
export const SURFER_RUNTIME_PATHS = [
'surfer/index.html',
@@ -15,24 +15,24 @@ export const SURFER_RUNTIME_PATHS = [
];
export const LOCAL_RUNTIME_PATHS = [
- 'circt/circt-verilog.js',
- 'circt/circt-verilog.wasm',
- 'circt/circt-sim.js',
- 'circt/circt-sim.wasm',
- 'circt/circt-bmc.js',
- 'circt/circt-bmc.wasm',
- 'circt/circt-sim-vpi.js',
- 'circt/circt-sim-vpi.wasm',
- 'circt/circt-lec.js',
- 'circt/circt-lec.wasm',
- 'circt/uvm-core/uvm-manifest.json',
+ 'mox/mox-verilog.js',
+ 'mox/mox-verilog.wasm',
+ 'mox/mox-sim.js',
+ 'mox/mox-sim.wasm',
+ 'mox/mox-bmc.js',
+ 'mox/mox-bmc.wasm',
+ 'mox/mox-sim-vpi.js',
+ 'mox/mox-sim-vpi.wasm',
+ 'mox/mox-lec.js',
+ 'mox/mox-lec.wasm',
+ 'mox/uvm-core/uvm-manifest.json',
'z3/z3-built.js',
'z3/z3-built.wasm',
...SURFER_RUNTIME_PATHS,
];
export const PYODIDE_MANIFEST_RELATIVE_PATH = 'pyodide/pyodide-manifest.json';
-export const UVM_MANIFEST_RELATIVE_PATH = 'circt/uvm-core/uvm-manifest.json';
+export const UVM_MANIFEST_RELATIVE_PATH = 'mox/uvm-core/uvm-manifest.json';
export const PYODIDE_COMPANION_FILES = [
'pyodide.js',
diff --git a/src/lib/offline-cache.test.js b/src/lib/offline-cache.test.js
index ea4b767..25bf777 100644
--- a/src/lib/offline-cache.test.js
+++ b/src/lib/offline-cache.test.js
@@ -16,7 +16,7 @@ describe('offline-cache helpers', () => {
expect(normalizeBasePath('')).toBe('/');
expect(normalizeBasePath('/sv-tutorial')).toBe('/sv-tutorial/');
expect(normalizeBasePath('sv-tutorial')).toBe('/sv-tutorial/');
- expect(joinBasePath('/sv-tutorial', '/circt/circt-sim.js')).toBe('/sv-tutorial/circt/circt-sim.js');
+ expect(joinBasePath('/sv-tutorial', '/mox/mox-sim.js')).toBe('/sv-tutorial/mox/mox-sim.js');
});
it('dedupes string values', () => {
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index afbba94..3ab97bc 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -5,7 +5,7 @@
import { browser } from '$app/environment';
import { onMount, untrack } from 'svelte';
import '../app.css';
- import { getCirctRuntimeConfig, Z3_SCRIPT_URL } from '../runtime/circt-config.js';
+ import { getMoxRuntimeConfig, Z3_SCRIPT_URL } from '../runtime/mox-config.js';
import {
OFFLINE_APP_CACHE_PREFIX,
OFFLINE_RUNTIME_CACHE,
@@ -267,7 +267,7 @@
try {
await ensureOfflineServiceWorker();
- const config = getCirctRuntimeConfig();
+ const config = getMoxRuntimeConfig();
const allUrls = await resolveOfflineAssetUrls(config);
const urls = allUrls.filter((url) => isSameOriginAssetUrl(url));
const skippedCrossOrigin = allUrls.length - urls.length;
diff --git a/src/routes/lesson/[part]/[name]/+page.svelte b/src/routes/lesson/[part]/[name]/+page.svelte
index 76795fb..0bf0097 100644
--- a/src/routes/lesson/[part]/[name]/+page.svelte
+++ b/src/routes/lesson/[part]/[name]/+page.svelte
@@ -3,7 +3,7 @@
import { browser } from '$app/environment';
import { beforeNavigate, goto } from '$app/navigation';
import { base } from '$app/paths';
- import { getCirctWasmAdapter } from '$lib/circt.js';
+ import { getMoxWasmAdapter } from '$lib/mox.js';
import { darkMode, vimMode } from '$lib/stores/settings.js';
import { completedSlugs } from '$lib/stores/completed.js';
import { cloneFiles, mergeFiles, filesEqual, topNameFromFocus } from '$lib/lesson-utils.js';
@@ -38,7 +38,7 @@
let showCopyModal = $state(false);
let copyEnableChecked = $state(false);
let didAnnounceTrimThisRun = $state(false);
- let circt = $state(null);
+ let mox = $state(null);
let glossaryCard = $state(null); // { body, top, left }
let waveformRef = $state(null);
let waveSignalsReady = $state(false);
@@ -131,7 +131,7 @@
}
onMount(() => {
- circt = getCirctWasmAdapter();
+ mox = getMoxWasmAdapter();
if (browser && sessionStorage.getItem('copyEnabled') === 'true') copyEnabled = true;
_currentSlug = lesson.slug;
_loadWorkspace(lesson);
@@ -347,7 +347,7 @@
}
async function runSim(mode = 'sim') {
- if (running || !circt) return;
+ if (running || !mox) return;
running = true;
runMode = mode;
runPhase = 'compiling';
@@ -374,7 +374,7 @@
};
if (lesson.runner === 'cocotb') {
- const result = await circt.runCocotb({
+ const result = await mox.runCocotb({
files: workspace,
top: topNameFromFocus(lesson.focus),
onStatus, onLog
@@ -382,7 +382,7 @@
if (streamedEntries === 0) for (const entry of result.logs || []) appendLogEntry(entry);
else mergeNonStreamResultLogs(result.logs);
} else if (useLec) {
- const result = await circt.runLec({
+ const result = await mox.runLec({
files: workspace,
module1: lesson.module1 || 'Spec',
module2: lesson.module2 || 'Impl',
@@ -391,7 +391,7 @@
if (streamedEntries === 0) for (const entry of result.logs || []) appendLogEntry(entry);
else mergeNonStreamResultLogs(result.logs);
} else if (useBmc) {
- const result = await circt.runBmc({
+ const result = await mox.runBmc({
files: workspace,
top: topNameFromFocus(lesson.focus),
onStatus, onLog
@@ -399,7 +399,7 @@
if (streamedEntries === 0) for (const entry of result.logs || []) appendLogEntry(entry);
else mergeNonStreamResultLogs(result.logs);
} else {
- const result = await circt.run({
+ const result = await mox.run({
files: workspace,
top: topNameFromFocus(lesson.focus),
simulate: lesson.simulate,
@@ -418,8 +418,8 @@
}
function cancelRun() {
- if (!running || !circt) return;
- circt.cancel();
+ if (!running || !mox) return;
+ mox.cancel();
appendLogEntry('# run cancelled');
}
diff --git a/src/runtime/circt-config.js b/src/runtime/circt-config.js
deleted file mode 100644
index 85e4b69..0000000
--- a/src/runtime/circt-config.js
+++ /dev/null
@@ -1,139 +0,0 @@
-export const CIRCT_FORK_REPO = 'git@github.com:thomasnormal/circt.git';
-
-function normalizeBaseUrl(raw) {
- const base = String(raw || '').trim();
- if (!base || base === '.' || base === './') return '/';
-
- // Normalize optional leading "./" used by static builds.
- const noDotPrefix = base.startsWith('./') ? base.slice(1) : base;
- const withLeadingSlash = noDotPrefix.startsWith('/') ? noDotPrefix : `/${noDotPrefix}`;
- const withTrailingSlash = withLeadingSlash.endsWith('/')
- ? withLeadingSlash
- : `${withLeadingSlash}/`;
-
- // Remove "/./" segments so "/./circt" becomes "/circt".
- return withTrailingSlash.replace(/\/\.\//g, '/');
-}
-
-const BASE = normalizeBaseUrl(import.meta.env.VITE_BASE || import.meta.env.BASE_URL);
-
-export function getRuntimeBasePath() {
- return BASE;
-}
-
-export const Z3_SCRIPT_URL = `${BASE}z3/z3-built.js`;
-const DEFAULT_TOOLCHAIN = {
- verilog: {
- js: `${BASE}circt/circt-verilog.js`,
- wasm: `${BASE}circt/circt-verilog.wasm`
- },
- sim: {
- js: `${BASE}circt/circt-sim.js`,
- wasm: `${BASE}circt/circt-sim.wasm`
- },
- bmc: {
- js: `${BASE}circt/circt-bmc.js`,
- wasm: `${BASE}circt/circt-bmc.wasm`
- },
- simVpi: {
- js: `${BASE}circt/circt-sim-vpi.js`,
- wasm: `${BASE}circt/circt-sim-vpi.wasm`
- },
- lec: {
- js: `${BASE}circt/circt-lec.js`,
- wasm: `${BASE}circt/circt-lec.wasm`
- }
-};
-
-const DEFAULT_VERILOG_ARGS = ['--resource-guard=false', '--ir-llhd', '--timescale', '1ns/1ns', '--single-unit'];
-const DEFAULT_LEC_VERILOG_ARGS = ['--resource-guard=false', '--ir-hw', '--single-unit'];
-const DEFAULT_LEC_ARGS = [
- '--resource-guard=false',
- '--assume-known-inputs',
- '-c1', '{module1}',
- '-c2', '{module2}',
- '--emit-smtlib',
- '-o', '/workspace/out/check.smt2',
- '{input}'
-];
-const DEFAULT_SIM_ARGS = ['--resource-guard=false'];
-const DEFAULT_BMC_ARGS = [
- '--resource-guard=false',
- '--assume-known-inputs',
- '-b',
- '20',
- '--module',
- '{top}',
- '--emit-smtlib',
- '-o',
- '/workspace/out/check.smt2',
- '{input}'
-];
-
-function parseArgs(raw, fallback) {
- if (!raw) return fallback;
- try {
- const parsed = JSON.parse(raw);
- if (Array.isArray(parsed) && parsed.every((v) => typeof v === 'string')) {
- return parsed;
- }
- } catch {
- // Fallback to a simple shell-like split for convenience.
- }
- return raw
- .split(' ')
- .map((s) => s.trim())
- .filter(Boolean);
-}
-
-function pickUrlFromEnv(primary, fallback) {
- return primary || fallback;
-}
-
-export function getCirctRuntimeConfig() {
- return {
- toolchain: {
- verilog: {
- js: pickUrlFromEnv(import.meta.env.VITE_CIRCT_VERILOG_JS_URL, DEFAULT_TOOLCHAIN.verilog.js),
- wasm: pickUrlFromEnv(import.meta.env.VITE_CIRCT_VERILOG_WASM_URL, DEFAULT_TOOLCHAIN.verilog.wasm)
- },
- sim: {
- js: pickUrlFromEnv(import.meta.env.VITE_CIRCT_SIM_JS_URL, DEFAULT_TOOLCHAIN.sim.js),
- wasm: pickUrlFromEnv(import.meta.env.VITE_CIRCT_SIM_WASM_URL, DEFAULT_TOOLCHAIN.sim.wasm)
- },
- bmc: {
- js: pickUrlFromEnv(import.meta.env.VITE_CIRCT_BMC_JS_URL, DEFAULT_TOOLCHAIN.bmc.js),
- wasm: pickUrlFromEnv(import.meta.env.VITE_CIRCT_BMC_WASM_URL, DEFAULT_TOOLCHAIN.bmc.wasm)
- },
- simVpi: {
- js: pickUrlFromEnv(import.meta.env.VITE_CIRCT_SIM_VPI_JS_URL, DEFAULT_TOOLCHAIN.simVpi.js),
- wasm: pickUrlFromEnv(import.meta.env.VITE_CIRCT_SIM_VPI_WASM_URL, DEFAULT_TOOLCHAIN.simVpi.wasm)
- },
- lec: {
- js: pickUrlFromEnv(import.meta.env.VITE_CIRCT_LEC_JS_URL, DEFAULT_TOOLCHAIN.lec.js),
- wasm: pickUrlFromEnv(import.meta.env.VITE_CIRCT_LEC_WASM_URL, DEFAULT_TOOLCHAIN.lec.wasm)
- }
- },
- pyodideUrl: import.meta.env.VITE_PYODIDE_URL || `${BASE}pyodide/pyodide.js`,
- verilogArgs: parseArgs(import.meta.env.VITE_CIRCT_VERILOG_ARGS, DEFAULT_VERILOG_ARGS),
- simArgs: parseArgs(import.meta.env.VITE_CIRCT_SIM_ARGS, DEFAULT_SIM_ARGS),
- bmcArgs: parseArgs(import.meta.env.VITE_CIRCT_BMC_ARGS, DEFAULT_BMC_ARGS),
- lecVerilogArgs: parseArgs(import.meta.env.VITE_CIRCT_LEC_VERILOG_ARGS, DEFAULT_LEC_VERILOG_ARGS),
- lecArgs: parseArgs(import.meta.env.VITE_CIRCT_LEC_ARGS, DEFAULT_LEC_ARGS),
- note: import.meta.env.VITE_CIRCT_NOTE || ''
- };
-}
-
-export function getRuntimeEnvDoc() {
- return {
- VITE_CIRCT_VERILOG_JS_URL: 'circt-verilog JS artifact URL.',
- VITE_CIRCT_VERILOG_WASM_URL: 'circt-verilog WASM artifact URL.',
- VITE_CIRCT_SIM_JS_URL: 'circt-sim JS artifact URL.',
- VITE_CIRCT_SIM_WASM_URL: 'circt-sim WASM artifact URL.',
- VITE_CIRCT_BMC_JS_URL: 'circt-bmc JS artifact URL.',
- VITE_CIRCT_BMC_WASM_URL: 'circt-bmc WASM artifact URL.',
- VITE_CIRCT_VERILOG_ARGS: 'JSON array or space-separated args passed before source files.',
- VITE_CIRCT_SIM_ARGS: 'JSON array or space-separated args passed before MLIR input.',
- VITE_CIRCT_BMC_ARGS: 'JSON array or space-separated args for BMC fallback.'
- };
-}
diff --git a/src/runtime/cocotb-shim.py b/src/runtime/cocotb-shim.py
index c73abe0..e10b5db 100644
--- a/src/runtime/cocotb-shim.py
+++ b/src/runtime/cocotb-shim.py
@@ -1,5 +1,5 @@
"""
-Minimal cocotb-compatible API for in-browser simulation via Pyodide + CIRCT WASM VPI.
+Minimal cocotb-compatible API for in-browser simulation via Pyodide + MOX WASM VPI.
User-facing API (matches real cocotb):
import cocotb
diff --git a/src/runtime/cocotb-worker-source.js b/src/runtime/cocotb-worker-source.js
index 72bb657..b292a8c 100644
--- a/src/runtime/cocotb-worker-source.js
+++ b/src/runtime/cocotb-worker-source.js
@@ -375,7 +375,7 @@ self.onmessage = async function(event) {
}
try {
- // ── 1. Load the VPI circt-sim WASM ───────────────────────────────────────
+ // ── 1. Load the VPI mox-sim WASM ───────────────────────────────────────
// Fetch the JS source first so we can detect NODERAWFS=1 (recognisable by
// the unconditional require('path') / require('fs') calls at module level).
var simInMemFS = null;
@@ -387,7 +387,7 @@ self.onmessage = async function(event) {
printErr: function(line) { onLog(String(line)); },
locateFile: function(path) { return path.endsWith('.wasm') ? simWasmUrl : path; },
instantiateWasm: function(imports, callback) {
- // Wrap _circt_vpi_wasm_yield (import 'r') with Asyncify.handleAsync so
+ // Wrap _mox_vpi_wasm_yield (import 'r') with Asyncify.handleAsync so
// WASM calls to the yield import trigger Asyncify unwind/rewind instead
// of running synchronously (instrumentWasmImports is never called by the
// compiled artifact's createWasm(), so we must wrap here ourselves).
@@ -443,7 +443,7 @@ self.onmessage = async function(event) {
});
// ── 1b. Patch Module to expose Emscripten internals needed by VPI helpers ─
- // circt-sim-vpi.js assigns _malloc/_free to module-level globals but not to
+ // mox-sim-vpi.js assigns _malloc/_free to module-level globals but not to
// Module["_malloc"] / Module["_free"]. setValue/getValue and HEAPU8 are
// absent from EXPORTED_RUNTIME_METHODS for this build. After importScripts
// (or indirect eval) these become worker-scope globals we can forward.
@@ -536,7 +536,7 @@ self.onmessage = async function(event) {
// ── 7. Create a no-op cb_rtn function pointer for VPI callbacks ──────────
// VPIRuntime::registerCb rejects null cb_rtn (returns 0 without storing).
// We need a valid WASM (i32)->i32 function pointer for the cb_rtn field.
- // Compile a tiny WASM module and insert its export into circt-sim's table.
+ // Compile a tiny WASM module and insert its export into mox-sim's table.
// Fallback to WebAssembly.Function (Chrome 97+) or placeholder value 1.
var noopCbPtr = wsAddFunctionToTable(WS_NOOP_CB_WASM);
if (!noopCbPtr) { try {
@@ -544,7 +544,7 @@ self.onmessage = async function(event) {
var tbl = wasmTable; var s = tbl.length; tbl.grow(1); tbl.set(s, cFn); noopCbPtr = s;
} catch(_) {} }
// Last resort: value 1 — registerCb only checks non-zero; the patched
- // _circt_vpi_wasm_yield wraps the table call in try-catch.
+ // _mox_vpi_wasm_yield wraps the table call in try-catch.
var cbRtn = noopCbPtr || 1;
// ── 8. Install a VPI startup routine in the WASM function table ──────────
@@ -553,7 +553,7 @@ self.onmessage = async function(event) {
//
// Fix: compile a tiny WASM module (type ()->()) that imports one JS function
// "r" and calls it. Insert the export into a null slot in the WASM table,
- // then call _vpi_startup_register(slot). circt-sim invokes startup routines
+ // then call _vpi_startup_register(slot). mox-sim invokes startup routines
// via invoke_v(slot) inside callMain once active=true, so "r" runs and can
// call _vpi_register_cb successfully to register cbStartOfSimulation.
//
@@ -604,12 +604,12 @@ self.onmessage = async function(event) {
}
// ── 9. Set up the Asyncify yield hook ─────────────────────────────────────
- // _circt_vpi_wasm_yield (in circt-sim-vpi.js) calls:
- // await globalThis.circtSimVpiYieldHook(cbFuncPtr, cbDataPtr)
+ // _mox_vpi_wasm_yield (in mox-sim-vpi.js) calls:
+ // await globalThis.moxSimVpiYieldHook(cbFuncPtr, cbDataPtr)
// try { wasmTable.get(cbFuncPtr)(cbDataPtr) } catch(e) {} [patched]
// Our hook handles all Python dispatch; cbRtn is always non-zero, which
// satisfies registerCb's cb_rtn check. The wasmTable callback is wrapped.
- self.circtSimVpiYieldHook = async function(_cbFuncPtr, cbDataPtr) {
+ self.moxSimVpiYieldHook = async function(_cbFuncPtr, cbDataPtr) {
var reason = simModule.getValue(cbDataPtr + 0, 'i32');
var triggerId = simModule.getValue(cbDataPtr + 24, 'i32');
@@ -675,7 +675,7 @@ self.onmessage = async function(event) {
'--top', topModule,
mlirPath
];
- onLog('$ ' + ['circt-sim'].concat(simArgs).map(wsShellQuote).join(' '));
+ onLog('$ ' + ['mox-sim'].concat(simArgs).map(wsShellQuote).join(' '));
try {
simModule.callMain(simArgs);
} catch(e) {
diff --git a/src/runtime/lec-model.test.js b/src/runtime/lec-model.test.js
index b861582..8d01b90 100644
--- a/src/runtime/lec-model.test.js
+++ b/src/runtime/lec-model.test.js
@@ -1,7 +1,7 @@
/**
* Unit tests for LEC counterexample extraction.
*
- * These tests exercise the same C API calls that circt-adapter.js uses in the
+ * These tests exercise the same C API calls that mox-adapter.js uses in the
* browser (Z3_mk_config / Z3_mk_context / Z3_eval_smtlib2_string / Z3_del_context)
* but run them in Node.js via the z3-solver package — the same WASM binary that
* gets served to the browser at /z3/z3-built.js.
@@ -23,7 +23,7 @@ beforeAll(async () => {
({ em } = await init());
}, 30_000);
-// Mirror the evalSmtlib function from circt-adapter.js exactly.
+// Mirror the evalSmtlib function from mox-adapter.js exactly.
function evalSmtlib(smtlibText, { produceModels = false, em: emOverride = null } = {}) {
const mod = emOverride ?? em;
const cfg = mod.ccall('Z3_mk_config', 'number', [], []);
@@ -39,7 +39,7 @@ function evalSmtlib(smtlibText, { produceModels = false, em: emOverride = null }
}
}
-// Mirror the model parsing from circt-adapter.js exactly.
+// Mirror the model parsing from mox-adapter.js exactly.
function parseModel(modelOut) {
const modelFlat = (modelOut || '').replace(/\s+/g, ' ');
const assignments = [];
diff --git a/src/runtime/circt-adapter.js b/src/runtime/mox-adapter.js
similarity index 93%
rename from src/runtime/circt-adapter.js
rename to src/runtime/mox-adapter.js
index ef930d8..cc8294e 100644
--- a/src/runtime/circt-adapter.js
+++ b/src/runtime/mox-adapter.js
@@ -1,4 +1,4 @@
-import { CIRCT_FORK_REPO, getCirctRuntimeConfig, getRuntimeBasePath, Z3_SCRIPT_URL } from './circt-config.js';
+import { MOX_FORK_REPO, getMoxRuntimeConfig, getRuntimeBasePath, Z3_SCRIPT_URL } from './mox-config.js';
import COCOTB_SHIM from './cocotb-shim.py?raw';
import { COCOTB_WORKER_SOURCE } from './cocotb-worker-source.js';
import { WORKER_RUNTIME_HELPERS_SOURCE } from './worker-runtime-helpers-source.js';
@@ -164,7 +164,7 @@ function needsUvmLibrary(files) {
);
}
-// circt-sim inlines child-instance ports as dotted names (e.g. "dut.sum") into
+// mox-sim inlines child-instance ports as dotted names (e.g. "dut.sum") into
// the parent scope alongside the parent wire ("result"). Strip those duplicates
// so the waveform viewer only shows the canonical wire name.
function removeInlinedPortsFromVcd(vcd) {
@@ -202,7 +202,7 @@ function removeInlinedPortsFromVcd(vcd) {
}).join('\n');
}
-// CIRCT/LLHD encodes every 4-state `logic` bit as a 2-bit pair in VCD:
+// MOX/LLHD encodes every 4-state `logic` bit as a 2-bit pair in VCD:
// high bit = value (0 or 1)
// low bit = 4-state flag (0 = known, 1 = x or z)
// This doubles the declared width of every logic signal, so Surfer displays the
@@ -265,8 +265,8 @@ function fixLlhdVcdEncoding(vcd) {
function addMissingLlhdSignalNames(mlirText) {
if (typeof mlirText !== 'string') return null;
- // Add name attributes to llhd.sig ops that lack them so circt-sim's VCD
- // writer can emit $var entries. circt-verilog only sets name on module
+ // Add name attributes to llhd.sig ops that lack them so mox-sim's VCD
+ // writer can emit $var entries. mox-verilog only sets name on module
// port connections; testbench-level logic signals get no name attribute.
// We use the SSA result identifier (%clk -> name "clk") as the signal name.
return mlirText.replace(
@@ -348,7 +348,7 @@ function isRetryableVerilogCrashText(text) {
return /memory access out of bounds|Malformed attribute storage object|Aborted\(/i.test(value);
}
-const UVM_FS_ROOT = '/circt/uvm-core';
+const UVM_FS_ROOT = '/mox/uvm-core';
const UVM_INCLUDE_ROOT = `${UVM_FS_ROOT}/src`;
const UVM_SIM_MAX_TIME_FS = '1000000';
@@ -472,7 +472,7 @@ function readWorkspaceFiles(FS, paths) {
${WORKER_RUNTIME_HELPERS_SOURCE}
-// In-memory filesystem for Emscripten NODERAWFS builds (like circt-sim.js).
+// In-memory filesystem for Emscripten NODERAWFS builds (like mox-sim.js).
// NODERAWFS replaces the entire Emscripten FS layer with direct Node.js fs calls.
// We provide a fake require('fs') that stores data in memory so that
// module.FS.writeFile / callMain / module.FS.readFile all share the same store.
@@ -486,9 +486,9 @@ function makeInMemFS(onStdoutChunk = null, onStderrChunk = null) {
'/workspace',
'/workspace/src',
'/workspace/out',
- '/circt',
- '/circt/uvm-core',
- '/circt/uvm-core/src'
+ '/mox',
+ '/mox/uvm-core',
+ '/mox/uvm-core/src'
]);
var fds = {};
var nextFd = 3;
@@ -739,7 +739,7 @@ function makeInMemFS(onStdoutChunk = null, onStderrChunk = null) {
};
}
-var circtWorkerRuntimeReady = false;
+var moxWorkerRuntimeReady = false;
function getModuleValue(module, name) {
if (!module) return null;
@@ -791,7 +791,7 @@ function waitForRuntime(timeoutMs = 45000) {
const fsApi = resolveFS(module);
if (
- circtWorkerRuntimeReady &&
+ moxWorkerRuntimeReady &&
module &&
!!callMain &&
!!main &&
@@ -854,8 +854,8 @@ self.onmessage = async (event) => {
self.Module = {
noInitialRun: true,
onRuntimeInitialized: () => {
- console.log('[circt-worker] onRuntimeInitialized fired');
- circtWorkerRuntimeReady = true;
+ console.log('[mox-worker] onRuntimeInitialized fired');
+ moxWorkerRuntimeReady = true;
},
print: (line) => appendStreamLine('stdout', line),
printErr: (line) => appendStreamLine('stderr', line),
@@ -865,23 +865,23 @@ self.onmessage = async (event) => {
},
// Use streaming WASM compilation for all tools to avoid slow sync readBinary path.
instantiateWasm: function(imports, callback) {
- console.log('[circt-worker] instantiateWasm called for', req.wasmUrl);
+ console.log('[mox-worker] instantiateWasm called for', req.wasmUrl);
WebAssembly.instantiateStreaming(fetch(req.wasmUrl), imports)
.then(function(result) {
- console.log('[circt-worker] instantiateStreaming succeeded');
+ console.log('[mox-worker] instantiateStreaming succeeded');
callback(result.instance, result.module);
})
.catch(function(streamErr) {
- console.log('[circt-worker] instantiateStreaming failed, trying ArrayBuffer fallback:', String(streamErr));
+ console.log('[mox-worker] instantiateStreaming failed, trying ArrayBuffer fallback:', String(streamErr));
return fetch(req.wasmUrl)
.then(function(r) { return r.arrayBuffer(); })
.then(function(buf) { return WebAssembly.instantiate(buf, imports); })
.then(function(result) {
- console.log('[circt-worker] ArrayBuffer instantiate succeeded');
+ console.log('[mox-worker] ArrayBuffer instantiate succeeded');
callback(result.instance, result.module);
})
.catch(function(abErr) {
- console.error('[circt-worker] both WASM instantiation paths failed:', String(abErr));
+ console.error('[mox-worker] both WASM instantiation paths failed:', String(abErr));
});
});
return {};
@@ -895,7 +895,7 @@ self.onmessage = async (event) => {
makeFs: function() {
// NODERAWFS builds call require('path') / require('fs') at module scope.
// Provide a Node-like fs backed by memory so tool I/O stays in-worker.
- console.log('[circt-worker] NODERAWFS detected, setting up Node.js emulation');
+ console.log('[mox-worker] NODERAWFS detected, setting up Node.js emulation');
inMemFS = makeInMemFS(
(text) => appendStreamText('stdout', text),
(text) => appendStreamText('stderr', text)
@@ -904,11 +904,11 @@ self.onmessage = async (event) => {
},
onStdout: function(s) { appendStreamText('stdout', s); },
onStderr: function(s) { appendStreamText('stderr', s); },
- beforeEval: function() { console.log('[circt-worker] starting eval of tool script'); },
- afterEval: function() { console.log('[circt-worker] eval complete'); }
+ beforeEval: function() { console.log('[mox-worker] starting eval of tool script'); },
+ afterEval: function() { console.log('[mox-worker] eval complete'); }
});
- console.log('[circt-worker] waiting for runtime...');
+ console.log('[mox-worker] waiting for runtime...');
const module = await waitForRuntime();
const fsApi = resolveFS(module);
if (!fsApi) {
@@ -962,7 +962,7 @@ self.onmessage = async (event) => {
const rootPath = (manifest && typeof manifest.rootPath === 'string' && manifest.rootPath.length > 0)
? manifest.rootPath
- : '/circt/uvm-core/src';
+ : '/mox/uvm-core/src';
const relPaths = Array.isArray(manifest && manifest.files) ? manifest.files : [];
const srcBaseUrl = new URL('src/', manifestUrl).href;
for (const relRaw of relPaths) {
@@ -1001,7 +1001,7 @@ self.onmessage = async (event) => {
}
}
}
- console.log('[circt-worker] runtime ready, writing files');
+ console.log('[mox-worker] runtime ready, writing files');
if (inMemFS) {
for (const [path, content] of Object.entries(req.files || {})) {
inMemFS.writeTextFile(String(path), content);
@@ -1016,12 +1016,12 @@ self.onmessage = async (event) => {
}
}
- console.log('[circt-worker] calling callMain with args:', req.args);
+ console.log('[mox-worker] calling callMain with args:', req.args);
let exitCode = 0;
try {
const callMain = resolveCallMain(module);
if (!callMain) {
- throw new Error('CIRCT runtime is missing callMain entrypoint');
+ throw new Error('MOX runtime is missing callMain entrypoint');
}
const ret = callMain(Array.isArray(req.args) ? req.args : []);
if (typeof ret === 'number' && Number.isFinite(ret)) {
@@ -1031,7 +1031,7 @@ self.onmessage = async (event) => {
if (!isExitException(error)) throw error;
exitCode = extractExitCode(error);
}
- console.log('[circt-worker] callMain done, exitCode:', exitCode);
+ console.log('[mox-worker] callMain done, exitCode:', exitCode);
flushStreamRemainders();
const files = inMemFS
@@ -1233,18 +1233,18 @@ function toAbsoluteUrl(rawUrl) {
}
function getUvmManifestUrl() {
- return toAbsoluteUrl(`${getRuntimeBasePath()}circt/uvm-core/uvm-manifest.json`);
+ return toAbsoluteUrl(`${getRuntimeBasePath()}mox/uvm-core/uvm-manifest.json`);
}
// ── Cocotb worker ─────────────────────────────────────────────────────────────
// Self-contained Web Worker source for running cocotb tests via Pyodide +
-// a VPI-capable, Asyncify-transformed circt-sim WASM.
+// a VPI-capable, Asyncify-transformed mox-sim WASM.
//
-// circt-sim-vpi may be built with NODERAWFS=1 (the Emscripten default).
+// mox-sim-vpi may be built with NODERAWFS=1 (the Emscripten default).
// In that case importScripts() fails immediately because the script calls
// require('path') at module level. We detect this and fall back to eval()
// with a fake Node.js environment backed by an in-memory filesystem, exactly
-// like WORKER_SOURCE does for the regular circt-sim.
+// like WORKER_SOURCE does for the regular mox-sim.
let cocotbWorkerBlobUrl = null;
@@ -1328,10 +1328,10 @@ function runCocotbInWorker({
});
}
-export class CirctWasmAdapter {
+export class MoxWasmAdapter {
constructor() {
- this.repo = CIRCT_FORK_REPO;
- this.config = getCirctRuntimeConfig();
+ this.repo = MOX_FORK_REPO;
+ this.config = getMoxRuntimeConfig();
this.ready = false;
this._runController = null;
}
@@ -1350,7 +1350,7 @@ export class CirctWasmAdapter {
});
if (missing.length) {
- throw new Error(`CIRCT toolchain is incomplete in config: ${missing.join(', ')}`);
+ throw new Error(`MOX toolchain is incomplete in config: ${missing.join(', ')}`);
}
this.ready = true;
@@ -1361,7 +1361,7 @@ export class CirctWasmAdapter {
{ args, files = {}, readFiles = [], createDirs = [], uvmManifestUrl = null, onOutput = null }
) {
const tool = this.config.toolchain[toolName];
- if (!tool) throw new Error(`Unknown CIRCT tool: ${toolName}`);
+ if (!tool) throw new Error(`Unknown MOX tool: ${toolName}`);
return runToolInWorker({
jsUrl: toAbsoluteUrl(tool.js),
@@ -1382,17 +1382,17 @@ export class CirctWasmAdapter {
try {
await this.init();
- logs.push(formatCommand('circt-verilog', ['--help']));
+ logs.push(formatCommand('mox-verilog', ['--help']));
const verilogHelp = await this._invokeTool('verilog', {
args: ['--help']
});
- appendNonZeroExit(logs, 'circt-verilog', verilogHelp.exitCode);
+ appendNonZeroExit(logs, 'mox-verilog', verilogHelp.exitCode);
- logs.push(formatCommand('circt-sim', ['--help']));
+ logs.push(formatCommand('mox-sim', ['--help']));
const simHelp = await this._invokeTool('sim', {
args: ['--help']
});
- appendNonZeroExit(logs, 'circt-sim', simHelp.exitCode);
+ appendNonZeroExit(logs, 'mox-sim', simHelp.exitCode);
const ok = verilogHelp.exitCode === 0 && simHelp.exitCode === 0;
if (verilogHelp.stderr) logs.push(`[stderr] ${verilogHelp.stderr}`);
@@ -1495,7 +1495,7 @@ export class CirctWasmAdapter {
for (let attempt = 0; attempt < compilePlans.length; attempt += 1) {
const plan = compilePlans[attempt];
if (attempt > 0) {
- emitLog(`# circt-verilog: retrying in ${plan.label}`);
+ emitLog(`# mox-verilog: retrying in ${plan.label}`);
}
if (plan.bundledCompile.bundled) {
emitLog(
@@ -1503,7 +1503,7 @@ export class CirctWasmAdapter {
'for stable UVM compilation'
);
}
- emitLog(formatCommand('circt-verilog', plan.compileArgs));
+ emitLog(formatCommand('mox-verilog', plan.compileArgs));
const compileStream = makeToolOutputHandler();
let attemptCompile;
@@ -1519,7 +1519,7 @@ export class CirctWasmAdapter {
} catch (error) {
const text = String(error?.message || error || '');
if (useFullUvm && text.includes('Aborted(OOM)')) {
- emitLog('# circt-verilog: out of memory compiling UVM — rebuild wasm with larger heap');
+ emitLog('# mox-verilog: out of memory compiling UVM — rebuild wasm with larger heap');
if (typeof onStatus === 'function') onStatus('done');
return { ok: false, logs, waveform: null };
}
@@ -1531,7 +1531,7 @@ export class CirctWasmAdapter {
if (attemptCompile.stdout) emitLog(`[stdout] ${attemptCompile.stdout}`);
if (attemptCompile.stderr) emitLog(`[stderr] ${attemptCompile.stderr}`);
}
- appendNonZeroExit(logs, 'circt-verilog', attemptCompile.exitCode, emitLog);
+ appendNonZeroExit(logs, 'mox-verilog', attemptCompile.exitCode, emitLog);
const rawMlir = attemptCompile.files?.[mlirPath] || null;
const attemptLoweredMlir = addMissingLlhdSignalNames(rawMlir);
@@ -1595,7 +1595,7 @@ export class CirctWasmAdapter {
if (withTraceAll) simArgs.push('--trace-all');
simArgs.push(mlirPath);
- emitLog(formatCommand('circt-sim', simArgs));
+ emitLog(formatCommand('mox-sim', simArgs));
const sim = await this._invokeTool('sim', {
args: simArgs,
files: {
@@ -1606,7 +1606,7 @@ export class CirctWasmAdapter {
onOutput: simStream.onOutput
});
if (sim.exitCode !== 0 && isRetryableSimAbortText(sim.stderr)) {
- throw new Error(String(sim.stderr || `circt-sim exited ${sim.exitCode}`));
+ throw new Error(String(sim.stderr || `mox-sim exited ${sim.exitCode}`));
}
return { sim, withVcd };
};
@@ -1617,13 +1617,13 @@ export class CirctWasmAdapter {
} catch (error) {
const retryable = isRetryableSimAbortText(error?.message || error);
if (!retryable) throw error;
- emitLog('# circt-sim: runtime abort with --trace-all; retrying without --trace-all');
+ emitLog('# mox-sim: runtime abort with --trace-all; retrying without --trace-all');
try {
simResult = await runSimAttempt({ withTraceAll: false, withVcd: true });
} catch (retryError) {
const retryableNoTrace = isRetryableSimAbortText(retryError?.message || retryError);
if (!retryableNoTrace) throw retryError;
- emitLog('# circt-sim: runtime abort while writing VCD; retrying without waveform capture');
+ emitLog('# mox-sim: runtime abort while writing VCD; retrying without waveform capture');
simResult = await runSimAttempt({ withTraceAll: false, withVcd: false });
}
}
@@ -1634,7 +1634,7 @@ export class CirctWasmAdapter {
if (sim.stdout) emitLog(`[stdout] ${sim.stdout}`);
if (sim.stderr) emitLog(`[stderr] ${sim.stderr}`);
}
- appendNonZeroExit(logs, 'circt-sim', sim.exitCode, emitLog);
+ appendNonZeroExit(logs, 'mox-sim', sim.exitCode, emitLog);
const rawVcdText = simResult.withVcd ? sim.files?.[wavePath] || null : null;
const vcdText = fixLlhdVcdEncoding(removeInlinedPortsFromVcd(rawVcdText));
@@ -1657,11 +1657,11 @@ export class CirctWasmAdapter {
ok: false,
logs: [
`# runtime unavailable: ${error.message}`,
- `# circt-verilog js: ${this.config.toolchain.verilog.js}`,
- `# circt-verilog wasm: ${this.config.toolchain.verilog.wasm}`,
- `# circt-sim js: ${this.config.toolchain.sim.js}`,
- `# circt-sim wasm: ${this.config.toolchain.sim.wasm}`,
- '# run scripts/setup-circt.sh and npm run sync:circt to refresh artifacts'
+ `# mox-verilog js: ${this.config.toolchain.verilog.js}`,
+ `# mox-verilog wasm: ${this.config.toolchain.verilog.wasm}`,
+ `# mox-sim js: ${this.config.toolchain.sim.js}`,
+ `# mox-sim wasm: ${this.config.toolchain.sim.wasm}`,
+ '# run scripts/setup-mox.sh and npm run sync:mox to refresh artifacts'
],
waveform: null
};
@@ -1735,7 +1735,7 @@ export class CirctWasmAdapter {
'for stable UVM compilation'
);
}
- emitLog(formatCommand('circt-verilog', compileArgs));
+ emitLog(formatCommand('mox-verilog', compileArgs));
if (typeof onStatus === 'function') onStatus('compiling');
let compile;
@@ -1754,7 +1754,7 @@ export class CirctWasmAdapter {
} catch (error) {
const text = String(error?.message || error || '');
if (useFullUvm && text.includes('Aborted(OOM)')) {
- emitLog('# circt-verilog: out of memory compiling UVM — rebuild wasm with larger heap');
+ emitLog('# mox-verilog: out of memory compiling UVM — rebuild wasm with larger heap');
if (typeof onStatus === 'function') onStatus('done');
return { ok: false, logs };
}
@@ -1764,7 +1764,7 @@ export class CirctWasmAdapter {
if (compile.stdout) emitLog(`[stdout] ${compile.stdout}`);
if (compile.stderr) emitLog(`[stderr] ${compile.stderr}`);
}
- appendNonZeroExit(logs, 'circt-verilog', compile.exitCode, emitLog);
+ appendNonZeroExit(logs, 'mox-verilog', compile.exitCode, emitLog);
const mlirText = compile.files?.[mlirPath] || null;
if (compile.exitCode !== 0 || !mlirText) {
@@ -1779,7 +1779,7 @@ export class CirctWasmAdapter {
arg.replace('{top}', topModule).replace('{input}', mlirPath)
);
- emitLog(formatCommand('circt-bmc', bmcArgs));
+ emitLog(formatCommand('mox-bmc', bmcArgs));
if (typeof onStatus === 'function') onStatus('running');
const bmcStream = makeToolOutputHandler();
@@ -1799,7 +1799,7 @@ export class CirctWasmAdapter {
.join('\n')
.trim();
if (!bmcStream.sawStream() && bmcStderr) emitLog(`[stderr] ${bmcStderr}`);
- appendNonZeroExit(logs, 'circt-bmc', bmc.exitCode, emitLog);
+ appendNonZeroExit(logs, 'mox-bmc', bmc.exitCode, emitLog);
const smtlibText = bmc.files?.[smtPath] || null;
if (!smtlibText) {
@@ -1829,9 +1829,9 @@ export class CirctWasmAdapter {
ok: false,
logs: [
`# runtime unavailable: ${error.message}`,
- `# circt-bmc js: ${this.config.toolchain.bmc.js}`,
- `# circt-bmc wasm: ${this.config.toolchain.bmc.wasm}`,
- '# run scripts/setup-circt.sh to refresh artifacts'
+ `# mox-bmc js: ${this.config.toolchain.bmc.js}`,
+ `# mox-bmc wasm: ${this.config.toolchain.bmc.wasm}`,
+ '# run scripts/setup-mox.sh to refresh artifacts'
]
};
}
@@ -1888,7 +1888,7 @@ export class CirctWasmAdapter {
sawStream: () => sawStream
};
};
- emitLog(formatCommand('circt-verilog', compileArgs));
+ emitLog(formatCommand('mox-verilog', compileArgs));
if (typeof onStatus === 'function') onStatus('compiling');
const compileStream = makeToolOutputHandler();
@@ -1905,7 +1905,7 @@ export class CirctWasmAdapter {
if (compile.stdout) emitLog(`[stdout] ${compile.stdout}`);
if (compile.stderr) emitLog(`[stderr] ${compile.stderr}`);
}
- appendNonZeroExit(logs, 'circt-verilog', compile.exitCode, emitLog);
+ appendNonZeroExit(logs, 'mox-verilog', compile.exitCode, emitLog);
const mlirText = compile.files?.[mlirPath] || null;
if (compile.exitCode !== 0 || !mlirText) {
@@ -1925,8 +1925,8 @@ export class CirctWasmAdapter {
// Check that the VPI sim is configured.
const simVpi = this.config.toolchain.simVpi;
if (!simVpi?.js || !simVpi?.wasm) {
- emitLog('# VPI-capable circt-sim not configured');
- emitLog('# set VITE_CIRCT_SIM_VPI_JS_URL and VITE_CIRCT_SIM_VPI_WASM_URL in .env');
+ emitLog('# VPI-capable mox-sim not configured');
+ emitLog('# set VITE_MOX_SIM_VPI_JS_URL and VITE_MOX_SIM_VPI_WASM_URL in .env');
if (typeof onStatus === 'function') onStatus('done');
return { ok: false, logs };
}
@@ -2010,7 +2010,7 @@ export class CirctWasmAdapter {
sawStream: () => sawStream
};
};
- emitLog(formatCommand('circt-verilog', compileArgs));
+ emitLog(formatCommand('mox-verilog', compileArgs));
if (typeof onStatus === 'function') onStatus('compiling');
const compileStream = makeToolOutputHandler();
@@ -2027,7 +2027,7 @@ export class CirctWasmAdapter {
if (compile.stdout) emitLog(`[stdout] ${compile.stdout}`);
if (compile.stderr) emitLog(`[stderr] ${compile.stderr}`);
}
- appendNonZeroExit(logs, 'circt-verilog', compile.exitCode, emitLog);
+ appendNonZeroExit(logs, 'mox-verilog', compile.exitCode, emitLog);
const mlirText = compile.files?.[mlirPath] || null;
if (compile.exitCode !== 0 || !mlirText) {
@@ -2042,7 +2042,7 @@ export class CirctWasmAdapter {
.replace('{input}', mlirPath)
);
- emitLog(formatCommand('circt-lec', lecArgs));
+ emitLog(formatCommand('mox-lec', lecArgs));
if (typeof onStatus === 'function') onStatus('running');
const lecStream = makeToolOutputHandler();
@@ -2061,7 +2061,7 @@ export class CirctWasmAdapter {
.join('\n')
.trim();
if (!lecStream.sawStream() && lecStderr) emitLog(`[stderr] ${lecStderr}`);
- appendNonZeroExit(logs, 'circt-lec', lec.exitCode, emitLog);
+ appendNonZeroExit(logs, 'mox-lec', lec.exitCode, emitLog);
const smtlibText = lec.files?.[smtPath] || null;
if (!smtlibText) {
@@ -2090,7 +2090,7 @@ export class CirctWasmAdapter {
try {
emitLog(`$ z3 -model ${smtPath} | grep define-fun`);
const freshEm = await getFreshZ3Module();
- // Insert (get-model) before (reset) — circt-lec SMT-LIB ends with
+ // Insert (get-model) before (reset) — mox-lec SMT-LIB ends with
// (reset) which clears solver state; appending after it loses the model.
const resetIdx = smtlibText.lastIndexOf('(reset)');
const smtWithModel = resetIdx >= 0
@@ -2111,7 +2111,7 @@ export class CirctWasmAdapter {
if (/^c\d+_/.test(name)) continue;
const width = parseInt(widthStr, 10);
const raw = val.startsWith('#x') ? parseInt(val.slice(2), 16) : parseInt(val.slice(2), 2);
- // CIRCT encodes N-bit SV signals as 2N-bit SMT bitvectors: the lower N
+ // MOX encodes N-bit SV signals as 2N-bit SMT bitvectors: the lower N
// bits are "unknown" flags and the upper N bits are the logic values.
// Decode to the plain N-bit value when all unknown bits are zero.
let displayVal = raw;
@@ -2149,21 +2149,21 @@ export class CirctWasmAdapter {
ok: false,
logs: [
`# runtime unavailable: ${error.message}`,
- `# circt-lec js: ${this.config.toolchain.lec?.js}`,
- `# circt-lec wasm: ${this.config.toolchain.lec?.wasm}`,
- '# run scripts/setup-circt.sh to refresh artifacts'
+ `# mox-lec js: ${this.config.toolchain.lec?.js}`,
+ `# mox-lec wasm: ${this.config.toolchain.lec?.wasm}`,
+ '# run scripts/setup-mox.sh to refresh artifacts'
]
};
}
}
}
-export function createCirctWasmAdapter() {
- return new CirctWasmAdapter();
+export function createMoxWasmAdapter() {
+ return new MoxWasmAdapter();
}
let _adapter = null;
-export function getCirctWasmAdapter() {
- _adapter ??= createCirctWasmAdapter();
+export function getMoxWasmAdapter() {
+ _adapter ??= createMoxWasmAdapter();
return _adapter;
}
diff --git a/src/runtime/circt-adapter.test.js b/src/runtime/mox-adapter.test.js
similarity index 93%
rename from src/runtime/circt-adapter.test.js
rename to src/runtime/mox-adapter.test.js
index 5c37ce7..c6e420e 100644
--- a/src/runtime/circt-adapter.test.js
+++ b/src/runtime/mox-adapter.test.js
@@ -1,8 +1,8 @@
import { describe, expect, it } from 'vitest';
-import { CirctWasmAdapter } from './circt-adapter.js';
+import { MoxWasmAdapter } from './mox-adapter.js';
function createAdapterWithInvokeTool(invokeTool) {
- const adapter = new CirctWasmAdapter();
+ const adapter = new MoxWasmAdapter();
adapter.init = async () => {
adapter.ready = true;
};
@@ -10,7 +10,7 @@ function createAdapterWithInvokeTool(invokeTool) {
return adapter;
}
-describe('CirctWasmAdapter.run with MLIR workspace input', () => {
+describe('MoxWasmAdapter.run with MLIR workspace input', () => {
it('simulates MLIR input directly without requiring SystemVerilog files', async () => {
const calls = [];
const adapter = createAdapterWithInvokeTool(async (toolName, request) => {
diff --git a/src/runtime/mox-config.js b/src/runtime/mox-config.js
new file mode 100644
index 0000000..4a3436c
--- /dev/null
+++ b/src/runtime/mox-config.js
@@ -0,0 +1,139 @@
+export const MOX_FORK_REPO = 'git@github.com:normal-computing/mox.git';
+
+function normalizeBaseUrl(raw) {
+ const base = String(raw || '').trim();
+ if (!base || base === '.' || base === './') return '/';
+
+ // Normalize optional leading "./" used by static builds.
+ const noDotPrefix = base.startsWith('./') ? base.slice(1) : base;
+ const withLeadingSlash = noDotPrefix.startsWith('/') ? noDotPrefix : `/${noDotPrefix}`;
+ const withTrailingSlash = withLeadingSlash.endsWith('/')
+ ? withLeadingSlash
+ : `${withLeadingSlash}/`;
+
+ // Remove "/./" segments so "/./mox" becomes "/mox".
+ return withTrailingSlash.replace(/\/\.\//g, '/');
+}
+
+const BASE = normalizeBaseUrl(import.meta.env.VITE_BASE || import.meta.env.BASE_URL);
+
+export function getRuntimeBasePath() {
+ return BASE;
+}
+
+export const Z3_SCRIPT_URL = `${BASE}z3/z3-built.js`;
+const DEFAULT_TOOLCHAIN = {
+ verilog: {
+ js: `${BASE}mox/mox-verilog.js`,
+ wasm: `${BASE}mox/mox-verilog.wasm`
+ },
+ sim: {
+ js: `${BASE}mox/mox-sim.js`,
+ wasm: `${BASE}mox/mox-sim.wasm`
+ },
+ bmc: {
+ js: `${BASE}mox/mox-bmc.js`,
+ wasm: `${BASE}mox/mox-bmc.wasm`
+ },
+ simVpi: {
+ js: `${BASE}mox/mox-sim-vpi.js`,
+ wasm: `${BASE}mox/mox-sim-vpi.wasm`
+ },
+ lec: {
+ js: `${BASE}mox/mox-lec.js`,
+ wasm: `${BASE}mox/mox-lec.wasm`
+ }
+};
+
+const DEFAULT_VERILOG_ARGS = ['--resource-guard=false', '--ir-llhd', '--timescale', '1ns/1ns', '--single-unit'];
+const DEFAULT_LEC_VERILOG_ARGS = ['--resource-guard=false', '--ir-hw', '--single-unit'];
+const DEFAULT_LEC_ARGS = [
+ '--resource-guard=false',
+ '--assume-known-inputs',
+ '-c1', '{module1}',
+ '-c2', '{module2}',
+ '--emit-smtlib',
+ '-o', '/workspace/out/check.smt2',
+ '{input}'
+];
+const DEFAULT_SIM_ARGS = ['--resource-guard=false'];
+const DEFAULT_BMC_ARGS = [
+ '--resource-guard=false',
+ '--assume-known-inputs',
+ '-b',
+ '20',
+ '--module',
+ '{top}',
+ '--emit-smtlib',
+ '-o',
+ '/workspace/out/check.smt2',
+ '{input}'
+];
+
+function parseArgs(raw, fallback) {
+ if (!raw) return fallback;
+ try {
+ const parsed = JSON.parse(raw);
+ if (Array.isArray(parsed) && parsed.every((v) => typeof v === 'string')) {
+ return parsed;
+ }
+ } catch {
+ // Fallback to a simple shell-like split for convenience.
+ }
+ return raw
+ .split(' ')
+ .map((s) => s.trim())
+ .filter(Boolean);
+}
+
+function pickUrlFromEnv(primary, fallback) {
+ return primary || fallback;
+}
+
+export function getMoxRuntimeConfig() {
+ return {
+ toolchain: {
+ verilog: {
+ js: pickUrlFromEnv(import.meta.env.VITE_MOX_VERILOG_JS_URL, DEFAULT_TOOLCHAIN.verilog.js),
+ wasm: pickUrlFromEnv(import.meta.env.VITE_MOX_VERILOG_WASM_URL, DEFAULT_TOOLCHAIN.verilog.wasm)
+ },
+ sim: {
+ js: pickUrlFromEnv(import.meta.env.VITE_MOX_SIM_JS_URL, DEFAULT_TOOLCHAIN.sim.js),
+ wasm: pickUrlFromEnv(import.meta.env.VITE_MOX_SIM_WASM_URL, DEFAULT_TOOLCHAIN.sim.wasm)
+ },
+ bmc: {
+ js: pickUrlFromEnv(import.meta.env.VITE_MOX_BMC_JS_URL, DEFAULT_TOOLCHAIN.bmc.js),
+ wasm: pickUrlFromEnv(import.meta.env.VITE_MOX_BMC_WASM_URL, DEFAULT_TOOLCHAIN.bmc.wasm)
+ },
+ simVpi: {
+ js: pickUrlFromEnv(import.meta.env.VITE_MOX_SIM_VPI_JS_URL, DEFAULT_TOOLCHAIN.simVpi.js),
+ wasm: pickUrlFromEnv(import.meta.env.VITE_MOX_SIM_VPI_WASM_URL, DEFAULT_TOOLCHAIN.simVpi.wasm)
+ },
+ lec: {
+ js: pickUrlFromEnv(import.meta.env.VITE_MOX_LEC_JS_URL, DEFAULT_TOOLCHAIN.lec.js),
+ wasm: pickUrlFromEnv(import.meta.env.VITE_MOX_LEC_WASM_URL, DEFAULT_TOOLCHAIN.lec.wasm)
+ }
+ },
+ pyodideUrl: import.meta.env.VITE_PYODIDE_URL || `${BASE}pyodide/pyodide.js`,
+ verilogArgs: parseArgs(import.meta.env.VITE_MOX_VERILOG_ARGS, DEFAULT_VERILOG_ARGS),
+ simArgs: parseArgs(import.meta.env.VITE_MOX_SIM_ARGS, DEFAULT_SIM_ARGS),
+ bmcArgs: parseArgs(import.meta.env.VITE_MOX_BMC_ARGS, DEFAULT_BMC_ARGS),
+ lecVerilogArgs: parseArgs(import.meta.env.VITE_MOX_LEC_VERILOG_ARGS, DEFAULT_LEC_VERILOG_ARGS),
+ lecArgs: parseArgs(import.meta.env.VITE_MOX_LEC_ARGS, DEFAULT_LEC_ARGS),
+ note: import.meta.env.VITE_MOX_NOTE || ''
+ };
+}
+
+export function getRuntimeEnvDoc() {
+ return {
+ VITE_MOX_VERILOG_JS_URL: 'mox-verilog JS artifact URL.',
+ VITE_MOX_VERILOG_WASM_URL: 'mox-verilog WASM artifact URL.',
+ VITE_MOX_SIM_JS_URL: 'mox-sim JS artifact URL.',
+ VITE_MOX_SIM_WASM_URL: 'mox-sim WASM artifact URL.',
+ VITE_MOX_BMC_JS_URL: 'mox-bmc JS artifact URL.',
+ VITE_MOX_BMC_WASM_URL: 'mox-bmc WASM artifact URL.',
+ VITE_MOX_VERILOG_ARGS: 'JSON array or space-separated args passed before source files.',
+ VITE_MOX_SIM_ARGS: 'JSON array or space-separated args passed before MLIR input.',
+ VITE_MOX_BMC_ARGS: 'JSON array or space-separated args for BMC fallback.'
+ };
+}
diff --git a/src/runtime/circt-wasm-smoke.test.js b/src/runtime/mox-wasm-smoke.test.js
similarity index 77%
rename from src/runtime/circt-wasm-smoke.test.js
rename to src/runtime/mox-wasm-smoke.test.js
index e21c562..f4e3aaa 100644
--- a/src/runtime/circt-wasm-smoke.test.js
+++ b/src/runtime/mox-wasm-smoke.test.js
@@ -1,9 +1,9 @@
/**
- * Integration tests that load and run the real CIRCT WASM artifacts via Node.js.
- * These tests require `static/circt/` to be populated (run `npm run sync:circt` first).
+ * Integration tests that load and run the real MOX WASM artifacts via Node.js.
+ * These tests require `static/mox/` to be populated (run `npm run sync:mox` first).
*
- * circt-verilog.js uses NODERAWFS (real filesystem in Node.js), so we use a real
- * temp directory as the workspace. circt-sim.js is patched to use MEMFS, so it
+ * mox-verilog.js uses NODERAWFS (real filesystem in Node.js), so we use a real
+ * temp directory as the workspace. mox-sim.js is patched to use MEMFS, so it
* works with any virtual path.
*/
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
@@ -14,21 +14,21 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { createRequire } from 'node:module';
-const CIRCT_DIR = path.resolve(
+const MOX_DIR = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
- '../../static/circt'
+ '../../static/mox'
);
-const artifactsPresent = fs.existsSync(path.join(CIRCT_DIR, 'circt-verilog.js'));
+const artifactsPresent = fs.existsSync(path.join(MOX_DIR, 'mox-verilog.js'));
/**
- * Load a CIRCT WASM tool into an isolated vm context.
+ * Load a MOX WASM tool into an isolated vm context.
* Returns an object with `invoke(inputFiles, args)` that resets output capture per call.
*/
async function loadTool(toolName, { initTimeout = 45_000 } = {}) {
- const jsPath = path.join(CIRCT_DIR, `${toolName}.js`);
+ const jsPath = path.join(MOX_DIR, `${toolName}.js`);
if (!fs.existsSync(jsPath)) {
- throw new Error(`WASM artifact not found: ${jsPath}\nRun: npm run sync:circt`);
+ throw new Error(`WASM artifact not found: ${jsPath}\nRun: npm run sync:mox`);
}
const source = fs.readFileSync(jsPath, 'utf8');
@@ -36,7 +36,7 @@ async function loadTool(toolName, { initTimeout = 45_000 } = {}) {
const capture = { out: '', err: '' };
// Custom require that intercepts `require('fs')` to capture fd=1/2 writes.
- // circt-verilog uses NODERAWFS which calls fs.writeSync(1, ...) for stdout,
+ // mox-verilog uses NODERAWFS which calls fs.writeSync(1, ...) for stdout,
// bypassing Emscripten's `out` function and Module.print entirely.
const realRequire = createRequire(jsPath);
const patchedFsRequire = (id) => {
@@ -81,7 +81,7 @@ async function loadTool(toolName, { initTimeout = 45_000 } = {}) {
setInterval,
clearInterval,
performance,
- __dirname: CIRCT_DIR,
+ __dirname: MOX_DIR,
__filename: jsPath,
};
context.globalThis = context;
@@ -91,7 +91,7 @@ async function loadTool(toolName, { initTimeout = 45_000 } = {}) {
// instead of console.log / console.error.
context.Module = {
noInitialRun: true,
- locateFile: (f) => path.join(CIRCT_DIR, f),
+ locateFile: (f) => path.join(MOX_DIR, f),
print: (s) => { capture.out += s + '\n'; },
printErr: (s) => { capture.err += s + '\n'; },
};
@@ -152,17 +152,17 @@ function waitForReady(context, ms) {
// ---------------------------------------------------------------------------
-describe.skipIf(!artifactsPresent)('CIRCT WASM smoke tests', { timeout: 90_000 }, () => {
+describe.skipIf(!artifactsPresent)('MOX WASM smoke tests', { timeout: 90_000 }, () => {
let verilog;
let sim;
- // Real temp directory — required because circt-verilog uses NODERAWFS (real fs).
+ // Real temp directory — required because mox-verilog uses NODERAWFS (real fs).
let WORK;
beforeAll(async () => {
- WORK = fs.mkdtempSync(path.join(os.tmpdir(), 'circt-smoke-'));
+ WORK = fs.mkdtempSync(path.join(os.tmpdir(), 'mox-smoke-'));
[verilog, sim] = await Promise.all([
- loadTool('circt-verilog'),
- loadTool('circt-sim'),
+ loadTool('mox-verilog'),
+ loadTool('mox-sim'),
]);
}, 60_000);
@@ -170,15 +170,15 @@ describe.skipIf(!artifactsPresent)('CIRCT WASM smoke tests', { timeout: 90_000 }
fs.rmSync(WORK, { recursive: true, force: true });
});
- // -- circt-verilog --
+ // -- mox-verilog --
- it('circt-verilog --version exits 0', () => {
+ it('mox-verilog --version exits 0', () => {
const { exitCode, stdout, stderr } = verilog.invoke({}, ['--version']);
expect(exitCode).toBe(0);
- expect(stdout + stderr).toMatch(/circt|CIRCT/i);
+ expect(stdout + stderr).toMatch(/mox|MOX/i);
});
- it('circt-verilog compiles a simple combinational module', () => {
+ it('mox-verilog compiles a simple combinational module', () => {
const sv = `
module top (input logic a, b, output logic y);
assign y = a & b;
@@ -195,24 +195,24 @@ endmodule
expect(mlir).toContain('hw.module @top');
});
- // -- circt-sim --
+ // -- mox-sim --
- it('circt-sim --version exits 0', () => {
+ it('mox-sim --version exits 0', () => {
const { exitCode, stdout, stderr } = sim.invoke({}, ['--version']);
expect(exitCode).toBe(0);
- expect(stdout + stderr).toMatch(/circt|CIRCT/i);
+ expect(stdout + stderr).toMatch(/mox|MOX/i);
});
- it('circt-sim simulates a minimal testbench end-to-end', () => {
+ it('mox-sim simulates a minimal testbench end-to-end', () => {
const sv = `
module tb;
initial begin
- $display("circt-sim-ok");
+ $display("mox-sim-ok");
$finish;
end
endmodule
`;
- // Compile SV → MLIR via circt-verilog (NODERAWFS → real filesystem)
+ // Compile SV → MLIR via mox-verilog (NODERAWFS → real filesystem)
const svPath = `${WORK}/tb.sv`;
const mlirPath = `${WORK}/tb.mlir`;
const { exitCode: compileExit } = verilog.invoke(
@@ -222,12 +222,12 @@ endmodule
expect(compileExit).toBe(0);
const mlir = verilog.readFile(mlirPath);
- // Simulate MLIR via circt-sim (MEMFS — NODERAWFS was patched out)
+ // Simulate MLIR via mox-sim (MEMFS — NODERAWFS was patched out)
const { exitCode, stdout, stderr } = sim.invoke(
{ '/workspace/tb.mlir': mlir },
['--top', 'tb', '/workspace/tb.mlir'],
);
expect(exitCode).toBe(0);
- expect(stdout + stderr).toContain('circt-sim-ok');
+ expect(stdout + stderr).toContain('mox-sim-ok');
});
});
diff --git a/src/runtime/vpi-abi.js b/src/runtime/vpi-abi.js
index f650bb2..63d4f53 100644
--- a/src/runtime/vpi-abi.js
+++ b/src/runtime/vpi-abi.js
@@ -1,5 +1,5 @@
/**
- * Shared VPI ABI constants/helpers for wasm32 circt-sim bridges.
+ * Shared VPI ABI constants/helpers for wasm32 mox-sim bridges.
*
* Keep this as the single source of truth for:
* - VPI enum values used by JS <-> wasm calls
diff --git a/src/runtime/vpi-abi.test.js b/src/runtime/vpi-abi.test.js
index 70c6e12..92a340e 100644
--- a/src/runtime/vpi-abi.test.js
+++ b/src/runtime/vpi-abi.test.js
@@ -41,7 +41,7 @@ function makeMockModule(bytes = 1024) {
}
describe('vpi-abi constants', () => {
- it('matches CIRCT VPI value/time enums', () => {
+ it('matches MOX VPI value/time enums', () => {
expect(VPI.vpiIntVal).toBe(6);
expect(VPI.vpiScalarVal).toBe(5);
expect(VPI.vpiVectorVal).toBe(9);
diff --git a/src/runtime/worker-shim.test.js b/src/runtime/worker-shim.test.js
index d496c67..3d9c985 100644
--- a/src/runtime/worker-shim.test.js
+++ b/src/runtime/worker-shim.test.js
@@ -1,6 +1,6 @@
/**
* Unit tests for the NODERAWFS process shim used in WORKER_SOURCE and
- * COCOTB_WORKER_SOURCE inside circt-adapter.js.
+ * COCOTB_WORKER_SOURCE inside mox-adapter.js.
*
* Emscripten tools compiled with NODERAWFS call process.version.match(/v(\d+)/)
* to detect the Node.js major version. Before the fix, the shim set
diff --git a/vite.config.js b/vite.config.js
index fe66663..e31141a 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -94,7 +94,7 @@ export default defineConfig({
target: 'esnext',
minify: 'esbuild',
sourcemap: true,
- // Single chunk is ~218 kB gzipped (CodeMirror + Svelte + CIRCT adapter).
+ // Single chunk is ~218 kB gzipped (CodeMirror + Svelte + MOX adapter).
// The raw size exceeds Rollup's 500 kB default but gzip makes it fine.
chunkSizeWarningLimit: 800,
rollupOptions: {