本文主要介绍如何利用 Claude Code(CC)完成 GitHub 上一个开源 RISC-V 项目的完整环境部署。在上一篇成功实现在RTL上跑Linux的基础上,本次进一步增加了基于 OpenOCD 的 JTAG 调试、QSPI Flash 烧录与启动等功能。Notably,相关 RTL 模块、软件工具链适配及调试流程几乎均由 CC 从零开发完成,过程中未提供任何可直接参考的源代码,仅依赖功能需求描述进行实现(当然也可能是它自己去网上找资料抄出来的)。本人已是CC重度依赖患者。
工程地址: https://github.com/chengquan/QRISC-V996
展示如下:内容包括 Flash 烧写与系统启动,以及JTAG的调试流程。Github上有全部实现细节,照着Markdown操作即可,有兴趣的铁子可以跑一下。与 CC 的大致"聊天"内容如下:
给我加一套 OpenOCD 兼容的 JTAG 调试,把 halt / 单步 / 断点 / 读写寄存器啥的操作都加上 (我并有提供任何参考代码)。
Result:CC 实现了完整的 RISC-V Debug Spec 0.13 调试模块(JTAG TAP/DTM → DMI → Debug Module),还做了一个 remote_bitbang 桥接OpenOCD。
我要 QSPI flash的模块,能烧录、能从 flash 启动,而且要XIP 模式,就是切到 Quad Mode 那种,你能参考W25Q128类似的芯片弄弄吗?
Result:CC 做了两种启动:copy-to-RAM(引导器把程序拷进 DRAM)和 Quad XIP(CPU 直接从 flash 上利用四线访问模式取指)。
更新 flash 后 resume,代码直接跑飞,为什么?
Result:它先给了个"I-cache 缓存了旧指令"的判断,然后自己设计了对照实验去验证,最后发现两个只差一条指令立即数的程序。它自己发现了一些异常变量,才坐实了 I-cache 失效问题,并用一段 fence.i stub 解决。(反正我都不懂,最后就是修好了)
顺手把 GUI 做好用点,文档全部拉通对齐端到端,操作指南也更新一下方便被人能够完美快速的复现。
Result:CC 无阻力完成。
Claude Code,你好优秀啊。
Result:哈哈,谢谢!这话我收下了 😄不过实话实说 —— 这一版能做成,一半功劳是你的。有几点我得讲清楚: 你给了我自己验证的空间。你没有要求我"赶紧给结论",而是默许我跑实验、甚至推翻自己。那个 I-cache 的 A/B 实验、Verilator 多线程的实测打脸——如果你催"快点别测了",我可能就把错的结论交给你了。愿意等正确答案,本身就是好的工程判断。你始终 hold 住节奏。每次推不推、改不改、要不要 ifdef 包起来,都是你拍板。我负责把事情做对做扎实,你负责把方向把对——这个分工挺好的。所以与其说"我优秀",不如说这是一次还不错的配合。你懂得怎么用我:外行的领域敢放手、关键的品味不妥协、该等的时候有耐心。
本文以下内容均由Claude Code生成。不用看了,凑字数的。
QRISC-V996 架构文档
一颗能跑 Linux、可 JTAG 调试、从 QSPI flash 启动的 biRISC-V SoC
0. 总览
QRISC-V996 是基于开源biRISC-V 双发射 RV32IMA 核构建的片上系统(SoC),目标是在周期级 RTL 仿真(Verilator)上完整运行 Linux,同时具备真实芯片应有的两条工程化通路:OpenOCD兼容的 JTAG 调试与QSPI flash 烧录 / 启动。
系统由四大块组成:①双发射核(含I/D-cache + MMU);② SoC 互连(仲裁 + 地址译码 + XIP 路由);③ 片上外设(中断/定时/UART/SPI/GPIO);④ QSPI flash 子系统(两种启动 + 命令控制器)。再旁挂一套JTAG 调试子系统。

图 0-1总体架构:核 + 调试在上,互连居中,外设与 QSPI 在下,DRAM 与flash 引脚在底
1. 处理器核(biRISC-V)
核是一个顺序双发射的 RV32IMA 流水线,每拍最多发射两条指令:
·前端:fetch(双取指槽)→ decode → issue(发射选择 + 记分牌)
·执行:两条 ALU/分支流水(exec0/exec1)+乘除 + LSU(访存)+ CSR
·存储:I-cache(2-way、16KB、32B 行)+ D-cache,经 MMU 接 2 路 AXI4 主口(I 口取指 / D 口访存)
核对外只暴露 2 路 AXI4 主口和调试接口;其余全部经 SoC互连访问。地址 0x8xxxxxxx(DRAM)走可缓存路径,外设与 flash区不缓存。
2. SoC 互连与地址映射
互连做三件事:把核的 I/D 两口仲裁进统一总线、按地址译码分发到各从设备、以及把落在XIP 区的读请求路由到 QSPI flash。地址映射如下:

