RISC-V嵌⼊式开发⼊门篇1:RISC-VGCC⼯具链的介绍
随着国内第⼀本RISC-V中⽂书籍《⼿把⼿教你设计CPU——RISC-V处理器篇》正式上市,越来越多的爱好者开始使⽤开源的蜂鸟E203 RISC-V处理核,很多初学者留⾔询问有关RISC-V⼯具链使⽤的问题,因此本将开始陆续发表若⼲篇有关RISC-V软件⼯具链使⽤的⽂章,包括:
RISC-V嵌⼊式开发⼊门篇2:RISC-V汇编语⾔程序设计
RISC-V嵌⼊式开发上⼿篇:基于HBird-E-SDK平台的软件开发与运⾏
RISC-V嵌⼊式开发实践篇:运⾏开源蜂鸟E200 MCU更多⽰例程序
RISC-V嵌⼊式开发新奇篇:基于Windows Eclipse IDE的软件开发与运⾏
RISC-V嵌⼊式开发升华篇:基于开源蜂鸟E200 MCU移植RTOS
本⽂为RISC-V嵌⼊式开发⼊门篇1:RISC-V GCC⼯具链的介绍。
本⽂的⽬的是对RISC-V GCC⼯具链进⾏简单的中⽂科普与介绍。
注:本⽂⼒求通俗易懂,主要⾯向初学者,对RISC-V GCC⼯具链有所了解的读者可以忽略此⽂。
1 RISC-V GCC⼯具链种类
在本号上次发表的⽂章《编译过程简介》中已经介绍了通⽤的GCC⼯具链,RISC-V GCC⼯具链与普通的GCC⼯具链基本相同,⽤户可以遵照开源的riscv-gnu-toolchain项⽬(请在Github中搜索riscv-gnu-toolchain)中的说明⾃⾏⽣成全套的GCC⼯具链。
由于GCC⼯具链⽀持各种不同的处理器架构,因此不同处理器架构的GCC⼯具链会有不同的命名。遵循GCC⼯具链的命名规则,当前RISC-V GCC⼯具链有如下⼏个版本:
以“riscv64-unknown-linux-gnu-”为前缀的版本,譬如riscv64-unknown-linux-gnu-gcc、riscv64-unknown-linux-gnu-gdb、riscv64-unknown-linux-gnu-ar等。具体的后缀名称与《编译过程简介》中描述的GCC、GDB和Binutils⼯具相对应。
“riscv64-unknown-linux-gnu-”前缀表⽰该版本的⼯具链是64位架构的Linux版本⼯具链。注意:此Linux不是指当前版本⼯具链⼀定要运⾏在Linux操作系统的电脑上,此Linux是指该GCC⼯具链会使⽤Linux的Glibc作为C运⾏库,请参见《编译过程简介》了解Glibc的更多信息。
同理,“riscv32-unknown-linux-gnu-”前缀的版本则是32位架构。
注意:此处的前缀riscv64(还有riscv32的版本)与运⾏在64位或者32位电脑上毫⽆关系,此处的64和
32是指如果没有通过-march和-mabi选项指定RISC-V架构的位宽,默认将会按照64位还是32位的RISC-V架构来编译程序。有关-march和-mabi选项的含义,请参见第3节。
以“riscv64-unknown-elf-”为前缀的版本,则表⽰该版本为⾮Linux(Non-linux)版本的⼯具链。注意:
此Non-Linux不是指当前版本⼯具链⼀定不能运⾏在Linux操作系统的电脑上,此Non-Linux是指该GCC⼯具链会使⽤newlib作为C运⾏库,请参见本号上次发表的⽂章《嵌⼊式开发特点》中了解newlib的更多信息。
同上理,此处的前缀riscv64(还有riscv32的版本)与运⾏在64位或者32位电脑上毫⽆关系,此处的64和32是指如果没有通过-march和-mabi选项指定RISC-V架构的位宽,默认将会按照64位还是32位的RISC-V架构来编译程序。有关-march和-mabi 选项的含义,请参见第3节。
以“riscv-none-embed-”为前缀的版本,则表⽰是最新为裸机(bare-metal)嵌⼊式系统⽽⽣成的交叉编译⼯具链,所谓裸机(bare-metal)是嵌⼊式领域的⼀个常见形态,表⽰不运⾏操作系统的系统。该版本使⽤新版本的newlib作为C运⾏库,并且⽀持newlib-nano,能够为嵌⼊式系统⽣成更加优化的代码体积(Code Size)。开源的蜂鸟E203 MCU系统是典型的嵌⼊式系统,因此将使⽤“riscv-none-embed-”为前缀的版本作为RISC-V GCC交叉⼯具链。注意:
此版本编译器由于使⽤newlib和newlib-nano作为C运⾏库,所以必须对 newlib底层的桩函数进⾏移植,否则⽆法正常使⽤调⽤底层桩函数的C函数(譬如printf会调⽤write桩函数)。
关于Newlib和newlib-nano及其桩函数,请参见本号上次发表的⽂章《嵌⼊式开发特点》中了解更多信息。
2 riscv-none-embed⼯具链下载
电影源代码免费观看对于riscv-none-embed版本的⼯具链⽽⾔,为了⽅便⽤户直接使⽤预编译好的⼯具链,Eclipse开源社区会定期更新发布最新版本的预编译好的RISC-V嵌⼊式GCC⼯具链,包括Windows版本和Linux版本。请在⾕歌中搜索“releases gnu-mcu-eclipse/riscv-none-gcc”进⼊⽹页下载Windows版本或者Linux版本,如图1中所⽰。对于Linux和Windows版本均只需在相应的操作系统中解压即可使⽤。
图1 riscv-none-embed⼯具链下载链接
新天龙八部字体颜代码3 RISC-V GCC⼯具链的(–march=)和(–mabi=)选项
3.1 (–march=)选项
由于RISC-V的指令集是模块化的指令集,因此在为⽬标RISC-V平台进⾏交叉编译之时,需要通过选项指定⽬标RISC-V平台所⽀持的模块化指令集组合,该选项为(-march=),有效的选项值如下:
rv32i[m][a][f[d]][c]
rv32g[c]
rv64i[m][a][f[d]][c]
rv64g[c]
注意:在上述选项中rv32表⽰⽬标平台是32位架构,rv64表⽰⽬标平台是64位架构,其他i/m/a/f/d/c/g分别代表了RISC-V模块化指令⼦集的字母简称。请参见RISC-V中⽂书籍《⼿把⼿教你设计CPU——RISC-V处理器篇》中附录A.1节中关于RISC-V架构指令集的详细中⽂介绍。
本节后⽂会介绍(-march=)选项使⽤的具体实例。
3.2 (–mabi=)选项
由于RISC-V的指令集是模块化的指令集,因此在为⽬标RISC-V平台进⾏交叉编译之时,需要通过选项指定嵌⼊式RISC-V⽬标平台所⽀持的ABI函数调⽤规则(有关ABI函数调⽤规则的相关信息请参见RISC-V中⽂书籍《⼿把⼿教你设计CPU——RISC-V处理器篇》中附录A的图A-1)。RISC-V定义了两种整数的ABI调⽤规则和三种浮点ABI调⽤规则,通过选项(-abi=)指明,有效的选项值如下:
ilp32
ilp32f
ilp32d
lp64
lp64f
lp64d
注意:
在上述选项中两种前缀(ilp32和lp64)表⽰的含义如下:
前缀ilp32表⽰⽬标平台是32位架构,在此架构下,C语⾔的“int”和“long”变量长度为32⽐特,“long long”变量为64位;
前缀lp64表⽰⽬标平台是64位架构,C语⾔的“int”变量长度为32⽐特,⽽“long”变量长度为64⽐特。
RISC-V的32位和64位架构下更多的数据类型宽度如图2中所⽰。
图2 RISC-V的32位和64位架构下的数据类型宽度
上述选项中的三种后缀类型(⽆后缀、后缀f、后缀d)表⽰的含义如下:
⽆后缀:在此架构下,如果使⽤了浮点类型的操作,直接使⽤RISC-V浮点指令进⾏⽀持。但是当浮点数作为函数参数进⾏传递之时,⽆论单精度浮点数还是双精度浮点数均需要通过存储器中的堆栈进⾏传递。
f:表⽰⽬标平台⽀持硬件单精度浮点指令。在此架构下,如果使⽤了浮点类型的操作,直接使⽤RISC-
V浮点指令进⾏⽀持。但是当浮点数作为函数参数进⾏传递之时,单精度浮点数可以直接通过寄存器传递,⽽双精度浮点数需要通过存储器中的堆栈进⾏传递。
d:表⽰⽬标平台⽀持硬件双精度浮点指令。在此架构下,如果使⽤了浮点类型的操作,直接使⽤RISC-V浮点指令进⾏⽀持。当浮点数作为函数参数进⾏传递之时,⽆论单精度还是双精度浮点数都可以直接通过寄存器传递。
本节后⽂会介绍(-mabi=)选项使⽤的具体实例。
3.3 (–march=)和(–mabi=)不同选项编译实例
为了便于读者更加形象地理解(-march=)和(-mabi=)选项的具体含义,下⾯以⼀个实例加以介绍。
假设有⼀段C语⾔函数代码,如下所⽰:
//这是⼀个名为dmul的函数,其有两个参数,为double类型的双精度浮点数
double dmul(double a,double b){
return b * a;
}
如果使⽤-march=rv64imafdc -mabi=lp64d的选项组合进⾏编译,则会⽣成如下汇编代码:
$ riscv64-unknown-elf-gcc test.c -march=rv64imafdc -mabi=lp64d -o- -S -O3
//所⽣成的汇编代码如下,从中可以看出,浮点数乘法操作直接使⽤了RISC-V的fmul.d指令进⾏⽀持,且函数的两个double类型的参数直接使⽤浮点通⽤寄存器fa0和fa1进⾏传递。这是因为:
-    -march选项指明了⽬标平台⽀持的模块化指令⼦集为imafdc,其中包含了F和D指令⼦集,即⽀持单精度和双精度浮点指令,因此可以直接使⽤RISC-V的浮点指令来⽀持浮点数的操作。
-    -mabi选项指明了后缀“d”,表⽰当浮点数作为函数参数进⾏传递之时,⽆论单精度还是双精度浮点数都可以直接通过寄存器传递。
dmul:
fmul.d  fa0,fa0,fa1
ret
如果使⽤-march=rv32imac -mabi=ilp32的选项组合进⾏编译,则会⽣成如下汇编代码:
$ riscv64-unknown-elf-gcc test.c -march=rv32imac -mabi=ilp32 -o- -S -O3
//所⽣成的汇编代码如下,从中可以看出,浮点数乘法操作由C库函数(__muldf3)进⾏⽀持,这是因为:
-    -march选项指明了⽬标平台⽀持的模块化指令⼦集为I/M/A/C,其中未包含了F和D指令⼦集,即不⽀持单精度和双精度浮点指令,因此⽆法直接使⽤RISC-V 的浮点指令来⽀持浮点数的操作。
dmul:
mv      a4,a2
mv      a5,a3
add    sp,sp,-16
mv      a2,a0
mv      a3,a1
mv      a0,a4
mv      a1,a5
sw      ra,12(sp)
call    __muldf3
lw      ra,12(sp)
add    sp,sp,16
jr      ra
如果使⽤-march=rv32imafdc -mabi=ilp32的选项组合进⾏编译,则会⽣成如下汇编代码:
$ riscv64-unknown-elf-gcc test.c -march=rv32imafdc -mabi=ilp32 -o- -S -O3
//所⽣成的汇编代码如下,从中可以看出,浮点数乘法操作直接使⽤了RISC-V的fmul.d指令进⾏⽀持,但是函数的两个浮点类型的参数均通过堆栈进⾏的传递,这是因为:
-
    -march选项指明了⽬标平台⽀持的模块化指令⼦集为I/M/A/F/D/C,其中包含了F和D指令⼦集,即⽀持单精度和双精度浮点指令,因此可以直接使⽤RISC-V 的浮点指令来⽀持浮点数的操作。
