上一篇文章Vivado软件 调试工具的使用初步中简单介绍了ILA(Integrated Logic Analyzer),集成内部逻辑分析仪的使用。大部分工程的调试,使用ILA已经可以满足观测跟踪信号的需求。然而在以下几种情况中,VIO(Virtual Input/Output,虚拟I/O)是更好的解决方法。
比如在某个系统下:
- 需要使用外部信号来驱动FPGA。FPGA板上的按键不足,而工程里的信号需要被控制输入,这个时候,VIO就可以进行相关信号的控制。也就是说,VIO可以作为ILA的补充,用于工程调试。
- 远程调试时,用户无法现场观察或是设置硬件的输入输出,例如无法远程按键,或是远程观察LED灯。VIO就是很好的解决方案。
- 如果需要观察一个FPGA开发板启动期间的信号状态,有些产品中没有相关的按键配合,那么ILA就无法抓取FPGA初始的一些信号,不利于调试,VIO就可以控制启动,提供观察的机会。
- 当需要开发的软件进行配合时,有些FPGA工程师对软件不熟悉,无法编写软件例程,就可以通过VIO模拟软件对寄存器的读写。
1. VIO简介
前面提到了VIO可以驱动FPGA内部信号,给其提供激励,除此之外,VIO也可以观测FPGA内部信号。注意,和ILA一样,VIO也是实时的。和ILA不一样的地方在于,VIO不会使用片内或片外的RAM。总的来说,VIO 可用于替换或增强FPGA板上的状态指示器(例如 LED)和控制(例如按键或拨码开关)。Xilinx公司提供的VIO IP核可以完美的和JTAG调试工具结合,不需要用户增加额外的设计来使用。
图1所示为VIO在FPGA调试中所处的位置。
图1
-
VIO输出
VIO模块的输出连接到FPGA设计模块的输入。VIO通过输出端口提供给FPGA内部信号虚拟按键和其他控制输入。VIO一般用作FPGA设计模块的复位输入。除此之外,VIO还包括了可以在FPGA配置和使用开始时可以提供给FPGA内部信号的初始值设置功能。
-
VIO输入
FPGA模块的输出连接到VIO的输入,即VIO可以提供虚拟的LED或是其它的状态指示器件。
-
VIO IP 核的配置
在Vivado IP Catalog下搜索vio,即可在Vivado Repository –> Debug & Verification –> Debug 下找到VIO,如图2所示。
图2 IP Catalog搜索
双击打开VIO IP核后界面如图3所示。
图3 VIO IP核
在VIO IP核配置界面上,有一些重要的配置选项如表1所示:
表1 [1]:
配置名称 | 描述 |
Component Name | 命名VIO模块名 |
Input Probe Count | 选择 VIO core的输入Probe 端口数。 Vivado IDE 中使用的有效范围是 0 到 64。如果需要超过 64 个输入 Probe 端口,则需要在生成 VIO 内核之前使用以下 Tcl 命令配置 VIO core,最大的 Probe 端口数是256。set_property -dict [ list CONFIG.C_NUM_PROBE_IN {250} ] [get_ips vio_0] 注意:至少需要指定一个输入或输出 Probe 端口 |
Output Probe Count | 选择 VIO core的输出Probe 端口数。 Vivado IDE 中使用的有效范围是 0 到 64。如果需要超过 64 个输出 Probe 端口,则需要在生成 VIO 内核之前使用以下 Tcl 命令配置 VIO core,最大的 Probe 端口数是256。set_property -dict [ list CONFIG.C_NUM_PROBE_OUT {250} ] [get_ips vio_0] 注意:至少需要指定一个输入或输出 Probe 端口 |
probe_in Ports Panels | 每个probe_in 端口面板最多有16 个端口 |
Probe Width | 使用Probe Width 字段设置每个 Probe 端口的宽度。 有效宽度范围为 1 至 256 bits宽 |
probe_out Ports Panels | 每个 probe_out 端口面板最多有 16 个端口 |
Probe Width | 使用Probe Width 字段设置每个 Probe 端口的宽度。 有效宽度范围为 1 至 256 bits宽 |
Initial Value | 使用初始值字段将输出 Probe 端口的初始值设置为特定值。 该值将以带有“0x”前缀的十六进制格式指定 |
Ports Panels 额外解释:如果选择Input/Output Probe Count的个数大于16, 则在配置每个Probe的宽度时,每个界面会最多容纳16个Probe。举例:Input Probe Count为20时,对Input Probe Width的配置会分成两个界面PROBE_IN Ports (0..15)和PROBE_IN Ports (16..19),如图4所示:
图4 Ports Panels
2. VIO使用实例
-
VIO工程实例1-VIO的基本使用
沿用上一篇文章Vivado软件 调试工具的使用初步中flow_led_top.v的代码,并做出一些修改得到flow_led_vio.v,使其连接到VIO IP核上,可以远程控制和观察信号。
flow_led_top.v代码如下:
module flow_led_top #(parameter end_cnt = 50000000) ( input wire IN_CLK_50M, output reg [7:0] LED = 8'hff ); reg [31:0] cnt = 0; always @(posedge IN_CLK_50M) begin if(cnt < (end_cnt - 1)) cnt <= cnt + 1; else cnt <= 0; end always @(posedge IN_CLK_50M) begin if(LED == 8'hff) LED <= 8'hfe; else begin if(cnt == end_cnt -1) LED <= {LED[6:0], LED[7]}; else LED <= LED; end end endmodule
修改上述代码,加上VIO IP核,flow_led_vio.v代码如下。
例1:
`timescale 1ns / 1ps `define DEBUG_VIO module flow_led_vio #(parameter end_cnt = 50000000) ( input wire IN_CLK_50M, output reg [7:0] LED = 8'hff ); reg [31:0] cnt = 0; wire vio_rst; always @(posedge IN_CLK_50M or posedge vio_rst) if(vio_rst) cnt <= 0; else begin if(cnt < (end_cnt - 1)) cnt <= cnt + 1; else cnt <= 0; end always @(posedge IN_CLK_50M or posedge vio_rst) if (vio_rst) LED <= 8'hff; else begin if(LED == 8'hff) LED <= 8'hfe; else begin if(cnt == end_cnt -1) LED <= {LED[6:0], LED[7]}; else LED <= LED; end end `ifdef DEBUG_VIO flow_led_top vio_inst ( .clk(IN_CLK_50M), // input wire clk .probe_in0(LED), // input wire [7 : 0] probe_in0 .probe_out0(vio_rst) // output wire [0 : 0] probe_out0 ); `else assign vio_rst = 1'b0; `endif endmodule
比较代码可以看出,flow_led_vio.v中添加了vio_rst信号,作为VIO控制的复位信号,以及将LED加进了VIO的输入观察信号里。关于flow_led_top VIO核的配置如图5-图7所示:
图5中勾选了Enable Input Probe Activity Detectors,原因在后面解释。
图5 VIO IP核配置
图6 VIO IP核配置
图7 VIO IP核配置
在FII-PRX100-D FPGA开发板上做完管脚分配后,生成的*.xdc文件如下所示:
set_property PACKAGE_PIN N23 [get_ports {LED[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[6]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[0]}] set_property PACKAGE_PIN N24 [get_ports {LED[6]}] set_property PACKAGE_PIN P19 [get_ports {LED[5]}] set_property PACKAGE_PIN N19 [get_ports {LED[4]}] set_property PACKAGE_PIN N16 [get_ports {LED[3]}] set_property PACKAGE_PIN P16 [get_ports {LED[2]}] set_property PACKAGE_PIN M19 [get_ports {LED[1]}] set_property PACKAGE_PIN N17 [get_ports {LED[0]}] set_property PACKAGE_PIN D18 [get_ports IN_CLK_50M] set_property IOSTANDARD LVCMOS33 [get_ports IN_CLK_50M]
将工程综合,实现,生成*.bit文件,下载到FII-PRX100-D FPGA开发板的时候,可以发现,工程不仅生成了*.bit文件,还生成了*.ltx文件,如图8所示。
图8 下载*.bit文件和*.ltx文件到FII-PRX100-D开发板上
下载完成后,Vivado显示的页面如图9所示,在hw_vio_1的界面下,点击“ + ”来添加控制和观察信号,这里添加了LED_OBUF[7:0]和vio_rst,如图10所示。
图9 hw_vio_1界面
图10 添加控制或观察信号
添加LED_OBUF[7:0]和vio_rst后,如图11所示。可以看出LED_OBUF[7:0]信号是VIO的输入,并且Activity一栏有蓝色的小箭头,代表在持续变化。观察图12和图13,可以看到对于变化的信号,勾选了Enable Input Probe Activity Detectors可以清楚的显示出信号上升或是下降的变化。对比没有勾选Enable Input Probe Activity Detectors的显示信号,是没有Acitivity的上升或是下降沿的显示。
图11 控制vio_rst信号
图12 勾选Enable Input Probe Activity Detectors
图13 未勾选Enable Input Probe Activity Detectors
可以通过控制vio_rst的值来控制LED_OBUF[7:0]的值,当vio_rst的值为1时,根据代码flow_led_vio.v,LED_OBUF[7:0]应该是一直保持0xff,并且不再变化,如图14所示。
图14 vio_rst = 1
注意,LED不仅输出给了VIO,FII-PRX100-D上也做了管脚分配,连接到了板上真实的LED。可以通过控制vio_rst,观察VIO中LED_OBUF[7:0]和真实LED灯显示的情况是否一致。
在例1中,不仅使用了VIO的控制功能(vio_rst),也使用了VIO的检测功能(LED_OBUF[7:0])。VIO的使用操作简单。如果在远程调试时,用户无法设置硬件的输入输出,而工程里的信号需要被控制/检测,这个时候VIO就非常有用。
-
VIO工程实例2-联合ILA观察FPGA开发板启动状态
有时候FPGA开发板上的启动状态太快,难以捕捉到,解决方法是可以使用VIO控制FPGA板的启动,提供观察的机会。
修改例1中的代码,设计一个从0加到255的8-bit counter。当counter加到了255,就稳定停留在255,整个过程将counter连续赋值给LED信号,如下所示:
例2:
`timescale 1ns / 1ps module top ( input wire IN_CLK_50M, (* mark_debug = "TRUE" *) output [7:0] LED ); reg [7:0] cnt = 0; always @(posedge IN_CLK_50M) begin if(cnt < 255) cnt <= cnt + 1; end assign LED = cnt; endmodule
在程序综合后,设置ILA需要调试的信号,做好管脚分配后,生成的*.xdc文件如下所示:
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 4 [get_debug_cores u_ila_0] set_property C_ADV_TRIGGER true [get_debug_cores u_ila_0] set_property C_DATA_DEPTH 1024 [get_debug_cores u_ila_0] set_property C_EN_STRG_QUAL true [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 ] set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe0] set_property port_width 8 [get_debug_ports u_ila_0/probe0] connect_debug_port u_ila_0/probe0 [get_nets } {LED_OBUF[1]} {LED_OBUF[2]} {LED_OBUF[3]} {LED_OBUF[4]} {LED_OBUF[5]} {LED_OBUF[6]} {LED_OBUF[7]}]] 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 IN_CLK_50M_IBUF_BUFG] set_property PACKAGE_PIN N23 [get_ports {LED[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[6]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {LED[0]}] set_property PACKAGE_PIN N24 [get_ports {LED[6]}] set_property PACKAGE_PIN P19 [get_ports {LED[5]}] set_property PACKAGE_PIN N19 [get_ports {LED[4]}] set_property PACKAGE_PIN N16 [get_ports {LED[3]}] set_property PACKAGE_PIN P16 [get_ports {LED[2]}] set_property PACKAGE_PIN M19 [get_ports {LED[1]}] set_property PACKAGE_PIN N17 [get_ports {LED[0]}] set_property PACKAGE_PIN D18 [get_ports IN_CLK_50M] set_property IOSTANDARD LVCMOS33 [get_ports IN_CLK_50M]
将程序下载到FII-PRX100-D开发板上,在ILA中添加观察LED信号,发现因为50 MHz时钟过快,下载完程序后,无法观测到LED信号的变化过程,只能看到LED信号稳定的停留在8’hff,如下图15所示:
图15 LED信号稳定停留在8’hff
如果想要观测LED信号从8’h00到8’hff的变化过程,使用VIO添加一个输出的复位信号,修改代码如下所示:
`timescale 1ns / 1ps module top ( input wire IN_CLK_50M, (* mark_debug = "TRUE" *)output [7:0] LED ); reg [7:0] cnt = 0; wire vio_rst; always @(posedge IN_CLK_50M or posedge vio_rst) if(vio_rst) cnt <= 0; else begin if(cnt < 255) cnt <= cnt + 1; end assign LED = cnt; flow_led_top vio_inst ( .clk(IN_CLK_50M), // input wire clk .probe_out0(vio_rst) // output wire [0 : 0] probe_out0 ); endmodule
并修改例1中的VIO IP核,生成只保留1 bit输出的VIO IP核。重新生成bitstream文件后,下载到FPGA板上,并设置好相应的ILA trigger,开始捕捉LED信号,如图16所示:
图 16 设置ILA trigger
当ILA trigger设置完后,打开VIO的控制面板,如图17所示,将vio_rst信号由初始值0置为1,再设置为0。
图17 设置VIO信号vio_rst
在代码中,如果复位信号为高电平,就可以将LED信号重置为0,因为ILA 已经被设置好准备捕捉波形,ILA显示波形如图18所示:
图18 ILA捕捉到FPGA板的初始状态
在例2中,因为需要观察FPGA板的启动状态,所以使用VIO IP核做一个虚拟的控制启动,就可以很好的联合ILA调试工具观察。
-
VIO工程实例3- 16×16乘法器实现
本例同样也使用FII-PRX100-D FPGA开发板完成,因为开发板上只有8个拨码开关,7个按键作为可以直接从FPGA板上输入的信号,不够16X16乘法器需要的32位输入,所以需要使用VIO制作虚拟的外部信号输入,来驱动FPGA,并且可以直接在VIO中观察到乘法器输出结果。
参考文章Verilog for 循环语句例2中4×4乘法器的代码如下:
module for_mult ( input inclk, input [3:0] a,b, output reg [7:0] p ); integer i; always@(posedge inclk) begin p = 0; for(i = 0; i < 4; i = i + 1) begin if(b[ i ]) p = p + (a << i); end end endmodule
在此基础上实现16×16乘法器,如下所示:
例3:
`timescale 1ns / 1ps module top ( input IN_CLK_50M ); integer i; wire [15:0] a,b; reg [31:0] p = 0; always@(posedge IN_CLK_50M) begin p = 0; for(i = 0; i < 16; i = i + 1) begin if(b[ i ]) p = p + (a << i); end end flow_led_top vio_inst ( .clk(IN_CLK_50M), // input wire clk .probe_in0(p), // input wire [31 : 0] probe_in0 .probe_out0(a), // output wire [15 : 0] probe_out0 .probe_out1(b) // output wire [15 : 0] probe_out1 ); endmodule
相应的VIO IP核设置如下图19-21所示:
图19 设置两个VIO输出,一个VIO 输入
图20 VIO输入的位宽位32-bit
图21 两个VIO输入位宽都是16-bit
在设置完IP核后,综合整个工程,并分配好时钟管脚,下载综合后生成的bitstream文件,VIO界面如图22所示:
图22
从图23中可以看出,任意给出a,b的值,乘积p会立刻显示。这里是16’1456 X 16’8524 = 32’h0A93_8A18
图23
通过例3可以看出VIO在FPGA板上输入或是输出不足的时候,可以提供控制信号,并观测输出结果。
3. 总结
通过以上3个例子全面了解了VIO的使用场景及使用技巧。注意之后在实际工程中遇到类似问题,比如FPGA开发板上输入键不足,输出不足,或是需要远程观测输入输出,FPGA开发板启动状态观测,或是需要模拟软件对硬件寄存器的读写等场景时,可以使用VIO作为解决方法。
参考文档:
文章对应视频: