浮点运算单元(FPU)¶
项目中使用的 FPU 是来自于 pulp-platform 的 FPnew。我们对其使用 Chisel 进行了适配,单独形成 此项目。下列内容为 FPnew 文档 的翻译,接口均修改为 Chisel 版本。
FPnew 是一个支持标准 RISC-V 操作和多精度格式的参数化浮点单元,使用 SystemVerilog 编写。
顶层接口¶
FPU 的顶层模块是 FPNew,这一节将给出接口的详细描述。FPnew 使用同步接口在 FPU 与外界间握手和传输数据。
参数¶
FPU 的主要配置通过 FPConfig 类型完成,实现中提供了默认的选择。支持的配置如下:
| 名称 | 类型 | 描述 |
|---|---|---|
fLen |
Int |
FPU 的最大浮点宽度 |
tagWidth |
Int |
操作标签宽度 |
pipelineStages |
Int |
数据同步拍数 |
Note
目前 Chisel 的适配中,并未支持原版的所有参数。其他参数的默认配置可参见 此文件
端口¶
FPnew 对外接口类型为 FPIO,包括以下四个成员:
| 名称 | 方向 | 类型 | 描述 |
|---|---|---|---|
req |
in | Flipped(Decoupled(FPRequest)) |
向 FPU 发出的请求 |
resp |
out | Decoupled(FPResponse) |
FPU 的响应 |
flush |
in | Bool |
清空(同步流水线复位) |
busy |
out | Bool |
FPU 正在执行操作 |
注意到 req 和 resp 都是 Decoupled 类型,即除数据外还包括 ready 和 valid 的握手信号。
其中 FPRequest 类型定义为:
| 名称 | 类型 | 描述 |
|---|---|---|
operands |
Vec(3, UInt(fLen.W)) |
操作数 |
roundingMode |
FPRoundingMode |
浮点舍入模式 |
op |
FpOperation |
操作选择 |
opModifier |
Bool |
操作修饰符 |
srcFormat |
FPFloatFormat |
源浮点数格式 |
dstFormat |
FPFloatFormat |
目标浮点数格式 |
intFormat |
FPIntFormat |
整数格式 |
vectorialOp |
Bool |
向量操作选择 |
tag |
UInt(tagWidth.W) |
操作标签 |
FPResponse 类型定义为:
| 名称 | 类型 | 描述 |
|---|---|---|
result |
UInt(fLen.W) |
操作结果 |
status |
FPStatus |
RISC-V 浮点状态标记 fflags |
tag |
UInt(tagWidth.W) |
操作标签 |
数据类型¶
下面列出了 FPnew 使用的各种数据类型(包括枚举量)。
FPRoundingMode - 浮点舍入模式¶
下面列出了可用的浮点舍入模式,其编码与 RISC-V 中使用的相同。
| 名称 | 编码值 | 舍入模式 |
|---|---|---|
RNE |
3'b000 |
向最近舍入到偶数(默认) |
RTZ |
3'b001 |
向零舍入 |
RDN |
3'b010 |
向负无穷大舍入 |
RUP |
3'b011 |
向正无穷大舍入 |
RMM |
3'b100 |
向最近舍入并远离零 |
DYN |
3'b111 |
RISC-V 动态舍入模式,传递给指令是无效的 |
FPOperation - 浮点操作¶
操作修饰符 opModifier 可用于更改操作的行为。如果没有特别指明,则操作使用第一个操作数(operands(0))。
| 名称 | 修饰符 | 操作 |
|---|---|---|
FMADD |
0 |
融合乘加 ((op[0] * op[1]) + op[2]) |
FMADD |
1 |
融合乘减 ((op[0] * op[1]) - op[2]) |
FNMSUB |
0 |
取反的融合乘减 (-(op[0] * op[1]) + op[2]) |
FNMSUB |
1 |
取反的融合乘加 (-(op[0] * op[1]) - op[2]) |
ADD |
0 |
加法 (op[1] + op[2]) 注意操作数下标 |
ADD |
1 |
减法 (op[1] - op[2]) 注意操作数下标 |
MUL |
0 |
乘法 (op[0] * op[1]) |
DIV |
0 |
除法 (op[0] / op[1]) |
SQRT |
0 |
平方根 |
SGNJ |
0 |
符号注入,使用舍入模式来编码操作RNE: op[0] 使用 sign(op[1])RTZ: op[0] 使用 ~sign(op[1])RDN: op[0] 使用 sign(op[0]) ^ sign(op[1])RUP: op[0] (不做修改) |
SGNJ |
1 |
与上面相同,但是给出符号扩展而非 NaN-装箱 的结果 |
MINMAX |
0 |
取最大/最小值,使用舍入模式来编码操作RNE: minimumNumber(op[0], op[1])RTZ: maximumNumber(op[0], op[1]) |
CMP |
0 |
比较,使用舍入模式来编码操作RNE: op[0] <= op[1]RTZ: op[0] < op[1]RDN: op[0] == op[1] |
CLASSIFY |
0 |
分类,返回 RISC-V 类别块 |
F2F |
0 |
浮点-浮点转换,使用 srcFormat 和 dstFormat 指定的类型 |
F2I |
0 |
浮点-有符号整数转换,使用 srcFormat 和 intFormat 指定的类型 |
F2I |
1 |
浮点-无符号整数转换,使用 srcFormat 和 intFormat 指定的类型 |
I2F |
0 |
有符号整数-浮点转换,使用 intFormat 和 dstFormat 指定的类型 |
I2F |
1 |
无符号整数-浮点转换,使用 intFormat 和 dstFormat 指定的类型 |
CPKAB |
0 |
将 op[0] 与 op[1] 转换并包装进向量 op[2] 的条目 0, 1 |
CPKAB |
1 |
将 op[0] 与 op[1] 转换并包装进向量 op[2] 的条目 2, 3 |
CPKCD |
0 |
将 op[0] 与 op[1] 转换并包装进向量 op[2] 的条目 4, 5 |
CPKCD |
1 |
将 op[0] 与 op[1] 转换并包装进向量 op[2] 的条目 6, 7 |
FPFloatFormat - 浮点数格式¶
| 名称 | 格式 | 宽度 | 指数宽度 | 尾数宽度 |
|---|---|---|---|---|
Fp32 |
IEEE binary32 | 32 bit | 8 | 23 |
Fp64 |
IEEE binary64 | 64 bit | 11 | 52 |
Fp16 |
IEEE binary16 | 16 bit | 5 | 10 |
Fp8 |
binary8 | 8 bit | 5 | 2 |
Fp16Alt |
binary16alt | 16 bit | 8 | 7 |
FPIntFormat - 整数格式¶
| 名称 | 宽度 |
|---|---|
Int8 |
8 bit |
Int16 |
16 bit |
Int32 |
32 bit |
Int64 |
64 bit |
FPStatus - 浮点状态标志¶
| 名称 | 描述 |
|---|---|
NV |
无效操作 |
DZ |
除零 |
OF |
向上溢出 |
UF |
向下溢出 |
NX |
非精确操作 |
NaN-装箱(NaN-Boxing)¶
RISC-V 对于系统中所有比可用的最大宽度窄的浮点数强制要求进行 NaN-装箱,也就是说较窄的格式的所有未使用的高位都需要置为 1,否则该值将被视为不可用(一个 NaN)。
Note
默认会检查输入值是否正确进行 NaN-装箱,此行为可以关闭(见配置一节)。 FPU 给出的窄浮点数总是进行 NaN-装箱,整数输出总是进行符号扩展(即使是无符号数)。
握手接口¶
FPnew 的输入和输出都使用 valid/ready 握手接口来控制数据的流动。握手协议和通用协议(如 AXI)中使用的相同:
- 置位的
valid信号表明对应接口上的数据是有效并且稳定的。 - 一旦
valid置位,在握手完成前 不允许 取消。 - 置位的
ready信号表明接口在下一个时钟正沿能够处理数据。 - 一旦
valid和ready在同一个时钟正沿置位,事务就完成了。 - 在事务完成后,
valid可以保持置位,为下一次传输提供新数据。 - 协议方向是 自顶向下 的。
ready可以依赖于valid,但是valid不允许 依赖于ready。
操作标签¶
操作标签是附带在操作上的元数据,用于关联结果和对应的操作。标签经过 FPU 时不会被修改,总是与和它们一同发射的指令保持一致。
通过 tagWidth 参数,可以控制标签的宽度。