diff --git a/CURRICULUM.md b/CURRICULUM.md index 977c24c..fc004f4 100644 --- a/CURRICULUM.md +++ b/CURRICULUM.md @@ -73,6 +73,11 @@ Flag numbers identify the weak dimension(s): 1=Concept Focus, 2=Starter Calibrat |---|---|---|---|---|---| | `sv/coverage-option-text` | Coverage Option Text | ✅ | — | `sv/covergroup-basics` | default and procedural assignment of a covergroup instance's `option.comment` | +### Chapter: Interface Method Receivers (October 2026) +| Slug | Title | Status | Score | Prereqs | Teaches | +|---|---|---|---|---|---| +| `sv/interface-method-receiver` | Interface Method Receivers | ✅ | — | `sv/interfaces`, `sv/classes` | receiver-specific `%m` paths and parenthesized calls through a virtual interface | + ### Chapter: Introduction | Slug | Title | Status | Score | Prereqs | Teaches | |---|---|---|---|---|---| diff --git a/artifacts/tutorial/SUMMARY.md b/artifacts/tutorial/SUMMARY.md index 8a6bfb8..6603b0a 100644 --- a/artifacts/tutorial/SUMMARY.md +++ b/artifacts/tutorial/SUMMARY.md @@ -90,7 +90,7 @@ One commit per issue, each with the test that fails before it and passes after: ### Landed capability chapters -Added eight one-lesson chapters for user-facing SystemVerilog capabilities +Added nine one-lesson chapters for user-facing SystemVerilog capabilities landed in Mox between September 22 and October 1, 2026. The UDP chapter tracks landing tip `36b040f6190c`, and the virtual-provider chapter tracks `3bc88e77921e`; the pinned browser WASM remains unchanged. @@ -105,6 +105,7 @@ tracks landing tip `36b040f6190c`, and the virtual-provider chapter tracks | `sv/virtual-provider-closure` | §§8.20, 8.22 | starter FAIL; solution PASS in interpreter and compile modes | starter both_fail; solution both_pass; output equal | `artifacts/tutorial/virtual-provider-closure/*` | | `sv/wide-readmem` | §§21.4, 21.4.1 | starter FAIL; solution PASS in interpreter and compile modes | starter both_fail; solution both_pass; output equal | `artifacts/tutorial/wide-readmem/*` | | `sv/coverage-option-text` | §19.7, Table 19-1 | starter FAIL; solution PASS in interpreter and compile modes | starter both_fail; solution both_pass; output equal | `artifacts/tutorial/coverage-option-text/*` | +| `sv/interface-method-receiver` | §§21.2.1.5, 25.9 | starter FAIL; solution PASS in interpreter and compile modes | starter both_fail; solution both_pass; output equal | `artifacts/tutorial/interface-method-receiver/*` | The capability receipt summaries are in `artifacts/tutorial/capability-receipts/{summary,final-summary}.tsv`. @@ -114,7 +115,7 @@ receipt are recorded in ## Receipt coverage on origin/main -The 84 registered lesson slugs are now accounted for by either the original +The 85 registered lesson slugs are now accounted for by either the original generic receipts, a capability-specific bundle, or the missing-matrix bundle at `artifacts/tutorial/receipts/20261001-missing/`. That matrix records the 18 previously uncovered slugs: native Mox passes for both RTL lessons and all @@ -188,6 +189,18 @@ cache keys even when `reference_cached` is true. Receipts and the b481 landing provenance are under `artifacts/tutorial/coverage-option-text/`. +### Interface method receiver chapter + +`sv/interface-method-receiver` teaches that a method inside an interface keeps +the receiver instance selected by a virtual-interface handle, including casts +and parenthesized calls. The exercise uses two interface instances with +different answers; the starter binds `u_a`, while the solution binds `u_b`. +The solution passes native interpreter and compile modes, and Xcelium and Mox +agree on the starter `both_fail` and solution `both_pass` receipts. The browser +entry is an expected pinned-WASM failure because this receiver lowering landed +after the checked-in WASM; it does not qualify native AOT. Receipts and landing +provenance are under `artifacts/tutorial/interface-method-receiver/`. + ## WASM rebuild (done locally, NOT published; release `mox-wasm` is unchanged) Built with emsdk 4.0.21 from Mox main `9c5418532b9` (and landing `ea0fcd2`): mox-verilog, mox-sim, mox-bmc and mox-lec. Mox has no wasm target for mox-run (GAPS TUT-WASM-MOXRUN), so two more commits went in: diff --git a/artifacts/tutorial/content-census.md b/artifacts/tutorial/content-census.md index 268b4a6..b42bfe1 100644 --- a/artifacts/tutorial/content-census.md +++ b/artifacts/tutorial/content-census.md @@ -20,7 +20,7 @@ tutorial's runnable coverage for the landed readmem behavior. ## New landed-capability chapters -These ten short chapters correspond to the user-facing Mox capabilities present +These eleven short chapters correspond to the user-facing Mox capabilities present on the current `origin/main` by October 1, 2026. The compile-mode status page is listed separately below because it reports qualification status rather than teaching a new language capability. Every solution passes Mox in both @@ -40,13 +40,13 @@ attempts decryption without a key. | `sv/protected-envelope-boundary` | `c3799f427f1e51abcd389dcf15771150223cae75`, `test/Conversion/ImportVerilog/protected-comment-callback.sv` | §§34.2, 34.3, 34.4, 34.5.3–34.5.4: protected text is transformed before analysis and delimiters close the envelope; this lesson does not claim decryption. | solution PASS; starter FAIL | solution PASS; starter FAIL | `reference_only_fail` for solution; Xcelium attempts unkeyed decryption | added same-buffer opaque callback-boundary exercise | | `sv/wide-readmem` | `e7da9630dcd`, `test/Tools/mox-sim/aot-readmem-wide-fourstate.sv` | §§21.4, 21.4.1: `$readmemh` accepts optional address bounds and loads packed elements of an unpacked memory, preserving four-state digits. | solution PASS; starter FAIL | solution PASS; starter FAIL | starter `both_fail`; solution `both_pass`, output equal | added a width-calibration readmem exercise | | `sv/coverage-option-text` | `b481355f9fe`, `test/Tools/mox-sim/coverage-covergroup-option-comment-assignment.sv` | §19.7 and Table 19-1: an instance-specific covergroup `comment` defaults to `""` and may be assigned procedurally after instantiation. | solution PASS; starter FAIL | solution PASS; starter FAIL | starter `both_fail`; solution `both_pass`, output equal | added a default-and-assignment coverage-option exercise | +| `sv/interface-method-receiver` | `ed441eb5b58`, `test/Tools/mox-sim/interface-method-percent-m-instance-path.sv` and `vif-method-call-parenthesized-receiver.sv` | §§21.2.1.5, 25.9: `%m` identifies the invoking method scope, and a virtual interface variable represents the selected interface instance whose components are accessed through dot notation. | solution PASS; starter FAIL | solution PASS; starter FAIL | starter `both_fail`; solution `both_pass`, output equal | added receiver-specific `%m`, cast, and parenthesized virtual-interface calls | -The remaining current-main capability commits are queued for their own short -chapters and are not silently folded into an existing lesson: VPI system-function -argument marshalling (`d83c4b1dde8`), and interface-method `%m` receiver scope plus parenthesized -virtual-interface receivers (`ed441eb5b58`). +The remaining current-main capability commit is queued for its own short +chapter and is not silently folded into an existing lesson: VPI system-function +argument marshalling (`d83c4b1dde8`). -This census covers every lesson in `src/lessons/` (meta.js, 84 lessons) and CURRICULUM.md, checked against +This census covers every lesson in `src/lessons/` (meta.js, 85 lessons) and CURRICULUM.md, checked against IEEE 1800-2023 (`spec/ieee-1800-2023.txt`) and IEEE 1800.2-2020 (UVM). Each row gives: lesson | claim/example | what is wrong | IEEE clause | evidence | proposed fix | severity. diff --git a/artifacts/tutorial/interface-method-receiver/README.md b/artifacts/tutorial/interface-method-receiver/README.md new file mode 100644 index 0000000..5787042 --- /dev/null +++ b/artifacts/tutorial/interface-method-receiver/README.md @@ -0,0 +1,63 @@ +# Interface method receiver receipt + +This receipt supports `sv/interface-method-receiver`. The lesson uses two +instances of one interface and a class-held `virtual` interface. The starter +binds `u_a`; the solution binds `u_b` and checks plain, cast, and parenthesized +method calls against `u_b`'s path and answer. + +## Standard and landing basis + +IEEE 1800-2023 §21.2.1.5 defines `%m` as the hierarchical name of the design +element or subroutine that invokes the system task containing the format +specifier. Section §25.9 defines a virtual interface as a variable representing +an interface instance, permits passing it to methods, and makes the selected +instance's components available through dot notation after initialization. + +The native capability landed in Mox commit `ed441eb5b583c8ae6146bbb4b32073fedd4d7b77`, +recorded in the landing ledger as interface-method receiver handling. The +exact-tip build used here is `/var/tmp/thomas-ahle/fleet-probes/ed441-tutorial-20261001/build-dev-fast`; +the source tree is read-only and no Mox worktree was changed. The checked-in +browser WASM predates this landing and is not used as native evidence. + +## Native runs + +Each run is pinned to CPUs `0-79` and guarded by a 30-second wall timeout. The +import step uses `mox-verilog --ir-llhd`; simulation uses `mox-sim` in the +requested mode. + +```text +taskset -c 0-79 timeout --kill-after=3s 30s /var/tmp/thomas-ahle/fleet-probes/ed441-tutorial-20261001/build-dev-fast/bin/mox-verilog --ir-llhd --top=tb src/lessons/sv/interface-method-receiver/interface_method_receiver.sv -o .mlir +taskset -c 0-79 timeout --kill-after=3s 30s /var/tmp/thomas-ahle/fleet-probes/ed441-tutorial-20261001/build-dev-fast/bin/mox-sim .mlir --top tb --mode=interpret +taskset -c 0-79 timeout --kill-after=3s 30s /var/tmp/thomas-ahle/fleet-probes/ed441-tutorial-20261001/build-dev-fast/bin/mox-sim .mlir --top tb --mode=compile --aot-require-zero-interpreter +``` + +| variant | mode | exit | first result line | +|---|---:|---:|---| +| starter | interpret | 0 | `FAIL: path=tb.u_a cast=tb.u_a paren=tb.u_a answers=1/1` | +| starter | compile | 0 | `FAIL: path=tb.u_a cast=tb.u_a paren=tb.u_a answers=1/1` | +| solution | interpret | 0 | `PASS` | +| solution | compile | 0 | `PASS` | + +The solution compile log reports the whole-design zero-interpreter gate as +satisfied. Full logs are `starter-interpret.log`, `starter-compile.log`, +`solution-interpret.log`, and `solution-compile.log`. + +## Differential runs + +`refdiff` was run on each committed fixture against the exact-tip native build: + +```text +/var/tmp/thomas-ahle/fleet/bin/refdiff src/lessons/sv/interface-method-receiver/interface_method_receiver.sv --build-dir /var/tmp/thomas-ahle/fleet-probes/ed441-tutorial-20261001/build-dev-fast +/var/tmp/thomas-ahle/fleet/bin/refdiff src/lessons/sv/interface-method-receiver/interface_method_receiver.sol.sv --build-dir /var/tmp/thomas-ahle/fleet-probes/ed441-tutorial-20261001/build-dev-fast +``` + +- `starter-refdiff.json`: `both_fail`; reference and Mox exit 0 and output is equal. +- `solution-refdiff.json`: `both_pass`; reference and Mox exit 0 and output is equal. +- The JSON `sha256` values are the committed source hashes. The separate + `refdiff_cache_key` fields retain the differential-run cache identities. + +## Browser qualification + +`browser-qa.md` records the focused route result. The browser uses the pinned +WASM, which predates this receiver lowering, so a native receipt must not be +presented as browser qualification or native AOT qualification. diff --git a/artifacts/tutorial/interface-method-receiver/browser-qa.md b/artifacts/tutorial/interface-method-receiver/browser-qa.md new file mode 100644 index 0000000..c60084e --- /dev/null +++ b/artifacts/tutorial/interface-method-receiver/browser-qa.md @@ -0,0 +1,20 @@ +# Browser QA receipt + +The focused browser check is expected to fail against the checked-in WASM: +the interface-method receiver lowering landed in Mox `ed441eb5b58` after the +pinned browser artifact. Native Mox interpreter and compile receipts pass the +solution, but this chapter does not claim that the old WASM implements it. + +Expected focused command: + +```text +npx playwright test e2e/qa-all-lessons.spec.js --grep 'Interface Method Receivers' --reporter=line +``` + +The route remains registered and the failure is quarantined with a reason in +`e2e/qa-all-lessons.spec.js`. Remove that expectation only after a qualified +WASM rebuild and rerun of the focused browser check. + +Receipt: October 1, 2026, `1 passed` in 31.3 seconds. The pass is the +expected-failure disposition, not evidence that the pinned WASM supports the +new receiver behavior. diff --git a/artifacts/tutorial/interface-method-receiver/native-summary.tsv b/artifacts/tutorial/interface-method-receiver/native-summary.tsv new file mode 100644 index 0000000..aeb6906 --- /dev/null +++ b/artifacts/tutorial/interface-method-receiver/native-summary.tsv @@ -0,0 +1,7 @@ +variant mode exit pass_line +starter interpret 0 FAIL: path=tb.u_a cast=tb.u_a paren=tb.u_a answers=1/1 +starter compile 0 FAIL: path=tb.u_a cast=tb.u_a paren=tb.u_a answers=1/1 +starter refdiff 1 both_fail ref=FAIL mox=FAIL equal=true +solution interpret 0 PASS +solution compile 0 PASS +solution refdiff 0 both_pass ref=PASS mox=PASS equal=true diff --git a/artifacts/tutorial/interface-method-receiver/solution-compile.log b/artifacts/tutorial/interface-method-receiver/solution-compile.log new file mode 100644 index 0000000..a7feca9 --- /dev/null +++ b/artifacts/tutorial/interface-method-receiver/solution-compile.log @@ -0,0 +1,42 @@ + +=== solution compile === +[mox-sim] Auto-enabling --skip-passes for module marked mox.sim.preprocessed +[mox-sim] Stage: passes (prev: 0ms, total: 0ms) +[mox-sim] aot-publication/v2 domain=module-loader-functions expected=3 accounted=3 positive=3 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:42403e255eb93ebfd84bd1b4f678cfd9b4ecf9dbedd8a2cc455eab79f8d8db5d +[mox-sim] aot-publication/v2 domain=module-loader-processes expected=5 accounted=5 positive=5 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:4f6af561e3453305089281dccbf5af4eb3179386260a94c249572b79469558e3 +[mox-sim] aot-publication/v2 domain=module-loader-address-bound-globals expected=173 accounted=173 positive=173 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:329abfbd0388ee100456c8d635a0b09f9603db498312a70276ab41839b7ef8e0 +[mox-sim] aot-publication/v2 domain=module-loader-entry-table expected=3 accounted=3 positive=3 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:3d8a7d8d0991adcee0bdb14b8f5137b5e86a46768fe22c68fb4ee866536761c0 +[mox-sim] Loaded RTTI parent table: 2 entries +[mox-sim] Loaded compiled module '/tmp/mox-scratch/768049c71d419e041f39edd530f4670752ae26167b2ac730406bc5d55491bf5e/session-1db7a724798b7158e90899820e69e3add3830661ff293e0465b6eec829ada18c/mox-sim-autocompile-0eb2e7.so': 3 functions, 5 processes, 173 address-bound globals, 3 entry table entries (build: mox-sim-abi-v19-x86_64-unknown-linux-gnu-453d4363abed7a61819923613cf75a4d) +[mox-sim] Address-bound global ownership: role=main, module='/tmp/mox-scratch/768049c71d419e041f39edd530f4670752ae26167b2ac730406bc5d55491bf5e/session-1db7a724798b7158e90899820e69e3add3830661ff293e0465b6eec829ada18c/mox-sim-autocompile-0eb2e7.so', descriptor-declared=173, retained=173 +[mox-sim] M3 loaded callable union: artifacts=1 raw-rows=6 demand-rows=3 distinct-demand-keys=3 slot-rows=0 provider-rows=3 checked-keys=3 missing=0 duplicate=0 malformed=0 unresolved=0 dropped=0 digest=sha256:45e158e18b5ed9a9d32feba6a81d560d9e044f4005a242d87dcca5ee667c2183 status=ok +[mox-sim] Stage: init (prev: 336ms, total: 336ms) +[mox-sim] Pre-aliased 173 address-bound globals to .so storage +[mox-sim] Pre-aliased 1 globals to .so storage +[mox-sim] Unmapped native func.call policy: default deny runtime bridges and pointer-typed get_/set_/create_/m_initialize* (allow others) +[mox-sim] Loaded 3 compiled functions: 3 native-dispatched, 0 not-native-dispatched, 0 intercepted +[mox-sim] aot-publication/v2 domain=compiled-function-dispatch expected=3 accounted=3 positive=3 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:89a20dbec599cdbb92beaae3c359c879c17d3c5997c579a344460c58123922de +[mox-sim] Entry table: 3 entries for tagged-FuncId dispatch (3 native, 0 non-native) +[mox-sim] Address-bound final-LLVM-global probes: 173/173 rows, 1015/1015 bytes bidirectional, owner-generation=1 +[mox-sim] Aliased 0 globals to .so storage (1 already pre-aliased, unified) +[mox-sim] Compiled process dispatch: 5/5 processes wired +[mox-sim] aot-publication/v2 domain=process-dispatch expected=5 accounted=5 positive=5 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:bce0429c6f2cc9ab2eb2c0515f3d79ff95c9e77e5a2eea3ff489f0c47d2784b3 +[mox-sim] aot-publication/v2 domain=process-dispatch identity='tb.process_0' outcome=wired polarity=positive reason='' +[mox-sim] aot-publication/v2 domain=process-dispatch identity='tb.process_1' outcome=wired polarity=positive reason='' +[mox-sim] aot-publication/v2 domain=process-dispatch identity='tb.process_2' outcome=wired polarity=positive reason='' +[mox-sim] aot-publication/v2 domain=process-dispatch identity='tb.process_3' outcome=wired polarity=positive reason='' +[mox-sim] aot-publication/v2 domain=process-dispatch identity='tb.process_4' outcome=wired polarity=positive reason='' +[mox-sim] Stage: load-compiled (prev: 9ms, total: 345ms) +[mox-sim] Found 5 LLHD processes, 0 LLHD finals, 0 seq.initial blocks, and 0 hw.instance ops (out of 589 total ops) in module +[mox-sim] Registered 3 LLHD signals and 5 LLHD processes/initial blocks +[mox-sim] Receipt: INIT_COMPLETE_OK execution_failure=0 process_dispatches=0 +[mox-sim] Stage: run (prev: 0ms, total: 345ms) +[mox-sim] Starting simulation +PASS +[mox-sim] Simulation terminated at time 0 fs (success=true, verbose=true) +[mox-sim] Main loop exit: shouldContinue()=false at time 0 fs, iter=1, deltas=1 +[mox-sim] Simulation finished at time 0 fs +[mox-sim] Simulation completed at time 0 fs +[mox-sim] whole-design AOT zero-interpreter gate satisfied: counted process=0 combinational=0 initializer-operation=0 direct-call=0 ABI-demotion=0 deferred-initial-prewait-operation=0 deferred-initial-prewait-binding=PROVEN dpi-export-function-binding=NOT-REQUIRED; residual-compiled-process=false interpreted-continuous-assignment=0 initializer-operation-filtered=0; instrumented-classes=interpreted-process,interpreted-callable,interpreted-continuous-assignment,module-initializer-operation,deferred-initial-prewait-operation measured-classes=interpreted-process,interpreted-callable,interpreted-continuous-assignment,module-initializer-operation,deferred-initial-prewait-operation unavailable-classes=NONE operation-level-other=UNMEASURED +[mox-sim] Simulation completed +import_exit=0 run_exit=0 diff --git a/artifacts/tutorial/interface-method-receiver/solution-interpret.log b/artifacts/tutorial/interface-method-receiver/solution-interpret.log new file mode 100644 index 0000000..d78f5d0 --- /dev/null +++ b/artifacts/tutorial/interface-method-receiver/solution-interpret.log @@ -0,0 +1,18 @@ + +=== solution interpret === +[mox-sim] Auto-enabling --skip-passes for module marked mox.sim.preprocessed +[mox-sim] Stage: passes (prev: 0ms, total: 0ms) +[mox-sim] Stage: init (prev: 0ms, total: 0ms) +[mox-sim] Found 5 LLHD processes, 0 LLHD finals, 0 seq.initial blocks, and 0 hw.instance ops (out of 589 total ops) in module +[mox-sim] Registered 3 LLHD signals and 5 LLHD processes/initial blocks +[mox-sim] Receipt: INIT_COMPLETE_OK execution_failure=0 process_dispatches=0 +[mox-sim] Stage: run (prev: 2ms, total: 2ms) +[mox-sim] Starting simulation +PASS +[mox-sim] sim.terminate triggered in process ID 3 at loc("/tmp/interface-method-receiver.R8sOGl/design.mlir":756:7) +[mox-sim] Simulation terminated at time 0 fs (success=true, verbose=true) +[mox-sim] Main loop exit: shouldContinue()=false at time 0 fs, iter=1, deltas=1 +[mox-sim] Simulation finished at time 0 fs +[mox-sim] Simulation completed at time 0 fs +[mox-sim] Simulation completed +import_exit=0 run_exit=0 diff --git a/artifacts/tutorial/interface-method-receiver/solution-refdiff.json b/artifacts/tutorial/interface-method-receiver/solution-refdiff.json new file mode 100644 index 0000000..e16f1a3 --- /dev/null +++ b/artifacts/tutorial/interface-method-receiver/solution-refdiff.json @@ -0,0 +1,25 @@ +{ + "source": "/var/tmp/thomas-ahle/sv-tutorial/src/lessons/sv/interface-method-receiver/interface_method_receiver.sol.sv", + "sha256": "3076e990acfe783c81a1cfb45f2ff6ec0661d28e2171dd4bbc876ff6771e13ae", + "reference_cached": false, + "reference": { + "verdict": "PASS", + "exit": 0, + "final_status": "completed" + }, + "mox": { + "verdict": "PASS", + "exit": 0, + "phase": "simulate", + "final_status": "completed" + }, + "category": "both_pass", + "output_equal": true, + "equivalent": true, + "metadata": { + "_has_pass": true + }, + "build_dir": "/var/tmp/thomas-ahle/fleet-probes/ed441-tutorial-20261001/build-dev-fast", + "artifacts": "/var/tmp/thomas-ahle/fleet/sv/sv-harness-tlsdermp", + "refdiff_cache_key": "5ed658c8076a705749ff0a00883e741ae1385609ab7c1aa0b46794df29c0d373" +} diff --git a/artifacts/tutorial/interface-method-receiver/solution-refdiff.log b/artifacts/tutorial/interface-method-receiver/solution-refdiff.log new file mode 100644 index 0000000..e69de29 diff --git a/artifacts/tutorial/interface-method-receiver/solution-source.sha256 b/artifacts/tutorial/interface-method-receiver/solution-source.sha256 new file mode 100644 index 0000000..ed6b76e --- /dev/null +++ b/artifacts/tutorial/interface-method-receiver/solution-source.sha256 @@ -0,0 +1 @@ +3076e990acfe783c81a1cfb45f2ff6ec0661d28e2171dd4bbc876ff6771e13ae diff --git a/artifacts/tutorial/interface-method-receiver/starter-compile.log b/artifacts/tutorial/interface-method-receiver/starter-compile.log new file mode 100644 index 0000000..0873135 --- /dev/null +++ b/artifacts/tutorial/interface-method-receiver/starter-compile.log @@ -0,0 +1,42 @@ + +=== starter compile === +[mox-sim] Auto-enabling --skip-passes for module marked mox.sim.preprocessed +[mox-sim] Stage: passes (prev: 0ms, total: 0ms) +[mox-sim] aot-publication/v2 domain=module-loader-functions expected=3 accounted=3 positive=3 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:42403e255eb93ebfd84bd1b4f678cfd9b4ecf9dbedd8a2cc455eab79f8d8db5d +[mox-sim] aot-publication/v2 domain=module-loader-processes expected=5 accounted=5 positive=5 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:4f6af561e3453305089281dccbf5af4eb3179386260a94c249572b79469558e3 +[mox-sim] aot-publication/v2 domain=module-loader-address-bound-globals expected=173 accounted=173 positive=173 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:329abfbd0388ee100456c8d635a0b09f9603db498312a70276ab41839b7ef8e0 +[mox-sim] aot-publication/v2 domain=module-loader-entry-table expected=3 accounted=3 positive=3 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:3d8a7d8d0991adcee0bdb14b8f5137b5e86a46768fe22c68fb4ee866536761c0 +[mox-sim] Loaded RTTI parent table: 2 entries +[mox-sim] Loaded compiled module '/tmp/mox-scratch/768049c71d419e041f39edd530f4670752ae26167b2ac730406bc5d55491bf5e/session-be88f33f9c8393eb407ae6028c4d1eef2ee17f416350ca866fe0570ce7cae8e4/mox-sim-autocompile-d5ce78.so': 3 functions, 5 processes, 173 address-bound globals, 3 entry table entries (build: mox-sim-abi-v19-x86_64-unknown-linux-gnu-f429dfbbd8fcfc98268ece2eb983063e) +[mox-sim] Address-bound global ownership: role=main, module='/tmp/mox-scratch/768049c71d419e041f39edd530f4670752ae26167b2ac730406bc5d55491bf5e/session-be88f33f9c8393eb407ae6028c4d1eef2ee17f416350ca866fe0570ce7cae8e4/mox-sim-autocompile-d5ce78.so', descriptor-declared=173, retained=173 +[mox-sim] M3 loaded callable union: artifacts=1 raw-rows=6 demand-rows=3 distinct-demand-keys=3 slot-rows=0 provider-rows=3 checked-keys=3 missing=0 duplicate=0 malformed=0 unresolved=0 dropped=0 digest=sha256:5dd3eb169bdedecfa9998b64f09dba4bc2d0543e417d03e4a9320a3c32ed92e9 status=ok +[mox-sim] Stage: init (prev: 376ms, total: 376ms) +[mox-sim] Pre-aliased 173 address-bound globals to .so storage +[mox-sim] Pre-aliased 1 globals to .so storage +[mox-sim] Unmapped native func.call policy: default deny runtime bridges and pointer-typed get_/set_/create_/m_initialize* (allow others) +[mox-sim] Loaded 3 compiled functions: 3 native-dispatched, 0 not-native-dispatched, 0 intercepted +[mox-sim] aot-publication/v2 domain=compiled-function-dispatch expected=3 accounted=3 positive=3 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:89a20dbec599cdbb92beaae3c359c879c17d3c5997c579a344460c58123922de +[mox-sim] Entry table: 3 entries for tagged-FuncId dispatch (3 native, 0 non-native) +[mox-sim] Address-bound final-LLVM-global probes: 173/173 rows, 1015/1015 bytes bidirectional, owner-generation=1 +[mox-sim] Aliased 0 globals to .so storage (1 already pre-aliased, unified) +[mox-sim] Compiled process dispatch: 5/5 processes wired +[mox-sim] aot-publication/v2 domain=process-dispatch expected=5 accounted=5 positive=5 negative=0 missing=0 duplicate=0 unexpected=0 malformed=0 status=ok digest=sha256:bce0429c6f2cc9ab2eb2c0515f3d79ff95c9e77e5a2eea3ff489f0c47d2784b3 +[mox-sim] aot-publication/v2 domain=process-dispatch identity='tb.process_0' outcome=wired polarity=positive reason='' +[mox-sim] aot-publication/v2 domain=process-dispatch identity='tb.process_1' outcome=wired polarity=positive reason='' +[mox-sim] aot-publication/v2 domain=process-dispatch identity='tb.process_2' outcome=wired polarity=positive reason='' +[mox-sim] aot-publication/v2 domain=process-dispatch identity='tb.process_3' outcome=wired polarity=positive reason='' +[mox-sim] aot-publication/v2 domain=process-dispatch identity='tb.process_4' outcome=wired polarity=positive reason='' +[mox-sim] Stage: load-compiled (prev: 9ms, total: 386ms) +[mox-sim] Found 5 LLHD processes, 0 LLHD finals, 0 seq.initial blocks, and 0 hw.instance ops (out of 603 total ops) in module +[mox-sim] Registered 3 LLHD signals and 5 LLHD processes/initial blocks +[mox-sim] Receipt: INIT_COMPLETE_OK execution_failure=0 process_dispatches=0 +[mox-sim] Stage: run (prev: 0ms, total: 386ms) +[mox-sim] Starting simulation +FAIL: path=tb.u_a cast=tb.u_a paren=tb.u_a answers=1/1 +[mox-sim] Simulation terminated at time 0 fs (success=true, verbose=true) +[mox-sim] Main loop exit: shouldContinue()=false at time 0 fs, iter=1, deltas=1 +[mox-sim] Simulation finished at time 0 fs +[mox-sim] Simulation completed at time 0 fs +[mox-sim] whole-design AOT zero-interpreter gate satisfied: counted process=0 combinational=0 initializer-operation=0 direct-call=0 ABI-demotion=0 deferred-initial-prewait-operation=0 deferred-initial-prewait-binding=PROVEN dpi-export-function-binding=NOT-REQUIRED; residual-compiled-process=false interpreted-continuous-assignment=0 initializer-operation-filtered=0; instrumented-classes=interpreted-process,interpreted-callable,interpreted-continuous-assignment,module-initializer-operation,deferred-initial-prewait-operation measured-classes=interpreted-process,interpreted-callable,interpreted-continuous-assignment,module-initializer-operation,deferred-initial-prewait-operation unavailable-classes=NONE operation-level-other=UNMEASURED +[mox-sim] Simulation completed +import_exit=0 run_exit=0 diff --git a/artifacts/tutorial/interface-method-receiver/starter-interpret.log b/artifacts/tutorial/interface-method-receiver/starter-interpret.log new file mode 100644 index 0000000..b7d2b2e --- /dev/null +++ b/artifacts/tutorial/interface-method-receiver/starter-interpret.log @@ -0,0 +1,18 @@ + +=== starter interpret === +[mox-sim] Auto-enabling --skip-passes for module marked mox.sim.preprocessed +[mox-sim] Stage: passes (prev: 0ms, total: 0ms) +[mox-sim] Stage: init (prev: 0ms, total: 0ms) +[mox-sim] Found 5 LLHD processes, 0 LLHD finals, 0 seq.initial blocks, and 0 hw.instance ops (out of 603 total ops) in module +[mox-sim] Registered 3 LLHD signals and 5 LLHD processes/initial blocks +[mox-sim] Receipt: INIT_COMPLETE_OK execution_failure=0 process_dispatches=0 +[mox-sim] Stage: run (prev: 3ms, total: 3ms) +[mox-sim] Starting simulation +FAIL: path=tb.u_a cast=tb.u_a paren=tb.u_a answers=1/1 +[mox-sim] sim.terminate triggered in process ID 3 at loc("/tmp/interface-method-receiver.XjdpGp/design.mlir":749:7) +[mox-sim] Simulation terminated at time 0 fs (success=true, verbose=true) +[mox-sim] Main loop exit: shouldContinue()=false at time 0 fs, iter=1, deltas=1 +[mox-sim] Simulation finished at time 0 fs +[mox-sim] Simulation completed at time 0 fs +[mox-sim] Simulation completed +import_exit=0 run_exit=0 diff --git a/artifacts/tutorial/interface-method-receiver/starter-refdiff.json b/artifacts/tutorial/interface-method-receiver/starter-refdiff.json new file mode 100644 index 0000000..59e2c9d --- /dev/null +++ b/artifacts/tutorial/interface-method-receiver/starter-refdiff.json @@ -0,0 +1,25 @@ +{ + "source": "/var/tmp/thomas-ahle/sv-tutorial/src/lessons/sv/interface-method-receiver/interface_method_receiver.sv", + "sha256": "49c083aa8714757d81ac040cccc3e67b179de1cd1f5f562b4e4f8cc0c765d84b", + "reference_cached": false, + "reference": { + "verdict": "FAIL", + "exit": 0, + "final_status": "fail" + }, + "mox": { + "verdict": "FAIL", + "exit": 0, + "phase": "simulate", + "final_status": "fail" + }, + "category": "both_fail", + "output_equal": true, + "equivalent": false, + "metadata": { + "_has_pass": true + }, + "build_dir": "/var/tmp/thomas-ahle/fleet-probes/ed441-tutorial-20261001/build-dev-fast", + "artifacts": "/var/tmp/thomas-ahle/fleet/sv/sv-harness-5a6kv03a", + "refdiff_cache_key": "871b74b8defde2e23f1d2cff70d0260078ebafe3e83e3dec22104f6e2570580f" +} diff --git a/artifacts/tutorial/interface-method-receiver/starter-refdiff.log b/artifacts/tutorial/interface-method-receiver/starter-refdiff.log new file mode 100644 index 0000000..e69de29 diff --git a/artifacts/tutorial/interface-method-receiver/starter-source.sha256 b/artifacts/tutorial/interface-method-receiver/starter-source.sha256 new file mode 100644 index 0000000..d54f2a4 --- /dev/null +++ b/artifacts/tutorial/interface-method-receiver/starter-source.sha256 @@ -0,0 +1 @@ +49c083aa8714757d81ac040cccc3e67b179de1cd1f5f562b4e4f8cc0c765d84b diff --git a/e2e/qa-all-lessons.spec.js b/e2e/qa-all-lessons.spec.js index ca39d8b..13981c0 100644 --- a/e2e/qa-all-lessons.spec.js +++ b/e2e/qa-all-lessons.spec.js @@ -20,6 +20,7 @@ const KNOWN_FAILURES = { 'sv/fsm run': `false "mem driven by always_ff" error on sram.sv: ${WASM_REBUILD}`, 'sv/protected-envelope-boundary run': `comment-form protected envelope support is not in the pinned WASM; native Mox passes: ${WASM_REBUILD}`, 'sv/coverage-option-text run': 'pinned browser WASM lacks the coverage runtime host-allocation linkage; native Mox passes — needs a WASM rebuild', + 'sv/interface-method-receiver run': `interface-method receiver support is newer than the pinned WASM; native Mox passes: ${WASM_REBUILD}`, 'sva/sequence-basics verify': 'Mox BMC crashes on an assert with a pass action (llhd.process handoff)', 'sva/formal-assume run': 'Mox evaluates an initial assume property at every clock edge, not once (§16.14.6)', 'cocotb/first-test run': `mox-sim-vpi aborts when the simulation starts: ${WASM_REBUILD}`, diff --git a/src/lessons/capability-census.test.js b/src/lessons/capability-census.test.js index 18a5815..2631356 100644 --- a/src/lessons/capability-census.test.js +++ b/src/lessons/capability-census.test.js @@ -68,7 +68,7 @@ describe('landed capability census', () => { expect(census).toContain('| `sv/clocking-sampler-retention` | `3b1760ff2030378cfde16ca319e2c1b806ab9d31`,'); expect(census).toContain('| `sv/protected-envelope-boundary` | `c3799f427f1e51abcd389dcf15771150223cae75`,'); expect(census).toContain('same-buffer opaque callback-boundary exercise'); - expect(census).toContain('interface-method `%m` receiver scope'); + expect(census).toContain('| `sv/interface-method-receiver` | `ed441eb5b58`,'); }); it('labels the native receipt binary as an intermediate landing build', () => { diff --git a/src/lessons/index.js b/src/lessons/index.js index fe6af29..5389120 100644 --- a/src/lessons/index.js +++ b/src/lessons/index.js @@ -94,6 +94,7 @@ export const parts = [ { title: 'Virtual Method Provider Closure', lessons: [L('sv/virtual-provider-closure')] }, { title: 'Wide Four-State Memory Loading', lessons: [L('sv/wide-readmem')] }, { title: 'Coverage Option Text', lessons: [L('sv/coverage-option-text')] }, + { title: 'Interface Method Receivers', lessons: [L('sv/interface-method-receiver')] }, ], }, { diff --git a/src/lessons/landed-capabilities.test.js b/src/lessons/landed-capabilities.test.js index 2ca92a0..cf403f1 100644 --- a/src/lessons/landed-capabilities.test.js +++ b/src/lessons/landed-capabilities.test.js @@ -12,7 +12,8 @@ const capabilities = [ ['sv/nested-child-input', 'nested_child_input'], ['sv/sequential-udp-init', 'sequential_udp'], ['sv/wide-readmem', 'wide_readmem'], - ['sv/coverage-option-text', 'coverage_option_text'] + ['sv/coverage-option-text', 'coverage_option_text'], + ['sv/interface-method-receiver', 'interface_method_receiver'] ]; function receiptSourceMatches(receiptSource, sourcePath) { @@ -315,4 +316,37 @@ describe('landed Mox capability lessons and status pages', () => { ).trim()).toBe(sourceHash); } }); + + it('registers the interface-method receiver chapter and its landed behavior', () => { + const slug = 'sv/interface-method-receiver'; + const dir = path.join(root, slug); + const starter = readFileSync(path.join(dir, 'interface_method_receiver.sv'), 'utf8'); + const solution = readFileSync(path.join(dir, 'interface_method_receiver.sol.sv'), 'utf8'); + const description = readFileSync(path.join(dir, 'description.html'), 'utf8'); + expect(meta[slug]?.runner ?? 'sim').toBe('sim'); + expect(meta[slug]?.focus).toBe('/src/interface_method_receiver.sv'); + expect(starter).toContain('h.vif = u_a;'); + expect(solution).toContain('h.vif = u_b;'); + expect(description).toContain('§21.2.1.5'); + expect(description).toContain('§25.9'); + expect(description).toContain('ed441eb5b58'); + expect(solution).toContain('$display("PASS")'); + + for (const [variant, filename] of [ + ['starter', 'interface_method_receiver.sv'], + ['solution', 'interface_method_receiver.sol.sv'] + ]) { + const sourcePath = path.join(dir, filename); + const sourceHash = createHash('sha256') + .update(readFileSync(sourcePath)) + .digest('hex'); + const receipt = JSON.parse(readFileSync( + path.resolve(process.cwd(), `artifacts/tutorial/interface-method-receiver/${variant}-refdiff.json`), + 'utf8' + )); + expect(receiptSourceMatches(receipt.source, sourcePath)).toBe(true); + expect(receipt.sha256).toBe(sourceHash); + expect(receipt.refdiff_cache_key).toMatch(/^[0-9a-f]{64}$/); + } + }); }); diff --git a/src/lessons/meta.js b/src/lessons/meta.js index ab67868..02eca92 100644 --- a/src/lessons/meta.js +++ b/src/lessons/meta.js @@ -35,6 +35,7 @@ export default { 'sv/virtual-provider-closure': { title: 'Virtual Method Provider Closure', focus: '/src/virtual_provider.sv', top: 'tb' }, 'sv/wide-readmem': { title: 'Wide Four-State Memory Loading', focus: '/src/wide_readmem.sv', top: 'tb' }, 'sv/coverage-option-text': { title: 'Coverage Option Text', focus: '/src/coverage_option_text.sv', top: 'tb' }, + 'sv/interface-method-receiver': { title: 'Interface Method Receivers', focus: '/src/interface_method_receiver.sv', top: 'tb' }, // ── SystemVerilog Assertions ─────────────────────────────────────────────── 'sva/concurrent-sim': { title: 'Concurrent Assertions in Simulation', focus: '/src/monitor.sv', runner: null }, diff --git a/src/lessons/receipt-matrix.test.js b/src/lessons/receipt-matrix.test.js index 4f96b75..868f4af 100644 --- a/src/lessons/receipt-matrix.test.js +++ b/src/lessons/receipt-matrix.test.js @@ -27,7 +27,8 @@ describe('tutorial receipt coverage', () => { 'sv/struct-field-refs', 'sv/virtual-provider-closure', 'sv/wide-readmem', - 'sv/coverage-option-text' + 'sv/coverage-option-text', + 'sv/interface-method-receiver' ]; const covered = new Set([ ...genericReceiptSlugs(), diff --git a/src/lessons/sv/interface-method-receiver/description.html b/src/lessons/sv/interface-method-receiver/description.html new file mode 100644 index 0000000..62414c0 --- /dev/null +++ b/src/lessons/sv/interface-method-receiver/description.html @@ -0,0 +1,20 @@ +