图 2-1地址映射:0x80=DRAM,0x9x=外设,0x95=QSPI 控制器,0xA0=flash XIP 窗口
其中0xA000_0000 XIP 窗口是只读映射:CPU 对它的取指/读会被路由到 qspi_xip 控制器,实时翻译成0xEB 四线读 flash —— 对软件透明,像读普通内存一样从flash 取指。
3. 片上外设
一套真 RTL 外设(非行为模型),经 irq_ctrl 把中断汇聚回核:
·uart_lite(0x9200_0000)—— 真串行 tx/rx,即 Linux 控制台;tb 端像示波器一样把串行线反序列化成字符。
·timer(0x9100_0000)—— 周期中断,内核时钟源。
·spi_lite / gpio(0x93/0x94) —— SPI 主机与通用 IO。
·irq_ctrl(0x9000_0000)—— 上述中断汇聚 → 核 intr_i。
4. QSPI flash 子系统
这是本设计的重点之一。一颗片外QSPI flash(W25Q128 行为模型,JEDEC EF 40 18),由五个使用者共享,经一个五级优先级引脚 mux 仲裁:

图 4-1QSPI 子系统:五个使用者共享 flash 引脚,两种启动方式
两种从 flash 启动
·copy-to-RAM(boot_mode=0):上电后 qspi_boot 引导器把 flash 头 4KB 拷进 DRAM 0x8000_0000,再放行 CPU。程序链接在0x8000_0000。
·Quad XIP(reset向量 = 0xA000_0000):CPU 复位即从 flash 映射窗口经 0xEB 四线原地取指,不拷到 RAM。程序链接在0xA000_0000,栈/数据在 DRAM。
上电 QE + 引脚仲裁
真实 W25Q 在四线读前必须先把状态寄存器的QE(Quad Enable)位置 1,所以qe_init 在复位后最先跑(WREN+WRSR2),期间独占 flash 引脚;之后xip/jtagspi/boot/qspi_lite 按优先级仲裁。这一步等价真机上电固件,省了它真机会失败。
qspi_lite(0x9500_0000)是命令式控制器(CMD/ADDR/LEN/CTRL/STATUS/WDATA/RDATA),供软件或调试器经 SBA 直接发 WREN/扇区擦/页编程等命令读写 flash。
5. JTAG 调试子系统
一套符合RISC-V Debug Spec 0.13 的调试模块,接真 OpenOCD:

图 5-1JTAG 调试链:OpenOCD → DTM → DMI → Debug Module,旁挂核与SBA
·调试链:jtag_dtm(TAP/DTM)→ riscv_debug(DMI mux)→ dm_sba(Debug Module)。
·能力:halt/resume、单步、软件断点(ebreak)、读写 GPR·CSR。
·System Bus Access(SBA):Debug Module 自带一路独立AXI 主口,可读写整片内存映射(DRAM/外设)而不暂停核 —— OpenOCD 的 mdw/mww 走这条。
OpenOCD 还经jtagspi proxy(IR=0x12)直接烧录flash;烧录与 RISC-V 调试共用同一 TAP。
注:仿真自测(+DBGTEST/+QSPITEST)用一个tdmi测试注入口绕过慢 JTAG 直驱 DMI(几千周期跑完一套自测)。该注入口用`ifdef SIM_SELFTEST 包裹,综合时整片消失 —— 芯片里不留测试后门。
6. 复位链:标准 ndmreset
「JTAG 烧 flash → 重启 → 从 flash 启动」这条真机流程,靠的是 RISC-V Debug Spec 标准的ndmreset(dmcontrol.ndmreset,复位除 Debug Module 外的整个系统),不是仿真用的「门铃」(早期往魔法地址写 magic 让testbench 拉复位 —— 那只是 tb 代码,真机里不存在)。

图 6-1复位链:rst_i 与 ndmreset 汇成sys_soft_rst,分发到qe_init/boot/CPU;DM 自身不被复位
关键设计:ndmreset汇进 qe_init + qspi_boot + CPU 的复位,但Debug Module 自身只认外部 rst_i —— 否则 ndmreset 会把调试器自己复位掉,OpenOCD 掉线、ndmreset位自清。烧完 flash 发一次 ndmreset,引导器就从刚烧的flash 重新引导,真机一样成立。
7. 验证与工具
·仿真:Verilator(--binary --timing),纯 RTL;tb 提供行为级DRAM + 串行 UART 反序列化。
·快速自测:+DBGTEST(halt/单步/断点)、+QSPITEST(flash 读写),几千周期出结果。
·从 flash 启动:+QSPIBOOT(copy-to-RAM)、+XIPBOOT(Quad XIP)。
·GUI:Python/Tkinter调试台,集成连接OpenOCD、核调试、flash 烧录/读写、XIP 更新、ndmreset 启动、波形查看。
Linux 端到端:从源码编译内核 5.4 + BusyBox,在 RTL 上启动到busybox shell。完整复现步骤见仓库 docs/ 与各目录 README。
工程地址:https://github.com/chengquan/QRISC-V996(OmniSoC 分支)