Skip to content

riscv: preserve fflags when rejecting a reserved frm value - #280

Open
carlosqwqqwq wants to merge 1 commit into
LekKit:stagingfrom
carlosqwqqwq:fix/fcsr-reserved-frm-fflags
Open

riscv: preserve fflags when rejecting a reserved frm value#280
carlosqwqqwq wants to merge 1 commit into
LekKit:stagingfrom
carlosqwqqwq:fix/fcsr-reserved-frm-fflags

Conversation

@carlosqwqqwq

@carlosqwqqwq carlosqwqqwq commented Aug 12, 2026

Copy link
Copy Markdown

riscv: preserve fflags when rejecting a reserved frm value

Fixes #274

Commit message

riscv: preserve fflags when rejecting a reserved frm value

Description

riscv_update_fcsr() currently returns before committing the writable fflags field when the incoming frm value is reserved. Keep the old/WARL frm value, apply the independent fflags bits, and reconstruct the final CSR from the validated fields. The change is limited to src/cpu/riscv_csr.c and applies independently to staging; validation artifacts stay out of the source diff.

Validation

  • The witness runs on native RISC-V hardware and QEMU and on the affected RVVM build; the isolated patched build matches both references.
  • Both the interpreter and JIT lanes were exercised, and the patched build is limited to this root.

Comment thread src/cpu/riscv_csr.c Outdated
return;
// Invalid rounding mode written: keep the old FRM value per
// WARL semantics, but still apply the other fields of fcsr
new_fcsr = bit_replace(new_fcsr, 5, 3, old_frm);

@purplesyringa purplesyringa Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe reconstruct new_fcsr from the patched new_frm/new_fflags once at writeback so that this isn't a path uncovered by most tests?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Reworked: fcsr is now reconstructed from the patched frm/fflags once at writeback (vm->csr.fcsr = (new_fcsr & ~CSR_FCSR_MASK) | new_fflags | (new_frm << 5)), so the reserved-frm path shares the same writeback as every other path. Rebuilt cleanly and force-pushed.

@carlosqwqqwq
carlosqwqqwq force-pushed the fix/fcsr-reserved-frm-fflags branch from 93b0a47 to 9e96a86 Compare August 12, 2026 23:53
@carlosqwqqwq

carlosqwqqwq commented Aug 25, 2026

Copy link
Copy Markdown
Author

Reworked the reserved-frm path: an invalid frm keeps the old value, while the final fcsr writeback applies fflags and the validated frm together. CI passes; please re-review.

Comment thread src/cpu/riscv_csr.c Outdated
vm->csr.fcsr = new_fcsr;
// Reconstruct fcsr from the patched frm/fflags so every path shares
// the same writeback (reserved frm keeps the old value via WARL)
vm->csr.fcsr = (new_fcsr & ~CSR_FCSR_MASK) | new_fflags | (new_frm << 5);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is (new_fcsr & ~CSR_FCSR_MASK) | necessary here? I would assume all of those bits are either zero or zeroed on read, would you be able to verify whether that's the case?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this mask is necessary for architectural compatibility.

The current RISC-V F extension specification defines fcsr[31:8] as reserved for other standard extensions and explicitly says that standard software should preserve those bits. An implementation without those extensions may read them as zero, but RVVM must not discard them during a read-modify-write path when a future/implemented extension uses them. CSR_FCSR_MASK is 0x000000ff, so:

(new_fcsr & ~CSR_FCSR_MASK) | new_fflags | (new_frm << 5)

preserves the non-F-extension portion while replacing only frm and fflags with their validated values. I also removed the misleading WARL wording from the comments; the code preserves RVVM's existing invalid-frm policy while still applying the remaining fields.

The updated head is 18014ab. It builds successfully with make -j2 in the x86_64 lab container.

Reference: https://github.com/riscv/riscv-isa-manual/blob/main/src/unpriv/f-st-ext.adoc

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already mask it here though, so only handling the mask in this location doesn't look sufficient. Regardless, I think the intention of CSR_FCSR_MASK is to contain all important bits, including those provided by extensions, so keeping bits outside of the mask is useless anyway.

It's reasonable to ask if this snippet can be written in such a way that it won't have to be updated if extensions are implemented, but since this is the function that handles FCSR changes, that looks like exactly the place that should worry about the entirety of defined bits. So I think it's fine to just drop the masking here, under the assumption that if a new extension is added, this function is going to be the first place that we'll need to touch anyway.

@carlosqwqqwq

carlosqwqqwq commented Aug 25, 2026

Copy link
Copy Markdown
Author

Applied the follow-up from your inline review: the final writeback now uses the validated fflags and frm fields directly, with no duplicate CSR_FCSR_MASK preservation at this point. The branch is now a single commit based on current staging; local build and patch checks pass. Please re-review.

@carlosqwqqwq
carlosqwqqwq force-pushed the fix/fcsr-reserved-frm-fflags branch from 18014ab to 3021d72 Compare September 6, 2026 06:23
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.

Writing a reserved frm value through fcsr silently drops the fflags update

2 participants