Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2c86e4c
docs: record current tutorial census
thomasahle Sep 30, 2026
e1114bc
test: use a current two-file lesson in split-view e2e
thomasahle Sep 30, 2026
d8e9937
feat: add chapters for landed Mox capabilities
thomasahle Sep 30, 2026
2802c6d
test: expect deliberate concurrent assertion failure
thomasahle Sep 30, 2026
c782105
fix: calibrate indexed part-select starter
thomasahle Sep 30, 2026
e096f9a
test: lock indexed starter receipt calibration
thomasahle Sep 30, 2026
698c20f
docs: record final capability receipt provenance
thomasahle Sep 30, 2026
d2c0ac7
docs: clarify receipt bundle digest scope
thomasahle Sep 30, 2026
728bcf3
feat: add sequential UDP initialization chapter
thomasahle Sep 30, 2026
18baa8e
test: bind UDP receipts to committed fixtures
thomasahle Sep 30, 2026
dc8629d
docs: preserve UDP full e2e receipt
thomasahle Sep 30, 2026
d745dab
feat: document compile-mode status and S4 census
thomasahle Sep 30, 2026
fb6360b
test: bind compile status receipts to fixtures
thomasahle Sep 30, 2026
194cea0
docs: record compile status review disposition
thomasahle Sep 30, 2026
506e7d1
feat: add virtual provider closure lesson
thomasahle Oct 1, 2026
9cb1e1b
docs: refresh compile mode census receipt
thomasahle Oct 1, 2026
62952f3
docs: close lesson receipt coverage gap
thomasahle Oct 1, 2026
0f383cc
docs: mark unimplemented curriculum lesson as planned
thomasahle Oct 1, 2026
71a3cb8
docs: refresh repository architecture and toolchain notes
thomasahle Oct 1, 2026
7c74ce3
docs: align curriculum teaching claims
thomasahle Oct 1, 2026
d5e00c4
docs: refresh landed capability census
thomasahle Oct 1, 2026
75547cd
docs: qualify native receipt provenance
thomasahle Oct 1, 2026
dd85bbf
test: pin capability census provenance
thomasahle Oct 1, 2026
346b353
test: make receipt paths checkout-independent
thomasahle Oct 1, 2026
f4ed562
feat: add clocking sampler retention chapter
thomasahle Oct 1, 2026
d43a413
feat: add protected envelope boundary chapter
thomasahle Oct 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 32 additions & 34 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Commands

```bash
npm install # Install dependencies
npm ci # Install the locked dependencies
npm test # Vitest unit and source-contract tests
npm run test:e2e # Playwright browser tests
npm run dev # Start dev server (Vite)
npm run build # Production build
npm run preview # Preview production build
Expand All @@ -17,55 +19,51 @@ scripts/setup-surfer.sh # Download Surfer waveform viewer web build into
scripts/setup-surfer.sh <dir> # Download into a custom directory
```

There are no tests in this project.
The unit tests use Vitest and the browser tests use Playwright. Keep focused
tests close to the lesson or runtime contract they protect.

## Architecture

This is a Svelte 5 + Vite single-page app. The entry point is `src/main.js` → `src/App.svelte`.
This is a SvelteKit static app using Svelte 5. The lesson route is
`src/routes/lesson/[part]/[name]/+page.svelte`; the root route redirects legacy
`?lesson=N` URLs in `src/routes/+page.js`.

### Lesson Data (`src/tutorial-data.js`)
### Lesson Data (`src/lessons/`)

Lessons are defined in a `parts → chapters → lessons` hierarchy and exported as a flat `lessons` array. Each lesson has:
- `files.a`: starter files (keyed by virtual path like `/src/top.sv`)
- `files.b`: solution delta (merged onto `a` to produce the solution)
- `focus`: the default file to show in the editor
- `html`: inline HTML string for the lesson description
The catalog hierarchy and flat lesson list live in `src/lessons/index.js`.
Titles, focus files, runners, and tops live in `src/lessons/meta.js`.
Each lesson keeps its starter source, solution source, and
`description.html` beside the lesson directory. `src/lib/tutorial-data.js` is
only the compatibility re-export used by the SvelteKit route loaders.

