RVF浮点扩展 — F Extension

F扩展浮点加减正确

📖 RISC-V F扩展

F扩展(Float)为RISC-V添加IEEE 754单精度(32位)浮点运算支持,包括浮点加载/存储、算术运算、比较、转换等指令。F扩展引入了32个浮点寄存器(f0-f31)和独立的fcsr控制寄存器。

IEEE 754单精度格式: 31 30 23 22 0 ┌───────┬───────┬──────────────┐ │ Sign │ Exp │ Mantissa │ │ (1bit)│(8bit) │ (23bit) │ └───────┴───────┴──────────────┘ 值 = (-1)^Sign × 1.Mantissa × 2^(Exp-127) 示例: 1.0 = 0 01111111 00000000000000000000000 2.0 = 0 10000000 00000000000000000000000 3.0 = 0 10000000 10000000000000000000000 0.5 = 0 01111110 00000000000000000000000 -1.0 = 1 01111111 00000000000000000000000 浮点加法步骤: 1. 对阶: 小阶向大阶对齐 2. 尾数相加/减 3. 规格化: 左移/右移使最高位为1 4. 舍入: 舍入到23位精度
F扩展指令组指令数量
加载/存储FLW, FSW2
算术FADD.S, FSUB.S, FMUL.S, FDIV.S4
融合乘加FMADD.S, FMSUB.S, FNMSUB.S, FNMADD.S4
比较FEQ.S, FLT.S, FLE.S3
转换FCVT.W.S, FCVT.S.W, FMV.X.W, FMV.W.X4
其他FSGNJ.S, FMIN.S, FMAX.S, FCLASS.S5

NaN-Boxing

RISC-V使用NaN-Boxing将32位浮点值扩展到64位:高32位全1,低32位是实际的float值。这样F和D扩展可以使用相同的寄存器文件。

F扩展的32个浮点寄存器(f0-f31)与整数寄存器(x0-x31)完全独立。这是RISC的设计选择——分离的寄存器文件避免了整数和浮点指令之间的端口冲突。

🖥️ Verilog实现

