跳转至

FPnew 使用规范

1. 概述

FPnew 是一个开源的、高度可配置的跨精度浮点单元,支持多种标准与非标准浮点格式,并具备标量与向量运算能力,实现精度与能耗之间的动态权衡。

FPnew 采用 SystemVerilog 编写,遵循 IEEE 754-2008 标准,支持多种浮点格式、多格式融合乘加、转换与打包操作等,具备高度可配置的流水线结构。

FPnew 的架构分为四个主要功能块,每个块处理一类指令:

  1. ADDMUL:融合乘加 (a*b)+c 、加法(a=1)、乘法(c=0)
  2. DIVSQRT:除法、平方根(迭代实现)
  3. COMP:比较、分类、位操作
  4. CONV:格式转换(FP↔FP、FP↔整数)

每个功能块可配置为并行合并格式切片,支持不同精度的独立或共享数据通路。

Merge vs Parallel

FPnew 通过 SystemVerilog 参数进行配置,其中支持的浮点格式包括: - FP64 (11,52) - FP32 (8,23) - FP16 (5,10) - BF16 (8,7) - FP8 (5,2)

2. 配置与端口

2.1 关键配置参数

FPU_FEATURES

配置项 描述
Width 数据路径的宽度(通常与 ISA XLEN 对应)
EnableVectors 是否启用向量模式(SIMD 格式切片)
EnableNanBox 是否启用 NaN Boxing(高位填 1)
FpFmtMask[4:0] 允许启用的浮点格式枚举(FP64/32/16/BF16/FP8)
IntFmtMask[3:0] 允许的整数格式(INT8/16/32/64)

FPU_IMPLEMENTATION

配置项 描述
PipeRegs 每个功能块的流水级数配置
UnitTypes 每个功能块选择 Parallel 或 Merged 实现
PipeConfig 流水化架构(集中在输入 / 集中在输出 / 分布式)

2.2 输入信号

端口 方向 描述
operands_i[2:0] input 3 个输入操作数(NaN boxing 后)
op_i input 操作类型(ADDMUL / DIVSQRT / COMP / CONV)
op_mod_i input 操作修饰符(如 ADD 中 =1 表示减法)
src_fmt_i input 输入格式(FP/BF16/INT)
dst_fmt_i input 输出格式
rnd_mode_i input 舍入模式(默认 RNE)
vectorial_op_i input 是否启用向量操作(SIMD 模式)
in_valid_i input 输入事务有效
tag_i input 标签
clk_i input 时钟

2.3 输出信号

端口 方向 描述
result_o output 浮点结果
status_o output 浮点状态标志
tag_o output 与 tag_i 对应
out_valid_o output 输出有效
in_ready_o output FPU 是否准备接受新指令
busy_o output FPU 是否忙碌(如 DIVSQRT 迭代中)

2.4 使用样例

FPU 的核心配置如下所示,以 BF16 的运算为例,这里的配置信号会决定具体的 fpnew 硬件实现方式。

localparam fpnew_pkg::fpu_features_t FPU_FEATURES = '{
      Width:         WIDTH,
      EnableVectors: 1'b1,
      EnableNanBox:  1'b1,     // 开启 NaN Boxing
      // Enable Format {FP16ALT,FP8,FP16,FP64,FP32}
      FpFmtMask:     5'b11111, // All FP format enabled
      // Enable Format {INT64,INT32,INT16,INT8}
      IntFmtMask:    4'b1111   // All INT format enabled
  };
  localparam fpnew_pkg::fpu_implementation_t FPU_IMPLEMENTATION = '{
      PipeRegs: '{
          // ADDMUL: 
          '{default: 2}, 
          // DIVSQRT
          '{default: 5},
          // NONCOMP
          '{default: 1},
          // CONV
          '{default: 1}
      },
      UnitTypes: '{
          '{default: fpnew_pkg::PARALLEL}, // ADDMUL
          '{default: fpnew_pkg::MERGED},   // DIVSQRT
          '{default: fpnew_pkg::PARALLEL}, // NONCOMP
          '{default: fpnew_pkg::MERGED}    // CONV
      },
      PipeConfig: fpnew_pkg::DISTRIBUTED
  };

如上实例化 FPU 之后,可以通过如下的方式驱动 FPU 进行计算。

  // Task to drive BF16 operations (Handles NaN boxing automatically)
  task send_bf16_op(
      input [15:0]                op_a_bf16,
      input [15:0]                op_b_bf16,
      input [15:0]                op_c_bf16,
      input fpnew_pkg::operation_e op,
      input logic                 op_mod,
      input int                   tag_id
  );
      begin
          // NaN Boxing: Fill upper 48 bits with 1s
          operands_i[0]  <= {48'hFFFF_FFFF_FFFF, op_a_bf16};
          operands_i[1]  <= {48'hFFFF_FFFF_FFFF, op_b_bf16};
          operands_i[2]  <= {48'hFFFF_FFFF_FFFF, op_c_bf16};
          op_i           <= op;               // Operation
          op_mod_i       <= op_mod;           // ADD时 =1表示减法
          // BF16 is typically mapped to FP16ALT in fpnew
          src_fmt_i      <= fpnew_pkg::FP16ALT; 
          dst_fmt_i      <= fpnew_pkg::FP16ALT;
          int_fmt_i      <= fpnew_pkg::INT64; // Don't care
          rnd_mode_i     <= fpnew_pkg::RNE;   // Round Nearest Even
          tag_i          <= tag_id;
          vectorial_op_i <= 1'b0;             // 是否为向量操作
          in_valid_i     <= 1'b1;

          do begin
              @(posedge clk_i);
          end while (in_ready_o == 1'b0);
          in_valid_i     <= 1'b0;

          do begin
              @(posedge clk_i);
          end while (busy_o == 1'b1);
      end
  endtask
需要注意的是,即使在硬件实现为向量实现,在实际使用过程中仍然可以向下兼容选择进行标量操作。但是进行标量的除法和开根操作时,FPU 会因等待没有进行操作的其他 lane 操作结束而进入死循环中,所以建议在向量化实现的 FPU 中将 fpnew_opgroup_multifmt_slice.sv:422 行更改为:

assign simd_synch_done = (EnableVectors && vectorial_op) ? &divsqrt_done  : divsqrt_done[0];

3. 集成至 RISC-V 处理器中

3.1 ISA 扩展与编译器配置

在 RISC-V 指令集中,体系结构根据基础位宽(RV32 / RV64)支持的扩展指令组合而成,例如:

  • RV32I
  • RV64I
  • RV64IM
  • RV64IMT
  • RV64IMFD
  • RV64GC(常见通用配置)

这些名称中的字母代表 CPU 所支持的扩展功能。

扩展字母 代表的功能 / 含义
I 基础整数指令集(必备)
M 整数乘除扩展(Mul/Div)
A 原子指令(Atomic)
F 单精度浮点(Float 32-bit)
D 双精度浮点(Double 64-bit)
C Compressed 压缩指令(16-bit,提升代码密度)

为了确保编译器能正确生成 F/D 浮点、整数、压缩等指令,需要在构建 riscv-gnu-toolchain 时配置:

GCC_CONFIGURE_OPTS="\
    --prefix=$PREFIX \
    --target=$TARGET \
    --enable-languages=c \
    --disable-libssp \
    --disable-libgomp \
    --disable-libmudflap
    --with-arch=rv64gc \
    --with-abi=lp64d \
    --enable-multilib"

其中

--with-arch=rv64gc
--with-abi=lp64d 
对应启用 RV64 + IMAFD + C,并且使用包含 Double 的 ABI(支持 F/D 浮点)

应用层编译也需要明确 ISA 扩展,否则可能出现 illegal instruction,即:

$(RISCV_GCC) -march=rv64gc -mabi=lp64d ...

3.2 CVA6 硬件配置

在将 C 代码编译为包含浮点指令的指令流之后,需要对 CVA6 RISC-V CPU 进行相应的硬件配置,以确保处理器能够正确识别并执行浮点指令。相关配置主要集中在三个位置:
- cva6_config_pkg:在此处启用 FPU,包括 FPU Enable、Vector Enable 以及各浮点格式(如 FP64/FP32/FP16/BF16 等)的独立使能开关,使得硬件层面允许这些格式的浮点运算;
- soc.sv:在 SoC 顶层的 CVA6 config 字段中进一步开启 FPU 相关选项,使能处理器内部的浮点单元,使其在系统集成时能够被正常调度与访问;
- fpu_wrap.sv:通过修改 FPU_FEATURESFPU_IMPLEMENTATION 两个参数,对 FPU 的具体硬件结构进行灵活配置,包括是否允许向量模式、FP 格式掩码、流水线级数、并行/合并结构等,从而确定最终浮点单元的微架构实现。

由于一般应用中 FP 指令只占全部指令流的一小部分,CVA6 默认不会对每条指令都启用浮点译码,而是要求软件在执行 FP 指令前通过 CSR 指令设置 FS 标志位,以显式允许浮点指令译码;而在 FP 指令执行完成的 commit 阶段,CPU 会自动清除该标志,使译码器再次屏蔽浮点路径。

如果编译器并未针对这个特性进行过定制化的优化,则需要在所有的浮点指令前手动插入配置 CSR 指令,增加使用成本。对于对功耗不敏感、且需要频繁使用 FP 指令的场景,可以在硬件上将浮点译码逻辑始终保持开启,在 cva6.sv:508id_stagefs_i 信号直接拉高,即可避免所有软件层面的 CSR 控制,简化整体流程。

Page Authors: Rick0423 (96.69%), Bwoah-Kimi (3.31%)