### App State (`src/App.svelte`)
### Lesson State (`src/routes/lesson/[part]/[name]/+page.svelte`)

All state lives in the single root component. Key derived values:
- `solutionFiles = merge(starterFiles, lesson.files.b)`
- `completed = filesEqual(workspace, solutionFiles)` — drives the "solve"/"reset" toggle
- Lesson navigation mutates `lessonIndex`; reactive blocks reset `workspace`, `logs`, and `lastWaveform` on lesson change
The lesson page owns the editor workspace, run state, runtime logs, and
waveform state. Shared completion and settings state lives in
`src/lib/stores/`. Lesson file merging and top-name inference are in
`src/lib/lesson-utils.js`.

### MOX WASM Runtime (`src/runtime/`)

Two files handle the runtime bridge:

**`mox-config.js`** — reads Vite env vars and resolves runtime configuration:
- `VITE_MOX_WASM_JS_URL` / `VITE_MOX_WASM_JS_URLS` — JS artifact URL(s) (comma-separated for fallback)
- `VITE_MOX_WASM_URL` / `VITE_MOX_WASM_URLS` — WASM artifact URL(s)
- `VITE_MOX_FACTORY_NAME` — optional Emscripten factory function name
- `VITE_MOX_TOOL_ARGS` — args for `run` (JSON array preferred, space-split fallback)
- `VITE_MOX_SELF_CHECK_ARGS` — args for the self-check smoke test
- Default JS candidates: `/mox/mox.js`, `/mox/mox-bmc.js`
- Default WASM candidates: `/mox/mox.wasm`, `/mox/mox-bmc.wasm`

**`mox-adapter.js`** — `MoxWasmAdapter` class, lazy-initialized on first `run()` or `selfCheck()`:
- Tries each JS candidate URL in order until one loads successfully
- Detects runtime mode automatically:
- **`custom-runtime`**: `window.MOX_WASM_RUNTIME` global exposes `{ init, run, selfCheck? }`
- **`emscripten-module`**: raw Emscripten output; looks for factory functions (`createMoxBmcModule`, `createModule`, `Module`) then falls back to `window.Module`
- In Emscripten mode, files are written into the module's virtual FS under `/workspace/`, and output waveform is read back from `/workspace/out/waves.vcd`
- Arg templates support `{top}`, `{input}`, `{waveform}` placeholders
**`mox-config.js`** reads Vite env vars and resolves the separate
`mox-verilog`, `mox-sim`, `mox-bmc`, `mox-lec`, and cocotb runtime URLs under
`/mox/`.

**`mox-adapter.js`** lazy-loads those workers. Plain SystemVerilog lessons
use the unified `mox-run` path; UVM lessons use the bundled UVM compile path;
MLIR lessons use `mox-verilog` followed by `mox-sim`; formal lessons use
`mox-bmc` or `mox-lec`. The adapter writes workspace files under the worker's
`/workspace/` filesystem and reads VCD output from `/workspace/out/`.

### MOX WASM Artifacts

Place built artifacts from the MOX fork (`git@github.com:normal-computing/mox.git`) at:
- `public/mox/mox-bmc.js` + `public/mox/mox-bmc.wasm`
- or custom shim: `public/mox/mox.js` + `public/mox/mox.wasm`
The generated runtime assets live under `static/mox/` and are gitignored.
Use the pinned values in `scripts/toolchain.lock.sh` with the setup/build
scripts to produce them.

Without these files, the runtime will fail gracefully with a log message directing you to run `scripts/setup-mox.sh`.
Without these files, the runtime reports that the Mox artifacts are missing.

### Surfer Waveform Viewer (`src/lib/components/WaveformViewer.svelte`)

Expand Down
55 changes: 50 additions & 5 deletions CURRICULUM.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,63 @@ Flag numbers identify the weak dimension(s): 1=Concept Focus, 2=Starter Calibrat

## Part 1 — SystemVerilog Basics

### Chapter: Macro Formal Continuations (September 2026)
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/macro-formal-continuation` | Macro Formal Continuations | ✅ | — | `sv/classes` | continued `` `define `` text, formal arguments, token pasting |

