基于ZYNQ-7000系列的FPGA学习笔记9——VIVADO在线调试
上期我们学习了呼吸灯,这一期我们基于上期的内容,介绍以下Vivado的在线调试功能
1. IP核介绍
在学习VIVADO的在线调试功能之前,我们需要先来了解一下什么是IP核:
IP(Intellectual Property),即知识产权,是ASIC或FPGA中的预先设计好的电路功能模块。在FPGA的设计过程中,难免会有一些实现起来比较复杂,且设计功能很难保证,但是使用频率比较高的模块,如果每次产品设计都要去重复开发,中间难免浪费大量的时间,降低开发效率,这样明显是吃力不讨好,所以VIVADO中植入了很多的IP核,这些IP核有些是免费的,有些是付费的,来帮助用户提高开发效率。下面是IP核的一些优缺点:
优点:
- 可靠性高:由于是VIVADO提供给,设计功能上来讲会比我们自己实现要好很多
- 提高开发效率:由于只需要了解如何使用对应的IP核,这样大大提高了开发的效率
- 加快产品上市:使用IP核,减少了自己设计,验证的环节,可以减轻开发人员的负担,加快产品上市
缺点:
- 移植性差:由于是VIVADO软件中自带的,无法在别家的FPGA芯片中使用
- 功能调整空间小:IP核的大部分功能都是固定死的,我们只能根据需求进行调用,无法知晓内部的具体实现,类似于一个黑匣子
- 部分需要付费:有一些IP核是需要我们付费的,这也是一大缺点
2. 在线逻辑分析仪介绍
我们在前面的内容中,都是先编写rtl代码,然后仿真,最后再下载到开发板中,来观察情况。但如果是一些比较复杂的场景,可能仿真之后的结果没有问题,板子上却有问题,这个时候就需要进行一个板级的调试。
常规的班级调试,是采用一些测试工具进行测试,比如万用表、示波器、逻辑分析仪这些,但是这些仪器要求都比较高(因为你必须要有对于的测试工具,否则无法调试),有没有什么办法,可以实现一个板级的调试呢?事实上是有点,就是使用在线逻辑分析仪。
在线逻辑分析仪借用了传统逻辑分析仪的理念以及大部分的功能,并利用 FPGA 中的逻辑资源,将这些功能植入到 FPGA 的设计当中。在线逻辑分析仪的应用原理框图如下图所示:
其中,待测设计(Design Under Test,DUT)就是用户逻辑,它和片内的在线逻辑分析仪都位于 FPGA中。在线逻辑分析仪通过一个或多个探针(Probe)来采集希望观察的信号,然后通过片内的 JTAG 硬核组件,将捕获到的数据传送给下载器,进而上传到 Vivado 供用户查看。
Vivado 也能够按照上述数据路径,反向地向 FPGA 中的在线逻辑分析仪传送一些控制信息。
在线逻辑分析仪不需要将待测信号引出至 I/O 上,也不需要电路板走线或者探测点,当然更不需要外部的逻辑分析仪,在 Vivado 中就可以将在线逻辑分析仪添加到设计中。但是在线逻辑分析仪会占用一定数量的内部逻辑资源,如块 RAM、查找表、触发器等等
3. 开启在线逻辑分析仪的方法
在 Vivado 中,在线逻辑分析仪的功能被称为“集成逻辑分析器(Integrated Logic Analyzer,ILA)”,它以 IP 核的形式来加入到用户设计中。Vivado 提供了三种具有不同集成层次的插入 ILA 方法如下:
- 直接在 HDL 代码中例化一个 ILA IP 核
- 在 HDL 代码综合之前为想要观察的 reg 或 wire 信号添加“Mark Debug”综合属性,然后通过一个简单的“Setup Debug”向导来设置各个探针和 ILA IP 核的工作参数
- 在综合后的网表中,分别标记要进行调试观察的信号,然后通过一个简单的“Setup Debug”向导来设置各个探针和 ILA IP 核的工作参数
下面我来介绍一下这三种方法对于的使用步骤:
3.1 直接在 HDL 代码中例化一个 ILA IP 核
这种方法是直接在 HDL 代码中例化一个 ILA IP 核,也被称为“HDL 实例化调试探针流程”,这是集成层次最高的方法。ILA IP 核可以在 IP Catalog(IP 目录)中找到,并对其进行配置,以符合所需的调试需求,这是最直接的方法,但其灵活性也较差。在调试工作完毕之后,还需要在 HDL 源代码中删除ILA IP 核,然后重新综合以生成最终的比特流。
下面是详细的使用步骤:
- 点击进入ILA配置选项
- 对LIA通用配置
- 探针端口配置
完成上述步骤之后,点击生成即可成功创建ILA 的IP核。
这里选择ooc方式综合,这样子就可以只综合一次,无论后面这么修改代码,都只会综合修改的代码,而不综合ILA部分的代码。
这里介绍一下OOC综合的概念:
对于顶层设计,Vivado 使用自顶向下的全局(Global)综合方式,将顶层之下的所有逻辑模块都进行综合,但是设置为 OOC 方式的模块除外,它们独立于顶层设计而单独综合。通常在整个设计周期中,顶层设计会被多次修改并综合,但有些子模块在创建完毕之后不会因为顶层设计的修改而被修改,如 IP,它们被设置为 OOC 综合方式。OOC 模块只会在综合顶层之前被综合一次,这样在顶层的设计迭代过程中,OOC 模块就不必跟随顶层模块而一次次产生相同结果的多余综合了,所以 OOC 流程减少了设计的周期,并消除了设计迭代,使您可以保存和重用综合结果。
Out-of-Context(OOC) 综合是一种自底向上的设计流程,默认情况下,Vivado 设计套件使用 OOC 的设计流程来综合 OOC 模块。OOC 模块可以是来自 IP Catalog 的 IP、Vivado IP Integrator 的 block design 或者顶层模块下手动设置为 OOC 方式的任何子模块。
- 对ILA模块进行例化
在我们编写的顶层模块中,添加如下代码,对ILA模块进行例化:
ila_0 u_ila_0(
.clk (sys_clk),
.probe0 (sys_rst_n),
.probe1 (cnt_200us),
.probe2 (cnt_20ms),
.probe3 (cnt_2s),
.probe4 (led_flag),
.probe5 (led)
);
【注】:这里的代码是根据上一期内容呼吸灯来进行的,如果模块的代码不同,需要修改称自己的变量名。
至此,我们完成了直接在 HDL 代码中例化一个 ILA IP 核。
3.2 使用 Debug 标记创建 ILA 调试环境
使用 Debug 标记创建 ILA 就是在综合之前的 HDL 代码中为想要观察的 reg 或 wire 信号添加“Mark Debug”综合属性,比如:
【注】:添加的代码为:(* mark_debug = “true” *)
添加完成之后,进行综合,然后打开综合后的界面,选择 “ Set Up Debug ” 选项。
下一步就是配置一些信号的信息,比如时钟源、探针类型、采样深度等
完成上述步骤之后,发现综合生成的网表中需要检测的内容变成了虚线,表示ILA IP核的分配完成。之后点击保存当前界面,根据提示生成对应的XDC文件,在实现阶段,Vivado 会读取这些约束,并按照这些命令的参数来自动地加入 ILA IP 核。
下面是生成的XDC文件:
#时序约束
create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
#IO 管脚约束
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports led]
create_debug_core u_ila_0 ila
set_property ALL_PROBE_SAME_MU true [get_debug_cores u_ila_0]
set_property ALL_PROBE_SAME_MU_CNT 1 [get_debug_cores u_ila_0]
set_property C_ADV_TRIGGER false [get_debug_cores u_ila_0]
set_property C_DATA_DEPTH 4096 [get_debug_cores u_ila_0]
set_property C_EN_STRG_QUAL false [get_debug_cores u_ila_0]
set_property C_INPUT_PIPE_STAGES 0 [get_debug_cores u_ila_0]
set_property C_TRIGIN_EN false [get_debug_cores u_ila_0]
set_property C_TRIGOUT_EN false [get_debug_cores u_ila_0]
set_property port_width 1 [get_debug_ports u_ila_0/clk]
connect_debug_port u_ila_0/clk [get_nets [list sys_clk_IBUF_BUFG]]
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe0]
set_property port_width 14 [get_debug_ports u_ila_0/probe0]
connect_debug_port u_ila_0/probe0 [get_nets [list {cnt_200us[0]} {cnt_200us[1]} {cnt_200us[2]} {cnt_200us[3]} {cnt_200us[4]} {cnt_200us[5]} {cnt_200us[6]} {cnt_200us[7]} {cnt_200us[8]} {cnt_200us[9]} {cnt_200us[10]} {cnt_200us[11]} {cnt_200us[12]} {cnt_200us[13]}]]
create_debug_port u_ila_0 probe
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe1]
set_property port_width 7 [get_debug_ports u_ila_0/probe1]
connect_debug_port u_ila_0/probe1 [get_nets [list {cnt_20ms[0]} {cnt_20ms[1]} {cnt_20ms[2]} {cnt_20ms[3]} {cnt_20ms[4]} {cnt_20ms[5]} {cnt_20ms[6]}]]
create_debug_port u_ila_0 probe
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe2]
set_property port_width 7 [get_debug_ports u_ila_0/probe2]
connect_debug_port u_ila_0/probe2 [get_nets [list {cnt_2s[0]} {cnt_2s[1]} {cnt_2s[2]} {cnt_2s[3]} {cnt_2s[4]} {cnt_2s[5]} {cnt_2s[6]}]]
create_debug_port u_ila_0 probe
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe3]
set_property port_width 1 [get_debug_ports u_ila_0/probe3]
connect_debug_port u_ila_0/probe3 [get_nets [list led_flag]]
create_debug_port u_ila_0 probe
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe4]
set_property port_width 1 [get_debug_ports u_ila_0/probe4]
connect_debug_port u_ila_0/probe4 [get_nets [list led_OBUF]]
create_debug_port u_ila_0 probe
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe5]
set_property port_width 1 [get_debug_ports u_ila_0/probe5]
connect_debug_port u_ila_0/probe5 [get_nets [list sys_rst_n_IBUF]]
set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub]
set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub]
set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub]
connect_debug_port dbg_hub/clk [get_nets sys_clk_IBUF_BUFG]
至此,我们完成了使用 Debug 标记创建 ILA 调试环境。
3.3 网表插入调试探针流程
网表插入调试探针流程需要在综合后的网表中进行,即将要进行调试观察的各个信号在网表中标记为“mark_debug”属性,然后通过“Setup Debug”向导来设置 ILA IP 核的参数,最后工具会根据参数来自动创建 ILA IP 核。
这个方法和 “ 使用 Debug 标记创建 ILA 调试环境 ” 十分类似,唯一不同的就是添加mark debug的方式不同,如下:
其他部分请参考 3.2的内容。
4. 在线逻辑分析仪的使用
完成第三点中的内容之后,下一步就可以生成对应的比特流文件,然后下载到开发板上。
可以看到,这里多了debug对应的文件,点击program,即可下载到芯片,后进入debug界面,如图:
下一步就是根据自己的需求,对想要观察的信号进行采样,然后分析运行的结果与预期是否由偏差,如果有的话,就去修改代码,知道运行结果与预期一致即可删除掉debug的ILA模块,删除方式如下:
- 如果是在HDL代码中中例化ILA模块,直接选择对应模块,右键删除并且在HDL代码中删除对应例化代码就好
- 如果使用的是后两中方式,则直接删除HDL代码中的 “ mark debug ” 标记和删除生成的XDC代码即可
5. 总结
5.1 在线逻辑分析的三种使用方法的总结
- HDL 实例化调试探针流程:这种方法虽然操作流程稍显复杂,但其通用性强,作为 ILA 初学者,可以优先考虑掌握本方法。
- 使用 Debug 标记创建 ILA 调试环境:和“HDL 实例化调试探针流程”的步骤相比,直接使用“Debug 标记的方法创建 ILA 调试环境”的方法,能够弱化抓线信号的位宽对在线调试的影响,在线调试时灵活性比较高,并且可以防止标记的信号被软件优化掉。
- 网表插入调试探针流程:和“使用 Debug 标记创建 ILA 调试环境”相比,我们就不用在代码中进行标记,也不需要承担在调试完成后忘记在代码中删除 mark_debug 标记的风险。但是“网表插入调试探针流程”是在综合后的网表里面对信号进行标记的,软件综合容易导致一些信号被优化,所以一般可以结合“使用 Debug 标记创建 ILA 调试环境”的方法一起使用。软件综合后的信号名称是 Vivado 工具根据自己的规则命名的,一般都与我们 HDL 代码中的命名不一样,初学者很难找到自己需要调试的信号,所以“网表插入调试探针流程”的方法虽然灵活性高但不推荐初学者使用。
以上就是本期的所有内容,创造不易,点个关注再走呗。