
上个月评估一颗还没量产的 RISC-V AI 芯片手边没有开发板也没有完整 BSP只有一份零零散散的芯片手册。我的第一反应是先用 QEMU 搭一个模拟实验台把交叉工具链、Linux 内核、AI 推理流程全部在虚拟机里跑通。这次和以往不太一样的地方是我把一部分环境搭建工作交给了 AI Agent 去做——让 Agent 帮我出方案、生成启动脚本、分析编译报错。整个过程走完Agent 确实帮我省了不少检索文档的时间但也埋了几个坑尤其是启动参数那种细节错误差点让我误判是环境问题。这篇文章就把完整过程记录一遍从为什么要搭模拟实验台、怎么用 Agent 协作者手到 QEMU 启动参数拆解、PyTorch 软件栈落地最后是实测踩坑和排查思路。内容偏实操适合正在评估 RISC-V AI 芯片、或者想在真机到手前先把软件环境准备好的开发者参考。1. 为什么是模拟实验台而不是直接买板子1.1 一块 AI 芯片的开发成本账先说成本。我要评估的这颗芯片官方开发板售价折合人民币两千多供货周期还要八周左右。更大的问题是时间成本——很多 RISC-V AI 芯片还在流片验证阶段BSP 和 SDK 更新非常频繁年前拿到的驱动可能跟年后 SDK 就不配套了。如果每改一个版本就要烧一次板子、重新跑一遍环境调试一个启动问题可能等半天甚至好几天。模拟实验台的逻辑完全不一样。QEMU 跑在普通 x86 电脑上开虚拟机、关虚拟机、重置系统都在分钟级完成环境搞坏了从快照恢复或者从头重建都很快。它意味着我可以在芯片还没量产之前就把 Linux 内核、Python 工具链、AI 推理链路全部调通芯片 SDK 一到手就能直接在真机上接力而不是从零开始。这个价值在团队协作里更明显。同一份 QEMU 环境可以通过脚本分发到每台开发机新同学加入直接跑一个脚本就有完整的 RISC-V AI 开发环境不用折腾半天。1.2 QEMU 能模拟到什么程度别把 QEMU 当万能仿真器。它模拟的是标准 RISC-V 指令集和一套通用的 virt 虚拟平台不是某个厂商芯片的完整 SoC。AI 芯片上通常还有 NPU、DSP、ISP 这类专用加速器这些在 QEMU 里都不存在。模拟实验台真正能依赖的是 CPU 侧的标准向量扩展RVV以及完整 Linux 系统能提供的一切软件栈。我用一个比喻来理解这件事模拟器就像游戏机模拟器你可以在 PC 上跑通游戏的绝大部分内容但联机对战、体感外设这类依赖特定硬件的能力模拟器永远赶不上真机。放在芯片评估的场景里正确的策略是先在 QEMU 里把 RVV 算法和 PyTorch 推理链路验证清楚再针对真实硬件的 NPU 和专用指令做适配而不是指望模拟器替你验证芯片的所有特性。QEMU 的 virt 平台对 Linux 主线内核支持极好virtio 磁盘、virtio 网卡这些设备都是主线自带的驱动不需要厂商 BSP 就能启动一个干净的 Linux 发行版。这让模拟实验台特别适合做软件栈开发、算法验证和 CI 回归而不适合做硬件时序和性能评估。2. 让 Agent 先干活环境搭建的任务拆分2.1 我给 Agent 的提示词把模糊需求翻译成工程指令AI Agent 要上手干活第一步必须把需求说清楚。我这次没有直接说帮我搭 QEMU 环境而是给了一个包含五条硬性约束的提示词你是一名资深嵌入式工程师。请帮我规划在 x86_64 Ubuntu 22.04 上 用 QEMU 搭建一个 RISC-V 64 位 AI 实验台的完整步骤。要求 1. 使用 qemu-system-riscv64 系统态模拟不讨论用户态方案 2. 内核从源码交叉编译必须启用 RISC-V 向量扩展 3. 根文件系统使用 Ubuntu riscv64 rootfs 或 Buildroot二选一说明理由 4. 最终环境需要能安装 Python 3.10 和 PyTorch CPU 版 5. 给出每一步的具体命令以及在启动失败时优先检查什么。 请先给整体方案再给逐步操作。这么写的目的是逼着 Agent 先出架构思路再落具体命令。如果只丢一句帮我搭 QEMU 环境它大概率会返回一个泛泛的通用教程里面混杂着 x86 方案、ARM 方案最后你也不知道该执行哪条。约束条件给得越明确Agent 的产出越接近可执行状态。Agent 给了一份三步走的计划先交叉编译内核再用 Buildroot 制作根文件系统最后启动系统验证。整体方向是对的但它给的启动命令里有一个致命问题这个我留在第 5 章专门讲。2.2 Agent 产出物哪些直接用、哪些必须扔拿到 Agent 的回复我没有直接复制粘贴跑。先做三件事核对 QEMU 版本号确认参数是否对应当前版本核对内核 config 和 rootfs 格式是否匹配把关键的启动命令先在宿主机上用--help验证一遍。实际遇到的情况是Agent 给出的 CPU 参数用的是老版本写法在 QEMU 8.2 上直接启动失败提示找不到属性。原因很典型Agent 的知识库里混着不同版本的配置它自己并不会区分 QEMU 8.0 和 QEMU 8.2 的差异。它能生成看起来头头是道的文档但没办法替你做版本兼容性判断。所以我对 Agent 的使用定位很明确它是资料检索和草稿生成器不是验证器。真正关键的启动参数、内核 config、编译选项一定以官方文档和实测结果为准。所有 Agent 给的命令都要经过一次真实执行验证才能进版本库。3. QEMU 核心链路工具链、内核与根文件系统3.1 装对 QEMU 与交叉工具链先说 QEMU 版本选择。Ubuntu 自带仓库的 QEMU 版本偏老如果只是跑老教程里的命令可能够用但要开 RISC-V 向量扩展、用新版 virt 平台特性建议源码编译一份新版。我这次用的是 QEMU 8.2.2。交叉编译工具链直接用 apt 安装就行sudo apt install gcc-riscv64-linux-gnu装完执行riscv64-linux-gnu-gcc -v确认版本。我这边是 12.x编译 Linux 6.6 内核没有问题。如果后续编译某个库时报不支持的指令错误优先怀疑工具链版本太老升级工具链比瞎改编译参数靠谱。QEMU 源码编译需要一些依赖完整命令如下sudo apt install git build-essential glib2.0-dev libfdt-dev \ libpixman-1-dev zlib1g-dev ninja-build wget https://download.qemu.org/qemu-8.2.2.tar.xz tar xf qemu-8.2.2.tar.xz cd qemu-8.2.2 ./configure --target-listriscv64-softmmu,riscv64-linux-user --prefix/opt/qemu make -j $(nproc) sudo make install export PATH/opt/qemu/bin:$PATH--target-list这里我同时编译了两种模式riscv64-softmmu是系统态模拟riscv64-linux-user是用户态模拟。两个模式后面都会用到——系统态用来跑完整 Linux用户态用来快速跑单个交叉编译好的程序后者比启动一整个虚拟机快一个数量级。3.2 交叉编译内核对齐向量扩展内核源码我 checkout 了 Linux 6.6 LTS交叉编译命令如下git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git cd linux git checkout v6.6.30 make ARCHriscv CROSS_COMPILEriscv64-linux-gnu- defconfig scripts/config --enable CONFIG_RISCV_ISA_V make ARCHriscv CROSS_COMPILEriscv64-linux-gnu- -j$(nproc)编译产物是arch/riscv/boot/Image。网上有些教程会让你用Image.gzQEMU 两种格式都能加载我直接用 Image少一层解压逻辑启动速度略快。CONFIG_RISCV_ISA_V是 RISC-V 向量扩展的总开关release 版内核的 defconfig 默认不一定会开启它所以我在配置阶段专门用scripts/config强制打开。确认方式很简单编译完成后去.config文件里搜索CONFIG_RISCV_ISA_Vy。这一步漏掉的话后面 CPU 里开了向量属性内核也不一定能正确识别。编译时间参考8 核宿主机纯编译 Linux 6.6 大约 15 到 20 分钟。如果编译报错多半是工具链版本和内核版本不匹配建议先make clean再重新编译不要在一个脏的编译目录里反复折腾。3.3 根文件系统的三种路线选择根文件系统我试过三种方式各有取舍整理成表格方式优点缺点适用场景Ubuntu riscv64 rootfs包管理完整apt 直接装 Python、PyTorch 依赖体积大模拟器启动慢AI 软件栈开发推荐Buildroot定制强、体积小、启动快每加一个包几乎都要重新编译嵌入式产品原型手搓 busybox完全可控教学效果好缺依赖跑 AI 软件栈太痛苦学习内核启动机制我最开始用的 Buildroot 快速验证内核能不能启动因为它一条命令就能构建出内核加 rootfs 加 busyboxgit clone https://github.com/buildroot/buildroot.git cd buildroot make qemu_riscv64_virt_defconfig makeBuildroot 的产物在output/images/下包含Image、rootfs.ext4、fw_dynamic.bin。它的问题是可选的软件包太少Python 和 PyTorch 相关包维护不全所以验证完内核启动之后我立刻切换到 Ubuntu rootfs 作为正式的 AI 实验台。Ubuntu rootfs 可以用 debootstrap 手动制作也可以直接下载现成的 riscv64 cloud 镜像。我这里给出 debootstrap 的思路sudo apt install debootstrap qemu-user-static sudo debootstrap --archriscv64 noble /mnt/riscv-rootfs https://mirrors.ubuntu.com注意RISC-V 64 位的 Ubuntu port 目前不算完全成熟部分软件包可能缺失或滞后但用它装 Python 3.12 和 PyTorch 的编译依赖已经足够了。3.4 启动参数逐项拆解这是整个实验台最关键的部分。我最终使用的启动命令如下qemu-system-riscv64 \ -M virt \ -cpu rv64,vtrue,vlen256 \ -smp 4 \ -m 8G \ -kernel Image \ -append root/dev/vda rw consolettyS0 earlycon \ -drive filerootfs.ext4,formatraw,idhd0 \ -device virtio-blk-device,drivehd0 \ -netdev user,idnet0 \ -device virtio-net-device,netdevnet0 \ -nographic逐项解释为什么要这样组合-M virt选择通用 RISC-V virt 机器。这是 QEMU 和 Linux 主线共同维护的虚拟平台virtio 设备支持最完善。用-M sifive_u或-M spike会遇到外设不匹配的问题有些网卡驱动根本没挂上。-cpu rv64,vtrue,vlen256CPU 模型是rv64打开向量扩展vtrue向量寄存器长度设 256 位。vlen256这个参数在 virt 平台上实测可以生效。-smp 4 -m 8G四核八 GB 内存。这个配置在模拟器里跑小型编译任务不会立刻内存溢出但性能远不如物理机。-kernel Image直接加载内核镜像不需要额外的引导固件。-append root/dev/vda rw consolettyS0 earlycon根文件系统放在 virtio 块设备上内核日志输出到串口earlycon让启动早期就能看到打印信息排错时很管用。-drive配合-device virtio-blk-device加载 rootfs 镜像。-netdev user配合-device virtio-net-device使用用户态网络虚拟机通过 NAT 访问外网。-nographic无图形界面串口直接绑定当前终端。如果你是第一次启动建议把-nographic换成-serial mon:stdio这样可以通过特殊按键在 QEMU 监控器和串口终端之间切换排查问题更方便。等系统里配好 SSH 之后再改回-nographic。4. 塞进 PyTorchAI 软件栈的落地顺序4.1 先保证 Python 工具链干净系统起来之后先用uname -a确认内核和架构。正常会看到类似这样的输出Linux virt 6.6.30-gd5f1d1e6c783 #1 SMP ... riscv64 GNU/Linux然后执行cat /proc/cpuinfo确认 CPU 的 flags 里带有v标识表示向量扩展已经生效。这个细节很容易忽略我见过有人启动参数里写了vtrue但内核 config 没开结果程序里用 RVV 指令直接报非法指令。Python 安装在 Ubuntu rootfs 里很直接sudo apt update sudo apt install python3-dev python3-pip python3-venv装完确认一下python3 --version至少 3.10 起步。PyTorch 对 Python 版本有硬性要求版本低了根本编不过。4.2 PyTorch 源码构建与务实替代方案接下来是重头戏。PyTorch 官方目前还没有发布 riscv64 架构的 wheel 包直接pip install torch会报找不到匹配版本。唯一正路是从源码构建sudo apt install cmake ninja-build libffi-dev libopenblas-dev git clone --recursive https://github.com/pytorch/pytorch.git cd pytorch python3 -m pip install -r requirements.txt MAX_JOBS4 python3 setup.py build在 QEMU 模拟器里编译 PyTorch你要先有个心理准备。四核 TCG 模拟器的性能大约只有同配置物理机的十几分之一实测光编译依赖就等了一小时全部编完需要小半天。MAX_JOBS我特意设成 4如果设成 8内存会直接冲到 7GB虚拟机很容易卡死。如果等不了源码编译有两条务实的替代路线一是先用 NumPy 跑同类的算法逻辑验证的是 Python 环境和底层基础库是否正常整套工具链验证好之后PyTorch 的编译只是一个时间问题不再有未知风险。二是找第三方维护的 riscv64 torch wheel。网上确实有一些预编译包但版本通常偏旧还依赖你 rootfs 里特定的 glibc 版本装起来容易撞依赖。我更推荐前面这条路线——实验台验证的是流程和逻辑不是绝对性能没必要在这次编译上耗尽所有耐心。4.3 用 RVV 矩阵乘验证 AI 底层执行力不依赖 PyTorch我还可以直接验证模拟器的 AI 底层能力。方法很简单写一个矩阵乘法的 C 程序用 RISC-V 向量扩展编译然后在用户态模拟器里运行。#include stdio.h #include stdlib.h #define N 256 static float a[N][N], b[N][N], c[N][N]; int main(void) { for (int i 0; i N; i) for (int j 0; j N; j) { a[i][j] rand() % 10; b[i][j] rand() % 10; } for (int i 0; i N; i) for (int k 0; k N; k) for (int j 0; j N; j) c[i][j] a[i][k] * b[k][j]; printf(%.2f\n, c[0][0]); return 0; }在宿主机上交叉编译并运行riscv64-linux-gnu-gcc -O2 -marchrv64gcv -static matmul.c -o matmul qemu-riscv64 ./matmul-marchrv64gcv表示基础 ISA 是 rv64带通用指令组g和向量扩展v。如果你的工具链版本支持还可以加-mabilp64d指定双精度浮点 ABI。程序能打印出一个确定的数值说明 RVV 指令在模拟器中正确执行了。如果 PyTorch 也已经编译好可以在 QEMU 里跑一段最简单的张量运算import torch x torch.randn(128, 128) y torch.relu(x) print(y.sum().item())能打印出一个数字Tensor 运算链路就算打通了。我把这一步当作实验台跑通的最低标准。5. 实测踩坑加速失效、模式混淆与 Agent 幻觉5.1 纯 TCG 模拟的加速补救措施QEMU 模拟 RISC-V 目标时默认走 TCG 纯软件二进制翻译没有硬件虚拟化加速。x86 宿主机上的 KVM 只能加速 x86 虚拟机对 RISC-V 目标不起作用除非宿主本身就是 RISC-V 架构。这一点很多人一开始没意识到搭完发现慢得离谱还以为自己装坏了。实测下来能用的补救措施有这几个启动参数里加-accel tcg,threadmulti让 TCG 使用多线程模式编译类任务能快一些非交互式任务优先用qemu-riscv64用户态模拟不启动完整系统性能大概是系统态的两到三倍宿主机内存给足避免虚拟机内存频繁换页别在模拟环境里跑训练只跑推理和单次前向。也有人尝试硬加-accel kvm但那个参数要求宿主和客户架构一致才有意义。x86 PC 上跑 RISC-V 虚拟机还想开 KVM 加速基本不现实。5.2 用户态模拟和系统态模拟别混着用这是新手最容易翻车的地方。用户态模拟qemu-riscv64作用是在 x86 系统上直接跑一个编译好的 RISC-V 可执行文件它不需要完整的内核和 rootfs性能损失小但不能运行 shell、apt 这类系统级程序。系统态模拟qemu-system-riscv64则模拟整台机器可以启动完整 Linux缺点是启动流程重、配置复杂。我的使用习惯是调试单个 C 程序、跑算法验证用用户态模式要装 Python、跑完整 AI 软件栈、验证系统集成用系统态模式。两种模式共用同一套交叉编译产物互不冲突。但不要把两个模式的命令混在一个执行流程里网上有些教程会把两种命令交错贴出来照着做很容易混乱。5.3 识别 Agent 幻觉一次启动参数报错的完整排查回到第 2 章埋的那个坑。Agent 给的启动命令里CPU 参数写的是-cpu rv64gc在 QEMU 8.2 上执行直接报错qemu-system-riscv64: Property v not found我当时没有立刻怀疑 Agent第一反应是内核对向量扩展支持有问题差点去重新编译内核。后来一步步排查才发现是参数语法的问题。完整的排查链路是这样的执行qemu-system-riscv64 -cpu help查看支持的 CPU 模型确认rv64确实是可用模型执行qemu-system-riscv64 -cpu rv64,help查看该模型的属性确认v这个属性确实存在对比 Agent 给的-cpu rv64gc发现问题出在gc被当成 CPU 名称的一部分而实际上 CPU 模型就叫rv64gc并不属于模型名称把参数改成-cpu rv64,vtrue,vlen256启动成功。这个案例后来成了我给团队讲 Agent 协作的经典素材。经验是Agent 给的参数先在本地用-cpu help和-device help验证再放进完整命令。报错里出现 unknown property 或 invalid property 时优先怀疑参数语法而不是急着重编环境。每次只改一个参数改完立即启动验证不要一次性接受 Agent 给出的所有建议。6. 从模拟到真实芯片实验台的后续价值6.1 把 SSH 端口转发打开换成舒适的工作方式实验台搭好之后长期挂在-nographic串口上调试并不舒服。串口终端没有完整的转义和复制粘贴支持传文件更是麻烦。解决办法是使用 QEMU 的用户态网络端口转发把虚拟机的 22 端口映射到宿主机的 2222 端口qemu-system-riscv64 \ -M virt \ -cpu rv64,vtrue,vlen256 \ -smp 4 \ -m 8G \ -kernel Image \ -append root/dev/vda rw consolettyS0 \ -drive filerootfs.ext4,formatraw,idhd0 \ -device virtio-blk-device,drivehd0 \ -netdev user,idnet0,hostfwdtcp::2222-:22 \ -device virtio-net-device,netdevnet0 \ -nographic虚拟机里面起好 sshd宿主机执行ssh -p 2222 riscvlocalhost就能登录。之后一切操作都在 SSH 里进行文件传输直接用scp -P 2222比在串口上敲命令舒服太多了。6.2 迁移到真实 RISC-V AI 芯片时要注意的三个差异模拟实验台的最终价值是给真实芯片铺路。迁移到真机时有三个差异必须提前知道。第一指令集差异。QEMU 模拟的是标准 RISC-V 指令集真实芯片很可能有自定义的指令扩展。算法代码要尽量只依赖标准 RVV厂商扩展指令封装在独立的汇编文件里方便替换。第二外设差异。模拟器里的 virtio 设备和真实 SoC 的 DMA、ISP、网卡完全不同。写驱动前先查厂商 BSP别把 virtio 的路径硬编码进业务代码。第三内存与中断差异。真实芯片的 DDR 带宽、cache 层次、中断控制器行为和模拟器差异很大。凡是涉及调优、锁竞争、实时性的内容必须在真机上重新测试模拟器里的结论只能当作参考。我在 QEMU 里验证过的矩阵乘和 PyTorch 推理脚本后续迁移到厂商 SDK 环境时需要改动的部分主要集中在模型加载方式和外设接口层算法核心逻辑基本原样保留。这就是这个实验台存在的意义——它不能替代真机但能让你在真机到来之前就把大部分软件问题消化掉。