http://mp.weixin.qq.com/mp/homepage?__biz=MzU3OTczMzk5Mg==&hid=7&sn=ad5d5d0f15df84f4a92ebf72f88d4ee8&scene=18#wechat_redirect
--------------------------------------------------------------------------------------------------------------------------
赋值语句的实质:不是进行赋值,而是产生一个电路,要赋的值为电路的输出,被赋方为电路的输入。
if(!rst_n) cnt <= 0; else cnt <= cnt + 1;
在描述组合逻辑的 always 块中用阻塞赋值,则综合成组合逻辑的电路结构。
在描述时序逻辑的 always 块中用非阻塞赋值,则综合成时序逻辑的电路结构。
RHS – 赋值等号右边的表达式或变量可分别缩写为: RHS 表达式或 RHS 变量。
LHS – 赋值等号左边的表达式或变量可分别缩写为: LHS 表达式或 LHS 变量。
非阻塞赋值(<=):并行执行;块结束后完成对变量的赋值,赋的值为上次赋值得到的结果。
这是因为在赋值操作时刻开始时计算非阻塞赋值符的 RHS 表达式,赋值操作结束时刻才更新LHS。在计算非阻塞赋值的 RHS 表达式和更新 LHS 期间,其他的 Verilog 语句,包括其他的 Verilog 非阻塞赋值语句都能同时计算 RHS 表达式和更新 LHS。非阻塞赋值允许其他的Verilog 语句同时进行操作。
非阻塞赋值的操作可以看作为两个步骤的过程:
1)在赋值开始时刻,计算非阻塞赋值 RHS 表达式。
2)在赋值结束时刻,更新非阻塞赋值 LHS 表达式。
非阻塞赋值操作只能用于对寄存器类型变量进行赋值,因此只能用在"initial"块和"always"块等过程块中。非阻塞赋值不允许用于连续赋值。
[例]. 用非阻塞赋值的反馈振荡器
module fbosc2 (y1, y2, clk, rst);
output y1, y2;
input clk, rst;
reg y1, y2;
always @(posedge clk or posedge rst)
if (rst) y1 <= 0; // 预置值
else y1 <= y2;
always @(posedge clk or posedge rst)
if (rst) y2 <= 1; // 预置值
else y2 <= y1;
endmodule
同样,按照 IEEE Verilog 的标准,上例中两个 always 块是并行执行的,与前后次序无
关。复位信号回到 0 后,无论哪一个 always 块的有效沿先到,两个 always 块中的非阻塞赋值都在赋值开始时刻计算 RHS 表达式,而在结束时刻才更新 LHS 表达式。所以复位信号从1 回到 0 后,无论哪个 always 块的有效时钟沿早到几个皮秒, y1 为 1 而 y2 为 0 是确定的,因为实质上 y1 被赋的 y2 值是由 rst 正跳变沿确定的,而 y2 被赋的 y1 值也是由 rst 正跳变沿确定的(若以后 rst 继续保持为 0,时钟信号不断重复,则每次被赋值的 y1 和 y2 都是由上一个周期的时钟有效沿确定的)。从用户的角度看这两个非阻塞赋值好象是并行执行的。
阻塞赋值(=):顺序执行;赋值立即生效;当所有语句执行完后,块才结束。
阻塞赋值的执行可以认为是只有一个步骤的操作:计算 RHS 并更新 LHS,此时不能允许有来自任何其他 Verilog 语句的干扰。
所谓阻塞的概念是指在同一个 always 块中,其后面的赋值语句从概念上(即使不设定延迟)是在前一句赋值语句结束后再开始赋值的。
如果在一个过程块中阻塞赋值的 RHS 变量正好是另一个过程块中阻塞赋值的 LHS 变量,这两个过程块又用同一个时钟沿触发,这时阻塞赋值操作会出现问题,即如果阻塞赋值的次序安排不好,就会出现竞争。若这两个阻塞赋值操作用同一个时钟沿触发,则执行的次序是
无法确定的。下面的例子可以说明这个问题:
[例]. 用阻塞赋值的反馈振荡器
module fbosc1 (y1, y2, clk, rst);
output y1, y2;
input clk, rst;
reg y1, y2;
always @(posedge clk or posedge rst)
if (rst) y1 = 0;
else y1 = y2;
always @(posedge clk or posedge rst)
if (rst) y2 = 1;
else y2 = y1;
endmodule
按照 IEEE Verilog 的标准,上例中两个 always 块是并行执行的,与前后次序无关。若
复位信号已从 1 到回 0,且上面的 always 块的有效时钟沿比下面的 always 块的时钟沿早几个皮秒(由时钟偏差造成)到达,则 y1 和 y2 都会取 1,而若下面的那个 always 块的有效时钟沿早几个皮秒到达,则 y1 和 y2 都会取 0。这清楚地说明这个 Verilog 模块是不稳定的,会产生冒险和竞争的情况。
阻塞非阻塞语句的编程要点:
1) 时序电路建模时,用非阻塞赋值。
2) 锁存器电路建模时,用非阻塞赋值。
3) 用 always 块建立组合逻辑模型时,用阻塞赋值。
4) 在同一个 always 块中建立时序和组合逻辑电路时,用非阻塞赋值。
5) 在同一个 always 块中不要既用非阻塞赋值又用阻塞赋值。
6) 不要在一个以上的 always 块中为同一个变量赋值。
7) 用$strobe 系统任务来显示用非阻塞赋值的变量值。
8) 在赋值时不要使用 #0 延迟。