D Vivado使用进阶
D.1 定制RAM IP核
Vivado中集成了一些常用的IP单元,比如RAM、AXI转换桥、以太网控制器等。
D.1.1 定制同步RAM IP核
Vivado中定制一个单周期返回的同步RAM IP的方法如下。
1)打开或新建一个Vivado工程后,在“PROJECT MANAGER”里点击“IP Catalog”,如图D.1所示。

图 D.1: 在“PROJECT MANAGER”里点击“IP Catalog”
2)在右侧列表中双击选择“Memories and Storage Elements\(\rightarrow\)RAMs & ROMs & BRAM”中的“Block Memory Generator”,如图D.2所示。

图 D.2: 在“IP Catalog”里选择“Block Memory Generator”
3)在打开的IP定制界面中设置RAM参数。
- 在RAM界面的“Basic”选项卡里将IP重命名为block_ram,内存类型设为单端口RAM,不要勾选“Byte Write Enable”,如图D.3所示。
- 在“Port A Options”选项卡中将RAM深度设为65536、宽度设为32,使能端口设为“Always Enabled”,不要勾选“Primitives Output Register”。其他保持默认设置即可,然后点击“OK”。如图D.4所示。

图 D.3: 设置同步RAM的Basic参数

图 D.4: 设置同步RAM的Port A Options参数
D.1.2 定制异步RAM IP核
与定制同步RAMIP核类似,定制一个异步RAMIP的方法如下。
1)打开或新建一个Vivado工程后,在“PROJECT MANAGER”里点击“IP Catalog”。
2)在右侧列表中双击选择“Memories and Storage Elements\(\rightarrow\)RAMs & ROMs”中的“Distributed Memory Generator”,如图D.5所示。

图 D.5: 在“IP Catalog”里选择“Distributed Memory Generator”
3)在打开的IP定制界面中设置RAM参数。在“memory config”界面将IP重命名为distributed_ram,内存类型设为单端口RAM,深度设为65536,宽度设为32。其他保持默认设置即可,点击“OK”。如图D.6所示。

图 D.6: 设置异步RAM的参数
D.1.3 查看时序结果和资源利用率
在对Vivado进行综合和实现后,我们可以查看时序结果和资源利用率(请确保已经完成了综合实现),如图D.7所示。
1)在Vivado的“Design Runs”界面查看时序结果(WNS和TNS栏)。WNS表示最长路径的违约值,TNS表示所有违约路径的总违约值。WNS和TNS为红色负值表示有违约。WNS为非负值表示时序满足极好,WNS违约值不超过300ps表示时序满足较好,WNS违约值超过300ps表示时序很糟糕,设计有可能无法上板运行。WNS违约越多,设计上板失败的可能性越大。
2)在Vivado的“Project Summary”界面查看资源利用率。LUT为主要资源,也就是查找表的资源(FPGA的实现原理主要就是查找表),RAM为内部集成的同步RAM的资源,IO为FPGAI/O接口的资源,BUFG为FPGA内部集成的BUF的资源。

图 D.7: 查看综合实现后的时序结果和资源利用率
除了以上方法,我们也可以在左侧导航栏Implementation下,打开实现结果(Open Implementation design),生成时序报告(report timing summary)或资源报告(report utilization)。
D.2 利用tcl创建Vivado工程
本书配套的实验环境中推荐使用tcl创建Vivado工程。用来创建Vivado工程的tcl脚本存放在各个实验环境的 run_vivado 目录下。下面介绍一种利用tcl创建Vivado工程的步骤。
步骤1:启动Vivado后,如图D.8所示点击最下方的“Tcl Console”标签。

图 D.8: 打开Tcl Console
步骤2:如图D.9所示位置,在打开的Tcl Console中输入命令,cd 到待使用 create_project.tcl 文件所在目录(如图D.10所示)。

图 D.9: Tcl Console中输入命令的位置

图 D.10: 进入create_project.tcl所在目录
步骤3:如图D.11所示,继续在Tcl Console中输入命令 source ./create_project.tcl
。接下来Vivado将根据 create_project.tcl
的内容创建工程。

图 D.11: (ref:label-vivado-source-create-project-tcl)
D.3 利用tcl向Vivado项目中添加设计文件
如果采用我们推荐的实验开发环境获取方式,那么会出现多个实践任务将使用同一个目录下的Vivado工程的情况。由于在新的实践任务中可能会增添新的设计文件,所以需要更新Vivado工程中的源文件列表。添加设计文件除了可以采用附录C.2中介绍的图形界面操作方式外,如果设计者可以保证 myCPU 目录下没有无用文件,那么就可以采用下面介绍的更加快捷的方式。
步骤1:如图D.12所示,在已经打开的工程中找到Tcl Console的命令输入位置。