A method declared inside an interface runs in the scope of the interface instance that receives the call. That matters when a class stores a virtual interface: the handle selects an instance, and every method call through it must keep that receiver.

+ +

Exercise

+

The testbench creates two instances of the same interface. Bind the class's virtual-interface handle to u_b, then check the ordinary, cast, and parenthesized calls. The two instances return different answers so a call that silently uses the wrong receiver is visible.

+ +
class holder;
+  virtual probe_if vif;
+endclass
+
+holder h = new;
+h.vif = u_b;
+string path = string'(h.vif.getPath());
+int answer = (h.vif.getAnswer());
+ +

The starter deliberately binds u_a. Change that binding so all three path forms name the u_b instance and both answer forms return 2.

+ +

IEEE 1800-2023 §21.2.1.5 says %m prints the hierarchical name of the design element or subroutine that invokes the system task containing it. Section §25.9 defines a virtual interface as a variable representing an interface instance; after initialization, the underlying instance's components are available through dot notation, and virtual interfaces may be passed to methods.

+ +

What landed in Mox

+

Mox commit ed441eb5b58 preserves the interface receiver while lowering %m inside interface methods and while lowering parenthesized virtual-interface calls. The native receipts run the starter and solution in interpreter and compile modes; the browser still uses the pinned WASM and does not qualify this newer native behavior.