### Chapter: Packed-Struct Field References (September 2026)
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/struct-field-refs` | Packed-Struct Field References | ✅ | — | `sv/packed-structs` | named access to a packed struct through module connections |

### Chapter: Indexed Part-Select Bounds (September 2026)
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/indexed-part-select` | Indexed Part-Select Bounds | ✅ | — | `sv/data-types` | `+:` indexed selects and four-state out-of-range reads |

### Chapter: Nested Child Input Propagation (September 2026)
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/nested-child-input` | Nested Child Input Propagation | ✅ | — | `sv/always-ff` | live child input connections across nested modules |

### Chapter: Sequential UDP Initialization (September 2026)
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/sequential-udp-init` | Sequential UDP Initialization | ✅ | — | `sv/always-ff` | sequential UDP state, edge-sensitive tables, and output initialization |

### Chapter: Compile-Mode Status (September 2026)
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/compile-mode-status` | Compile-Mode Status | ✅ | — | `sv/modules-and-ports` | native `--mode=compile`, refusal vocabulary, and the S4 UVM qualification runner |

### Chapter: Clocking Sampler Retention (October 2026)
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/clocking-sampler-retention` | Clocking Sampler Retention | ✅ | — | `sv/interfaces` | explicit `#0` clocking-input sampling and same-slot sample retention |

### Chapter: Protected Envelope Boundary (October 2026)
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/protected-envelope-boundary` | Protected Envelope Boundary | ✅ | — | `sv/modules-and-ports` | same-buffer protected-envelope delimiters and no-key opaque handling |

### Chapter: Virtual Method Provider Closure (October 2026)
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/virtual-provider-closure` | Virtual Method Provider Closure | ✅ | — | `sv/classes` | virtual overrides, base-class handles, and native AOT provider retention |

### Chapter: Introduction
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/welcome` | Welcome | ✅ | 23/27 ⚠️4,5 | — | `module`/`endmodule`, `$display`, simulation loop, tutorial roadmap |
| `sv/modules-and-ports` | Modules and Ports | ✅ | 25/27 ⚠️1,4 | `sv/welcome` | port directions (`input`/`output`), `logic`, vectors, `assign`, module instantiation |
| `sv/data-types` | Data Types | ✅ | 25/27 ⚠️5 | `sv/modules-and-ports` | 4-state `logic` (RTL) vs 2-state `int`/`bit` (testbench), X state, `$isunknown()` |
| `sv/data-types` | Data Types | ✅ | 25/27 ⚠️5 | `sv/modules-and-ports` | 4-state `logic` vs 2-state `int`/`bit`, X state, `$isunknown()` |

### Chapter: Combinational Logic
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/always-comb` | always_comb and case | ✅ | 27/27 | `sv/modules-and-ports` | `always_comb`, `case`/`if` in procedural block, combinational output |
| `sv/priority-enc` | Priority Encoder (casez) | ✅ | 22/27 | `sv/always-comb` | `casez`, `?` wildcard match, priority-ordered selection |
| `sv/priority-enc` | Priority Encoder (casez) | 📝 | — | `sv/always-comb` | `casez`, `?` wildcard match, priority-ordered selection |
| `sv/assign-operators` | Operators & Arithmetic | 📝 | — | `sv/modules-and-ports` | `assign`, bit/reduction/ternary operators, signed arithmetic, overflow |

> Cover reduction operators (`|req`), ternary, signed arithmetic,
Expand All @@ -41,7 +86,7 @@ Flag numbers identify the weak dimension(s): 1=Concept Focus, 2=Starter Calibrat
|---|---|---|---|---|---|
| `sv/events` | Events | ✅ | 24/27 ⚠️4,5,7 | `sv/modules-and-ports` | `event`, `->` (post), `@(event_name)` (wait), concurrent-process synchronization |
| `sv/always-ff` | Flip-Flops with always_ff | ✅ | 26/27 ⚠️1 | `sv/modules-and-ports`, `sv/always-comb` | `always_ff`, `posedge`, non-blocking `<=`, unpacked array `mem[]`, 1-cycle read latency |
| `sv/counter` | Up-Counter | ✅ | 23/27 ⚠️1,8,9 | `sv/always-ff` | enable/reset counter, address stepping, `@(posedge clk)` in `initial` |
| `sv/counter` | Up-Counter | ✅ | 23/27 ⚠️1,8,9 | `sv/always-ff` | enable/reset counter, cycle-counted stimulus, `@(posedge clk)` in `initial` |
| `sv/shift-reg` | Shift Register | 📝 | — | `sv/always-ff` | bit shift, concatenation `{}`, serial-in/serial-out |