-    -mabi选项指明了“⽆后缀”,表⽰当浮点数作为函数参数进⾏传递之时,⽆论单精度还是双精度浮点数都需要通过堆栈进⾏传递。
dmul:
add    sp,sp,-16    //对堆栈指针寄存器(sp)进⾏调整,分配堆栈空间
sw      a0,8(sp)    //将函数参数寄存器a0中的值存⼊堆栈
sw      a1,12(sp)    //将函数参数寄存器a1中的值存⼊堆栈
fld    fa5,8(sp)    //从堆栈中取回双精度浮点操作数
sw      a2,8(sp)    //将函数参数寄存器a2中的值存⼊堆栈
sw      a3,12(sp)    //将函数参数寄存器a3中的值存⼊堆栈
fld    fa4,8(sp)    //从堆栈中取回双精度浮点操作数
fmul.d  fa5,fa5,fa4  //调⽤RISC-V的浮点指令进⾏运算
java的类是啥fsd    fa5,8(sp)    //将计算结果存回堆栈
lw      a0,8(sp)      //通过堆栈将结果赋值给函数结果返回寄存器a0
lw      a1,12(sp)    //通过堆栈将结果赋值给函数结果返回寄存器a1
add    sp,sp,16      //对堆栈指针寄存器(sp)进⾏调整,回收堆栈空间
jr      ra
如果使⽤-march=rv32imac -mabi=ilp32d的选项组合进⾏编译,则会报⾮法错误:
$ riscv64-unknown-elf-gcc test.c -march=rv32imac -mabi=ilp32d -o- -S -O3
cc1: error: requested ABI requires -march to subsume the 'D' extension
//从中可以看出报⾮法错误,这是因为:
-    -march选项指明了⽬标平台⽀持的模块化指令⼦集为I/M/A/C,其中未包含了F和D指令⼦集,即不⽀持单精度和双精度浮点指令,因此⽆法直接使⽤RISC-V 的浮点指令来⽀持浮点数的操作。linux操作系统书籍
-    -mabi选项指明了后缀“d”,表⽰⽬标平台⽀持硬件浮点指令。这⼀点与-march选项中指明的指令集⼦集产⽣了冲突。
3.4 (–march=)和(–mabi=)选项合法组合
c语言函数返回数组指针虽然(–march=)和(–mabi=)选项理论上可以组成很多种不同的组合,但是⽬前并不是所有的(–march=)和(–mabi=)选项组合都是合法,⽬前的riscv-none-embed⼯具所⽀持的组合如下:
march=rv32i/mabi=ilp32
march=rv32ic/mabi=ilp32
march=rv32im/mabi=ilp32
march=rv32imc/mabi=ilp32
march=rv32iac/mabi=ilp32
march=rv32imac/mabi=ilp32
march=rv32imaf/mabi=ilp32f
march=rv32imafc/mabi=ilp32f
march=rv32imafdc/mabi=ilp32f
march=rv32gc/mabi=ilp32f
march=rv64imac/mabi=lp64
march=rv64imafdc/mabi=lp64d
march=rv64gc/mabi=lp64d
注意:上述有效组合来⾃于本⽂撰写时的信息。随着时间推移,新发布的riscv-none-embed⼯具可能会⽀持更多的组合,请读者以其最新的发布说明(Release Notes)为准。
>自动生成6位数

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。