软件环境:vivado 2017.4 硬件平台:XC7Z020
这篇呢来说一个FPGA调试的小方法,也就是通过hw_vio来模拟系统的输入/输出,有什么好处呢?当然是方便许多啦,举个例子,如果想观察前一级模块输出(由hw_vio输入观察),或者如果系统某些事件处理,是通过高低电平或者特定数值触发不同状态机(由hw_vio输出观察),那可真是再方便不过了,再或者,布板时候没搞几个按钮,也没搞几个状态灯,系统调试的时候,正好可以利用hw_vio来模拟按键或者状态灯的作用。
系统很简单,如下图所示,想做的测试是通过probe_out0和probe_out1来模拟两个按键,通过probe_in0和probe_in2来模拟状态灯,probe_in1和probe_in3是计数测试用的,当模拟按键按下时,点亮两个状态灯,分别计数500ms和1s时候,两个状态灯自动熄灭。
顶层逻辑如下。
`timescale 1 ps / 1 ps
module hw_vio_wrapper
(clk,
//probe_in0,
//probe_in1,
//probe_in2,
//probe_in3,
probe_out0,
probe_out1,
rst_n);
input clk;
//input [0:0]probe_in0;
//input [31:0]probe_in1;
//input [0:0]probe_in2;
//input [31:0]probe_in3;
output [0:0]probe_out0;
output [0:0]probe_out1;
input [0:0]rst_n;
wire clk;
wire [0:0]probe_in0;
wire [31:0]probe_in1;
wire [0:0]probe_in2;
wire [31:0]probe_in3;
wire [0:0]probe_out0;
wire [0:0]probe_out1;
wire [0:0]rst_n;
reg [1:0] state_led0;
reg [31:0] count_1s;
reg [0:0] output_led0;
reg [1:0] state_led1;
reg [31:0] count_500ms;
reg [0:0] output_led1;
wire [0:0] btn1_triger;
wire [0:0] btn2_triger;
assign probe_in0 = output_led0;
assign probe_in1 = count_1s;
assign probe_in2 = output_led1;
assign probe_in3 = count_500ms;
assign probe_out0 = output_led0;
assign probe_out1 = output_led1;
always@(posedge clk)
begin
if(!rst_n)
begin
output_led0 <= 1'b0;
state_led0 <= 2'd0;
count_1s <= 32'd0;
end
else
begin
case(state_led0)
2'd0:
begin
if(btn1_triger == 1'b1)
state_led0 <= 2'd1;
else
state_led0 <= 2'd0;
end
2'd1:
begin
if(count_1s < 32'd100000000)
begin
count_1s <= count_1s + 1'b1;
output_led0 <= 1'b1;
end
else
state_led0 <= 2'd2;
end
2'd2:
begin
output_led0 <= 1'b0;
state_led0 <= 2'd0;
count_1s <= 32'd0;
end
endcase
end
end
always@(posedge clk)
begin
if(!rst_n)
begin
output_led1 <= 1'b0;
state_led1 <= 2'd0;
count_500ms <= 32'd0;
end
else
begin
case(state_led1)
2'd0:
begin
if(btn2_triger == 1'b1)
state_led1 <= 2'd1;
else
state_led1 <= 2'd0;
end
2'd1:
begin
if(count_500ms < 32'd50000000)
begin
count_500ms <= count_500ms + 1'b1;
output_led1 <= 1'b1;
end
else
state_led1 <= 2'd2;
end
2'd2:
begin
output_led1 <= 1'b0;
state_led1 <= 2'd0;
count_500ms <= 32'd0;
end
endcase
end
end
hw_vio hw_vio_i
(.clk(clk),
.probe_in0(probe_in0),
.probe_in1(probe_in1),
.probe_in2(probe_in2),
.probe_in3(probe_in3),
.probe_out0(btn1_triger),
.probe_out1(btn2_triger),
.rst_n(rst_n));
endmodule
管脚约束如下,这里把两个输出口也连到我板子上的两个led上了,方便直接观察。
create_clock -period 10.000 -name clk_i [get_ports clk]
set_property PACKAGE_PIN H16 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property PACKAGE_PIN R19 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports {probe_out0[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {probe_out1[0]}]
set_property PACKAGE_PIN K16 [get_ports {probe_out0[0]}]
set_property PACKAGE_PIN H15 [get_ports {probe_out1[0]}]
debug的时候可以看到多出了一个dashboard界面,这里面就可以设置hw_vio的输入和输出,hw_vio的输入口可以有数值和led两种显示方式。
led的话,甚至可以设置多种颜色。
输出的话一样有多种设置,包括数值、按钮,其中按钮又分成了高电平有效自动回弹按钮、低电平有效自动回弹按钮和按一次改变一次状态的不回弹按钮。
按下时,输入的状态灯亮起,然后开始计数。
与此同时,抓输出的下降沿,因为计数到100000000时候,灯自动熄灭。
嗯哼,确实是这样没错滴,另外一个延迟500ms的与此类似,结果也是一样滴。