diff --git a/src/lessons/sv/interface-method-receiver/interface_method_receiver.sol.sv b/src/lessons/sv/interface-method-receiver/interface_method_receiver.sol.sv new file mode 100644 index 0000000..f767d9e --- /dev/null +++ b/src/lessons/sv/interface-method-receiver/interface_method_receiver.sol.sv @@ -0,0 +1,59 @@ +interface probe_if (input logic clk); + string instance_path = $sformatf("%m"); + int answer = 0; + + function automatic string getPath(); + return instance_path; + endfunction + + function automatic int getAnswer(); + return answer; + endfunction +endinterface + +class holder; + virtual probe_if vif; + string plain_path; + string cast_path; + string parenthesized_path; + int cast_answer; + int parenthesized_answer; + + function void report(); + plain_path = vif.getPath(); + cast_path = string'(vif.getPath()); + parenthesized_path = (vif.getPath()); + cast_answer = int'(vif.getAnswer()); + parenthesized_answer = (vif.getAnswer()); + endfunction +endclass + +module tb; + logic clk = 0; + probe_if u_a(clk); + probe_if u_b(clk); + + initial begin + holder h; + string expected_path; + h = new; + u_a.answer = 1; + u_b.answer = 2; + h.vif = u_b; + h.report(); + expected_path = u_b.getPath(); + + if (h.plain_path != expected_path || + h.cast_path != expected_path || + h.parenthesized_path != expected_path || + h.cast_answer != 2 || h.parenthesized_answer != 2) begin + $display("FAIL: path=%s cast=%s paren=%s answers=%0d/%0d", + h.plain_path, h.cast_path, h.parenthesized_path, + h.cast_answer, h.parenthesized_answer); + $finish; + end + + $display("PASS"); + $finish; + end +endmodule diff --git a/src/lessons/sv/interface-method-receiver/interface_method_receiver.sv b/src/lessons/sv/interface-method-receiver/interface_method_receiver.sv new file mode 100644 index 0000000..6a06355 --- /dev/null +++ b/src/lessons/sv/interface-method-receiver/interface_method_receiver.sv @@ -0,0 +1,59 @@ +interface probe_if (input logic clk); + string instance_path = $sformatf("%m"); + int answer = 0; + + function automatic string getPath(); + return instance_path; + endfunction + + function automatic int getAnswer(); + return answer; + endfunction +endinterface + +class holder; + virtual probe_if vif; + string plain_path; + string cast_path; + string parenthesized_path; + int cast_answer; + int parenthesized_answer; + + function void report(); + plain_path = vif.getPath(); + cast_path = string'(vif.getPath()); + parenthesized_path = (vif.getPath()); + cast_answer = int'(vif.getAnswer()); + parenthesized_answer = (vif.getAnswer()); + endfunction +endclass + +module tb; + logic clk = 0; + probe_if u_a(clk); + probe_if u_b(clk); + + initial begin + holder h; + string expected_path; + h = new; + u_a.answer = 1; + u_b.answer = 2; + h.vif = u_a; + h.report(); + expected_path = u_b.getPath(); + + if (h.plain_path != expected_path || + h.cast_path != expected_path || + h.parenthesized_path != expected_path || + h.cast_answer != 2 || h.parenthesized_answer != 2) begin + $display("FAIL: path=%s cast=%s paren=%s answers=%0d/%0d", + h.plain_path, h.cast_path, h.parenthesized_path, + h.cast_answer, h.parenthesized_answer); + $finish; + end + + $display("PASS: receiver=%s answer=%0d", expected_path, h.cast_answer); + $finish; + end +endmodule