云计算百科
云计算领域专业知识百科平台

RISC-V芯片开发的工具系列 -- 1. RISC-V交叉编译器

本篇开始一个新的系列—-RISC-V芯片开发的工具系列。本篇从RISC-V交叉编译器看起。显然,这需要Linux环境了,本次使用的是Ubuntu 24.04 LTS版本。

前面的项目,基于RISC-V的全套指令集,使用Chisel语言,编写了单周期指令架构处理器(Single Cycle Processor)和五级流水线架构处理器(5 Stage Pipeline Processor),并使用自行构造的指令序列进行了测试,包括在五级流水线架构的芯片上通过指令之间插入空指令来模拟“指令空泡”、解决流水线架构中的数据冒险的问题。

这种手工构造指令序列的方式,用来炼手还是很好的,包括对指令集的各字段的熟悉。但是,这毕竟太原始了,对于更多指令的构造,太繁琐了。这也是为什么前面只能构造Load*6 + Add*5 + Store*1的指令集合,没有对更多的指令进行测试。更简单的方式,显然是使用 {高级语言 + 编译器} 编译出RISC-V指令序列并能对Chisel/Verilog编写的RISC-V处理器芯片进行测试!从软件世界到硬件世界“打通”!

通常,RISC-V的交叉编译器都是推荐使用riscv-gnu-toolchain来构造。然而,riscv-gnu-toolchain是一个巨大的“全家桶”,很容易在某一个步骤卡住!为此,需要对这个全家桶拆开、化整为零,锚定RISC-V交叉编译器这一个事情去做。

RISC-V的交叉编译器,需要两个项目,一个是riscv-binutils-gdb,另一个是riscv-gcc。在编译的时候,需要先编译前者,并把前者的二进制执行文家加入到PATH路径中,然后编译后者。下面是本次编译的记录:

1、新建一个目录:

chipcamp@ChipCamp:~/src$ mkdir riscv-gcc-minimal2

chipcamp@ChipCamp:~/src$ cd riscv-gcc-minimal2

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$

2、下载riscv-binutils和riscv-gcc两个库!分别有2.4G和875M之多!

国内镜像地址1:git clone https://gitee.com/mirrors/riscv-binutils-gdb.git

国内镜像地址2:git clone https://gitee.com/mirrors/riscv-gcc.git

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ git clone https://gitee.com/mirrors/riscv-gcc.git

Cloning into 'riscv-gcc'…

remote: Enumerating objects: 2812555, done.

remote: Total 2812555 (delta 0), reused 0 (delta 0), pack-reused 2812555 (from 1)

Receiving objects: 100% (2812555/2812555), 1.47 GiB | 14.62 MiB/s, done.

Resolving deltas: 100% (2196240/2196240), done.

Updating files: 100% (100556/100556), done.

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ git clone https://gitee.com/mirrors/riscv-binutils-gdb.git

Cloning into 'riscv-binutils-gdb'…

remote: Enumerating objects: 1006156, done.

remote: Total 1006156 (delta 0), reused 0 (delta 0), pack-reused 1006156 (from 1)

Receiving objects: 100% (1006156/1006156), 390.38 MiB | 14.09 MiB/s, done.

Resolving deltas: 100% (841657/841657), done.

Updating files: 100% (37128/37128), done.

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ du -h –max-depth=1

2.4G ./riscv-gcc

875M ./riscv-binutils-gdb

3.3G .

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ du -h –max-depth=0 ./riscv-gcc/.git

1.6G ./riscv-gcc/.git

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ du -h –max-depth=0 ./riscv-binutils-gdb/.git

425M ./riscv-binutils-gdb/.git

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$

3、查各个依赖库!

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev

//具体输出略!

—-》这一步骤很容易被忽视但实际非常重要。被忽视是想着出错以后再来按需安装,但是一旦忘记以后再出错就更难想起来了,因为缺少这些基础工具以后的出错提示会很难看懂,会走到其它定位路径上去!非常消耗时间。

—-》想起来在编译gcc的过程中,因为flex, texinfo, bison等没有安装,编译过程先后发现多个错误,然后再逐一安装,还是没有解决问题,进而怀疑–with-newlib这个配置选项是否意味着gcc依赖newlib在先编译,于是转到newlib的下载编译和安装上去了。

—-》而newlib的编译又提示依赖riscv64-unknown-elf-cc,于是怀疑newlib和gcc之间存在循环依赖!当然还有其它问题,解决问题过程中大概又又又安装了一些库。

—-》无数次试错以后,又回到了binutils + gcc的编译上来了,结果gcc的编译成功了!不依赖newlib(但configure的时候要加上–with-newlib)。如本文所述。

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$

4、首先对binutils进行编译!

—-套路1:为binutils创建目录/opt/binutils2,以及为项目编译创建./build目录!

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ cd riscv-binutils-gdb/

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-binutils-gdb$ sudo mkdir /opt/binutils2

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-binutils-gdb$ mkdir build

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-binutils-gdb$ cd build

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-binutils-gdb/build$ ../configure –prefix=/opt/binutils2 –target=riscv64-unknown-elf –disable-multilib –disable-gdb –disable-sim

//具体输出省略。

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-binutils-gdb/build$ make 2>&1 | tee build.log

//具体输出略!这个make的套路是使用tee build.log以及2>&1,这样可以将日志含错误都输出到stdout上并且通过管道符号给tee,tee会打印到2个地方—-1是stdout另一个是build.log!

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-binutils-gdb/build$ sudo make install

//具体输出略!但是随后可以查看到这些文件都生成了!

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-binutils-gdb/build$ ls -l /opt/binutils2/

drwxr-xr-x 2 root root 4096 Aug 14 13:26 bin

drwxr-xr-x 3 root root 4096 Aug 14 13:26 lib

drwxr-xr-x 4 root root 4096 Aug 14 13:26 riscv64-unknown-elf

drwxr-xr-x 5 root root 4096 Aug 14 13:26 share

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-binutils-gdb/build$ export PATH=$PATH:/opt/binutils2/bin

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-binutils-gdb/build$

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-binutils-gdb/build$ which riscv64-unknown-elf-objdump

/opt/riscv-binutils/bin/riscv64-unknown-elf-objdump

5、其次对gcc进行编译!

—-套路1:为binutils创建目录/opt/binutils2,以及为项目编译创建./build目录!

—-套路2:在已经构建过的目录下重新构建要make clean + rm build + 重新mkdir build!

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-binutils-gdb/build$ cd ../../riscv-gcc

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc$ sudo mkdir /opt/riscv-gcc2

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc$ mkdir build

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc$ cd build

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc/build$ ../configure –prefix=/opt/riscv-gcc2 \\

> –target=riscv64-unknown-elf \\

–disable-multilib \\

–disable-shared \\

–disable-threads \\

–enable-languages=c \\

–without-headers \\

–with-newlib \\

–with-system-zlib=no

//具体输出略!!

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc/build$ make 2>&1 | tee build.log

//套路同上,包括使用2>&1和tee build.log两个!

//这部分输出省略。—-出错了!!重新来但需要改变configure!!幸亏此前保留了配置。

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc/build$ cd ..

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc$ rm -rf build

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc$ mkdir build

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc$ cd build

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc/build$ cat ~/riscv-gcc-buildcmd.txt

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc/build$

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc/build$ ../configure –target=riscv64-unknown-elf –prefix=/opt/riscv-gcc2 –enable-languages=c –with-newlib –with-sysroot=/opt/riscv-gcc/riscv64-unknown-elf –with-gnu-as –with-gnu-ld –disable-shared –disable-threads –disable-nls –disable-libssp –disable-libgomp –disable-libquadmath –with-arch=rv64imac –with-abi=lp64

//这里省略。

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc/build$ make 2>&1 | tee build.log

//套路同上,使用tee!编译成功!

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc/build$ sudo make install

