This document gives additional information about Zfinx which is not included in the ISA specification.
Each Z*inx extension is distinct and maps directly to an existing floating point extension. Once one floating point extension has been mapped to a Zfinx version then the F registers are not implemented so all must be mapped to a Zfinx version.
For example the Zfinx version of RV32IMCD_Zfh would be RV32IMC_Zdinx_Zhinx as D→Zdinx and Zfh→Zhinx.
RV32IMCD_Zhinx would not be legal.
If any Zfinx extension is specified then the compiler will have the following #define set:
__riscv_zfinx
So software can use this to choose between Zfinx or normal versions of floating point code.
Non-privileged code can detect whether Zfinx is implemented as follows:
li a0, 0 # set a0 to zero
#ifdef __riscv_zfinx
fneg.s a0, a0 # this will invert a0
#else
fneg.s fa0, fa0 # this will invert fa0
#endifIf a0 is non-zero then it’s a Zfinx core, otherwise it’s a non-Zfinx core. Both branches result in the same encoding, but the assembly syntax is different for each variant.
Any references to F registers, or removed instructions will cause assembler errors.
For example, the encoding for:
FMADD.S <1>, <2>, <3>, <4>
will disassemble and execute as:
FMADD.S f1, f2, f3, f4
on a non-Zfinx core, or:
FMADD.S x1, x2, x3, x4
on a Zfinx core.
We considered allowing pseudo-instructions for the deleted instructions for easier code porting. For example allowing FLW to be a pseudo-instruction for LW, but decided not to. Because the register specifiers must change to integer registers, it makes sense to also remove the use of FLW etc. In this way the user is forced to rewrite their code for a Zfinx core, reducing the chance of undiscovered porting bugs. This only affects assembly code, high level language code is unaffected as the compiler will target the correct architecture.
Because all floating point loads, stores and floating point to/from integer moves are removed on Zfinx cores, the following sections show the deleted instructions and give suggested replacements to get the same semantics.
|
Note
|
Where a floating point load loads fewer than XLEN bits software NaN-boxing in software is required to get the same semantics as a non-Zfinx core. This is specified for consistency but is unlikely to be necessary. The compiler should not NaN-box in software as there is no reason to do so. Assembly writers can choose whether to NaN-box in software to give better error detection.
|
|
Note
|
Where a floating point move moves fewer than XLEN bits then either sign extension (if the target is an X register) or NaN-boxing (if the target is an F register) is required in software to get the same semantics.
|
The modifications to the ISA of the F extension are shown in Table 1.
F extension floating point load/store/move instructions
| Instruction | RV32_Zfinx | RV64_Zfinx |
|---|---|---|
replacement to get the same semantics |
||
FLW frd, offset(xrs1) |
LW |
LW[U] and NaN-box in software |
C.FLW[SP] frd, uimm(x2) |
C.LW[SP] |
C.LW[SP] and NaN-box in software |
FSW frd, offset(xrs1) |
SW |
SW |
C.FSW[SP] frd, uimm(x2) |
C.SW[SP] |
C.SW[SP] |
FMV.X.W xrd, frs1 |
MV |
MV and sign extend in software |
FMV.W.X frd, xrs1 |
MV |
MV and NaN-box in software |
The modifications to the ISA of the D extension are shown in Table 2.
D extension floating point load/store/move instructions
| Instruction | RV32_Zdinx | RV64_Zdinx |
|---|---|---|
replacement to get the same semantics |
||
FLD frd, offset(xrs1) |
LW,LW |
LD |
C.FLD[SP] frd, uimm(x2) |
C.LW[SP], C.LW[SP] |
C.LD[SP] |
FSD frd, offset(xrs1) |
SW,SW |
SD |
C.FSD frd, offset(xrs1) |
C.SW,C.SW |
C.SD |
C.FSD[SP] frd, uimm(x2) |
C.SW[SP],C.SW[SP] |
C.SD[SP] |
FMV.X.D xrd, frs1 |
FSGNJ.D xrd, xrs1, xrs1 |
MV |
FMV.D.X frd, xrs1 |
FSGNJ.D xrd, xrs1, xrs1 |
MV |
D floating point load/store/move instructions
| Instruction | RV32_Zhinx | RV64_Zhinx |
|---|---|---|
replacement to get the same semantics |
||
FLH frd, offset(xrs1) |
LH[U] and NaN-box in software |
|
FSH frd, offset(xrs1) |
SH |
|
FMV.X.H xrd, frs1 |
MV and sign extend in software |
|
FMV.H.X frd, xrs1 |
MV and NaN-box in software |
|
The B-extension is useful for sign extending and NaN-boxing.
To sign-extend using the B-extension:
FMV.X.H rd, rs1
is replaced by:
SEXT.H rd, rs1
Without the B-extension two instructions are required: shift left 16 places, then arithmetic shift right 16 places.
NaN boxing in software is more involved, as the upper part of the register must be set to 1. The B-extension is also helpful in this case.
FMV.H.X a0, a1
is replaced by:
C.ADDI a2, zero, -1
PACK a0, a1, a2
If the vector TG decide to specify a Zfinx version of the vector extension, the following instructions would be deleted, and the integer versions would be used instead:
| Instruction | Integer version |
|---|---|
vfmv.v.f |
vmv.v.x |
vfmv.f.s |
vmv.x.s |
vfmv.s.f |
vmv.s.x |
vfmerge.vfm |
vmerge.vxm |
Additionally, all instructions with funct3=OPFVF take the scalar floating point source from either a single or pair of X registers instead of a single F register.
When using GDB on a Zfinx core, GDB must report X registers instead of F registers when disassembling floating point opcodes. No other changes are required.
Zfinx allows small embedded cores to support floating point with:
-
Minimal area increase
-
RV32I_Zfinxsaves 1/2 the register file state compared toRV32IF. -
RV32E_Zfinxsaves 2/3 the register file state compared toRV32EF.
-
-
Similar context switch time as an integer only core
-
there are no
Fregisters to save/restore
-
-
Reduced code size by removing the floating point library
-
Implementing floating point purely in software can be an expensive choice as the floating point library can be large, and expensive in terms of ROM or flash storage.
-