阻塞赋值语句和非阻塞赋值语句都属于过程赋值语句,是用来对寄存器型变量赋值的方法。阻塞赋值使用“=”为变量赋值,在赋值结束以前不可以进行其它操作,在赋值结束后继续后面的操作。这个过程好像阻断了程序的运行,因而被称为阻塞赋值。连续的阻塞赋值操作是顺序完成的;非阻塞赋值使用“<=”为变量赋值,在执行到赋值语句时,仅仅对“<=”右侧的表达式的值进行评估,但并不马上执行赋值,然后继续执行后面的操作。这个过程好像没有阻断程序的运行,因而被称为非阻塞赋值。连续的非阻塞赋值操作是同时完成的。
多条阻塞赋值语句是顺序执行的,而多条非阻塞赋值语句是并行执行的,这就是两者的区别。下面列出了有关阻塞赋值和非阻塞赋值在使用上的一些注意事项,只要在设计中坚持做到下面列出的注意事项,就可以基本上避免由于使用阻塞赋值和非阻塞赋值 不当而引起的错误。
1)在使用always块描述组合逻辑时使用阻塞赋值,在使用always块描述时序逻辑时使用非阻塞赋值。可以理解为在电平敏感的always块内使用阻塞赋值,在边沿敏感的always块内使用非阻塞赋值。
2)不用再同一个always块内同时使用阻塞赋值和非阻塞赋值。
3)无论是使用阻塞赋值或者非阻塞赋值,不要在不同的always块内为同一个变量赋值。
例如:
module wrong_assign(
clk, //时钟输入信号
sel, //选择信号,当sel==1时,输出din1的值;当sel==0
//时,输出din2的值
din1, //数据输入信号
din2, //数据输入信号
dout //数据输出信号
);
input clk;
input sel;
input din1,din2;
output dout;
wire clk;
wire sel;
wire din1,din2;
reg dout;
//下面两个always块中都为dout赋了值,但似乎不会引起冲突
always @(posedge clk)
if(sel==1) dout<=din1;
always @(posedge clk)
if(sel==0) dout<=din2;
endmodule
在上例中两个always块内都为变量dout赋了值,并且似乎没有引起赋值的冲突。因为表明看来,当sel==1时,第1个always块生效;而当sel==0时,第2个always块生效。这是高级语言中的思路,在硬件描述语言中完全行不通。当clk的上升沿到来时,如果sel信号的值为1,第1个always块执行结果是将din1赋予dout,而第2个always块 并不是不执行,在不满足将din2的值赋予dout的条件下,第2个always块试图保持dout的值不变。由于这两个always块又是同时执行的,因而就有可能造成赋值冲突。所以如果想通过sel信号的控制实现而选一功能,可以将代码写成如下。
module wrong_assign(
clk, //时钟输入信号
sel, //选择信号,当sel==1时,输出din1的值;当sel==0
//时,输出din2的值
din1, //数据输入信号
din2, //数据输入信号
dout //数据输出信号
);
input clk;
input sel;
input din1,din2;
output dout;
wire clk;
wire sel;
wire din1,din2;
reg dout;
//在同一个always块内为同一个变量赋值
always @(posedge sel)
begin
if(sel==1)
dout<=din1; //当sel==1时,将din1的值赋予dout
else
dout<=din2; //当sel==0时,将din2的值赋予dout
end
endmodule
4)在程序中不要使用0延时。0延时指的是在值语句前面添加上“#0”,有的设计人员想用这种方法来排列两条赋值语句的执行顺序,但实际上这样做有可能会导致错误。
Verilog HDL 阻塞赋值语句和非阻塞赋值语句
最新推荐文章于 2021-10-16 17:13:33 发布