搭建RISC-V软核工程:在Vivado中创建RISC-V处理器工程
好,咱们正式开始动手。这一节,我带你走一遍在Vivado里搭建RISC-V软核工程的全流程。说白了,就是把一个开源的RISC-V处理器核(比如VexRiscv、PicoRV32这些)塞进FPGA里,让它能跑起来。
我个人习惯把这一步叫做“搭骨架”。骨架搭得稳,后面调试才不慌。你想想看,如果工程结构乱糟糟的,约束文件缺胳膊少腿,综合出来一堆时序违例,那后面仿真调试根本没法搞。
第一步:创建Vivado工程
打开Vivado,点“Create Project”。这里有个小细节——工程名字别用中文,路径也别带空格。我在项目中遇到过有人用中文路径,结果IP核生成时报了一堆莫名其妙的错误,排查了半天才发现是路径问题。
选RTL Project,勾上“Do not specify sources at this time”。为什么?因为咱们后面要加IP核,先建个空壳子更清爽。
器件型号怎么选?看你手里的板子。我用的是Xilinx Artix-7系列,具体型号XC7A35T。如果你用别的板子,比如Kintex或者Zynq,操作步骤完全一样,就是器件型号不同。
第二步:添加RISC-V处理器IP核
RISC-V处理器核不是Vivado自带的,得自己加。常用的开源方案有几种:
- VexRiscv:用SpinalHDL写的,可配置性极强,我比较推荐
- PicoRV32:纯Verilog,简单粗暴,适合入门
- Rocket Chip:Berkeley出品,功能全但有点重
我个人习惯用VexRiscv。为什么?因为它支持JTAG调试,而且能生成AXI总线接口,跟Vivado里的IP核对接特别方便。
添加IP核的步骤:
- 在Vivado里点“IP Catalog”
- 右键选“Add Repository”,指向你下载的RISC-V核文件夹
- 刷新一下,IP核就会出现在列表里
- 双击它,配置参数(比如指令缓存大小、乘法器类型等)
嗯,这里要注意:配置参数时,指令总线和数据总线宽度一定要匹配。我曾经帮一个同事排查问题,他配了32位指令总线但数据总线选了64位,结果访存时地址对齐出了问题,程序跑飞了。
第三步:添加其他必要IP核
光有CPU核不够,还得有内存和总线。我一般会加这几个:
| IP核名称 | 作用 | 配置要点 |
|---|---|---|
| Block Memory Generator | 做程序存储器(ROM)和数据存储器(RAM) | 深度至少4KB,宽度32位 |
| AXI Interconnect | 连接CPU核和各个外设 | 选“AXI4-Lite”模式,简单够用 |
| Clocking Wizard | 生成系统时钟 | 输入50MHz,输出设成CPU目标频率 |
| Processor System Reset | 提供复位信号 | 勾上“Ext Reset In”,连到板子按键 |
你想想看,如果没有AXI Interconnect,CPU核怎么访问内存?总不能直接连吧?那布线会乱成一锅粥。AXI总线的好处就是标准化,所有IP核都按这个协议来,省心。
第四步:编写顶层模块并连接
IP核都加好了,接下来写个顶层Verilog文件,把它们串起来。代码大概长这样:
module riscv_top (
input wire clk_50m,
input wire rst_n,
output wire [3:0] led
);
// 时钟和复位
wire clk_cpu;
wire rst_cpu;
clk_wiz_0 u_clk (
.clk_in1 (clk_50m),
.clk_out1 (clk_cpu)
);
proc_sys_reset_0 u_rst (
.slowest_sync_clk (clk_cpu),
.ext_reset_in (rst_n),
.peripheral_aresetn (rst_cpu)
);
// RISC-V处理器核
vexriscv_wrapper u_cpu (
.clk (clk_cpu),
.reset (~rst_cpu),
.axi_* (/* 连到AXI Interconnect */)
);
// Block Memory
blk_mem_gen_0 u_ram (
.clka (clk_cpu),
.addra (/* 地址总线 */),
.dina (/* 写数据 */),
.douta (/* 读数据 */)
);
// 简单外设:LED
assign led = /* CPU写某个地址的值 */;
endmodule
这段代码里,我故意省略了一些连线细节。为什么?因为不同RISC-V核的接口名字不一样,你得看它的数据手册。VexRiscv的AXI接口叫“io_axi_awready”这种,PicoRV32的叫“mem_axi_awready”,别搞混了。
第五步:添加约束文件
约束文件(XDC)是告诉Vivado你的信号对应板子上哪个引脚。比如:
# 时钟引脚
set_property PACKAGE_PIN E3 [get_ports clk_50m]
set_property IOSTANDARD LVCMOS33 [get_ports clk_50m]
# 复位引脚
set_property PACKAGE_PIN C12 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
# LED引脚
set_property PACKAGE_PIN H5 [get_ports {led[0]}]
set_property PACKAGE_PIN H6 [get_ports {led[1]}]
set_property PACKAGE_PIN G5 [get_ports {led[2]}]
set_property PACKAGE_PIN G6 [get_ports {led[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[*]}]
这里有个坑:时钟约束别忘了加。如果不加,Vivado会默认时钟周期是无穷大,综合出来的结果可能时序不收敛。加一句:
create_clock -period 20.000 [get_ports clk_50m]
20ns对应50MHz,如果你的板子时钟频率不同,自己换算一下。
第六步:综合与实现
点“Run Synthesis”,等几分钟。综合完成后,打开“Schematic”看看你的RISC-V核是不是正确连接了。我每次都会看一眼,确认IP核的接口没接错。
综合通过后,点“Run Implementation”。这一步会把你的设计映射到FPGA的查找表和触发器上。如果报时序违例,别慌,先看看是哪个路径。一般RISC-V核跑50MHz是没问题的,如果跑100MHz以上,可能需要优化代码或者降低频率。
实现完成后,点“Generate Bitstream”,生成比特流文件。下载到板子上,如果LED亮了或者串口打印了“Hello World”,恭喜你,RISC-V软核跑起来了!
知识体系图:RISC-V软核工程搭建流程
这张图把整个流程串起来了。你从左边开始,一步步走到右边,最后下载到板子。每一步都有坑,但踩过一次就记住了。
好了,这一节的内容就到这儿。你按照这个步骤走一遍,RISC-V软核工程就能搭起来。下一节咱们聊聊怎么往里面烧程序,以及如何用Vivado的仿真工具调试它。
公众号:蓝海资料掘金营,微信deep3321