|
最近写了一个分频的代码,但是在仿真中遇到了一个小问题,具体代码如下: 分频代码(该模块功能为将50MHz时钟分频为10Hz) module div_fre(
//-------------------------------Port Declaration---------------------------------
output o_clk_100Hz,
input i_sys_clk_50MHz,
input i_sys_reset
);
//-------------------------------Define Parameter---------------------------------
parameter div_cnt_max = 23'd4999999;
parameter div_cnt_half = 23'd2499999;
//-------------------------------Internal Registers-------------------------------
reg [22:0] div_cnt = 23'd0;
reg fall_en = 1'b0;
reg rise_en = 1'b0;
reg clk_temp = 1'b0;
//-------------------------------Internal Wire------------------------------------
//-------------------------------Code Starts Here---------------------------------
always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
if(i_sys_reset)
div_cnt <= 23'd0;
else if(div_cnt == div_cnt_max)
div_cnt <= 23'd0;
else
div_cnt <= div_cnt + 1;
end
/*
always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
if(i_sys_reset)
fall_en <= 1'b0;
else begin
if(div_cnt == div_cnt_half - 1)
fall_en <= 1'b1;
else
fall_en <= 1'b0;
end
end
always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
if(i_sys_reset)
rise_en <= 1'b0;
else begin
if(div_cnt == div_cnt_max - 1)
rise_en <= 1'b1;
else
rise_en <= 1'b0;
end
end
always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
if(i_sys_reset)
clk_temp <= 1'b1;
else begin
if(fall_en)
clk_temp <= 1'b0;
else if(rise_en)
clk_temp <= 1'b1;
else
clk_temp <= clk_temp;
end
end
*/
always@ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
fall_en = (i_sys_reset) ? (1'b0) :
((div_cnt == div_cnt_half - 1) ? (1'b1) : (1'b0));
end
always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
rise_en = (i_sys_reset) ? (1'b0) :
((div_cnt == div_cnt_max - 1) ? (1'b1) : (1'b0));
end
always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
clk_temp = (i_sys_reset) ? (1'b1) :
((fall_en) ? (1'b0) : ((rise_en) ? (1'b1) : (clk_temp)));
end
assign o_clk_100Hz = clk_temp;
endmodule
激励文件为: module div_fre_tb;
// Inputs
reg i_sys_clk_50MHz;
reg i_sys_reset;
// Outputs
wire o_clk_100Hz;
parameter HALF_PERIOD = 10;
// Instantiate the Unit Under Test (UUT)
div_fre uut (
.o_clk_100Hz(o_clk_100Hz),
.i_sys_clk_50MHz(i_sys_clk_50MHz),
.i_sys_reset(i_sys_reset)
);
initial begin
// Initialize Inputs
i_sys_clk_50MHz = 1;
i_sys_reset = 1;
// Wait 100 ns for global reset to finish
#100;
i_sys_reset = 0;
// Add stimulus here
end
initial begin
#HALF_PERIOD
forever
#HALF_PERIOD i_sys_clk_50MHz = ~i_sys_clk_50MHz;
end
endmodule
功能仿真波形为:
从仿真波形可以看出来clk_temp跳变的时刻跟我所设计的跳变时刻不太符合,本来应该是i_sys_clk_50MHz的上升沿去采fall_en的高电平来产生clk_temp = 0,可是从仿真波形中可以看到clk_temp信号是在fall_en变高的一开始就进行了变化。我通过chipscope在线调试,将程序下载到FPGA中进行在线调试却是正常的,可以看到clk_temp在fall_en=1的结束位置进行了跳变。为什么功能仿真会出现这样的问题呢? 我重新看了代码,并重新用传统的always块的方法重新写了程序(具体为程序中注释的部分),如下: always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
if(i_sys_reset)
fall_en <= 1'b0;
else begin
if(div_cnt == div_cnt_half - 1)
fall_en <= 1'b1;
else
fall_en <= 1'b0;
end
end
always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
if(i_sys_reset)
rise_en <= 1'b0;
else begin
if(div_cnt == div_cnt_max - 1)
rise_en <= 1'b1;
else
rise_en <= 1'b0;
end
end
always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
if(i_sys_reset)
clk_temp <= 1'b1;
else begin
if(fall_en)
clk_temp <= 1'b0;
else if(rise_en)
clk_temp <= 1'b1;
else
clk_temp <= clk_temp;
end
end
通过仿真,波形如下:
可以看到仿真波形跟想要的是一样的。 通过代码对比,发现问题出在了 always@ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
fall_en = (i_sys_reset) ? (1'b0) :
((div_cnt == div_cnt_half - 1) ? (1'b1) : (1'b0));
end
always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
rise_en = (i_sys_reset) ? (1'b0) :
((div_cnt == div_cnt_max - 1) ? (1'b1) : (1'b0));
end
always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
clk_temp = (i_sys_reset) ? (1'b1) :
((fall_en) ? (1'b0) : ((rise_en) ? (1'b1) : (clk_temp)));
end
这段代码中的阻塞赋值。我开始认为这段代码中每个always块中只有一句话,可以不用考虑阻塞和非阻塞赋值。但是出了问题锁定到这个地方的时候,详细想一想,由于是采用阻塞赋值,在时钟上升沿,两个always块是并行执行的。在verilog中两个always块的执行可以按照任何顺序执行。而这种先后顺序导致的仿真结果也是不一样的。所以以后写代码需要在此加以注意。 By:冰风溪谷 |