浮点加法器

算法流程

浮点加法完整数据通路:

graph LR
    S1((输入处理)) 
    --> S2[规格化指数减法 ES] 
    --> S3[尾数对齐 Align] 
    --> S4[有效数加法 SA]
    --> S5[转化 Conv]
    --> S6[前导零检测 LZD]
    --> S7[归一化 Norm]
    --> S8[舍入 Round]
    --> S9((输出检查))
  • Conv, LZD, Norm 这三步是为了将最后的输出进行规格化
  • 输入处理和输出检查是所有浮点操作所必需的,因此可以和其他浮点操作共用

需要处理的问题:

  1. 不同指数导致的尾数对齐;
  2. 异号相加时可能发生严重相消;
  3. IEEE 754 正确舍入;
  4. NaN、无穷、非规格数和异常标志处理。

设输入为:

$$
A=(-1)^{s_A}M_A2^{E_A},\qquad
B=(-1)^{s_B}M_B2^{E_B}
$$

1. 输入处理

  • 任一输入为 sNaN:置 invalid,输出 qNaN;
  • qNaN 输入:输出 NaN;
  • 正负无穷相加 $+\infty+(-\infty)$:无效操作,输出 NaN;
  • 同号无穷相加:保持无穷;
  • 零和精确相消结果:需要按照舍入模式确定正负零

在 RISC-V 中,浮点指令产生对应的标志位(非异常) fflags

  • NV:invalid;
  • DZ:divide by zero;
  • OF:overflow;
  • UF:underflow;
  • NX:inexact。

加法不会产生 DZ,但可能产生其余四种标志。RISC-V 默认使用规范 NaN,并要求支持非规格数运算。

2. 规格化指数减法 (Exponent Subtraction,ES)

求规格化的指数之差(求指数差的绝对值): $d=|E_A-E_B|$

硬件做法:

  1. 先比较:$(E_A,M_A)\quad\text{和}\quad(E_B,M_B)$
  2. 然后交换操作数,使 $E_L\geq E_S$, 其中 (L) 表示较大操作数,(S) 表示较小操作数。
  3. 计算指数差:$d=E_L-E_S$

这样做的好处是:

  • 指数差始终非负;
  • 异号时可以固定执行“大数减小数”;
  • 结果符号通常就是较大操作数的符号;
  • 尾数减法不需要处理负的中间结果。

3. 尾数对齐 (Alignment, Align)

较小操作数的尾数右移:$M’_S=M_S\gg d$

使二者指数相同:$A\pm B=\left(M_L\pm M’_S\right)2^{E_L}$

硬件不能简单丢弃被移出的位,因为它们决定最终舍入。一般至少保留三位:

  • G:Guard bit,保留位之后的第一位;
  • R:Round bit,第二位;
  • S:Sticky bit,其余所有被丢弃位的逻辑或, 即 $S=b_0\lor b_1\lor b_2\lor\cdots$

这种右移通常称为 shiftRightJam

如果指数差已经大于 (p+2) 或 (p+3),较小操作数对结果有效尾数已无直接贡献,硬件不必真正进行全距离移位,只需要判断它是否非零并生成 sticky 位 (p 指浮点格式的有效数精度,也就是尾数参与运算的总位数,包含规格数隐含的最高位 1)

对齐电路通常是浮点加法器中面积和延迟都很显著的模块,一般实现为多级桶形移位器和并行 sticky 归约树

4. 有效数加法 (Signicand addition,SA)

操作由符号决定:

  • 同号 $s_A=s_B$, 执行 $M_R=M_L+M’_S$, 结果符号为共同符号
  • 异号 $s_A\ne s_B$, 执行 $M_R=M_L-M’_S$, 结果符号为绝对值较大的操作数符号

硬件中通常是一个加法器实现,减法通过补码加法完成

5. 转化(Conversion, Conv)

将结果转换为符号-幅度表示 $(s_R, M_f)$, 这一步是为了方便规格化

如果有效数字加法结果 $M_R$ 为负:

  • $s_R$ 就是 $M_R$ 的最高位, 即 1
  • $M_f$ 就是 $M_R$ 的相反数(硬件补码加一)

否则,$s_R = 0, M_f = M_R$

6. 前导零检测(Leading zero detection,LZD)

