2026/10/29 19:16:28

用AI Agent辅助搭建QEMU RISC-V AI芯片实验台:从零到RVV验证

用AI Agent辅助搭建QEMU RISC-V AI芯片实验台:从零到RVV验证 一台还没有拿到手的 AI 芯片、一个能用软件模拟出来的指令集、一个会自己写命令的 AGENT——这三样东西组合在一起就成了我这几天一直在折腾的事用 AGENT 做 QEMU 环境搭建拉起一块 RISC-V AI 芯片的实验台。实际操作下来其实就是让 AI Agent 帮我生成、执行和修正一套能在 x86 电脑上模拟 RISC-V 虚拟机的完整流程。文章不打算写成教程式复读机而是把整个“人和 Agent 配合搭环境”的过程摊开讲哪些决策交给 Agent 没问题哪些必须自己判断以及最后这台“模拟芯片”到底能干什么。如果你手上没有 RISC-V 开发板又想提前跑 AI 推理栈、摸一摸向量扩展指令这篇应该能帮你省下不少时间。开始之前我默认你用的是 Ubuntu 22.04 或同类发行版并且知道终端怎么开后面所有操作都围绕系统级 QEMU 模拟展开。1. 选型逻辑RISC-V AI 芯片为什么值得用 QEMU 先“拉起”很多人听到“AI 芯片实验台”就以为得买开发板、接 JTAG、调驱动。实际上在架构早期验证阶段虚拟化模拟往往是性价比最高的选择。RISC-V 是一个开放指令集架构AI 芯片厂商通常会在标准 RISC-V 基础上扩展向量指令RVV这一点 QEMU 从 7.0 开始已经能做得比较完整。用 QEMU 拉起一块虚拟 RISC-V 芯片不需要等待流片不需要布板子改一行模拟参数就能改变 CPU 核数、内存大小、向量长度这种灵活性是真实硬件很难给的。另一个原因是整个软件栈的验证需要“先跑起来再说”。交叉编译器、内核镜像、根文件系统、AI 推理运行时这些组件如果直接放在真实芯片上出了问题很难判断是硬件还是软件的问题。QEMU 的-machine virt会生成一套标准的虚拟设备树提供 virtio 总线、串口、网卡、磁盘等于给 RISC-V Linux 一个“标准开发板”。系统能不能启动、驱动能不能加载、向量指令能不能算出正确结果全在可控的日志范围里这比在纸上推演靠谱得多。我这次的目标很明确在 x86 主机上用 QEMU 跑一个 riscv64 的完整 Linux 系统然后在这个系统里验证 RVV 向量指令的加法和点积运算作为后续跑 AI 算子的基线。至于 PyTorch、llama.cpp 这类重量级框架属于实验台“通电”之后的下一步不会在第一篇里硬塞。2. Agent 接手第一步让 AI Agent 先出依赖树和版本矩阵搭 QEMU 环境最烦的不是 QEMU 本身而是它背后一连串依赖和版本匹配问题。我一开始就决定让 AGENT 出方案。我先把主机的信息喂给 Agentuname -a、lsb_release -a、gcc --version、内存/磁盘情况然后给一条明确指令。我现在在 x86_64 Ubuntu 22.04 上想搭建一个面向 RISC-V AI 实验的 QEMU 系统级模拟环境。 目标 - 模拟器为 QEMU 7.2riscv64 softmmu - 能启动最新 Linux 6.x 内核 - 支持 RISC-V Vector Extension v1.0 - 虚拟机内要能运行交叉编译的 C 程序 请输出 1. 依赖包清单apt 安装 2. QEMU 源码编译参数建议 3. 内核/根文件系统获取方案 4. 虚拟机启动命令模板Agent 给出的第一版方案很标准安装ninja-build, pkg-config, libglib2.0-dev, libpixman-1-dev, libslirp-dev下载 QEMU 源码然后用--target-listriscv64-softmmu配置。这些都没问题但有两处我需要亲自修正。第一Agent 默认让我直接用发行版仓库的 QEMU版本是 6.2。这个版本虽然能跑 RISC-V但对 RVV 1.0 的支持不完整跑向量指令会偶尔报Illegal instruction。所以我坚持从源码编译 QEMU版本选 8.1因为从这一版开始-cpu max才能完整暴露v扩展。第二Agent 给的依赖包里漏掉了python3-venv和zlib1g-dev。前者在后续构建 Buildroot 时需要后者是编译 QEMU 时slirp网络后端必需的。这说明 Agent 给依赖树依赖的是训练数据里的通用答案并不能感知你本机已经装了什么、缺什么。让 Agent 出“版本矩阵”可以但真正的“依赖校验”必须靠命令实测。2.1 版本矩阵怎么定这里我让 Agent 生成了一张对照表然后自己标出优先级组件版本/分支选择原因QEMU8.1.0 源码编译RVV 1.0 支持完整virt 板型稳定Buildroot2024.02 LTS一条命令生成内核根文件系统省去手工制作Linux Kernel6.6.xBuildroot内置virt 平台支持好AI 所需动态库兼容性高交叉工具链riscv64-buildroot-linux-gnu-gcc由 Buildroot 内部生成避免手工配置 sysroot目标运行时静态编译的 RVV C 程序先验证指令通路再逐步叠加 AI 框架这个矩阵并不是 Agent 直接给我的而是它提供了初稿我根据“AI 实验台”目标做了两处替换一是内核版本不能太新太新设备树变化多二是工具链不单独装 Linaro 版直接用 Buildroot 内置工具链保证后续 rootfs 和内核的 ABI 一致。3. 真正动手编译 QEMU三条命令和一次参数修正依赖装好之后编译过程反而没什么好讲的。真正有意思的是参数调整。git clone https://gitlab.com/qemu-project/qemu.git -b v8.1.0 cd qemu ./configure --target-listriscv64-softmmu --enable-slirp --disable-werror make -j$(nproc)这里--disable-werror是我自己加的。Agent 给的原始命令没有这一项但在 Ubuntu 22.04 上编译 QEMU 8.1会遇到一些头文件告警被当作错误的情况加上这一项可以避免无谓中断。--enable-slirp则是为了启用 user-mode 网络让虚拟机可以通过 NAT 访问外网方便后面apt安装软件。第一次跑完 configureAgent 建议我直接qemu-system-riscv64 -machine virt -cpu rv64启动但我拒绝了因为我希望虚拟芯片暴露完整的 AI 向量能力。查阅资料后我在启动参数里加了如下 CPU 描述qemu-system-riscv64 \ -machine virt \ -cpu rv64,vtrue,vext_specv1.0 \ -smp 4 -m 4G \ -nographic \ ...补充说明一下QEMU 不同版本对 RISC-V CPU 属性的写法并不一致。8.1 版本里用-cpu rv64,vtrue,vext_specv1.0能打开标准向量扩展但到了更早的 7.2你可能得写成-cpu rv64,x-vtrue。如果实在不确定直接qemu-system-riscv64 -cpu help看当前支持哪些扩展属性别盲信 Agent 给的参数。这个坑我后面还会具体说。3.1 为什么用 virt 板型而不是 sifive_uAgent 第一次给出的参数用的是-machine sifive_u。这板子比较接近真实 SiFive 硬件但它的设备树是固定的外设数量和内存上限都受限。我改用了virt。virt是 QEMU 给 RISC-V 设计的通用虚拟平台类似 ARM 下的virt优点是会自动生成设备树通过 PCIe 和 virtio 接入外设Linux 主线内核对它支持最完善。对 AI 实验台来说我们后期可能要挂大内存、加模拟 NPU 设备virt的扩展性明显更好。3.2 编译完先跑一次“空系统”编译完成后不要急着找内核先用无内核方式检查模拟器能起来qemu-system-riscv64 -machine virt -cpu rv64,vtrue,vext_specv1.0 -m 256M -nographic这条命令会进入 QEMU monitor显示(qemu)提示符说明模拟器本身没毛病。这个时候按Ctrl-a x退出。很多人一上来就放内核结果有问题分不清是内核还是 QEMU 配置问题先验证模拟器就打好了地基。4. 给虚拟机一块能跑 AI 的“芯”内核与根文件系统QEMU 模拟的是硬件本身里面还得有操作系统。这里我选了 Buildroot因为手工配内核.config再下载压缩 rootfs 太容易踩版本冲突的坑。Buildroot 对 QEMU virt 平台有现成支持一条命令就能生成Image内核镜像和rootfs.ext2。git clone https://github.com/buildroot/buildroot.git -b 2024.02 cd buildroot make qemu_riscv64_virt_defconfig make -j$(nproc)这一步会跑挺久主要是编译交叉工具链和内核。完成后在output/images/下能看到ImageLinux 内核镜像RISC-V 64 位vmlinuz 格式rootfs.ext2最小根文件系统包含 busybox 和基础工具fw_dynamic.elfOpenSBI 固件这里有个概念不能省RISC-V Linux 的启动过程和 ARM 不一样需要 OpenSBI 作为机器模式固件把系统切换到管理员模式再引导内核。QEMU virt 板型可以使用-bios default让 QEMU 自动加载自带的 OpenSBI也可以指定 Buildroot 生成的fw_dynamic.elf。实测下来用-bios default最省事但如果你要调试 SBI 层就必须指定自己的固件。然后启动命令变成qemu-system-riscv64 \ -machine virt \ -cpu rv64,vtrue,vext_specv1.0 \ -smp 4 -m 4G \ -kernel Image \ -drive filerootfs.ext2,formatraw,ifvirtio \ -append root/dev/vda rw consolettyS0 \ -netdev user,idnet0 \ -device virtio-net-device,netdevnet0 \ -nographic启动后看到Buildroot login:时用root登录Buildroot 默认 root 无密码。进去先跑一句uname -a如果输出riscv64 GNU/Linux说明虚拟芯片已经点亮了。4.1 host 与 guest 之间怎么传文件后面要在虚拟机里跑 AI 验证程序必然涉及文件传输。最简单稳定的是用 QEMU 的 virtfs 9p 共享目录比网络 SSH 省事。启动命令里加上-virtfs local,path/home/user/riscv-share,mount_taghostshare,security_modelnone虚拟机内挂载mkdir /mnt/share mount -t 9p -o transvirtio,version9p2000.L hostshare /mnt/share这样宿主机上交叉编译好的二进制文件放到共享目录guest 里直接就能执行。9p 在虚拟化里性能一般但传几个小测试程序完全够用。4.2 交叉编译第一个 RVV 程序要验证 AI 芯片最关心的向量计算能力我写了一个很小的 RISC-V Vector C 程序做两个长度 128 的浮点数组加法。Buildroot 工具链在output/host/bin/下我用它静态编译// rvv_add.c #include riscv_vector.h #include stdio.h #include stdint.h void vec_add(float *a, float *b, float *c, int n) { size_t vl vsetvlmax_e32m1(); for (size_t i 0; i n; i vl) { vl vsetvl_e32m1(n - i); vfloat32m1_t va vle32_v_f32m1(a i, vl); vfloat32m1_t vb vle32_v_f32m1(b i, vl); vfloat32m1_t vc vfadd_vv_f32m1(va, vb, vl); vse32_v_f32m1(c i, vc, vl); } } int main() { int n 128; float a[128], b[128], c[128]; for (int i 0; i n; i) { a[i] i * 0.5f; b[i] i * 1.5f; } vec_add(a, b, c, n); printf(c[127] %f\n, c[127]); return 0; }编译output/host/bin/riscv64-buildroot-linux-gnu-gcc -O2 -marchrv64gcv -mabilp64d -static rvv_add.c -o rvv_add然后把rvv_add放到共享目录进 guest 执行。得到c[127] 254.000000和预期一致。这一步意味着 RISC-V 向量扩展从 CPU 模拟到工具链再到用户态程序整条链路已经打通。这就是“AI 芯片实验台”最底层的通电测试。5. 踩坑实录三个差点让我放弃的问题和完整排查链路搭建过程不可能一帆风顺这里把三个卡我最久的问题列出来每个都附上排查思路方便你日后对照。5.1 坑一QEMU 8.1 上 RVV 程序报 Illegal instruction第一次在 guest 里跑rvv_add直接Illegal instruction (core dumped)。我第一反应是交叉编译参数错了但程序在 Buildroot 生成的 qemu user-mode 下又能跑。后来我把 guest 的/proc/cpuinfo拉出来看isa: rv64imafdc注意没有v。问题不在编译器在 QEMU 的 CPU 模型设置。我的启动参数写了-cpu rv64,vtrue但 guest 里内核看到的 ISA 还是没带v。排查中发现QEMU 8.1 里vtrue属性需要在-cpu时同时指定vext_spec否则内部会把向量扩展降级为“无”。把参数改成-cpu rv64,vtrue,vext_specv1.0后再次查看/proc/cpuinfoisa变成了rv64imafdc_v。Agent 在这一步给了方向但具体属性写法是我通过对比不同版本文档确认的所以排错时不要把 Agent 输出当最终答案。5.2 坑二rootfs 加载后一直 kernel panic那是一开始最让人崩溃的现象内核起来了但挂载 rootfs 时直接 panic日志最后一行写着VFS: Unable to mount root fs on unknown-block(254,0)问题出在-drive ifvirtio的启动参数和root/dev/vda对不上。Buildroot 生成的 rootfs.ext2 默认是 ext2 格式但 virtio 块设备在 Linux 里的命名要看内核配置。我一开始用-drive filerootfs.ext2,formatraw,ifnone再手动加-device virtio-blk-device,drivehd0设备名就变成了/dev/vdb。所以要么保持简单在-drive里直接指定ifvirtio确认为/dev/vda要么就明确建一个 virtio-blk 设备并改 root 参数。我当时反复改了三次才知道是这个映射关系。5.3 坑三user-mode 网络下 apt 更新失败Buildroot 默认 rootfs 的/etc/resolv.conf是空的直接apt update会报 DNS 解析失败。QEMU user-mode 网络的默认网关是10.0.2.2DNS 服务器默认也是10.0.2.3。但 Buildroot 精简系统里根本没写这个配置。手动执行echo nameserver 10.0.2.3 /etc/resolv.conf再配合-netdev user,idnet0后网络就通了。这个坑在于 Agent 生成的启动命令里缺了-netdev user这一整段它默认以为 Buildroot 会自动配置网络实际上精简 rootfs 不会替你配 DNS。6. 实验台的可复现清单与后续还能长成什么样搭建到这里一台“能通电”的 RISC-V AI 实验台已经立起来了。为了让你也快速复现把关键动作收敛成一张清单步骤命令/参数验证方式编译 QEMU 8.1./configure --target-listriscv64-softmmu --enable-slirpqemu-system-riscv64 --version构建 Buildroot 系统make qemu_riscv64_virt_defconfig makeoutput/images/Image存在启动系统带vtrue,vext_specv1.0的启动命令guestuname -a/proc/cpuinfo含_v交叉编译 RVV 程序gcc -marchrv64gcv -staticguest 运行输出c[127]254.0挂载共享目录-virtfs local,path...mount -t 9p成功下一步有两个方向比较值得投入。第一是把整个 virtio 盘换成 SD/NVMe 模拟让 I/O 压力更接近真实 AI 盒子第二是在这里面编译 llama.cpp 或者 ONNX Runtime真正跑一个 0.1B 的小模型。QEMU 的 TCG 模式比原生慢不少但用来做软件栈验证和算法迁移已经足够。我个人在实际操作中的体会是AGENT 能从头到尾给你一套看似完整的方案但“完整”和“正确”之间往往差着一个/proc/cpuinfo。让 Agent 干体力活、生成启动命令、分析 panic 日志把校验和决策留给自己这才是用 AGENT 做环境搭建的正确姿态。等后面真的把 llama.cpp 搬进去我再开一篇把性能数据和踩坑记录补上。