RISC-V IDE MRS2 代码编译 : 通过配置FPU提升浮点运算性能

0 阅读5分钟

本文介绍嵌入式中的浮点数与青稞系列芯片的FPU硬件浮点单元,并说明如何使用MRS2配置FPU提升浮点性能以及串口打印浮点数。

一、单精度浮点数与双精度浮点数

嵌入式处理器使用的浮点数遵循 IEEE 754 标准。这套标准规定了一种将实数编码为有限位二进制的方式,其核心思想是把一个数分解为三个独立的字段:符号位(Sign)、指数位(Exponent)和尾数位(Mantissa)。这三个字段在内存中是紧密排列的。

 = (−1)^S  ×  2^(E − bias)  ×  (1 + Mantissa)

浮点数一般根据其占用的位宽度分为单精度浮点数(float)与双精度浮点数(double)。其在内存中的布局如下所示。

图片4.png

单精度float占用 4 字节,能够提供约 7 位有效十进制数的精度,数值范围覆盖 ±3.4×10³⁸。双精度double则占用 8 字节,精度提升到约 15~16 位,范围扩展到 ±1.7×10³⁰⁸。从数学上看,double显然更精确,但在嵌入式领域,精度优势无法弥补它花费的巨大开销,优先使用float才是更好的选择。

二、浮点数常量

嵌入式开发中浮点数有一个非常容易被忽视的细节。

C 语言里所有不带后缀的浮点字面量,比如0.01、3.14,其类型默认是double而不是float 。

例如一个简单的浮点计算并赋值的代码:

float x = 3.14 * 2.0;

3.14和2.0都没有f后缀,所以编译器会把这两个常量都当作double来处理。由于赋值给float变量,因此在以double运算后编译器会进行一次截断,将64位运算结果截断为32位的float。

还有一种混合的情况:

float x = 3.14f * 2.0;

3.14添加了f后缀,显式定义为float常量,2.0未加f后缀,依然默认为double常量。C 语言规定,当 float 和 double 混合运算时,float 那一方会被隐式提升为 double,然后以 double 精度完成乘法,最后再截断回 float。也就是说,只要包含一个未加后缀的操作数,表达式就会以double进行运算。

建议给所有浮点数添加后缀f显式声明其为float常量。

float x = 3.14f * 2.0f;

此时由于全部操作数都为float,表达式会以float进行运算。在使用软件浮点库中的函数进行运算时似乎与使用double没有太大差别,但当芯片内置支持单精度运算的硬件浮点单元(FPU)时,float运算会有巨大的提升。

三、FPU 硬件浮点单元

FPU(Floating Point Unit,浮点运算单元)是处理器中专门用于执行浮点数运算的硬件模块。利用软件浮点库进行浮点运算时,调用相关的浮点运算函数进行模拟,一般需要十几到几十条指令才能完成。而在FPU的帮助下,加法、乘法等基础浮点运算可以在单个时钟周期内完成,极大提高浮点运算效率。

WCH部分芯片支持FPU,例如青稞V3F\V5F内核芯片(CH32H416、CH32H415、CH32H417)和青稞V4F内核芯片(CH32V303、CH32V305、CH32V307、CH32V317)。以上型号支持RISC-V F指令集,拥有F0-F31共32个浮点寄存器,用于存储单精度浮点指令所需数据。

使用MRS2开发时,通过几步配置即可使用芯片的FPU提高浮点运算性能。

  1. 勾选浮点扩展与ABI

打开工程配置Build Settings->Tool Settings->Target Processor页面:

Floating point选择Single precision extension**(R****VF)**单精度浮点扩展;

Floating point ABI选择**Single precision(f)**单精度浮点。

     2. 勾选浮点优化选项

打开工程配置Build Settings->Tool Settings->****Optimization页面

勾选Single precision constants**(-fsingle-precision-constant****)**选项。

开启这个选项之后,会将源码里所有不带后缀的浮点常量强制当作float来处理,效果等同于在每一个浮点常量后手动加了f。可确保浮点运算为单精度,充分利用FPU硬件浮点单元提高浮点运算性能。

四、浮点数打印

嵌入式开发环境一般默认使用裁剪过的C库(如newlib-nano),出于代码体积考虑,printf的实现删去了浮点格式化的支持。如果直接调用printf("%.2f", val) ,串口浮点数输出为空。

若需通过串口打印浮点数,需要链接相应的浮点打印库。

MRS2中通过勾选链接选项,选择合适的浮点打印库,即可在串口打印浮点数。

打开工程配置Build Settings->Tool Settings->****GNU RISC-V Cross Linker->Miscellaneous页面。

勾选Use float with nano printf**(-u _printf_float)**会使用标准库newlib-nano中的浮点打印函数,支持更全面的输出格式,相应的链接库体积会稍大;

勾选Use **wchprint****float(-lprintfloat)**会使用MRS提供的精简浮点打印函数,仅保留常用的输出格式,能够有效减小代码体积。

同时,**Use wchprintfloat(-lprintfloat)**还可支持64位数据打印。

根据自身需求选择合适的选项即可。推荐使用Use wchprintfloat选项,基本可满足常见浮点打印格式需求,且代码体积优势较为明显。