双精度运算正确
D扩展(Double)为RISC-V添加IEEE 754双精度(64位)浮点运算支持。D扩展依赖F扩展,共享32个浮点寄存器(每个扩展为64位宽)。双精度提供15-17位有效数字,是科学计算和数值模拟的必需。
| D扩展指令 | 对应F扩展 | 差异 |
|---|---|---|
| FLD/FSD | FLW/FSW | 64位加载/存储 |
| FADD.D/FSUB.D | FADD.S/FSUB.S | 64位运算 |
| FCVT.S.D/FCVT.D.S | — | 单双精度互转 |
| FCVT.L.D/FCVT.D.L | FCVT.W.S/FCVT.S.W | 64位整数转换 |
科学计算中,单精度的7位有效数字远远不够。例如:N-body模拟中,单精度的累积误差在几千次迭代后就会使结果完全错误。双精度的15位有效数字可以支撑数十亿次迭代的精度需求。
// Lesson 26: RVD Double-Precision Float Add/Sub
module rvd_add_sub(input wire clk, rst_n, start, is_sub,
input wire [63:0] dp_a, dp_b, output reg [63:0] dp_result, output reg done);
wire sign_a=dp_a[63]; wire [10:0] exp_a=dp_a[62:52];
wire [52:0] man_a=(exp_a!=0)?{1'b1,dp_a[51:0]}:{1'b0,dp_a[51:0]};
wire sign_b_eff=is_sub?~dp_b[63]:dp_b[63]; wire [10:0] exp_b=dp_b[62:52];
wire [52:0] man_b=(exp_b!=0)?{1'b1,dp_b[51:0]}:{1'b0,dp_b[51:0]};
wire a_larger=(exp_a>exp_b)||(exp_a==exp_b&&man_a>=man_b);
wire [10:0] exp_big=a_larger?exp_a:exp_b, exp_small=a_larger?exp_b:exp_a;
wire [52:0] man_big=a_larger?man_a:man_b, man_small=a_larger?man_b:man_a;
wire [10:0] shift_amt=exp_big-exp_small;
wire [53:0] man_aligned={1'b0,man_small}>>shift_amt;
wire same_sign=(sign_a==sign_b_eff);
wire [53: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 [53:0] man_norm1=man_result[53]?(man_result>>1):man_result;
wire [10:0] exp_norm1=man_result[53]?(exp_big+1):exp_big;
reg [5:0] lz; reg [53:0] man_final; reg [10: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[52]) begin if(man_final[51])lz=1; else if(man_final[50])lz=2;
else if(man_final[49])lz=3; else if(man_final[48])lz=4; else if(man_final[47])lz=5;
else if(man_final[46])lz=6; else if(man_final[45])lz=7; else if(man_final[44])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 dp_result<=0; done<=0; end
else if(start) begin dp_result<={sign_final,exp_final,man_final[51:0]}; done<=1; end
else done<=0; end
endmodule
| 处理器 | 单精度GFLOPS | 双精度GFLOPS | FPU延迟 |
|---|---|---|---|
| Rocket (FPU) | 0.5 | 0.5 | 5周期 |
| BOOM v3 | 2.0 | 1.0 | 4周期 |
| SiFive U74 | 1.5 | 0.75 | 5周期 |
| ARM Cortex-A76 | 4.0 | 2.0 | 4周期 |
双精度运算通常是单精度吞吐量的一半,因为64位乘法器面积是32位的4倍。高性能FPU通常使用流水线化设计来隐藏延迟。
掌握本课内容需要结合理论学习和动手实践:
| 工具 | 用途 | 安装 |
|---|---|---|
| Verilator 5.020 | Verilog编译仿真 | 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 |
本课程推荐以下开发工具链:
| 工具 | 用途 | 安装命令 |
|---|---|---|
| Verilator | Verilog编译/仿真 | 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 |
| Spike | ISA模拟器 | 从源码编译 |
# 编译本课Verilog代码
cd verilog/
iverilog -o tb_test *.v
vvp tb_test
# Verilator lint检查
verilator --lint-only -Wno-BLKLOOPINIT *.v
# 应无Error输出
本课是第26课,在整体课程中承上启下。每一课都构建在前一课的基础上,建议按顺序学习。