蜂鸟E203 RISC-V处理器在FPGA上的移植实战指南
简介一份面向FPGA与RISC-V学习者的蜂鸟E203移植工程资源包。该工程将蜂鸟E203 RISC-V处理器核心成功部署到Xilinx Zynq SoC的FPGA部分支持通过调试器下载程序并利用UART串口实现数据回传适合嵌入式开发、处理器设计及FPGA原型验证场景。压缩包共652个文件大小约25.36MB包含Verilog/VHDL源码、XDC约束文件、Tcl/Shell脚本、仿真平台与日志报告以及可直接上板的BIT流文件覆盖从RTL设计到上板运行的完整环节。目前已有3266人学习下载。资源内E203_PRJ目录组织清晰几乎汇集了蜂鸟E203在Zynq上运行所需的全部源码与调试配置并附有工程日志与校验报告既能帮助初学者快速上手RISC-V处理器移植流程也可为后续扩展外设或修改微架构提供可复用工程模板。 我一直觉得玩FPGA的人如果没试过在里面跑一个完整的RISC-V处理器多少有点遗憾。蜂鸟E203正好是这个方向最合适的选择之一它开源、资料全、有配套书籍和社区更重要的是它的SoC本身就是为FPGA验证设计的。我最初接触它是因为想研究RISC-V的指令集和时序但真正动手在FPGA上把蜂鸟E203移植成功之后收获的东西远超预期不仅搞清楚了处理器怎么和总线、外设打交道还把Vivado的工程组织、引脚约束、调试链路这些基本功都重新打磨了一遍。这篇文章就记录我的完整移植过程从环境准备到上板跑通程序希望能帮大家少踩一些坑。1. 蜂鸟E203项目概览与移植前必知1.1 蜂鸟E203到底是什么蜂鸟E203是芯来科技开源的RISC-V处理器核和SoC指令集是RV32IMAC也就是32位基础整数指令再加上整数乘法除法、原子操作、压缩指令还有个M模式。它采用两级流水线设计主频不高但代码量少、结构清晰非常适合做教学和二次开发。配套的SoC叫HummingBird E203 SoC包含处理器核、中断控制器、UART、GPIO、QSPI、定时器等常用外设直接就是一颗小芯片的完整形态。和很多开源处理器项目不同蜂鸟E203不只是给你一个网表或者仿真模型它给的是完整可综合的RTL源码而且在GitHub上维护得非常活跃。核心代码大概几万行Verilog属于“认真读一两个月能读透”的量级对想深入理解处理器内部的人来说再合适不过。我选择它还有一个现实原因市面上讲RISC-V的书不少但大多是讲指令集架构ISA的理论真正能把一个完整的处理器核和SoC代码摊开看还能移植到真实FPGA上跑起来的项目E203算是独一档。1.2 移植前需要准备哪些东西硬件方面蜂鸟E203官方推荐的FPGA是Xilinx 7系列比如Artix-7、Spartan-7因为这颗芯片的时序余量不算宽裕7系列的时钟资源和逻辑结构比较友好。我这边手头是一块Artix-7的板卡逻辑单元大概几万LUT的级别跑E203的SoC完全够用。如果你用的是国产FPGA或者其他厂家芯片理论也能移植但综合工具改动较大Vivado路径最顺新手强烈建议直接用Xilinx平台。工具链方面Vivado我建议用2018.x到2020.x之间的版本太新的版本综合策略变化大太旧的对新板卡支持差。除了Vivado还需要准备Nuclei SDK用于编译RISC-V程序和OpenOCD用于JTAG调试和下载。E203的调试方案是基于RISC-V Debug Module 0.13规范的后面我会详细讲怎么把调试链路搭起来。提示如果你的板卡没有板载JTAG调试器需要准备一个支持RISC-V调试的便宜调试器或者用常见的FT2232模块自制本质就是把PC端的USB转换成JTAG时序。2. 代码结构与关键模块解析2.1 从GitHub拉代码后先看懂目录蜂鸟E203的GitHub仓库是riscv-mcu/e203_hbirdv2拉下来之后不能急着创建工程先把目录结构搞清楚。核心代码都在rtl目录下面我简单梳理一下关键内容rtl/e203/core处理器核本体包括取指、译码、执行、写回各级流水逻辑以及CSR控制状态寄存器模块。这是最核心的部分想深挖处理器细节就看这里。rtl/e203/socSoC集成层处理器核在这里和总线矩阵、外设互联顶层是e203_soc_top。rtl/e203/general通用组件比如FIFO、同步器、时钟管理相关的基础模块。fpga目录官方适配FPGA的约束文件和集成脚本不同板卡有对应的.xdc文件。移植的第一步是修改e203_soc_top这个顶层模块的引脚和时钟约束因为不同板卡的时钟频率、复位极性、引脚分配都不一样。我在初次移植时犯过一个错误想把整个SoC的所有信号都引出来看波形结果导致顶层端口暴增综合布线一团乱。实际上e203_soc_top对外只暴露必要接口比如系统时钟、复位、JTAG、UART、GPIO和QSPI其他内部信号完全可以通过ILA集成逻辑分析仪来抓取没必要全引出来。2.2 总线架构和内存映射蜂鸟E203内部总线用的是自己的一套ICBInternal Chip Bus协议简单说就是一个高扇出的控制通道和数据通道分离的片上总线。这套总线和AMBA的AHB协议类似处理器核作为主设备通过总线矩阵连接各个从设备比如ITCM指令紧耦合存储器、DTCM数据紧耦合存储器、UART、GPIO、QSPI Flash控制器等。内存映射方面E203的ITCM和DTCM是紧耦合存储器直接挂在处理器核旁边访问延迟很低。调试器通过JTAG接口访问调试模块Debug Module可以读写内存、设置断点、单步执行。这里有个细节值得注意E203的调试模块和处理器核的主流水线是并行运行的也就是调试功能不影响核的正常流水执行这一点对实时调试非常重要。我在看代码时最喜欢画一张简单的SoC整体框图把处理器核、总线矩阵、内存控制器、外设控制器画在一个页面里然后对着RTL代码逐个模块看接口信号。这个习惯帮我省了很多排查时间建议你也这样做。3. FPGA移植实操全流程3.1 Vivado工程创建与RTL源文件添加第一步是打开Vivado创建一个新工程选择自己板卡对应的FPGA型号。如果板卡有对应的Board Files直接选型号即可没有也没关系后面手动加约束就行。创建工程之后最关键的一步是添加RTL源文件。E203的RTL文件分布在多个子目录一个个添加太累而且容易漏。我推荐用Tcl命令批量添加在Vivado的Tcl Console里执行# 假设E203工程源码在D:/work/e203_hbirdv2 set rtl_dir D:/work/e203_hbirdv2/rtl add_files -norecurse [glob $rtl_dir/e203/*/*.v] add_files -norecurse [glob $rtl_dir/e203/*/*/*.v]这条命令会把rtl目录下各级子目录的.v文件全部加入工程。注意E203的代码是纯Verilog编写的不需要第三方IP核这一点对工程管理特别友好也适合离线环境开发。不过仅仅添加文件还不够需要在工程设置里把rtl根目录添加到Verilog Include Path否则编译会报找不到头文件。在Vivado的Settings - Simulation或者Synthesis里把D:/work/e203_hbirdv2/rtl加入Verilog Options的include路径即可。3.2 引脚约束适配自己的板卡这是整个移植过程中最容易出问题、也最需要耐心的环节。官方提供了一份针对官方评估板的e203.xdc约束文件你需要把它替换成自己板卡的实际引脚约束。我总结了一份最基础的约束清单信号名说明建议动作sys_clk系统时钟输入绑定板卡时钟引脚通常是一个差分或单端晶振sys_rst_n系统复位输入低有效绑定按键或配置为上电复位逻辑jtag_tck/tms/tdi/tdoJTAG调试接口绑定调试器连接引脚tck和tms必须保证信号质量uart_tx/rxUART串口绑定USB转串口芯片引脚gpio_*通用GPIO绑定LED、按键、拨码开关等时钟约束不能只绑引脚还要写时钟周期。E203的SoC默认设计时钟频率不高我实测在Artix-7上跑到50MHz完全没有问题官方文档建议也是20MHz到50MHz之间比较稳。约束写法如下create_clock -period 20.000 [get_ports sys_clk]这条语句代表50MHz时钟周期是20ns。如果你板卡是100MHz晶振那么就写-period 10.000然后在内部通过MMCM/PLL分频到需要的频率。E203工程里其实有对应的时钟管理模块直接映射系统时钟引脚之后内部会自动做分频处理具体要看官方代码里的时钟配置逻辑。复位信号务必确认极性。E203的复位是低有效也就是说sys_rst_n为低时SoC复位高时正常运行。很多板卡的按键是按下为低接上正好但也有的按键是按下为高这种情况要么换个引脚要么加个反相器逻辑。我第一次上板就是复位极性搞反了结果下载完bit文件之后处理器一直卡在复位状态串口毫无反应排查了半个小时。3.3 综合、实现与bit文件生成约束写完之后就可以开始综合Synthesis和实现Implementation了。Vivado默认的综合策略对E203这种中小规模设计问题不大但有几个选项值得手动调整综合设置里把-flatten_hierarchy设为full有利于时序优化。实现策略直接用默认的Performance_Explore即可如果时序紧张再换Performance_ExplorePostRoutePhysOpt。E203的SoC资源占用不算大在我的Artix-7上逻辑单元LUT和寄存器FF的占用率大概在30%到50%之间BRAM会被ITCM和DTCM占用一部分。综合时间几分钟实现时间十几分钟取决于你电脑性能。如果发现时序违规Setup Timing失败优先检查时钟约束是否正确次优调整综合选项不要一上来就加流水级那会破坏原设计的时序意图。生成bit文件点击Generate Bitstream成功之后会在工程目录的runs/impl_1下生成.bit文件。到这里FPGA移植的第一步就算完成了你已经把这个RISC-V SoC“烧”进了FPGA。4. 上板验证与功能测试4.1 硬件连接与调试链路搭建bit文件生成之后下一步是上板验证。先把bit文件通过Vivado Hardware Manager下载到FPGA里或者用write_cfgmem把bit转换成flash格式固化每块板卡上电自动加载。第一次调试建议直接用JTAG加载方便修改和重试。调试链路是移植成功与否的关键一环。蜂鸟E203的调试模块遵循RISC-V Debug Module 0.13规范支持标准的JTAG访问。也就是说只要能通过JTAG连上SoC的调试模块就能用OpenOCD加GDB远程调试。Nuclei官方维护了一个OpenOCD分支里面有针对E203的配置脚本。基本用法是openocd -f board/nuclei_fpga_e203.cfg连接成功后OpenOCD会启动一个GDB Server监听在localhost:3333端口。然后用riscv-none-embed-gdb连接riscv-none-embed-gdb hello_world.elf target remote localhost:3333 load如果没有板载JTAG需要外接调试器。我用的是FT2232H模块在OpenOCD的配置里指定ftdi接口并映射对应的管脚就能完成JTAG链路的搭建。这一步如果能跑通基本说明SoC的JTAG控制逻辑在FPGA上工作正常。提示连接FPGA的JTAG引脚时TCK建议加上拉电阻到VCCTMS和TDI同理TDO是输出不需要上拉。这个细节虽然小但能显著提升信号稳定性。4.2 跑通第一个程序调试链路打通之后就可以开始跑程序了。先用一个最简单的GPIO点灯程序验证SoC基本工作然后再用串口输出验证UART外设。我建议初学者按这个顺序来先点灯再串口再中断最后再跑RTOS。举一个最经典的例子用Nuclei SDK创建一个hello world工程编译之后生成.elf。下载到FPGA后程序会执行初始化把“Hello World”字符串通过UART发送出去。如果你在电脑上用串口助手能看到正确的输出说明处理器核取指、执行、访存、写回这条流水线在FPGA上完全跑通了。我在这个阶段还做了一件有意思的事用Vivado的ILA在线逻辑分析仪抓取UART的TX引脚波形对比串口输出数据确认协议时序和数据内容完全正确。ILA的用法很简单在Vivado里添加ILA核约束到uart_tx引脚重新综合实现就能在硬件上抓取时序。这个习惯真心建议养成因为FPGA调试和纯软件调试不同看不到寄存器实时状态只能靠逻辑分析仪捕捉关键信号。4.3 进阶玩法程序跑通之后你还可以做两件事进一步验证移植的完整性。第一是运行CoreMark基准测试E203的两个流水线设计让它跑分不会高但能稳定跑完基准程序本身就说明SoC各方面功能正常。第二是移植FreeRTOS或RT-Thread我在博文标题里看到很多朋友关注FreeRTOS移植E203配套的Nuclei SDK已经包含了FreeRTOS的移植示例在SDK里直接选择对应的Demo编译下载即可。跑RTOS的意义和跑裸机程序完全不同裸机程序是单线程循环RTOS则要依赖定时器中断、任务切换、内存管理这些复杂的SoC功能任何一个环节移植不到位都会导致任务跑飞或系统死机。我第一次跑RTOS时因为系统时钟配置不对任务调度老是卡住后来排查发现是定时器中断里没有清除中断标志位导致中断风暴。这些坑光看书是真学不到的。5. 常见问题与排查经验5.1 移植中高频踩坑速查表移植过程中会遇到很多看似诡异的问题我把最典型的一批整理成了速查表方便大家对照排查现象可能原因解决方案下载bit后无任何反应复位极性接反或保持复位确认复位信号低有效按复位按键触发一次复位UART输出乱码波特率不匹配或系统时钟频率配置错误确认程序编译时的系统时钟频率与FPGA上实际时钟一致程序能跑但运行一两秒后死机ITCM/DTCM内存越界或者I/O访问冲突检查程序内存段映射确认链接脚本地址正确JTAG连接不上TCK/TMS上拉缺失或调试模块供电不稳定检查JTAG引脚电平加10K上拉电阻综合后时序违规严重时钟约束不写或者PCB时钟路径有噪声先写create_clock约束再综合确认时钟频率匹配内部PLL配置OpenOCD可以连接但load报错链接脚本的Flash地址与FPGA内RAM地址不匹配检查Nuclei SDK的链接脚本E203默认从ITCM启动地址为0x80000000起的空间程序在GDB单步正常全速运行出错总线仲裁或中断仲裁逻辑存在竞态E203原版代码理论上不应有此问题检查是否有代码改动或工程综合选项影响5.2 源码级排查的常用手段遇到上述问题还解决不了就需要对RTL做源码级排查这时候Vivado的仿真功能可以派上用场。E203官方在tb目录里提供了简单的测试平台可以用来做RTL仿真。注意跑RTL仿真比在FPGA上调试快得多因为你可以直接看到每个寄存器的翻转变化而FPGA上只能通过ILA抓有限信号。另一个常用手段是$display大法但用在Verilog模块内部比较麻烦。我更推荐用Vivado的逻辑分析仪ILA来抓内部信号ILA的触发条件可以设置为某个总线写事务的地址匹配这样就能精准定位是哪个外设访问异常。5.3 几个值得注意的必备小细节移植成功之后我再分享几个细节属于那种没人提醒就容易翻车提醒了就能省一天时间的点。时钟域的问题。E203的SoC有多个时钟域比如系统时钟和QSPI的慢速SCK时钟。官方RTL代码里已经尽量做了跨时钟域处理但如果你自己加了外设一定要考虑同步器的使用。我见过有同学在FPGA上加了一个自定义接口没做跨时钟域处理跑仿真一切正常上板随机死机这种情况最难查。调试器的TCK频率问题。OpenOCD使用RISC-V调试模块时TCK频率不能超过系统时钟频率的四分之一否则调试模块可能出现误触发。我当时用FT2232H默认的6MHz TCK连接一个50MHz的E203一切正常但换到一块低主频的板卡上就各种奇怪报错最后把TCK降到1MHz才稳定。最后是固件引导Boot的问题。E203默认是直接从ITCM启动的ITCM掉电即失内容因此每次上电后都需要通过调试器重新加载程序。如果你想做成独立的嵌入式设备需要配置QSPI Flash启动方式把程序固化到Flash里上电后由SoC内部的Bootloader搬移到ITCM执行。这一步涉及QSPI控制器的配置和Flash型号匹配我移植时也折腾了一整天。等下次有空我再单独写一篇QSPI引导固件的完整流程。回到开头说的在FPGA上移植蜂鸟E203这件事表面看是一个“把RTL代码放进FPGA”的机械操作实际练的是你对一个完整处理器SoC的理解深度。做完一次全流程移植你会发现系统时钟、复位、总线、外设、调试接口这套组合拳虽然繁琐但一旦打通整个计算机系统的基本轮廓就在你脑子里立起来了。如果你正准备动手我的建议是别跳步从点灯开始一步步跑通所有功能这比直接跑一个大程序更有收获。本文还有配套的精品资源点击获取