图 D.12: 已打开Vivado工程中Tcl Console中输入命令的位置
步骤2:在Tcl Console中输入命令“add_files -scan_for_includes ../../../myCPU/”。如图D.13所示。

图 D.13: 在Tcl Console中输入命令添加myCPU目录下的设计文件
D.4 升级工程和IP核
本书配套的CPU设计实验开发环境是在Vivado 2019.2中创建的,如果使用更高版本的Vivado打开,需要对工程和IP核进行升级。注意:Vivado不支持向前兼容,也就是低版本Vivado无法使用高版本Vivado创建的工程和IP核,若您遇到这种情况,请升级Vivado的版本。
高版本Vivado打开低版本的工程,升级工程和IP核的方法如下:
(1)高版本Vivado打开低版本的工程,会弹出如图D.14界面,选择第一个选项“Automatically Upgrade…”,点击“OK”进行升级。

图 D.14: 低版本工程升级
(2)如果你的工程里包含Vivado定制的IP核,则会提示图D.15左侧的提醒,选择“Report IP Status”,则会显示IP核状态,如图D.15右侧:三个IP和显示红色的锁标记,说明该IP核目前被锁住,无法修改。

图 D.15: 显示IP核被锁住
(3)需要对锁住的IP核依次进行升级,才能在此版本Vivado里修改这些IP核。在Sources窗口中找到要升级的IP,右键后点击“Upgrade IP…”,如图D.16。

图 D.16: 右键IP核选择“Upgrade IP…”
(4)之后,会弹出如图D.17所示界面,选择第二个选项“Continue with Core…”,点击“OK”。

图 D.17: 将IP核升级
(5)在弹出的Generate Output Product窗口中(如图D.18所示)点击Generate(根据需要选择global或ooc模式),完成升级。

图 D.18: 完成IP核升级
D.5 使用Chipscope进行在线调试
在使用FPGA开发的过程中,经常会遇到“仿真通过,上板不过”的现象。由于上板调试手段薄弱,导致很难定位错误。这时候可以借助Vivado里集成的Chipscope进行在线调试,在线调试是在FPGA上运行的过程中探测设定好的信号,然后通过USB编程线缆显示到调试上位机上。
本附录给出使用在线调试的基本方法:在RTL里设定需探测的信号,综合并建立Debug,实现并生产比特流文件,下载比特流和Debug文件,上板观察。
D.5.1 抓取需探测的信号
在RTL源码中,给想要在FPGA上探测的信号声明前增加(*mark_debug = “true”*)。
比如,我们想要在FPGA板上观察debug信号、PC寄存器和数码管寄存器,需要在代码里按图D.19进行设置。设定完成后,就可以运行综合了。

图 D.19: 在RTL设定要探测的信号
D.5.2 综合并建立Debug
在综合完成后,需建立Debug。
点击Vivado工程左侧的“synthesis\(\rightarrow\)Open Synthesized Desgin\(\rightarrow\)Set Up Debug”,如图D.20所示。

图 D.20: 综合后选择“Set Up Debug”
随后会出现图D.21所示界面,点击Next。

图 D.21: “Set Up Debug”的提示界面
随后会列出抓取的Debug信息,点击Next,如图D.22所示。

图 D.22: 显示所有抓取的信号
选择抓取的深度和触发控制类型,点击Next(更高级的调试可以勾选“Advanced trigger”),如图D.23所示。

图 D.23: 设定抓取信号的参数
最后,点击Finish,如图D.24所示。

图 D.24: 完成“Set Up Debug”
D.5.3 实现并生产比特流文件
完成上一节的操作后会出现类似图D.25所示界面,直接点击Generate Bitstream。弹出图D.26所示界面,点击Save。

图 D.25: 选择“Generate Bitstream”

图 D.26: 保存约束文件
如果有后续弹出界面,继续点击OK或Yes即可。这时就进入后续生成比特文件的流程了,此时就可以关闭Vivado界面里的synthesis design界面了。如果发现图D.27所示的错误,是因为路径太深,引用起来名字太长造成的,降低工程目录的路径深度即可:

