Summary
When frm holds a reserved value (5/6/7) and an instruction uses the dynamic rounding mode (rm=111, DYN), NaxRiscv fails to raise illegal-instruction for the exact integer→double conversions fcvt.d.w and fcvt.d.wu — it commits them. Spike (used as the golden reference) raises illegal-instruction. The rounding-dependent operations are handled correctly (see below), so the divergence is limited to these two exact conversions.
Observed behavior
With frm ∈ {5,6,7} and rm=111 (DYN):
| Instruction |
NaxRiscv |
Spike (reference) |
fadd.d, fmul.d, … (rounding-dependent) |
illegal-instruction ✔ |
illegal-instruction |
fcvt.d.w, fcvt.d.wu (exact int→double) |
commits (executed) |
illegal-instruction |
So the reserved-rounding-mode check is present for the rounding path but absent for the exact int→double conversions.
Root cause
FpuFloatExecute.scala:138 and FpuIntegerExecute.scala:82 resolve rm=DYN → frm:
val roundMode = (instrRounding === B"111") ? getService[FpuWriteback].getRoundingMode() | instrRounding
with no validity check at that site. The effective reserved-rounding-mode check for the rounding-dependent path lives downstream in the rounding logic; the always-exact int→double conversions bypass rounding and therefore also bypass the check, so a reserved frm is accepted and the instruction executes.
Reproducer
Minimal sequence (M-mode, mstatus.FS enabled, fcsr=0):
fmv.d.x f0, x0
li t1, 0xff
csrw fcsr, t1 # frm := 7 (reserved)
.4byte 0xd205f0d3 # fcvt.d.w f1,x11,rm=DYN
Result: NaxRiscv commits the fcvt.d.w; Spike raises illegal-instruction with mtval=0xd205f0d3.
Cross-checks:
- Standalone Spike on the same sequence: both
fadd.d …,dyn and fcvt.d.w …,dyn raise illegal-instruction — confirms the reference.
- On NaxRiscv,
fadd.d …,dyn with frm=7 traps (illegal, tval = the fadd), while fcvt.d.w …,dyn with frm=7 commits — this contrast isolates the missing check to the exact conversions.
Spec basis
Per the strict reading of the F/D extension — which Spike and the SAIL model implement — any FP instruction with rm=DYN while frm is reserved raises illegal-instruction, regardless of whether the operation actually rounds; NaxRiscv should therefore trap fcvt.d.w/fcvt.d.wu in this case as well. (There is a lenient reading under which an exact conversion never consults the rounding mode, so if the intended behavior is deliberately lenient here, feel free to close — but the current behavior diverges from Spike.)
Suggested fix
Apply the same reserved-rounding-mode illegal check the rounding path uses to the fcvt.d.w/fcvt.d.wu decode: reject rm=DYN when frm ∈ {5,6,7} (and static rm ∈ {5,6}).
Summary
When
frmholds a reserved value (5/6/7) and an instruction uses the dynamic rounding mode (rm=111, DYN), NaxRiscv fails to raiseillegal-instructionfor the exact integer→double conversionsfcvt.d.wandfcvt.d.wu— it commits them. Spike (used as the golden reference) raisesillegal-instruction. The rounding-dependent operations are handled correctly (see below), so the divergence is limited to these two exact conversions.Observed behavior
With
frm ∈ {5,6,7}andrm=111(DYN):fadd.d,fmul.d, … (rounding-dependent)fcvt.d.w,fcvt.d.wu(exact int→double)So the reserved-rounding-mode check is present for the rounding path but absent for the exact int→double conversions.
Root cause
FpuFloatExecute.scala:138andFpuIntegerExecute.scala:82resolverm=DYN → frm:with no validity check at that site. The effective reserved-rounding-mode check for the rounding-dependent path lives downstream in the rounding logic; the always-exact int→double conversions bypass rounding and therefore also bypass the check, so a reserved
frmis accepted and the instruction executes.Reproducer
Minimal sequence (M-mode,
mstatus.FSenabled,fcsr=0):Result: NaxRiscv commits the
fcvt.d.w; Spike raisesillegal-instructionwithmtval=0xd205f0d3.Cross-checks:
fadd.d …,dynandfcvt.d.w …,dynraise illegal-instruction — confirms the reference.fadd.d …,dynwithfrm=7traps (illegal,tval= thefadd), whilefcvt.d.w …,dynwithfrm=7commits — this contrast isolates the missing check to the exact conversions.Spec basis
Per the strict reading of the F/D extension — which Spike and the SAIL model implement — any FP instruction with
rm=DYNwhilefrmis reserved raises illegal-instruction, regardless of whether the operation actually rounds; NaxRiscv should therefore trapfcvt.d.w/fcvt.d.wuin this case as well. (There is a lenient reading under which an exact conversion never consults the rounding mode, so if the intended behavior is deliberately lenient here, feel free to close — but the current behavior diverges from Spike.)Suggested fix
Apply the same reserved-rounding-mode illegal check the rounding path uses to the
fcvt.d.w/fcvt.d.wudecode: rejectrm=DYNwhenfrm ∈ {5,6,7}(and staticrm ∈ {5,6}).