Skip to content

fix .vf scalar: NaN-box a narrow scalar FP operand - #88

Merged
jerryz123 merged 1 commit into
ucb-bar:masterfrom
emiliengnr:fix-vf-scalar-nanbox
Jul 14, 2026
Merged

fix .vf scalar: NaN-box a narrow scalar FP operand#88
jerryz123 merged 1 commit into
ucb-bar:masterfrom
emiliengnr:fix-vf-scalar-nanbox

Conversation

@emiliengnr

Copy link
Copy Markdown
Contributor

Hello, here is a pull request for a bug I found.

When a .vf scalar floating-point operand is read narrower than the FP register
(vs1_eew < 64) and its upper bits are not all ones, RISC-V requires it to read as
the canonical NaN of that width. Saturn passed the raw low bits, so a wider value
held in the register but consumed by a narrower .vf op (for example a double used
by a single-precision .vf) is treated as a valid float and produces a wrong
result.

The fix NaN-boxes the scalar at its source in ExecuteSequencer (0x7FC00000 for
e32, 0x7E00 for e16 when the upper bits are not all ones). Backend already splats
io.iss.bits.scalar into the per-lane operand the FP units read, so boxing this one
field covers every consumer. Non-.vf paths are unchanged.

Found by differential testing against Spike; the reduced reproducer
(vfwnmacc.vf with an unboxed scalar, seed 3217) diverges before and matches Spike
after.

Note: the defect was confirmed against Spike with the reproducer on the Saturn
version my fuzzer runs, and this is the same fix adapted to current master, where the
operand is still passed unboxed. I have not run a full Chisel build of the adapted
version (Saturn builds only through Chipyard), so a run through the cosim tests
before merging would be good.

@jerryz123

Copy link
Copy Markdown
Contributor

Thank you!

@emiliengnr

Copy link
Copy Markdown
Contributor Author

Note: this check needs a delivery-side fix in rocket-chip to work. On stock rocket-chip the .vf scalar reaches Saturn with its NaN-box stripped (the upper bits are just a copy of the low 32), so !sscalar(63,32).andR fires on correctly boxed singles and turns them into NaN. chipsalliance/rocket-chip#3820 delivers the full register so the box survives. This check is only correct once Saturn's rocket-chip pin is bumped to include #3820.

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