//安装!可以看到编译成功了!!至此,把整个编译过程又重新跑了一遍。

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc/build$ ls -l /opt/riscv-gcc2

drwxr-xr-x 2 root root 4096 Aug 14 13:57 bin

drwxr-xr-x 2 root root 4096 Aug 14 13:57 include

drwxr-xr-x 3 root root 4096 Aug 14 13:57 lib

drwxr-xr-x 3 root root 4096 Aug 14 13:57 libexec

drwxr-xr-x 4 root root 4096 Aug 14 13:57 share

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc/build$

####相对原来它们分别增加了1.1G和205M的大小,在build的目录下!这大概也是使用build目录的原因!!

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2/riscv-gcc/build$ cd ../../

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ du -h –max-depth=1

3.5G ./riscv-gcc

1.1G ./riscv-binutils-gdb

4.6G .

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ du -h –max-depth=0 ./riscv-gcc/build

1.1G ./riscv-gcc/build

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ du -h –max-depth=0 ./riscv-binutils-gdb/build

205M ./riscv-binutils-gdb/build

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$

####在安装目录下的大小如下:

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ du -h –max-depth=0 /opt/riscv-gcc2

498M /opt/riscv-gcc2

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$ du -h –max-depth=0 /opt/binutils2

82M /opt/binutils2

chipcamp@ChipCamp:~/src/riscv-gcc-minimal2$

6、上面的步骤编译的是riscv64-unknown-elf-xxx。还需要编译riscv32-unknown-elf-xxx,使用如下的步骤巩固一下:

riscv-binutils-gdb:下列第一个是riscv64的,第二个则是riscv32的。

../configure –prefix=/opt/binutils2 –target=riscv64-unknown-elf –disable-multilib –disable-gdb –disable-sim

../configure –prefix=/opt/binutils2 –target=riscv32-unknown-elf –disable-multilib –disable-gdb –disable-sim

riscv-gcc:下列第一个是riscv64的,第二个是riscv32的。

../configure –target=riscv64-unknown-elf –prefix=/opt/riscv-gcc2 –enable-languages=c –with-newlib –with-sysroot=/opt/riscv-gcc2/riscv64-unknown-elf –with-gnu-as –with-gnu-ld –disable-shared –disable-threads –disable-nls –disable-libssp –disable-libgomp –disable-libquadmath –with-arch=rv64imac –with-abi=lp64

../configure –target=riscv32-unknown-elf –prefix=/opt/riscv-gcc2 –enable-languages=c –with-newlib –with-sysroot=/opt/riscv-gcc2/riscv32-unknown-elf –with-gnu-as –with-gnu-ld –disable-shared –disable-threads –disable-nls –disable-libssp –disable-libgomp –disable-libquadmath

第一次编译的时候要解决可能出现的错误,因此使用 make 2>&1 | tee build.log。

第二次编译的时候可以使用make -j 8来加速编译了!

7、编译出来的可执行文件:

riscv-gcc编译出来的可执行文件

riscv-binutils-gdb编译出来的可执行文件:

8、使用交叉编译器

—-编译器(C语言编译为汇编.S)

—-汇编器(.S汇编为.o)

—-链接器(.o链接为.elf)

—-ELF转化为bin(ELF是有OS的可执行文件,bin是裸机可执行文件,两者注意区别TBD)。

—-bin转换为hex(就是在此前的chisel系列代码中使用的hex,是二进制文件的可读表达,在chisel代码中加载为CPU寄存器和存储器中的代码时又变为了二进制指令序列)。

—-elf转换为dump(同样也是二进制的可读表达,包含了比hex要多的元信息)。

 

各文件的格式如下:

9、看一下同一个test.c使用riscv64和riscv32编译出来的RISC-V汇编代码有什么不同?

从C代码到汇编代码,以及汇编代码对照RISC-V指令手册进行解读,要放在后面TBD了!

赞(0)
未经允许不得转载:网硕互联帮助中心 » RISC-V芯片开发的工具系列 -- 1. RISC-V交叉编译器
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!