> Introduces `[*]` bus shift and multi-bit `always_ff`; prerequisite
Expand Down Expand Up @@ -79,7 +124,7 @@ Flag numbers identify the weak dimension(s): 1=Concept Focus, 2=Starter Calibrat
### Chapter: State Machines
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/enums` | typedef enum | ✅ | 24/27 ⚠️2,9 | `sv/always-ff`, `sv/always-comb` | `typedef enum`, named constants, enum in `case`, apostrophe cast `state_t'(bits)` |
| `sv/enums` | typedef enum | ✅ | 24/27 ⚠️2,9 | `sv/always-ff`, `sv/always-comb` | `typedef enum`, named constants, enum-typed ports, enum in `case` |
| `sv/fsm` | Two-Always Moore FSM | ✅ | 27/27 | `sv/enums`, `sv/always-ff`, `sv/always-comb` | two-always Moore pattern (FF state + comb output), FSM-gated SRAM write/read |
| `sv/mealy-fsm` | Mealy FSM | 📝 | — | `sv/fsm` | Mealy output depends on current input, single-always style |

Expand All @@ -89,7 +134,7 @@ Flag numbers identify the weak dimension(s): 1=Concept Focus, 2=Starter Calibrat
### Chapter: Covergroups
| Slug | Title | Status | Score | Prereqs | Teaches |
|---|---|---|---|---|---|
| `sv/covergroup-basics` | covergroup and coverpoint | ✅ | 24/27 ⚠️2,9 | `sv/parameters` | `covergroup`, `coverpoint`, `sample()`, `$get_coverage()`, functional coverage concept |
| `sv/covergroup-basics` | covergroup and coverpoint | ✅ | 24/27 ⚠️2,9 | `sv/parameters` | `covergroup`, `coverpoint`, event sampling, functional coverage concept |
| `sv/coverpoint-bins` | Bins and ignore_bins | ✅ | 23/27 ⚠️7,8,9 | `sv/covergroup-basics` | explicit `bins`, range bins, `ignore_bins`, auto bins |
| `sv/cross-coverage` | Cross coverage | ✅ | 25/27 ⚠️9 | `sv/coverpoint-bins` | `cross`, 2D coverage matrix, identifying uncovered `{addr, we}` pairs |

Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ Pinned versions are centralized in `scripts/toolchain.lock.sh`:

- Node major: `22`
- Emscripten (emsdk): `4.0.21`
- MOX repo: `https://github.com/normal-computing/mox.git`
- MOX ref: `8e8ca87dcda1c8abd47103ae7789c8ed261d5de3`
- LLVM submodule ref: `972cd847efb20661ea7ee8982dd19730aa040c75`
- MOX repo: `https://github.com/normal-computing/mox.git` (ref and LLVM ref are
read from `scripts/toolchain.lock.sh`)

Host tools:

Expand Down Expand Up @@ -99,6 +98,10 @@ In `.env` (copy `.env.example`):
- Runtime uses a real 2-stage wasm toolchain by default:
- `mox-verilog` lowers SV/SVA/UVM source to MLIR
- `mox-sim` executes lowered MLIR and emits VCD for the waveform pane
- UVM lessons are currently qualified in interpreter mode only; `--mode=compile`
does not yet run the UVM-bench rows. Native receipt runs therefore report the
interpreter as the supported UVM path until the corresponding Mox AOT rows
land.
- Tool invocations run in isolated Web Workers to avoid global Emscripten symbol collisions and re-entry issues.
- UI includes a `self-check` action in the Runtime panel to validate artifact compatibility.
- Waves tab appears automatically only when a valid VCD is generated.
Expand Down
Loading
Loading