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
#endif
If 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_Zfinx
saves 1/2 the register file state compared toRV32IF
. -
RV32E_Zfinx
saves 2/3 the register file state compared toRV32EF
.
-
-
Similar context switch time as an integer only core
-
there are no
F
registers 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.
-