浮点乘加器 FMA 设计
浮点乘加器 FMA(Fused Multiply-Add,融合乘加)
$R=Round(A\times B+C)$
乘积不先舍入,先以足够高的内部精度与 (C) 相加,最后只舍入一次。
与依次执行浮点乘法、浮点加法不同 $R_{\text{非融合}}=Round\big(Round(A\times B)+C\big)$
因此,FMA 具有更好的数值精度、更少的指令数和更高的计算吞吐率
RISC-V 的
FMADD、FMSUB、FNMSUB和FNMADD都采用这种一次舍入语义,并使用三个源寄存器和一个目的寄存器的 R4 型指令格式
基本算法流程
设三个输入为:
$$
A=(-1)^{S_A}M_A2^{E_A}\
B=(-1)^{S_B}M_B2^{E_B}\
C=(-1)^{S_C}M_C2^{E_C}
$$
其中 M 是包含隐藏位的有效数
整体流程可以概括为:
1 | A、B、C |
1. 输入处理
从 IEEE 754 编码中提取:
- 符号位
- 指数字段
- 小数字段
- 隐藏的最高有效位
判断操作数属于:
- 规格化数;
- 非规格化数;
- 正零或负零;
- 正无穷或负无穷;
- quiet NaN;
- signaling NaN。
高性能实现通常让“普通数数据通路”和“特殊值判断通路”并行运行,最后由选择器决定输出,避免特殊值判断拉长主数据通路。
2. 计算乘积
- 乘积符号: $S_P=S_A\oplus S_B$
- 乘积指数:$E_P=E_A+E_B-\text{Bias}$
- 尾数乘积:$M_P=M_A\times M_B$
对于不同格式,精确乘积宽度为有效数精度 (p) 的 2 倍
3. 指数比较与对齐
接下来
- 比较乘积 $P=A\times B$ 与加数 $C$ 的指数 $D=E_P-E_C$
- 将指数较小的操作数右移,使两者的小数点对齐, 右移过程保留 GRS 位
4. 尾数加减
- 如果乘积与加数符号相同,则执行加法:$M_R=M_P’+M_C’$
- 如果符号不同,则执行减法:$M_R=\left|M_P’-M_C’\right|$
5. 规格化和舍入
操作处理和浮点加法一致
6. 输出检查
FMA可能设置:
NV:Invalid Operation;OF:Overflow;UF:Underflow;NX:Inexact。
FMA本身不产生除零异常 DZ。典型无效运算包括:$\infty\times0, \infty\times -\infty$
RISC-V 规范要求即使加数是 quiet NaN,$\infty\times0$ 仍应设置无效操作标志。
现代 FMA 的核心硬件结构
1. 乘法器部分
只针对尾数部分,同整数乘法器
2. 将加数直接注入压缩树
朴素实现是:尾数乘法器 → 完整乘积 → 大加法器加 C, 但这种结构需要先完成一次宽进位传播,再做第二次宽加法,延迟较大。
主流融合结构:
graph LR
S1[A×B 部分积]
S2[对齐后的 C]
S3[Carry-Save 压缩树]
S4[最终 CPA]
S1 --> S3
S2 --> S3
S3 --> S4
把对齐后的 C 直接作为额外一行操作数注入乘法部分积压缩树,避免先形成完整乘积再相加
不同 FMA 架构通常围绕部分积压缩、加数注入、规格化和舍入的组合方式展开([TechRxiv][1])
3. Close Path 与 Far Path
高性能浮点加法器和 FMA 经常采用双路径或多路径结构。
Far Path
当指数差很大时:$|E_P-E_C|\gg0$
同双通路浮点加法器的 far path
Close Path
当指数接近且符号相反时,可能发生严重相消:$E_P\approx E_C, S_P\neq S_C$
同双通路浮点加法器的 close path