模块是模块,测试是测试
无论是在vivado或者是modelsim,模块声明文件和测试文件都是分开的,模块声明文件主要负责功能上的所有逻辑,测试文件主要负责产生合适的时钟和合适的输入,就像数电实验一样,模块文件就是老师给的各种芯片,测试文件就是搭建的电路和时钟时序,搭建完了之后看时序。
所以如果不是为了仿真,测试文件是一点用都没有,如果不是下载的话,vivadoli的引脚约束文件(也就是xdc文件)也是一点用都没有。
按道理来说可以是直接复制黏贴就可以直接运行的,但是在移植的时候发现还是有细微的改动。
首先在vivado里有一个工程是流水灯的,他的模块文件内容如下:
//===========================================================================
// Module name: led_test.v
//===========================================================================
`timescale 1ns / 1ps
module led_test
(
sys_clk_p, // Differentia system clock 200Mhz input on board
sys_clk_n,
rst_n, // reset ,low active
led, // LED,use for control the LED signal on board
fan_pwm //fan control
);
//===========================================================================
// PORT declarations
//===========================================================================
input sys_clk_p;
input sys_clk_n;
input rst_n;
output [3:0] led;
output fan_pwm;
//define the time counter
reg [31:0] timer;
reg [3:0] led;
assign fan_pwm =1'b0;
//===========================================================================
//Differentia system clock to single end clock
//===========================================================================
wire sys_clk;
IBUFGDS u_ibufg_sys_clk //专用原语,差分信号输入
(
.I (sys_clk_p),
.IB (sys_clk_n),
.O (sys_clk )
);
//===========================================================================
// cycle counter:from 0 to 1 sec
//===========================================================================
always @(posedge sys_clk or negedge rst_n)
begin
if (~rst_n)
timer <= 32'd0; // when the reset signal valid,time counter clearing
else if (timer == 32'd199_999_999) //1 seconds count(200M-1=199999999) 系统时钟200Mhz,周期5ns,计数0-199_999_999,共2*10^8个周期
timer <= 32'd0; //count done,clearing the time counter
else
timer <= timer + 1'b1; //timer counter = timer counter + 1,每周期上升沿计数
end
//===========================================================================
// LED control
//===========================================================================
always @(posedge sys_clk or negedge rst_n)
begin
if (~rst_n)
led <= 4'b0000; //when the reset signal active
else if (timer == 32'd49_999_999) //time counter count to 0.25 sec,LED1 lighten
led <= 4'b0001;
else if (timer == 32'd99_999_999) //time counter count to 0.5 sec,LED2 lighten
begin
led <= 4'b0010;
end
else if (timer == 32'd149_999_999) //time counter count to 0.75 sec,LED3 lighten
led <= 4'b0100;
else if (timer == 32'd199_999_999) //time counter count to 1 sec,LED4 lighten
led <= 4'b1000;
end
endmodule
测试文件内容则是
`timescale 100ps / 1ps
//
// Module Name: vtf_led_test
//
module vtf_led_test;
// Inputs
reg sys_clk_p;
wire sys_clk_n;
reg rst_n;
// Outputs
wire [3:0] led;
// Instantiate the Unit Under Test (UUT)
led_test uut (
.sys_clk_p(sys_clk_p),
.sys_clk_n(sys_clk_n),
.rst_n(rst_n),
.led(led)
);
initial begin
// Initialize Inputs
sys_clk_p = 0;
rst_n = 0;
// Wait 100 ns for global reset to finish
#1000;
rst_n = 1;
// Add stimulus here
#20000;
// $stop;
end
always #25 sys_clk_p = ~ sys_clk_p; //5ns一个周期,产生200MHz时钟源
assign sys_clk_n=~sys_clk_p;
endmodule
上面的文件在vivado里是能够完全运行的,没有错误,但是在移植的时候,将模块文件复制移植到name.v文件,测试文件内容复制移植到name_tb.v文件里,在compile all的时候就会有错误。
①首先在模块声明文件中报错
IBUFGDS u_ibufg_sys_clk //专用原语,差分信号输入
(
.I (sys_clk_p),
.IB (sys_clk_n),
.O (sys_clk )
);
//说是这个模块没有声明,找不到,所以首先把这个模块删除掉
②然后能compile了,也能start simulation了,但是没有波形,仔细查看后问题出在
//首先观察模块声明文件中的以下这一段代码
always @(posedge sys_clk or negedge rst_n)
begin
if (~rst_n)
timer <= 32'd0; // when the reset signal valid,time counter clearing
else if (timer == 32'd199_999_999) //1 seconds count(200M-1=199999999) 系统时钟200Mhz,周期5ns,计数0-199_999_999,共2*10^8个周期
timer <= 32'd0; //count done,clearing the time counter
else
timer <= timer + 1'b1; //timer counter = timer counter + 1,每周期上升沿计数
end
//---------------------------------------------//
//再看看测试文件中的时钟代码
always #25 sys_clk_p = ~ sys_clk_p; //5ns一个周期,产生200MHz时钟源
assign sys_clk_n=~sys_clk_p;
你会发现在模块声明文件中的激励信号是sys_clk,而测试文件里则是sys_clk_p,这就导致了声明中的功能块得不到激励信号,所以也就没有波形,接下来就知道怎么改了,在模块声明文件中修改那两个always块,修改成下面这个样子。我这里把流水灯的频率也给改了。
always @(posedge sys_clk_p or negedge rst_n)
begin
if (~rst_n)
timer <= 32'd0; // when the reset signal valid,time counter clearing
else if (timer == 32'd199_999_999) //1 seconds count(200M-1=199999999) ????200Mhz???5ns???0-199_999_999,?2*10^8???
timer <= 32'd0; //count done,clearing the time counter
else
timer <= timer + 1'b1; //timer counter = timer counter + 1?????????
end
//===========================================================================
// LED control
//===========================================================================
always @(posedge sys_clk_p or negedge rst_n)
begin
if (~rst_n)
led <= 4'b0000; //when the reset signal active
else if (timer == 32'd4_999_999) //time counter count to 0.25 sec,LED1 lighten
led <= 4'b0001;
else if (timer == 32'd9_999_999) //time counter count to 0.5 sec,LED2 lighten
begin
led <= 4'b0010;
end
else if (timer == 32'd14_999_999) //time counter count to 0.75 sec,LED3 lighten
led <= 4'b0100;
else if (timer == 32'd19_999_999) //time counter count to 1 sec,LED4 lighten
led <= 4'b1000;
end
测试文件不需要改动,但是需要将时钟精度修改一下,首先在模块声明和测试文件的第一个没有注释的代码都是
`timescale 100ps / 1ps
//我们不需要那个高的仿真时钟精度,把它改成下面的这个代码,两个文件都要改
`timescale 1ns / 1ns
然后就能仿真了(注意仿真的时候不要使能这里)。
然后看一下波形:
这下对了。但是很奇怪的是,在原来的代码中明明在模块声明文件里的always里的激励信号和原测试文件的输入是不一样的,为什么在vivado里也能运行仿真。
移植后的代码:
模块声明文件:
`timescale 1ns / 1ns
module led_test
(
sys_clk_p, // Differentia system clock 200Mhz input on board
sys_clk_n,
rst_n, // reset ,low active
led, // LED,use for control the LED signal on board
fan_pwm //fan control
);
//===========================================================================
// PORT declarations
//===========================================================================
input sys_clk_p;
input sys_clk_n;
input rst_n;
output [3:0] led;
output fan_pwm;
//define the time counter
reg [31:0] timer;
reg [3:0] led;
assign fan_pwm =1'b0;
//===========================================================================
//Differentia system clock to single end clock
//===========================================================================
wire sys_clk;
//===========================================================================
// cycle counter:from 0 to 1 sec
//===========================================================================
always @(posedge sys_clk_p or negedge rst_n)
begin
if (~rst_n)
timer <= 32'd0; // when the reset signal valid,time counter clearing
else if (timer == 32'd199_999_999) //1 seconds count(200M-1=199999999) ????200Mhz???5ns???0-199_999_999,?2*10^8???
timer <= 32'd0; //count done,clearing the time counter
else
timer <= timer + 1'b1; //timer counter = timer counter + 1?????????
end
//===========================================================================
// LED control
//===========================================================================
always @(posedge sys_clk_p or negedge rst_n)
begin
if (~rst_n)
led <= 4'b0000; //when the reset signal active
else if (timer == 32'd4_999_999) //time counter count to 0.25 sec,LED1 lighten
led <= 4'b0001;
else if (timer == 32'd9_999_999) //time counter count to 0.5 sec,LED2 lighten
begin
led <= 4'b0010;
end
else if (timer == 32'd14_999_999) //time counter count to 0.75 sec,LED3 lighten
led <= 4'b0100;
else if (timer == 32'd19_999_999) //time counter count to 1 sec,LED4 lighten
led <= 4'b1000;
end
endmodule
测试文件代码:
`timescale 1ns / 1ns
//
// Module Name: vtf_led_test
//
module vtf_led_test;
// Inputs
reg sys_clk_p;
wire sys_clk_n;
reg rst_n;
// Outputs
wire [3:0] led;
// Instantiate the Unit Under Test (UUT)
led_test uut (
.sys_clk_p(sys_clk_p),
.sys_clk_n(sys_clk_n),
.rst_n(rst_n),
.led(led)
);
initial begin
// Initialize Inputs
sys_clk_p = 0;
rst_n = 0;
// Wait 100 ns for global reset to finish
#1000;
rst_n = 1;
// Add stimulus here
#20000;
// $stop;
end
always #25 sys_clk_p = ~ sys_clk_p; //5ns???????200MHz???
assign sys_clk_n=~sys_clk_p;
endmodule
结束