图 D.27: 提示工程路径过长
D.5.4 下载比特流文件和Debug文件
完成上一节的操作后,会生成比特流文件和调试使用的ltx文件。打开Open Hardware Manager,连接好FPGA开发板后,选择Program Device,如图D.28所示,自动加载比特流文件和调试的ltx文件。选择Program,等待下载完成。

图 D.28: 下载比特流文件和ltx文件
D.5.5 上板观察
在下载完成后,Vivado界面如图D.29所示,在线调试就是在hw_ila_1界面里进行的。

图 D.29: 在线调试界面
hw_ila_1界面主要分为3个分区,如图D.30所示。

图 D.30: 在线调试界面分区
首先,我们需要在右下角区域设定触发条件。所谓触发条件,就是设定该条件满足时获取波形,比如先设定触发条件是数码管寄存器到达0x0500_0005。在图D.31中,先点击“+”,再双击num_data。

图 D.31: 获取待触发的信号
之后会出现图D.32所示界面,设定好触发条件。

图 D.32: 设定触发条件
可以设定多个触发条件,比如,再加一个除法条件是写回使能为0xf,可以设定多个触发条件之间的关系,比如是任意一个条件满足、两个条件都满足等等,如图D.33所示。

图 D.33: 设定多个触发条件
在左下角窗口,选择settings,可以设定Capture选项,经常用到的是Trigger position in window,它用来设定触发条件满足的时刻在波形窗口的位置。比如,图D.34将其设定为500,表示当触发条件满足时,波形窗口的第500个clk的位置满足该条件。言下之意,将触发条件满足前的500个clk的信号值抓出来,这样可以看到触发条件之前的电路行为。Refresh rate设定了波形窗口的刷新频率。

图 D.34: 设定抓取模式
触发条件建立后,就可以启动波形抓取了,有三个关键的触发按键,即图D.35圈出的3个按键:
- 左起第一个,设定触发模式,有两个选项:单触发和循环触发。当按下该按键时,表示循环检测触发,那么只要触发条件满足,波形窗口就会更新。当设置为单触发时,就是触发一次完成后,就不会再检测触发条件了。比如,如果设定触发条件是PC=0x1c000690,那么该PC会被多次执行到。如果设定为单触发,那按下FPGA板上的复位键,波形窗口只会展示第一次触发时的情况。如果设定循环触发,那么波形窗口会以Refresh rate不停刷新捕获的触发条件。
- 左起第二个,等待触发条件被满足。点击该按键就是等待除法条件被满足,展示出波形。
- 左起第三个,立即触发。点击该按键,表示不管触发条件,立即抓取一段波形展示到窗口中。
图D.35就是点击第三个按键得到的波形,因为是立即触发,所以num_data不是0x0500_0005,且有一条标注为“T”的红色线,就是触发的时刻。由于触发时刻位于波形窗口的500 clk位置,所以红色的位置正好是500 clk处。

图 D.35: 三个触发按键
从图D.35也能看到,num_data是0x5c00_005c,表示一次测试已经完成了。这时候点击第二个触发按键等待触发,会发现波形窗口没有反应。这是因为触发条件没有被满足,按下FPGA板上的复位键即可。结果如图D.36所示。圈出的就是触发条件:num_data==32’h5c00_005c && rf_wen==4’hf。

