1. FPU概述:浮点运算单元在RISC-V体系结构中的角色

各位同学,咱们今天聊聊浮点运算单元——也就是FPU。说实话,我刚开始接触RISC-V那会儿,觉得FPU就是个“算小数的玩意儿”,后来才发现自己太天真了。

浮点运算单元在RISC-V体系里扮演什么角色?说白了,就是处理那些整数搞不定的数字。你想想看,做科学计算、图形渲染、AI推理,哪个离得开浮点数?RISC-V作为一个模块化架构,把FPU设计成可选扩展,这本身就是一种智慧——嵌入式场景可能用不上,但高性能计算场景必须得有。

核心要点:FPU不是CPU的附属品,而是RISC-V生态中处理非整数运算的“特种部队”。它负责执行加、减、乘、除、开方、比较等浮点操作,并且要严格遵循IEEE 754标准。

我在一个AI加速器项目里遇到过这种情况:没有硬件FPU,全靠软件模拟浮点运算,结果性能直接掉了两个数量级。嗯,从那以后我就明白了——FPU不是锦上添花,而是雪中送炭。

1.1 IEEE 754标准简介

说到浮点运算,绕不开IEEE 754。这个标准定义了浮点数怎么存、怎么算、怎么处理异常。我个人习惯把它分成三块来看:格式、运算、异常处理。

先看格式:

格式总位数指数位尾数位偏置值
单精度(binary32)32823127
双精度(binary64)6411521023
半精度(binary16)1651015

这里有个坑,我刚开始学的时候总搞混:指数是用移码表示的,不是补码。为什么要用移码?因为这样比较两个浮点数大小时,可以直接按位比较,省事多了。

避坑指南:我曾经在设计FPU比较器时,直接拿补码比较指数,结果NaN和无穷大的处理全乱了。记住:IEEE 754的指数是移码,尾数隐含了前导1(规格化数),非规格化数则没有这个前导1。

再说运算:

IEEE 754规定了五种基本运算:加、减、乘、除、开方。还规定了四种舍入模式:

  • 就近舍入(默认模式,遇到0.5时取偶数)
  • 向+∞舍入
  • 向-∞舍入
  • 向0舍入

为什么要有这么多舍入模式?我在做数值分析时发现,不同算法对舍入误差的敏感度不一样。比如某些迭代算法,用就近舍入可能不收敛,换成向0舍入反而稳定。嗯,这就是标准留了灵活性的原因。

异常处理:

IEEE 754定义了五种异常:

  1. 无效操作(比如0/0、∞-∞)
  2. 除以零
  3. 上溢
  4. 下溢
  5. 不精确

你可能会问:为什么“不精确”也算异常?因为浮点运算本质上是近似计算,结果需要舍入。IEEE 754要求硬件能报告“这次运算结果不精确”,方便软件做误差分析。

1.2 RISC-V浮点扩展(F/D/Q)概述

RISC-V的浮点扩展分三个档次:F(单精度)、D(双精度)、Q(四精度)。它们的关系是:D扩展包含F扩展,Q扩展包含D和F扩展。说白了就是向下兼容。

F扩展(单精度浮点):

  • 新增32个浮点寄存器f0-f31
  • 每个寄存器32位宽
  • 支持单精度浮点运算指令
  • 需要配套的浮点控制状态寄存器(fcsr)

D扩展(双精度浮点):

  • 复用F扩展的32个寄存器
  • 每个寄存器对(如f0-f1)存储一个双精度数
  • 支持双精度运算指令
  • 包含F扩展的所有功能

注意:D扩展的寄存器复用方式容易让人误解。f0存双精度数的低32位,f1存高32位。我曾经在写汇编代码时搞反了高低位顺序,调试了一整天才发现。记住:小端序!小端序!小端序!

Q扩展(四精度浮点):

  • 同样复用32个寄存器
  • 每四个寄存器存一个四精度数
  • 主要用于高精度科学计算
  • 目前硬件实现较少,多为软件模拟

来看看F扩展的几条典型指令:

# 单精度加法
fadd.s f1, f2, f3    # f1 = f2 + f3

# 单精度乘法
fmul.s f1, f2, f3    # f1 = f2 * f3

# 单精度乘加(融合乘加)
fmadd.s f1, f2, f3, f4  # f1 = f2 * f3 + f4

# 整数转浮点
fcvt.s.w f1, x1      # 将整数x1转为单精度存到f1

# 浮点比较
flt.s x1, f1, f2     # 如果f1 < f2,x1置1

我个人特别喜欢RISC-V的融合乘加指令(FMADD)。为什么?因为它在做乘加运算时只舍入一次,精度比分开做乘法和加法高得多。我在做矩阵乘法加速时,用FMADD替换了mul+add序列,误差直接降了一个数量级。

设计思路:RISC-V的浮点扩展设计遵循“精简”原则。它没有像x86那样搞一堆复杂的浮点指令,而是提供最基础的运算,让编译器去组合优化。这种设计降低了硬件复杂度,也方便了FPU的验证。

最后说一句:浮点扩展的配置是灵活的。你可以只实现F扩展,也可以F+D一起实现,甚至F+D+Q全上。但要注意,如果实现了D扩展,必须同时实现F扩展。这是RISC-V规范强制要求的。

好了,第一章就讲到这里。下一章咱们深入FPU的微架构设计,聊聊加法器、乘法器这些核心模块怎么在硬件里实现。到时候我会分享一些我在实际项目中踩过的坑,保证让你少走弯路。