前情提要:
阻塞赋值(=):该语句结束时就完成赋值操作,前面的语句没有完成前,后面的语
句是不能执行的。在一个过程块内多个阻塞赋值语句是顺序执行的。
非阻塞赋值(<=):一条非阻塞赋值语句的执行是不会阻塞下一条语句的执行,也就
是说在本条非阻塞赋值语句执行完毕前,下一条语句也可开始执行。非阻塞赋值语句在过
程块结束时才完成赋值操作。在一个过程块内的多个非阻塞赋值语句是并行执行的。
但是如果一个always过程块只有一个赋值语句,哪采用阻塞和非阻塞应该是一样的吗?
如果几个always中变量有关联,采用阻塞赋值会出现仿真错误,见如下代码和仿真截图
//always块1,放在前面
always @(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk <= 8'd0;
else if(cnt_clk == 8'd24)
cnt_clk <= 8'd0;
else
cnt_clk = cnt_clk + 1;
//always块2
always @(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
i2c_clk <= 1'b1;
else if(cnt_clk == 8'd24)
i2c_clk <= ~i2c_clk;
可以看到,i2c_clk 在cnt_clk == 8’d24时没有正确翻转,而是提前了,并且在cnt_clk == 8’d24时翻转了两次。
但是我们把两个always块的顺序调换
// always块的顺序调换
always @(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
i2c_clk <= 1'b1;
else if(cnt_clk == 8'd24)
i2c_clk <= ~i2c_clk;
//
always @(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk <= 8'd0;
else if(cnt_clk == 8'd24)
cnt_clk <= 8'd0;
else
cnt_clk = cnt_clk + 1;
这时仿真正确
总结:在描述时序电路时赋值符号一定要使用非阻塞赋值(<=),哪怕只有一个赋值语句!不要使用阻塞赋值。
其实也不是仿真软件的问题,只是两个always块分开写,错误使用了阻塞赋值,其实这两个always块内部的信号是相关联的,得用非阻塞赋值,哪怕在两个always赋值语句中,可以改写为一个always语句的,这时就非常容易看出来不能非阻塞赋值了,只是分开在两个always语句麻痹大意使用了阻塞赋值语句。
如下当always过程块时序电路有两个赋值语句时,这时肯定不会忘记使用非阻塞赋值的,结果也是正确的。
always @(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)begin
cnt_clk <= 8'd0;
i2c_clk <= 1'b1;
end
else if(cnt_clk == 8'd24)begin
cnt_clk <= 8'd0;
i2c_clk <= ~i2c_clk;
end
else
cnt_clk = cnt_clk + 1;
这时i2c_clk 在cnt_clk == 8’d24时能正确翻转。