D depends on F and widens the register file to FLEN = 64. Its
instructions are the F set at fmt = 01, defined “analogously” — so the
substantive new architecture in this chapter is really one idea, and it’s
one your FPU’s every input and output port must implement:
22.2 NaN-boxing
With multiple precisions in one register file, a valid narrower n-bit value is stored in the low n bits with all upper FLEN−n bits set to 1 — NaN-boxing nan-boxing Storing a valid narrower n-bit FP value in the low n bits of an FLEN-bit register with ALL upper bits = 1 (reads as a negative qNaN at wider widths). Transfers box on write and export raw low bits without checking; all other narrower ops check the box and substitute the n-bit canonical NaN when invalid. defined in ch. I·22 — open in glossary . Viewed at any wider width, a boxed value is a negative quiet NaN.
The box check: computational narrower ops verify the upper bits; failures don’t trap — they poison the operand with canonical NaN.
The rules split cleanly by instruction class:
| Writing a narrower value INTO f | Reading a narrower value OUT | |
|---|---|---|
| Transfers: FLn / FSn, FMV.n.X / FMV.X.n | Box it: upper bits ← all 1s | Take low n bits, ignore uppers — NO check |
| Everything else (arithmetic, converts, compares, FCLASS at width n) | Results are boxed like transfers | CHECK the box; invalid → operand = n-bit canonical NaN |
22.3–22.7 The D instruction set: F at fmt=01, plus the deltas
FLD/FSD move 64 bits verbatim (NaN payloads preserved) — atomic
only if naturally aligned and XLEN ≥ 64 (on RV32, an aligned FLD
may legally be two memory operations — recall the RVWMO exception list).
Arithmetic, FMA, sign-injection, compares, and FCLASS.D are exact
doubles of their F counterparts. The items that aren’t pure copies:
| Delta | |
|---|---|
| FCVT.S.D / FCVT.D.S | rs2 field = source type, fmt = destination type; S.D rounds, D.S is always exact |
| FCVT.D.W[U] | Always exact (every 32-bit integer is representable in double) — rm ignored in effect |
| FCVT.int.D edge cases | Identical to Table 27 of ch. I·21 — NaN → max positive, NV set |
| FMV.X.D / FMV.D.X | XLEN ≥ 64 only; bit-preserving |
Hardware Designer Notes
The NaN-box check/substitute/fill logic is THE new hardware in D — a few gates per operand port, but with outsized verification weight: directed tests must cover (bad box → canonical NaN) on every narrower computational op, and (bad box → raw bits) on every transfer. The RV32 FLD-splits-in-two subtlety matters if you ever build RV32+D: torn doubles across harts are architecturally possible there and reference models know it.
Minimal Linux-boot hart MUST
- Box every narrower result (upper bits all 1s) — writeback is always full FLEN width
- Check boxes on computational narrower operands and substitute canonical NaN on failure — silently
- Skip the check on transfers: FSW/FMV.X.W export raw low bits
- Guarantee FLD/FSD atomicity only when aligned and XLEN≥64 — on RV32 they may split
- Keep FCVT.D.S / FCVT.D.W[U] exact — no rounding, no NX
MAY simplify / trap-and-emulate
- Recode internally (tag NaNs via exponent encoding) or run non-recoded with comparator+fill — both anticipated by the spec
- Share the FCVT float-to-float path with the later Zfh/Q widths — the rs2-as-type-tag pattern scales
Check yourself — D & NaN-boxing
1.FADD.S executes on an f-register whose upper 32 bits are NOT all 1s (an invalid box). What does the FPU use as that operand?
2.FSW stores from that same badly-boxed register. What goes to memory?
3.What must FLW write into bits 63:32 of the destination f-register (FLEN=64)?
4.On RV32 with D, how does software move the upper 32 bits of an f-register into integer registers?