一、阻塞赋值
1.顶层模块代码
module blocking
(
input wire sys_clk ,
input wire sys_ret_n ,
input wire[1:0] in ,
output reg [1:0] out
);
reg[1:0] in_reg;
always@(posedge sys_clk or negedge sys_ret_n)
if(sys_ret_n == 1'b0)
begin
in_reg = 2'b0;
out = 2'b0;
end
else
begin
in_reg = in;
out = in_reg;
end
endmodule
描述了异步上升沿触发器,传递两位宽数据,定义了一个中间变量in_reg,没有在构成的电路显示:

2.testbench代码
`timescale 1ns/1ns
module tb_blocking();
reg sys_clk ;
reg sys_ret_n ;
reg [1:0] in ;
wire[1:0] out ;
initial
begin
sys_clk = 1'b1;
sys_ret_n <= 1'b0;
in <= 2'b0;
#20
sys_ret_n <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
always #20 in <= {$random} % 4;
blocking tb_blocking_inst
(
.sys_clk (sys_clk ),
.sys_ret_n (sys_ret_n ),
.in (in ),
.out (out )
);
endmodule
3.仿真结果

in_reg与in延迟一个周期是由于这一次的赋值由触发器完成,上一节笔记验证过,这是触发器的特性。
然而,作为中间变量的in_reg和out没有延迟,因为使用了阻塞赋值,等式右边的值(out)一旦变化会立即赋值给左边的变量(in_reg)。
非阻塞赋值
1.顶层模块代码
仅仅将always模块中的赋值全部改为非阻塞赋值。
module blocking
(
input wire sys_clk ,
input wire sys_ret_n ,
input wire[1:0] in ,
output reg [1:0] out
);
reg[1:0] in_reg;
always@(posedge sys_clk or negedge sys_ret_n)
if(sys_ret_n == 1'b0)
begin
in_reg <= 2'b0;
out <= 2'b0;
end
else
begin
in_reg <= in;
out <= in_reg;
end
endmodule
对应的电路图:

定义了两个触发器,前一个的Q接下一个的D,类似于移位寄存器,接了相同的异步置零和时钟。
2.仿真结果
testbench不变即可,得到下面的仿真结果:

发现in_reg滞后in一个周期,而out滞后in_reg一个周期。
总结以及注意
(1)在编写时序逻辑的代码时采用非阻塞赋值的方式
(2)使用 always 块来编写组合逻辑的代码时要用阻塞赋值的方式
(3)在同一个 always 块中不要既要用非阻塞赋值又用阻塞方式赋值
(4)虽然锁存器电路建模是不推荐的,但是如果使用到要采用非阻塞赋值的方式。
(5)一个 always 块只一个变量进行赋值
226

被折叠的 条评论
为什么被折叠?



