21.1-8"F": Single-Precision Floating-Point

Part I Linux boot: required Vol. I (Unprivileged) pp. 112–119 · ~7 min read

  • flen
  • fcsr
  • rounding mode
  • canonical nan
  • tininess after rounding
  • fsgnj family
  • signaling vs quiet comparison

F adds IEEE 754-2008 single precision: thirty-two f-registers ( FLEN = 32), a control/status CSR, and a design philosophy with hardware consequences — no FP traps, hardware-produced default results, canonical NaNs only, and integers never stored in f-registers. It depends on Zicsr.

21.2 fcsr: rounding and flags

fcsr

Reserved318frm75NV4DZ3OF2UF1NX0
WPRI/RO WLRL WARL RW
Click a field for semantics, reset state, and the minimal-implementation note.

frm (bits 7–5) and fflags (bits 4–0) are also standalone CSRs, with pseudo-instructions for each (FRCSR/FSCSR, FRRM/FSRM, FRFLAGS/FSFLAGS). Every rounding instruction carries a 3-bit rm field: a static mode , or 111 (DYN) to use frm.

Rounding modes (Table 24) and flags (Table 25)
rmMeaning
RNE000Round to nearest, ties to even — the default; also what software writes in rm fields that don’t matter
RTZ001Toward zero
RDN010Down (−∞)
RUP011Up (+∞)
RMM100Nearest, ties to max magnitude
(reserved)101 / 110Reserved — behavior reserved
DYN111In rm: use frm. Inside frm itself: reserved
Dotted-underlined cells have explanations — click one.

There are no FP traps. Flags (NV, DZ, OF, UF, NX) accrue stickily and software checks them explicitly; hardware must deliver IEEE default results (quiet NaN, ±∞, clipped integers…) with no user-level fixup — though an implementation may invisibly trap to M-mode firmware to produce them.

21.3–21.5 NaNs, subnormals, loads/stores

An arithmetic result that is NaN is the canonical NaN : 0x7fc00000 — positive sign, quiet bit, empty payload. No payload propagation (allowed only as a nonstandard mode). Subnormals are fully supported per IEEE, with tininess detected after rounding . FLW/FSW (LOAD-FP/STORE-FP opcodes, base+imm12) transfer bits verbatim — non-canonical NaN payloads survive loads and stores — and are atomic only when naturally aligned; misaligned behavior follows the u02 EEI rules.

21.6 Computation

Two-operand arithmetic is R-type under OP-FP: funct5 selects the operation, the 2-bit fmt field is 00 (S) throughout F:

funct53127fmt=002625rs22420rs11915rm1412rd117OP-FP60OP-FP
Click a field for its role.

FMIN.S/FMAX.S implement the 754-201x minimumNumber/maximumNumber semantics (amended in F v2.2): −0.0 < +0.0; both NaN → canonical NaN; one NaN → the other operand — but a signaling NaN input sets NV even when the result is a number.

The fused multiply-adds get RISC-V’s only four-source-field format, R4-type (rs3 replaces funct5’s slot at [31:27]):

The FMA family (R4-type; one rounding of rs1×rs2 ± rs3)
ComputesNote
FMADD.S(rs1 × rs2) + rs3One rounding — the point of fusion
FMSUB.S(rs1 × rs2) − rs3
FNMSUB.S−(rs1 × rs2) + rs3Negates the PRODUCT
FNMADD.S−(rs1 × rs2) − rs3See FNMSUB naming note
Dotted-underlined cells have explanations — click one.

One mandated flag subtlety: ∞ × 0 sets NV even when rs3 is a quiet NaN (IEEE merely permits this; RISC-V requires it).

21.7 Conversions and moves

FCVT.{W,WU,L,LU}.S / FCVT.S.{W,WU,L,LU} convert with rounding per rm (L forms RV64-only; W results sign-extend on RV64). Out-of-range inputs clip and set NV — memorize Table 27’s corners:

Float→integer conversion edge outputs (Table 27)
FCVT.W.SFCVT.WU.SFCVT.L.SFCVT.LU.S
Out-of-range negative / −∞−2³¹0−2⁶³0
Out-of-range positive / +∞2³¹−12³²−12⁶³−12⁶⁴−1
NaN2³¹−12³²−12⁶³−12⁶⁴−1
Dotted-underlined cells have explanations — click one.

Conversions set NX when the rounded result differs from the input (and NV isn’t set). FCVT.S.W rd, x0 materializes a clean +0.0.

The sign-injection trio FSGNJ/FSGNJN/FSGNJX builds FMV.S, FNEG.S, FABS.S (rs1 = rs2 forms) plus IEEE copySign — no flags, no NaN canonicalization. Raw-bit moves between files: FMV.X.W (RV64: upper 32 bits = copies of the sign bit) and FMV.W.X, both payload-preserving.

21.8 Compares

FEQ.S/FLT.S/FLE.S write 0/1 to an integer register; any NaN operand makes the result 0. FLT/FLE are signaling (NV on any NaN); FEQ is quiet (NV only on signaling NaN).

Hardware Designer Notes

An FPU for Linux boot is mostly about the edges, not the datapath: the canonical-NaN rule, Table 27’s corners, the v2.2 min/max semantics, and after-rounding tininess are where RTL diverges from softfloat references. Wire fflags as sticky ORs accumulated at retirement (they’re accumulating CSRs — no serialization), and note frm becomes a real pipeline input only for rm=DYN instructions; a write to frm then behaves like a serializing CSR write in simple cores. mstatus.FS dirty-tracking (Vol II ch. 3) is the other half of the context-switch story.

Minimal Linux-boot hart MUST

  • Produce IEEE default results in hardware (or via invisible M-mode traps) — user software never fixes up
  • Emit exactly 0x7fc00000 for arithmetic NaN results; preserve payloads only through FLW/FSW/FMV/FSGNJ
  • Implement v2.2 FMIN/FMAX (minimumNumber): sNaN → NV with non-NaN result
  • Clip FCVT per Table 27 — NaN to MAX positive; set NV/NX correctly
  • Set NV on FMA ∞×0 regardless of addend
  • Detect tininess after rounding

MAY simplify / trap-and-emulate

  • Recode FP values internally (subnormal handling) — FMV/loads/stores must un-recode bit-exactly
  • Trap on reserved rm encodings (101/110, DYN-in-frm) or treat as reserved — document it
  • Iterate FDIV/FSQRT over many cycles — nothing in Linux boot times them
  • Read one register when FSGNJ has rs1=rs2 — or not; it is a micro-optimization

Check yourself — F extension

1.FADD.S produces a NaN result. What bit pattern lands in rd?

2.FCVT.W.S of NaN. What integer results, and what flag?

3.FMIN.S with one signaling NaN input and one normal number. Result and flags?

4.Why must FMADD.S set NV for ∞×0 even when rs3 is a quiet NaN?

5.On RV64, FMV.X.W moves an f-register to an x-register. What fills bits 63:32?

5 questions