// Lesson 25: RVF Single-Precision Float Add/Sub
module rvf_add_sub(input wire clk, rst_n, start, is_sub,
    input wire [31:0] fp_a, fp_b, output reg [31:0] fp_result, output reg done);
    wire sign_a=fp_a[31]; wire [7:0] exp_a=fp_a[30:23];
    wire [23:0] man_a=(exp_a!=0)?{1'b1,fp_a[22:0]}:{1'b0,fp_a[22:0]};
    wire sign_b_eff=is_sub?~fp_b[31]:fp_b[31]; wire [7:0] exp_b=fp_b[30:23];
    wire [23:0] man_b=(exp_b!=0)?{1'b1,fp_b[22:0]}:{1'b0,fp_b[22:0]};
    wire a_larger=(exp_a>exp_b)||(exp_a==exp_b&&man_a>=man_b);
    wire [7:0] exp_big=a_larger?exp_a:exp_b, exp_small=a_larger?exp_b:exp_a;
    wire [23:0] man_big=a_larger?man_a:man_b, man_small=a_larger?man_b:man_a;
    wire [7:0] shift_amt=exp_big-exp_small;
    wire [24:0] man_aligned={1'b0,man_small}>>shift_amt;
    wire same_sign=(sign_a==sign_b_eff);
    wire [24:0] man_result=same_sign?({1'b0,man_big}+man_aligned):({1'b0,man_big}-man_aligned);
    wire result_sign=same_sign?sign_a:(a_larger?sign_a:sign_b_eff);
    wire [24:0] man_norm1=man_result[24]?(man_result>>1):man_result;
    wire [7:0] exp_norm1=man_result[24]?(exp_big+1):exp_big;
    reg [4:0] lz; reg [24:0] man_final; reg [7:0] exp_final; reg sign_final;
    always @(*) begin lz=0; man_final=man_norm1; exp_final=exp_norm1; sign_final=result_sign;
        if(!man_final[23]) begin if(man_final[22])lz=1; else if(man_final[21])lz=2;
            else if(man_final[20])lz=3; else if(man_final[19])lz=4; else if(man_final[18])lz=5;
            else if(man_final[17])lz=6; else if(man_final[16])lz=7; else if(man_final[15])lz=8; else lz=9; end
        if(lz>0) begin man_final=man_final<<lz; exp_final=exp_final-lz; end
        if(man_final==0) begin sign_final=0; exp_final=0; end end
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin fp_result<=0; done<=0; end
        else if(start) begin fp_result<={sign_final,exp_final,man_final[22:0]}; done<=1; end
        else done<=0; end
endmodule
Verilator仿真验证通过 — 1.0+1.0=2.0, 3.0-1.0=2.0 单精度浮点正确

代码解析

📊 F扩展在不同领域的应用

领域精度需求F扩展是否足够
图形渲染单精度是(F扩展足够)
机器学习推理FP16/BF16F扩展+自定义
科学计算双精度需要D扩展
信号处理单精度
游戏物理单精度

大多数AI/ML推理工作负载使用FP16或BF16精度,RVF扩展提供了基础,结合自定义指令可以实现更高效的推理。

🧪 实验练习

  1. 在当前实现基础上添加异常处理支持
  2. 实现流水线仿真,观察波形中的关键信号变化
  3. 添加性能计数器:统计吞吐量、延迟、利用率
  4. 前几课的模块集成,构建更完整的系统
F扩展浮点加减正确 — IEEE 754单精度浮点运算
思考题:IEEE 754浮点加法为什么需要对阶?不对阶直接相加会怎样?
参考资料:RISC-V Spec §9 (F Extension) | IEEE 754-2019 | Computer Organization and Design §3.5

📚 深入理解与实践建议

掌握本课内容需要结合理论学习和动手实践:

  1. 阅读源码:BOOM(Chisel)和Rocket(Chisel)是RISC-V处理器设计的最佳参考实现
  2. 修改实验:修改本课的Verilog代码,观察行为变化
  3. 波形仿真:使用GTKWave查看关键信号的时序关系
  4. 对比分析:将本课模块与前几课模块集成,测试端到端功能

开发环境

工具用途安装
Verilator 5.020Verilog编译仿真sudo apt install verilator
iverilog轻量仿真sudo apt install iverilog
GTKWave波形查看sudo apt install gtkwave
RISC-V GCC交叉编译apt install gcc-riscv64-unknown-elf
QEMU系统仿真apt install qemu-system-misc

📖 推荐阅读

在线资源

🔧 开发工具链与实践环境

本课程推荐以下开发工具链:

工具用途安装命令
VerilatorVerilog编译/仿真sudo apt install verilator
iverilog轻量Verilog仿真sudo apt install iverilog
GTKWave波形查看sudo apt install gtkwave
RISC-V GCC交叉编译apt install gcc-riscv64-unknown-elf
QEMU系统仿真apt install qemu-system-misc
SpikeISA模拟器从源码编译

快速验证

# 编译本课Verilog代码
cd verilog/
iverilog -o tb_test *.v
vvp tb_test

# Verilator lint检查
verilator --lint-only -Wno-BLKLOOPINIT *.v

# 应无Error输出

🎯 课程知识体系

RISC-V高级设计课程 (30课): 基础(L01-06): 特权架构→CSR→异常→中断→PLIC→CLINT 内存(L07-12): SV39 MMU→TLB→Cache系列 算术(L13-14): 乘法器→除法器 乱序(L15-19): OoO核心→ROB→寄存器重命名→记分牌→Tomasulo 预测(L20-21): 2位预测→BTB 扩展(L22-26): RVC→RVM→RVA→RVF→RVD 系统(L27-30): PMP→解码器→SoC→启动流程 每一课都是下一课的基础: 没有特权架构 → 无法理解CSR 没有CSR → 无法实现异常处理 没有异常处理 → 无法实现中断 没有中断 → 无法实现PLIC/CLINT 没有虚拟内存 → 无法运行Linux 没有Cache → 性能灾难 没有乱序执行 → ILP受限 没有分支预测 → 流水线气泡严重

🎯 课程知识体系

RISC-V高级设计课程 (30课): 基础(L01-06): 特权架构→CSR→异常→中断→PLIC→CLINT 内存(L07-12): SV39 MMU→TLB→直接映射Cache→组相联→写回→分离Cache 算术(L13-14): Booth乘法器→恢复余数除法器 乱序(L15-19): OoO核心→ROB→寄存器重命名→记分牌→Tomasulo 预测(L20-21): 2位饱和计数器→BTB分支目标缓冲 扩展(L22-26): RVC压缩→RVM乘除→RVA原子→RVF单精度→RVD双精度 系统(L27-30): PMP保护→全解码器→SoC集成→启动流程

本课是第25课,在整体课程中承上启下。每一课都构建在前一课的基础上,建议按顺序学习。

📚 推荐阅读

在线资源