Risc-V架构定义了可选的单精度浮点指令(F扩展指令集)和双精度浮点指令(D扩展指令集)。
Risc-V架构规定:处理器可以选择只实现F扩展指令子集而不支持D扩展指令子集;但是如果支持了D扩展指令子集,则必须支持F扩展指令子集。
Risc-V架构规定的浮点数符合IEEE754 2008规则,可以从下面的链接了解浮点数格式的详细信息:
https://www.cnblogs.com/german-iris/p/5759557.html
Risc-V规定,如果支持单精度浮点指令或者双精度浮点指令,则需要增加一组独立的通用浮点寄存器组,包括32个通用浮点寄存器,标号位f0到f31。如果仅支持F扩展指令子集,则每个通用寄存器是32位的,如果支持D扩展那指令子集,则每个通用寄存器是64位的。
Risc-V架构规定,如果支持单精度浮点指令或者双精度浮点指令,需要增加一个浮点控制状态寄存器fcsr,该寄存器是一个可读可写的csr寄存器。
fcsr寄存器包含浮点异常标志域(fflags),不同的标志位表示不同的异常类型。如果浮点运算单元在运算中出现了相应的异常,则会将fcsr寄存器中对应的标志位设置为1,且会一直保持累积。软件可以通过写0的方式单独清除某个异常标志位。
根据IEEE-754标准,浮点运算需要指定舍入模式(rounding mode),Risc-V架构浮点运算的舍入模式可以通过两种方式指定。
使用静态舍入模式,浮点指令编码中有3位作为舍入模式域,不同的舍入模式编码如下图,Risc-V支持5种合法的舍入模式。如果舍入模式编码为101或110,则为非法模式;如果舍入模式编码为111,则意味着使用动态舍入模式。如果使用动态舍入模式,则使用fcsr寄存器中的舍入模式域,舍入模式域定义如上图,如果fcsr寄存器中的舍入模式域指定为非法的舍入模式,则后续浮点指令会产生非法指令异常。
如果处理器不想使用浮点单元,比如把浮点单元关电以节省功耗,可以使用csr写指令将mstatus寄存器的FS域设置成0,将浮点单元的功能予以关闭。当浮点单元功能关闭后,任何访问浮点csr寄存器的操作或者执行浮点指令的行为将会产生非法指令异常。
Risc-V规定,对于非规格化数(subnormal Numbers)的处理完全遵循IEEE754定义。
根据IEEE-754标准,在浮点数的表示中,有一类特殊编码数据属于NaN(not a number)类型,且NaN分为Signaling-NaN和Quiet-NAN。
Risc-V架构规定,如果浮点运算的结果是一个NaN数,那么使用一个固定的NaN数,将之命名为Canonical-NaN。单精度浮点对应的Canonical-NaN数值为0x7fc00000,双精度浮点对应Canonical-NaN数值为0x7ff80000_00000000
如果同时支持单精度浮点(F扩展指令子集)和双精度浮点(D扩展指令子集),由于浮点通用寄存器的宽度为64位,Risc-V架构规定单精度浮点指令产生的32位结果写入浮点通用寄存器(64位)时,将结果写入低32位,而高位全部写入数值1,RiscV架构规定此种做法称之为NaN-Boxing。NaN-boxing可以发生在如下情形:
对于单精度浮点数的读(Load)/写(store)指令和传送(Move)指令(包括FLW,FSW,FMV.W.X,FMV.X.W),如果需要将32位的数值写入通用浮点寄存器,则采用NaN-boxing的方式;如果需要将浮点通用寄存器中的数值读出,则仅使用其低32位值。
对于单精度浮点运算(compute)和符号注入(sign-injection)指令,需要判断其操作数浮点寄存器中的值是否为合法的NaN-Boxed值,即高位都是1,如果是,则正常使用其低32位,如果不是,则将此操作数当作Canonical-NaN来使用。
对于整数至单精度的浮点转化指令(比如FCVT.S.X),则采用NaN-boxing的方式写回浮点通用寄存器。对于单精度浮点至整数的转化指令(比如FCVT.X.S),需要判断其操作数浮点寄存器中的值是否为合法的NaN-boxed值(即高位都为1)。如果是,则正常使用其低32位,如果不是,则将此操作数当作Canonical-NaN来使用。
RV32FM主要包括以下指令:
Category Fmt RV32F machine code(bin) comment float read/write instruction flw rd offset[11:0](RS1) [31-20, imm[11:0]][19-15,rs1]010[11-7, rd]‘0000111 rd=mem[rs1+offset], offset是一个12位符号数,所以加法操作时候,需要符号位扩展。flw指令从存储器中读回一个单精度浮点数,写回寄存器rd。 fsw rd2 offset[11:0](RS1) [31-25, imm[11:5]][24-20,rs2][19-15,rs1]010[11-7, imm[4:0]]‘0100111 mem[rs1+offset]=rd2, offset是一个12位符号数,所以加法操作时候,需要符号位扩展。Fsw指令将操作数寄存器rs2中的单精度浮点数写回存储器中。 fld rd offset[11:0](RS1) [31-20, imm[11:0]][19-15,rs1]011 [11-7, rd]‘0000111 rd=mem[rs1+offset], offset是一个12位符号数,所以加法操作时候,需要符号位扩展。flw指令从存储器中读回一个双精度浮点数,写回寄存器rd。 fsd rd2 offset[11:0](RS1) [31-25, imm[11:5]][24-20,rs2][19-15,rs1]011 [11-7, imm[4:0]]‘0100111 mem[rs1+offset]=rd2, offset是一个12位符号数,所以加法操作时候,需要符号位扩展。Fsw指令将操作数寄存器rs2中的双精度浮点数写回存储器中。 float compute instruciton fadd.s rd, rs1, rs2 0000000[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1010011 将操作数寄存器rs1和rs2中的单精度浮点数进行加法操作,结果返回rd