计算结果规格化所需的左移或右移量 $E_n$ ,右移为正,否则为负。

  1. 先进行零检测:结果为 0 时 ($M_f = 0$), 跳过正常规格化,结果直接置 0
  2. 同号加法产生进位时 ($2 \le M_f \lt 4$), 需要右移一位 $E_n = 1$
  3. 异号减法发生相消时 ($0 \lt M_f \lt 1$), 前导零检测器计算第一个 1 前面的零数,并左移 $E_n=-LZD(M_f)$
  4. 其余情况不需要移动 ($1 \le M_f \lt 2$): 已满足规格化要求 $E_n = 0$

7. 归一化(Normalization, Norm)

  1. 通过移 $E_n$ 位将有效数字归一化: $M_R = M_f \times 2^{-E_n}$
  2. 将 $E_n$ 加到 $E_L$ 上: $E_R = E_n + E_L$

8. 舍入(Rounding, Round)

根据 IEEE-754 标准舍入

  1. 必要时在 $M_R$ 的 LSB 上加 1

设保留部分最低位为 (L),丢弃部分是否非零为:$D=G\lor R\lor S$

不同舍入模式的尾数加一条件为:

舍入模式 尾数加一条件
RNE,最近偶数 $G\land(R\lor S\lor L)$
RTZ,向零 永不加一
RUP,向 (+\infty) 结果为正且 $D=1$
RDN,向 (-\infty) 结果为负且 $D=1$
RMM,最近且中点远离零 $G=1$
  1. 若舍入加一导致溢出,溢出时需要将尾数结果右移一位,同时指数 $E_R$ 加 1

9. 输出检查

最后检查指数

  1. 上溢: 指数超过最大值
    • 某些舍入模式得到无穷;
    • 某些舍入模式得到最大有限数;
    • 设置 OF
    • 通常同时设置 NX
  2. 下溢: 指数低于最小规格指数时,需要生成非规格结果:$0.f\times2^{E_{\min}}$
    • 需要再次右移有效数,并把移出位纳入 GRS
    • RISC-V 按舍入之后判断 tininess,因此只有最终结果既微小又不精确时才设置 UF

硬件实现

单路径浮点加法器

单路径结构基本对应前面的串行算法:

1
2
3
4
5
6
7
8
9
10
11
指数比较

大距离右移对齐

有效数加/减

前导零计数

左移规格化

舍入

优点:

  • 逻辑复用多, 面积较小;
  • 适合嵌入式处理器、低成本 ASIC 和 FPGA。

缺点:

  • 对齐移位、加减、LZD、规格化、舍入串在同一逻辑链上;
  • 高频实现必须切成较多流水级;
  • 正常加法也要经过为严重相消准备的复杂逻辑。

双路径浮点加法器

单通路浮点算法很慢,因为其步骤基本上都是串行执行的,可以通过以下方式改进该算法:

  1. 通过交换有效数字使 Conv 步骤和 Round 步骤可以互斥并行

    • Conv 步骤仅当结果为负时才需要执行,并且可以通过交换两操作数的有效数字来避免该步骤
    • 在指数不同的情况下, 通过检查 ES 步骤结果的正负号,并根据正负进行交换相应的有效数字,就可以保证总是计算较大的有效数字减去较小的有效数字
    • 在指数相等的情况下(ES 步骤结果为 0), 结果仍可能为负,需要进行转换,但这种情况下不需要舍入
    • 交换步骤只需要一个移位器
  2. ? LZD 步骤可以与 SA 步骤并行执行,将其从关键路径中移除(减法可能需要大量左移)

  3. Align 和 Norm 步骤是互斥并行的

  • 只有当 $d \le 1$ 时或者有效数减法时,归一化需要大量的左移
  • 只有当 $d \gt 1$ 时,对齐步骤需要大量的右移
  1. SA 步骤在有效数减法的情况下,其中一个有效数字是 2 的补码,求补码步骤和舍入步骤是互斥并行的

  • 等效加法或 $d \gt 1$ 的等效减法的通路称为 far 路径
  • $d \le 1$ 且等效减法的通路称为 close 路径
  • 含有无穷或 NaN 操作数的情况单独判断,不属于 far 路径或 close 路径

Far Path

