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) | 32 | 8 | 23 | 127 |
| 双精度(binary64) | 64 | 11 | 52 | 1023 |
| 半精度(binary16) | 16 | 5 | 10 | 15 |
这里有个坑,我刚开始学的时候总搞混:指数是用移码表示的,不是补码。为什么要用移码?因为这样比较两个浮点数大小时,可以直接按位比较,省事多了。
避坑指南:我曾经在设计FPU比较器时,直接拿补码比较指数,结果NaN和无穷大的处理全乱了。记住:IEEE 754的指数是移码,尾数隐含了前导1(规格化数),非规格化数则没有这个前导1。
再说运算:
IEEE 754规定了五种基本运算:加、减、乘、除、开方。还规定了四种舍入模式:
- 就近舍入(默认模式,遇到0.5时取偶数)
- 向+∞舍入
- 向-∞舍入
- 向0舍入
为什么要有这么多舍入模式?我在做数值分析时发现,不同算法对舍入误差的敏感度不一样。比如某些迭代算法,用就近舍入可能不收敛,换成向0舍入反而稳定。嗯,这就是标准留了灵活性的原因。
异常处理:
IEEE 754定义了五种异常:
- 无效操作(比如0/0、∞-∞)
- 除以零
- 上溢
- 下溢
- 不精确
你可能会问:为什么“不精确”也算异常?因为浮点运算本质上是近似计算,结果需要舍入。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的微架构设计,聊聊加法器、乘法器这些核心模块怎么在硬件里实现。到时候我会分享一些我在实际项目中踩过的坑,保证让你少走弯路。