第二章:开发环境搭建
好,咱们正式开始动手了。这一章我带你把整个开发环境搭起来。说实话,环境搭建这事儿看着琐碎,但要是没弄对,后面调试自定义指令时会让你抓狂。我自己就吃过这个亏——第一次做扩展指令时,工具链版本不对,折腾了两天才发现是编译器不支持新操作码。
这一章我们搞定三样东西:RISC-V GNU工具链、QEMU模拟器、还有Verilator仿真环境。这三样就是你后续开发自定义指令的“三驾马车”。
2.1 RISC-V GNU工具链编译
工具链是什么?说白了就是你把C代码变成RISC-V机器码的那套工具。包括编译器、汇编器、链接器、调试器等等。我们做自定义指令,必须自己编译工具链,因为要告诉编译器:嘿,我新加了一条指令,你得认识它。
2.1.1 获取源码
我建议直接从官方仓库拉代码。别去网上找什么打包好的二进制,版本对不上很麻烦。
git clone https://github.com/riscv-collab/riscv-gnu-toolchain.git
cd riscv-gnu-toolchain
git submodule update --init --recursive
嗯,这里要注意:submodule update这一步会下载很多子模块,包括binutils、gcc、newlib这些。网络不好的话可能会断,我建议用代理或者找个网络好的时间段搞。
2.1.2 配置与编译
配置时有两个选择:Newlib(轻量级C库,适合裸机)和glibc(完整版,适合Linux)。我们做自定义指令开发,用Newlib就够了,编译快很多。
mkdir build && cd build
../configure --prefix=/opt/riscv --with-arch=rv64gc --with-abi=lp64d
make -j$(nproc)
这里--prefix指定安装路径,我习惯装到/opt/riscv。--with-arch=rv64gc表示生成64位、带通用扩展(G)和压缩指令(C)的工具链。--with-abi=lp64d是LP64数据模型加双精度浮点ABI。
-j$(nproc)开启多核并行编译。另外,确保你的系统装了必要的依赖:flex bison autoconf automake libmpc-dev等。
2.1.3 验证安装
编译完成后,把工具链加入PATH:
export PATH=/opt/riscv/bin:$PATH
riscv64-unknown-elf-gcc --version
如果看到版本信息,恭喜你,工具链搞定了。写个简单的测试程序试试:
// test.c
int main() {
int a = 1, b = 2;
return a + b;
}
riscv64-unknown-elf-gcc -o test test.c
riscv64-unknown-elf-objdump -d test
看到RISC-V的汇编指令了吗?嗯,这就是我们后面要扩展的基础。
2.2 QEMU模拟器安装
QEMU是个好东西。你手头没有RISC-V开发板?没关系,QEMU能模拟一个完整的RISC-V系统。我在做自定义指令原型验证时,90%的调试都是在QEMU上完成的。
2.2.1 安装QEMU
我推荐从源码编译,这样能确保支持最新的RISC-V特性。Ubuntu系统上也可以直接apt安装,但版本可能比较老。
git clone https://github.com/qemu/qemu.git
cd qemu
mkdir build && cd build
../configure --target-list=riscv64-softmmu,riscv64-linux-user
make -j$(nproc)
sudo make install
这里--target-list指定了两个目标:riscv64-softmmu(系统模式,模拟完整机器)和riscv64-linux-user(用户模式,直接运行RISC-V程序)。
2.2.2 运行第一个RISC-V程序
用用户模式运行刚才编译的test程序:
qemu-riscv64-static ./test
echo $?
输出应该是3(1+2的结果)。看,没有硬件也能跑RISC-V代码了。
2.3 Verilator仿真环境配置
Verilator是什么?它能把Verilog代码转换成C++,然后编译成可执行文件进行仿真。速度比传统的ModelSim快很多,适合做大规模数字电路的验证。我们后面要设计自定义指令的硬件实现,Verilator是主力工具。
2.3.1 安装Verilator
Verilator依赖一些库,先装好:
sudo apt-get install git make autoconf g++ flex bison
sudo apt-get install libfl-dev libgoogle-perftools-dev
然后从源码编译:
git clone https://github.com/verilator/verilator.git
cd verilator
autoconf
./configure
make -j$(nproc)
sudo make install
验证安装:
verilator --version
看到版本号就对了。我目前用的是5.x版本,功能很全。
2.3.2 第一个Verilator仿真
写个简单的Verilog模块测试一下:
// counter.v
module counter(
input clk,
input rst_n,
output reg [7:0] count
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
count <= 8'b0;
else
count <= count + 1;
end
endmodule
然后写个C++测试文件:
// sim_main.cpp
#include <verilated.h>
#include "Vcounter.h"
int main(int argc, char** argv) {
Verilated::commandArgs(argc, argv);
Vcounter* top = new Vcounter;
for (int i = 0; i < 10; i++) {
top->clk = 0;
top->eval();
top->clk = 1;
top->eval();
printf("count = %d\n", top->count);
}
delete top;
return 0;
}
编译运行:
verilator --cc counter.v --exe sim_main.cpp
make -j -C obj_dir -f Vcounter.mk Vcounter
./obj_dir/Vcounter
看到计数器从0递增到9了吗?嗯,Verilator环境就绪了。
2.4 环境验证与常见问题
三样工具都装好了,我们来个综合测试。写一个简单的RISC-V汇编程序,用工具链编译,QEMU运行,同时用Verilator仿真一个对应的硬件模块。这样就能确认整个链路是通的。
我曾经遇到过一个坑:工具链编译时用了--with-arch=rv64imafdc,但QEMU模拟的CPU不支持D扩展(双精度浮点),结果程序一跑就崩。后来我统一用rv64gc才解决。所以,工具链和模拟器的架构参数一定要匹配。
| 工具 | 用途 | 验证命令 |
|---|---|---|
| GNU工具链 | 编译RISC-V程序 | riscv64-unknown-elf-gcc --version |
| QEMU | 运行RISC-V程序 | qemu-riscv64-static --version |
| Verilator | 仿真Verilog设计 | verilator --version |
好了,环境搭建就到这里。下一章我们开始真正进入自定义指令的设计——从指令编码到硬件实现,一步步来。到时候你会发现,今天搭的环境就是你的“试验田”,所有想法都能在这里快速验证。