本篇开始一个新的系列—-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了!
评论前必须登录!
注册