Skip to content

fix(csr): allow non-virtual user access and enforce counter enables - #6

Merged
RossComputerGuy merged 3 commits into
LilithSemi:masterfrom
murdoa:fix/user-mode-csr-access
Oct 6, 2026
Merged

RossComputerGuy merged 3 commits into
LilithSemi:masterfrom
murdoa:fix/user-mode-csr-access

Conversation

@murdoa

@murdoa murdoa commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

This follows up on the user-mode CSR problems encountered during River/ZedBoard bring-up. Both the static and microcoded executors rejected every U-mode CSR instruction before the CSR file could check whether the access was legal.

That prevented ordinary user code from reading an enabled time counter or accessing an implemented user-level CSR. Removing the blanket rejection alone wasn't enough: the CSR file also needed to enforce the counter-enable bits.

This permits implemented CSR accesses from non-virtual U-mode, leaving address privilege, existence and read-only checks in the CSR file. For non-virtual execution, it also:

  • Enforces mcounteren below M-mode.
  • Further restricts U-mode with scounteren when S-mode exists.
  • Makes TM writable in those enable registers only when a live time source is connected. Without one, rdtime continues to trap for firmware emulation.

Scope

This deliberately does not enable VU CSR access. The previous VU rejection and virtual-mode counter behavior are preserved until hcounteren, virtual-instruction exception selection, shared supervisor CSRs and virtual time can be handled together. The VU tests here check that compatibility boundary, not H-extension conformance.

It also doesn't implement fflags, frm or fcsr, which are absent from the current CSR file. This is a prerequisite for the local user FCSR fix, not the complete FP architectural port. Existing static virtual-instruction checks and SATP fence wiring are retained.

Testing

Added 40 cases across RV32/RV64 and static/microcoded execution. These cover enabled user counter reads, implemented user CSR read/write forms, M/S/U counter-enable combinations, and rejection of privileged, absent and read-only CSR accesses. Denied accesses also check that the destination register is preserved.

Another eight RV64 H-enabled cases check that ordinary U-mode works with hcounteren clear while VU read/write access remains rejected.

I compared the exact upstream parent (61acd21) and this branch with identical locked dependencies, Dart 3.13.0, and the same new tests/harness support:

Test set Baseline passed / failed Patched passed / failed
Complete CSR test set 71 / 10 81 / 0
Existing hypervisor tests 11 / 0 11 / 0
Total 82 / 10 92 / 0

All 44 pre-existing cases remain passing. Ten of the new cases fail on baseline and pass with the fix; the other 38 check protection and compatibility. No tests were removed.

For the final comparison, each of the 81 CSR cases ran in a fresh process to avoid accumulating simulator overhead from repeated full-core builds:

dart test "$file" --plain-name "$name" --timeout=60s --reporter=json

The hypervisor directory ran on both versions with:

dart test packages/river_hdl/test/hypervisor \
  --concurrency=4 --timeout=60s --reporter=json

Changed-file analysis reports the same two warnings and one info as baseline, with no new diagnostics. git diff --check passes.

I haven't run the full River suite, external RTL simulation, synthesis or hardware validation for this upstream port.

murdoa added 2 commits October 6, 2026 13:57
Delegate implemented-address, privilege and read-only checks to the CSR file in static and microcoded execution. Enforce mcounteren/scounteren and expose TM only with a live time source.

Add 40 RV32/RV64 regressions. The complete CSR directory passes 73 tests versus 65 passes and eight failures on the baseline, preserving all existing passes.

Checkpoint before upstream submission: hcounteren and VS/VU trap semantics still require review. Architectural FCSR support is separate and is not implemented by this change.
Limit new user CSR access and counter-enable checks to non-virtual execution. Keep the prior VU rejection until hcounteren, shared supervisor CSR handling, virtual time and cause-22 selection can be implemented together.

Add eight H-enabled boundary cases, including ordinary U-mode with hcounteren clear and retained VU read/write rejection. All 81 CSR cases and 11 existing hypervisor tests pass; the same baseline has ten expected CSR failures and no hypervisor failures.
Comment thread packages/river_hdl/test/csr/user_access_virtual_static_test.dart Outdated
Replace helper and entrypoint wrappers with one test file and a shared teardown. Preserve all 48 cases and assertions; all cases pass after consolidation. No production-code changes.
@murdoa

murdoa commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

Consolidated into packages/river_hdl/test/csr/user_access_test.dart in aaf45f8 and removed the helper/entrypoint wrappers. All 48 cases and assertions are retained, with one shared teardown.

Re-ran all 48 cases from the consolidated file; all pass, and analysis of the test file is clean. Process isolation for validation stays outside the PR. No production-code changes in this update.

@RossComputerGuy
RossComputerGuy merged commit 03df7bb into LilithSemi:master Oct 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants