LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

RISC-V:浮点规格、kernel中关于浮点配置和浮点相关流程

 关注RISC-V中浮点配置寄存器、浮点指令,以及Linux内核中浮点相关编译、配置流程、测试工具等。

1 RISC-V规格书关于浮点说明

 RISCV提供了多种浮点扩展,包括单精度浮点(F)、双精度浮点(D)、四倍精度浮点(Q)以及十进制浮点(L)扩展。这些扩展是可选的,可以根据应用场景的需求进行配置和使能。

1.2 机器特征寄存器 CSR_MISA

通过CSR_MISA寄存器可以查询当前处理器是否支持单精度或双精度浮点计算。如果支持其中之一,就表示当前处理器支持浮点计算。可以通过以下指令检查:

 单精度浮点和双精度浮点配置:

 浮点配置判断:

csrr t0, CSR_MISA
andi t0, t0, (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)
beqz t0, out

COMPAT_HWCAP_ISA_F和COMPAT_HWCAP_ISA_D分别代表单精度和双精度浮点支持的标志位。如果t0结果为0,表示不支持浮点计算,跳转到out标签处。

1.2 机器状态寄存器CSR_STATUS

如果机器硬件上支持浮点计算单元,通过CSR_STATUS寄存器可以启用或关闭浮点计算功能。其中,设置相应位就是启动浮点计算功能;清零相应位表示关闭浮点计算功能:

浮点在mstatus寄存器中配置:

FS的不同状态包括:

不同FS状态含义如下:

  1. Off (00):浮点单元处于关闭状态,此时访问浮点相关寄存器会触发非法指令异常。
  2. Initial (01):浮点单元处于初始状态。这个状态表明浮点寄存器包含初始值。
  3. Clean (10):浮点单元处于清洁状态。这意味着自上次修改后浮点寄存器没有变化,但与初始值不同。
  4. Dirty (11):浮点单元处于脏状态。这表明自上次修改后浮点寄存器有变化,需要将这些变化刷新回存储空间中。

FS字段的状态变化通常在操作系统进行上下文切换时非常重要。操作系统可以通过检查FS字段的值来快速判断是否有浮点寄存器的状态需要保存或恢复。

  • Context Save:
    • Dirty状态:需要保存FPU寄存器状态,并在保存后将状态切换为Clean。
    • Off、Init、Clean状态:不需要保存FPU寄存器,状态保持不变。
  • Context Restore:
    • Off状态:无动作。
    • Init状态:可以直接将0加载到FPU寄存器,无需内存加载访问。
    • Clean状态:从保存的内存栈中恢复。
    • Dirty状态:在Context Save时已经切换到Clean状态,因此不存在Dirty状态需要恢复。

配置浮点开关:

li t0, SR_FS
csrs CSR_STATUS, t0   # 启用浮点计算功能
li t0, SR_FS
csrc CSR_STATUS, t0   # 关闭浮点计算功能

SR_FS是CSR_STATUS寄存器中控制浮点状态的位字段。设置这个位可以启用浮点单元,清除这个位可以禁用浮点单元。

1.3 浮点控制状态寄存器 fcsr

浮点控制状态寄存器fcsr用于控制浮点操作的模式和记录异常状态。它可以通过frcsr和fscsr指令访问,这些指令是伪指令,分别用于读取和写入fcsr的值。

 fcsr寄存器中的Rounding Mode用于指定浮点运算的舍入模式。

 1.3.1 浮点异常处理

RISC-V架构的浮点指令在产生结果异常时不会跳转进入异常模式,而是设置fcsr寄存器中的异常标志位。这是RISC-V架构的一个显著特点,可以大幅简化处理器流水线的硬件实现。

Accrued Exception标志位详细说明如下:

  • NV (Invalid Operation):无效操作异常标志位。如果浮点运算单元在运算中出现了无效操作异常,则会将`fcsr`寄存器中的`NV`标志位设置为1。无效操作包括但不限于:
    • 产生非规格化的结果。
    • 0乘以无穷大。
    • Signaling NaN与任何值相乘。
    • 负数的对数。
    • 负数的平方根。
    • 除以零(不包括无穷大除以无穷大)。
  • DZ (Divide by Zero):被0除异常标志位。如果浮点运算单元在运算中遇到了除以零的情况,则会将`fcsr`寄存器中的`DZ`标志位设置为1。
  • OF (Overflow):上溢异常标志位。如果浮点运算结果太大,超出了浮点数能表示的范围,则会将`fcsr`寄存器中的`OF`标志位设置为1。
  • UF (Underflow):下溢异常标志位。如果浮点运算结果太小,低于浮点数能表示的最小非零值,则会将`fcsr`寄存器中的`UF`标志位设置为1。
  • NX (Inexact):不精确异常标志位。如果浮点运算结果需要被舍入,即实际结果与表示结果存在差异,则会将`fcsr`寄存器中的`NX`标志位设置为1。

这些异常标志位是累积的,意味着一旦设置,除非软件显式地将其清零,否则它们会一直保持设置状态。软件可以通过写0的方式单独清除`fcsr`寄存器中的某个异常标志位。这种设计允许软件灵活地处理浮点异常,而不是在每次异常发生时都触发异常处理流程。

1.4 单精度浮点和双精度浮点寄存器和指令

浮点扩展规格说明在《The RISC-V Instruction Set Manual Volume I: Unprivileged ISA》的Chapter 11和Chapter 12。

1.4.1 浮点寄存器

如果包含F(单精度浮点)或D(双精度浮点)扩展,则还有32个独立的浮点寄存器(f0-f31)。

F扩展每个寄存器32位,D扩展每个寄存器64位。
如果处理器同时支持RV32F和RV32D扩展,则单精度数据仅使用f寄存器中的低32位。
控制寄存器:RISCV还有一个浮点控制和状态寄存器fcsr,用于记录或配置浮点运算的状态。

1.4.2 浮点指令

RISCV中单精度和双精度浮点指令的分类及使用方法:

1. 加载/存储指令

FLW (Floatingpoint Load Word):从内存中加载单精度浮点数到浮点寄存器。

flw rd, offset(rs1)

将x[rs1] + sext(offset)处的单精度浮点数加载到f[rd]中。

FLD (Floatingpoint Load Doubleword):从内存中加载双精度浮点数到浮点寄存器。

fld rd, offset(rs1)

将x[rs1] + sext(offset)处的双精度浮点数加载到f[rd]中。

FSW (Floatingpoint Store Word):将单精度浮点数从浮点寄存器存储到内存。

fsw rs2, offset(rs1)

将f[rs2]中的单精度浮点数存储到x[rs1] + sext(offset)处。

FSD (Floatingpoint Store Doubleword):将双精度浮点数从浮点寄存器存储到内存。

fsd rs2, offset(rs1)

将f[rs2]中的双精度浮点数存储到x[rs1] + sext(offset)处。

2. 标准算数指令
FADD.S/D:执行单精度或双精度浮点加法。

fadd.s rd, rs1, rs2
fadd.d rd, rs1, rs2

将f[rs1]与f[rs2]相加,结果存入f[rd]。

FSUB.S/D:执行单精度或双精度浮点减法。

fsub.s rd, rs1, rs2
fsub.d rd, rs1, rs2

将f[rs1]与f[rs2]相减,结果存入f[rd]。

FMUL.S/D:执行单精度或双精度浮点乘法。

fmul.s rd, rs1, rs2
fmul.d rd, rs1, rs2

将f[rs1]与f[rs2]相乘,结果存入f[rd]。

FDIV.S/D:执行单精度或双精度浮点除法。

fdiv.s rd, rs1, rs2
fdiv.d rd, rs1, rs2

将f[rs1]除以f[rs2],结果存入f[rd]。

FSQRT.S/D:执行单精度或双精度浮点平方根。

fsqrt.s rd, rs1
fsqrt.d rd, rs1

计算f[rs1]的平方根,结果存入f[rd]。

3. R4指令(多算数操作指令)
FMADD.S/D:执行单精度或双精度浮点乘加。

fmadd.s rd, rs1, rs2, rs3
fmadd.d rd, rs1, rs2, rs3

将f[rs1]与f[rs2]相乘,并将结果与f[rs3]相加,结果存入f[rd]。

FMSUB.S/D:执行单精度或双精度浮点乘减。

fmsub.s rd, rs1, rs2, rs3
fmsub.d rd, rs1, rs2, rs3

将f[rs1]与f[rs2]相乘,并将结果与f[rs3]相减,结果存入f[rd]。

4. 最大值最小值指令
FMIN.S/D:执行单精度或双精度浮点最小值。

fmin.s rd, rs1, rs2
fmin.d rd, rs1, rs2

取f[rs1]与f[rs2]中的较小值,结果存入f[rd]。

FMAX.S/D:执行单精度或双精度浮点最大值。

fmax.s rd, rs1, rs2
fmax.d rd, rs1, rs2

取f[rs1]与f[rs2]中的最大值,结果存入f[rd]。

5. 比较指令
FEQ.S/D:执行单精度或双精度浮点相等比较。

feq.s rd, rs1, rs2
feq.d rd, rs1, rs2

如果f[rs1]等于f[rs2],则在x[rd]中写入1,否则写入0。

FLT.S/D:执行单精度或双精度浮点小于比较。

flt.s rd, rs1, rs2
flt.d rd, rs1, rs2

如果f[rs1]小于f[rs2],则在x[rd]中写入1,否则写入0。

FLE.S/D:执行单精度或双精度浮点小于等于比较。

fle.s rd, rs1, rs2
fle.d rd, rs1, rs2

如果f[rs1]小于等于f[rs2],则在x[rd]中写入1,否则写入0。

6. 分类指令
FCLASS.S/D:执行单精度或双精度浮点分类。

fclass.s rd, rs1
fclass.d rd, rs1

将表示f[rs1]中浮点数类别的掩码写入x[rd]中。

7. 浮点注入指令
FSGNJ.S/D:执行单精度或双精度浮点符号注入。

fsgnj.s rd, rs1, rs2
fsgnj.d rd, rs1, rs2

使用f[rs1]的值和f[rs2]的符号位构造新的浮点数,结果存入f[rd]。

8. 浮点数与整数之间的转换指令

FCVT.S.W (Floatingpoint Convert to Single from Word):将32位整数转换为单精度浮点数。

fcvt.s.w rd, rs1

将寄存器x[rs1]中的32位二进制补码整数转换为单精度浮点数,结果写入f[rd]中。

FCVT.S.WU (Floatingpoint Convert to Single from Unsigned Word):将32位无符号整数转换为单精度浮点数。

fcvt.s.wu rd, rs1

将寄存器x[rs1]中的32位无符号整数转换为单精度浮点数,结果写入f[rd]中。

FCVT.S.L (Floatingpoint Convert to Single from Long):将64位整数转换为单精度浮点数。

fcvt.s.l rd, rs1

将寄存器x[rs1]中的64位二进制补码整数转换为单精度浮点数,结果写入f[rd]中。

FCVT.S.LU (Floatingpoint Convert to Single from Unsigned Long):将64位无符号整数转换为单精度浮点数。

fcvt.s.lu rd, rs1

将寄存器x[rs1]中的64位无符号整数转换为单精度浮点数,结果写入f[rd]中。

FCVT.W.S (Floatingpoint Convert to Word from Single):将单精度浮点数转换为32位整数。

fcvt.w.s rd, rs1

将寄存器f[rs1]中的单精度浮点数转换为32位二进制补码整数,结果写入x[rd]中。

FCVT.WU.S (Floatingpoint Convert to Unsigned Word from Single):将单精度浮点数转换为32位无符号整数。

fcvt.wu.s rd, rs1

将寄存器f[rs1]中的单精度浮点数转换为32位无符号整数,结果写入x[rd]中。

FCVT.W.D (Floatingpoint Convert to Word from Double):将双精度浮点数转换为32位整数。

fcvt.w.d rd, rs1

将寄存器f[rs1]中的双精度浮点数转换为32位二进制补码整数,结果写入x[rd]中。

FCVT.WU.D (Floatingpoint Convert to Unsigned Word from Double):将双精度浮点数转换为32位无符号整数。

fcvt.wu.d rd, rs1

将寄存器f[rs1]中的双精度浮点数转换为32位无符号整数,结果写入x[rd]中。

9. 单精度与双精度浮点数之间的转换指令

FCVT.S.D (Floatingpoint Convert to Single from Double):将双精度浮点数转换为单精度浮点数。

fcvt.s.d rd, rs1

将寄存器f[rs1]中的双精度浮点数转换为单精度浮点数,结果写入f[rd]中。

FCVT.D.S (Floatingpoint Convert to Double from Single):将单精度浮点数转换为双精度浮点数。

fcvt.d.s rd, rs1

将寄存器f[rs1]中的单精度浮点数转换为双精度浮点数,结果写入f[rd]中。

2 内核关于浮点处理

2.1 内核关于浮点的mabi和march

在arch/riscv/Makefile中定义了RISC-V的-mabi和-march选项:

ifeq ($(CONFIG_ARCH_RV64I),y)
        BITS := 64
        UTS_MACHINE := riscv64

        KBUILD_CFLAGS += -mabi=lp64
        KBUILD_AFLAGS += -mabi=lp64

        KBUILD_LDFLAGS += -melf64lriscv

        KBUILD_RUSTFLAGS += -Ctarget-cpu=generic-rv64 --target=riscv64imac-unknown-none-elf \
                            -Cno-redzone
else
        BITS := 32
        UTS_MACHINE := riscv32

        KBUILD_CFLAGS += -mabi=ilp32
        KBUILD_AFLAGS += -mabi=ilp32--内核编译和链接使用的是ilp32不是ilp32d。
        KBUILD_LDFLAGS += -melf32lriscv
endif
...
# ISA string setting
riscv-march-$(CONFIG_ARCH_RV32I)        := rv32ima
riscv-march-$(CONFIG_ARCH_RV64I)        := rv64ima
riscv-march-$(CONFIG_FPU)               := $(riscv-march-y)fd
riscv-march-$(CONFIG_RISCV_ISA_C)       := $(riscv-march-y)c
riscv-march-$(CONFIG_RISCV_ISA_V)       := $(riscv-march-y)v

2.2 内核启动过程中浮点配置

内核在初始化时,是关闭浮点功能的:

_start_kernel
  li t0, SR_FS
  csrc CSR_STATUS, t0--清除STATUS中FS位,表示关闭浮点功能。

secondary_start_sbi
  li t0, SR_FS
  csrc CSR_STATUS, t0--关闭浮点功能。

 2.3 上下文中保存浮点寄存器

compat_setup_sigcontext -->compat_save_fp_state
copy_process --> dup_task_struct
setup_sigcontext --> save_fp_state
switch_to --> __switch_to_aux
  fstate_save--如果SR_FS为SR_FS_DIRTY,则保存上下文。
    __fstate_save
      li t1, SR_FS
      csrs CSR_STATUS, t1--打开FP功能。
      ...--保存fcsr、f0-f31寄存器。
      csrc CSR_STATUS, t1--关闭FP功能。

compat_restore_sigcontext --> compat_restore_fp_state
start_thread
restore_sigcontext --> restore_fp_state
swtich_to --> __switch_to_aux
  fstate_restore--如果SR_FS不为SR_FS_OFF,则恢复上下文。
    __fsatate_restore
      li t1, SR_FS
      csrs CSR_STATUS, t1--打开FP功能。
      ...--恢复f0-f31、fcsr寄存器。
      csrc CSR_STATUS, t1
    __fstate_clean--设置STATUS寄存器为SR_FS_CLEAN。

flush_thread
  fstate_off--设置STATUS状态为SR_FS_OFF。

 2.4 异常处理中浮点配置

 内核中禁止使用浮点功能:

handle_exception
  _save_context
    li t0, SR_SUM | SR_FS
    csrrc s1, CSR_STATUS, t0--读取STATUS值到s1中,然后关闭STATUS中FS和SUM位。关闭FPU可以检测到内核中非法使用浮点功能。

3 浮点测试工具

 

posted on 2024-11-08 23:59  ArnoldLu  阅读(98)  评论(0编辑  收藏  举报

导航