处理:

  • 等效加法
  • $d \gt 1$ 的等效减法
  1. 并行计算规格化指数差和操作数交换

    • 计算指数差: 为加快计算速度,使用两个加法器来计算规格化的指数差,同时计算 $d_{AB} = E_A - E_B$ 和 $d_{BA} = E_B - E_A$
    • 根据结果大小的比较结果选择出:
      • 正确的规格化的指数差 d
      • 指数较大的操作数的有效数字 $M_L$
      • 指数较小的操作数的有效数字 $M_S$
      • 较大的指数 $E_L$
  2. 当等效减法时,$E_L–$, 目的是调整有效数字做完减法后的值域,和等效加法值域统一起来方便后面选择出最终结果

    • 调整后有效数字加减结果的值域在 $[1-4)$ 之间,分为两种情况:
      • $[1,2)$ 之间:之后不需要右移
      • $[2,4)$ 之间:之后需要右移 1 位, 指数加 1
  3. 对较小的有效数字 $M_S$ 右移,并计算出右移后的 GRS 位

    • 此处右移分两种情况:
      1. 等效减法时先取反再算数右移 (?)
      2. 等效加法时直接逻辑右移
    • 为节省右移器的级数:
      1. 当 d 的高位全 0 时,右移时用 d 的低位 (具体位数 = log(有效数字宽度)) 进行右移
      2. 当 d 的高位不是全 0 时,表示 d 已超过有效数移位器关心的范围, 右移结果直接置 0
    • 为了正确舍入,需要提前计算两组 GRS
      • $GRS_{normal}$: 有效数字加减结果在 $[1,2)$ 之间:
      • $GRS_{overflow}$: 有效数字加减结果在 $[2,4)$ 之间, 最终还要右移一位,GRS 也要随之变化
  4. 进行有效数字加法: 两个有效数字加法器分别计算 $M_L + M_S’$ 和 $M_L + M_S’ + 2$, 最终舍入结果从中选择

  5. 产生最终结果

    • 根据 $M_L + M_S’ 的结果分为两种情况:
      • 情况一: $[1,2)$ 之间
      • 情况二: $[2,4)$ 之间
    • 尾数结果:根据两套 GRS 和舍入模式,分别确定两种情况选择两个有效数字加法器的条件,最后用四选一的独热码选择器选择出尾数结果
    • 指数结果:
      1. 情况一且尾数舍入后 < 1 : $E_L$
      2. 情况二或情况一舍入后 = 2: $E_L + 1$
      3. overflow 情况: 最终结果由 overflow 选出 overflow 结果和正常计算结果
    • 异常标志位: far 路径下只会产生上溢和不精确

Close Path

处理:等效减法且 $|E_A-E_B|\leq1$, 即指数非常接近的异号运算

  1. 并行做四组有效数字减法, 同时根据指数大小关系计算出 GRS 位:

    • d = 0, $M_A > M_B$: $M_A - M_B$, GRS 均为 0
    • d = 0, $M_B > M_A$: $M_B - M_A$, GRS 均为 0
    • d = 1, $E_A > E_B$: $M_A \times 2 - M_B$, RS 均为 0
    • d = 1, $E_B > E_A$: $M_B \times 2 - M_A$, RS 均为 0
    • 这四组加法器不能产生所有舍入的结果,增加第五个慢速加法器,$M_L - M_E >> 1$
  2. 确定选择四组有效数字减法的四个条件, 从四组加法器中选出减法结果后需要对减法结果进行 LZD + 左移

    • 选择条件:
      1. d
      2. 加法器结果的最高位
      3. GRS
      4. 舍入模式
    • 左移限制:根据 $E_L$ 的值产生一个 mask 值 (与减法结果位宽相同但最多只有一比特是 1),与减法结果或操作后再进行 LZD + 左移, 目的是限制左移位数不要超出规格化数的范围
  3. 确定选择第五个减法器的条件,选择第五个减法器结果时不需要左移,所以采用慢速加法器

  4. 指数结果和符号位结果

    • 指数位结果需要用 $E_L - LZD$
    • 若使用选择的是第五个减法器作为尾数结果,则指数保持原值
    • 当 d = 1 时符号位的取值就是 $s_L$
    • d = 0 时要根据尾数大小选择符号位, 结果为 0 且向下舍入时,符号位为 1