图 D.36: 得到触发条件满足时的波形
剩下的Debug过程,就和仿真Debug类似了。但是在线调试时,你无法添加之前RTL中未被添加debug mark的信号。在线调试过程中,可能需要不停地更换触发条件,不停地按复位键。
D.5.6 注意事项
添加要抓取的信号时,注意不要给太多信号标注debug mark。在线调试时抓取波形是需要消耗电路资源和存储单元的,因此能抓取的波形大小是受限的。应当只给必要的Debug信号添加debug mark。
抓取波形的深度不宜太深。如果设定得太深,那么会使存储资源不够,导致最后生成比特流和Debug文件失败。
抓取的信号数量和抓取的深度是一对矛盾的变量。如果抓取深度较低,那么抓取的信号数量可以相对多些。
相对仿真调试,在线调试对调试思想和技巧有更高的要求,请好好整理思路,多多总结技巧。特别强调以下几点:
- 触发条件的设定有很多组合,请根据需求认真考虑,好好设计。
- 通常只需要使用单触发模式,但循环触发有时候也很有用,必要时要好好利用。
- 在线调试界面里有很多按键,请自行学习,可以到网上搜索资料,或到Xilinx官网上搜索,查找官方文档等。
最后再提醒一点,遇到“仿真通过,上板不过”的问题,请先重点排查其他问题,最后再使用在线调试的方法。对面本书里的这种小规模的CPU设计,根据我们以往经验,很多“仿真通过,上板不过”都是以下问题之一导致的:
- 多驱动。
- 模块的input/output端口接入的信号方向不对。
- 时钟复位信号接错。
- 代码不规范,乱用阻塞赋值,随意使用always语句。
- 仿真时控制信号有“X”。仿真时,有“X”调“X”,有“Z”调“Z”。6)时序违约。
- 模块里的控制路径上的信号未进行复位。
D.6 在实验箱开发板上固化设计的方法
本节给出基于实验箱来固化一个FPGA设计的方法。
固化后,每次上电时,实验箱上的开发板会自动加载设计到FPGA芯片上。因此,断电重新上电后不需要重新下载比特流文件,极大方便了基于硬件设计的软件开发和调试。
固化的流程是先将一个比特流文件转换为mcs文件,将mcs文件下载到实验箱上开发板的一个SPI Flash上。
D.6.1 生成mcs文件
首先,需要确保FPGA设计的比特流文件已经生成。但比特流文件是用于直接下载到FPGA芯片里的文件,不能下载到Flash芯片里,因而需要转换为mcs文件。
在Vivado工具里,生成mcs文件需要在命令控制台(tcl console)里输入命令,如图D.37所示。

图 D.37: 在“tcl console”里输入命令
图D.37中蓝色字体为输入的命令,“pwd”用于查看目录。随后使用“cd”命令进入比特流文件所在的目录。
假设生成的比特流文件为soc_test.bit,则输入命令串“write_cfgmem -format mcs -interface spix1 -size 16 -loadbit “up 0 soc_test.bit” -file soc_test.mcs”即可生成mcs文件,如图D.38所示。

图 D.38: 输入生成mcs文件的命令
命令里的soc_test.bit为待转换的FPGA设计的比特文件,soc_test.mcs为生成的mcs文件名,可以自定义。另外,在生成soc_test.mcs文件的同时,也会生成soc_test.prm文件。
上述命令的作用是先输入“cd”命令将目录切换到了比特流文件的目录,再使用“write_cfgmem”命令将比特流文件转换为mcs文件。这两步可以使用命令“write_cfgmem -format mcs -interface spix1 -size 16 -loadbit “up 0 E:/run_vivado/mycpu_prj1/mycpu.runs/impl_1/soc_test.bit” -file E:/run_vivado/mycpu_prj1/mycpu.runs/impl_1/soc_test.mcs”一次完成。这一命令中明确指定了比特流文件的目录和生成的mcs文件的保存目录。比特流文件的目录和文件名必须正确,但mcs文件的目录和文件名可以自定义。
D.6.2 下载mcs文件
生成好mcs文件后,就需要将其下载到实验箱上开发板里的SPI Flash上。和下载比特流文件一样,打开Vivado工具里的“Open Hardwar Target”,连接设备。左键选中xc7a200t 后,右键选择“Add Configuration Memory Device”,如图D.39所示。

图 D.39: 下载界面选择“Add Configuration Memory Device…”
出现如图D.40所示界面,在search栏输入s25fl128s,出现两个可选的芯片型号:s25fl128sxxxxxx0-spi-x1_x2_x4和s25fl128sxxxxxx1-spi-x1_x2_x4。选择的型号,需要与板上固定的Flash芯片型号相同(看板上Flash型号标识的末尾是0还是1)。也可以在两者中先任选一个,如果后续编程Flash失败,再回来选另一个型号的。选好Flash型号后,点击OK。

图 D.40: 设置Memory设备配置
弹出如图D.41所示的窗口,询问是否现在编程Flash,点击OK。

图 D.41: 询问是否编程Flash
出现图D.42所示的编程Flash的界面后,在“Configuration file”栏选择之前生成的mcs文件,在“PRM file”那栏选择之前生成的prm文件,点击OK。

图 D.42: 在“Configuration file”栏里选择mcs文件
后续等待下载mcs到Flash芯片完成即可。Flash芯片会先进行擦除,再进行编写,完成后会提示“Flash programming completed successfully”,如图D.43所示。

图 D.43: flash编程成功
此时烧写就完成了,需要断开下载线缆,并将开发板断电重新上电,等待一段时间(约30秒),固化到开发板上的设计就被自动加载到FPGA芯片并开始运行了。