2. 开发环境搭建:QEMU、Spike 与 RISC-V GNU 工具链

做 RISC-V 向量开发,第一件事就是把环境搭好。我见过太多人卡在工具链编译上,一卡就是一整天。其实没那么玄乎,今天咱们就把 QEMU、Spike 和 GNU 工具链这三个核心组件捋清楚。

2.1 整体架构:你需要哪几样东西?

说白了,你要跑 RISC-V 向量程序,需要三样东西:

  • 编译器:把 C/C++ 代码编译成 RISC-V 机器码
  • 模拟器:在没有真实芯片时,模拟执行这些机器码
  • 代理内核(PK):提供操作系统级别的服务,比如文件读写、内存管理

它们的关系是这样的:

RISC-V 向量开发环境架构 用户向量程序 RISC-V GNU 工具链 QEMU 系统模拟 Spike + PK 代理内核 执行结果 / 调试输出 执行结果 / 调试输出 QEMU 适合系统级测试,Spike+PK 适合指令级验证和向量性能分析
我的建议:刚开始学向量指令,先用 Spike + PK。它启动快、调试方便。QEMU 等你要跑完整 Linux 系统时再用。

2.2 安装 RISC-V GNU 工具链

工具链是基础。我个人习惯从源码编译,虽然慢一点,但能保证版本可控。你也可以用发行版自带的包管理器,但版本可能比较老。

2.2.1 从源码编译

# 克隆仓库
git clone --recursive https://github.com/riscv-collab/riscv-gnu-toolchain
cd riscv-gnu-toolchain

# 配置(支持向量扩展)
./configure --prefix=/opt/riscv --with-arch=rv64gcv

# 编译(多核加速)
make -j$(nproc)

# 安装到 /opt/riscv
make install

这里 --with-arch=rv64gcv 是关键。g 代表通用扩展,c 是压缩指令,v 就是咱们要的向量扩展。少了 v,编译器不会生成向量指令。

注意:编译工具链需要 8GB 以上内存,磁盘空间至少 10GB。我曾经在 4GB 的虚拟机上编译,结果 swap 撑爆了,系统直接卡死。

2.2.2 验证安装

装完后,检查一下版本:

/opt/riscv/bin/riscv64-unknown-elf-gcc --version
/opt/riscv/bin/riscv64-unknown-elf-objdump -d  # 反汇编用

如果能正常输出版本号,说明工具链装好了。接下来写个简单的向量程序测试一下:

// test_v.c
#include <riscv_vector.h>
#include <stdio.h>

int main() {
    float a[4] = {1.0, 2.0, 3.0, 4.0};
    float b[4] = {5.0, 6.0, 7.0, 8.0};
    float c[4];

    size_t vl = vsetvl_e32m1(4);
    vfloat32m1_t va = vle32_v_f32m1(a, vl);
    vfloat32m1_t vb = vle32_v_f32m1(b, vl);
    vfloat32m1_t vc = vfadd_vv_f32m1(va, vb, vl);
    vse32_v_f32m1(c, vc, vl);

    for (int i = 0; i < 4; i++)
        printf("c[%d] = %f\n", i, c[i]);
    return 0;
}
# 编译
/opt/riscv/bin/riscv64-unknown-elf-gcc -O2 -march=rv64gcv -o test_v test_v.c

# 用 Spike 运行
spike pk test_v

输出应该是 c[0]=6.0, c[1]=8.0, c[2]=10.0, c[3]=12.0。嗯,向量加法跑通了。

2.3 配置 Spike 模拟器与 PK 代理内核

Spike 是 RISC-V 官方的指令集模拟器,轻量、精确。PK(Proxy Kernel)是个迷你操作系统内核,负责处理系统调用。

2.3.1 编译 Spike

git clone https://github.com/riscv-software-src/riscv-isa-sim
cd riscv-isa-sim
mkdir build && cd build
../configure --prefix=/opt/riscv
make -j$(nproc)
make install

2.3.2 编译 PK

git clone https://github.com/riscv-software-src/riscv-pk
cd riscv-pk
mkdir build && cd build
../configure --prefix=/opt/riscv --host=riscv64-unknown-elf
make -j$(nproc)
make install
避坑指南:PK 的 --host 参数必须和你工具链的前缀一致。我见过有人用 riscv64-linux-gnu 编译 PK,但工具链是 riscv64-unknown-elf,结果链接时报错,折腾了半天。

2.3.3 Spike 的常用参数

参数 说明 示例
-p<n> 模拟 n 个处理器核 spike -p4 pk a.out
-l 记录指令日志 spike -l pk a.out
--isa=rv64gcv 指定 ISA 扩展 spike --isa=rv64gcv pk a.out
-d 进入交互式调试模式 spike -d pk a.out

我个人最常用 -l 来调试向量指令。它会打印每条指令的 PC、指令编码和寄存器状态,对理解向量指令的执行流程特别有帮助。

2.4 配置 QEMU 系统模拟

QEMU 能模拟完整的 RISC-V 系统,包括外设、中断控制器、定时器等。适合跑 Linux 内核和复杂的多进程程序。

2.4.1 编译 QEMU

git clone https://github.com/qemu/qemu
cd qemu
mkdir build && cd build
../configure --target-list=riscv64-softmmu --prefix=/opt/qemu
make -j$(nproc)
make install

--target-list=riscv64-softmmu 只编译 RISC-V 64 位的系统模拟器,省时间。如果你还要用户态模拟,可以加上 riscv64-linux-user。

2.4.2 启动 QEMU 运行 Linux

# 下载 OpenSBI 和 Linux 内核
wget https://github.com/riscv-software-src/opensbi/releases/...
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/...

# 启动
/opt/qemu/bin/qemu-system-riscv64 \
  -machine virt \
  -cpu rv64,v=true \
  -m 2G \
  -kernel opensbi.bin \
  -append "root=/dev/vda ro" \
  -drive file=rootfs.img,format=raw,id=hd0 \
  -device virtio-blk-device,drive=hd0 \
  -nographic

这里 -cpu rv64,v=true 是开启向量扩展的关键。不加这个,QEMU 默认的 CPU 模型不支持向量指令。

关键点:QEMU 的向量支持在 7.0 版本之后才比较完善。如果你用旧版本,跑向量程序可能会报 "illegal instruction"。建议用 8.0 以上版本。

2.5 两种方案的对比与选择

对比项 Spike + PK QEMU 系统模拟
启动速度 毫秒级 秒级(加载内核)
指令精确度 完全精确 动态翻译,略有偏差
向量支持 完整(v1.0) 完整(v1.0)
调试能力 内置调试器 需配合 GDB
适用场景 指令验证、性能分析 系统级测试、驱动开发

我的建议是:前期学向量指令用 Spike,后期做项目集成测试用 QEMU。两个都装,不冲突。

2.6 环境验证清单

装完所有东西后,跑一遍这个清单,确保环境没问题:

  1. 工具链:riscv64-unknown-elf-gcc -v 能输出版本
  2. Spike:spike -v 能输出版本
  3. PK:spike pk /bin/true 不报错
  4. 向量编译:用 -march=rv64gcv 编译向量程序能通过
  5. QEMU:qemu-system-riscv64 --version 输出版本
小技巧:把 /opt/riscv/bin 加到 PATH 里,省得每次敲全路径。我在 .bashrc 里加了 export PATH=/opt/riscv/bin:$PATH,用起来方便多了。

环境搭好了,接下来就可以真正开始写向量代码了。记住,环境问题是最容易卡住人的,但也是最不值得花时间的——一次配好,后面就顺畅了。