发布时间:2022-11-20 16:00
例解阻塞赋值&非阻塞赋值
先简单介绍一下阻塞赋值与非阻塞赋值:
1.非阻塞(Non_Blocking)赋值方式( 如 b <= a; )
module block1(clk,a,b,c);
input [2:0]a;
input clk;
output reg [2:0]b,c;
always@(posedge clk)
begin
b=a;
c=b;
end
endmodule
block1综合后RTL视图
2.阻塞赋值形式2
module block2(clk,a,b,c);
input [2:0]a;
input clk;
output reg [2:0]b,c;
always@(posedge clk)
begin
c=b;
b=a;
end
endmodule
block2综合后RTL视图
3.非阻塞赋值形式1
module no_block1(clk,a,b,c);
input [2:0]a;
input clk;
output reg [2:0]b,c;
always@(posedge clk)
begin
b<=a;
c<=b;
end
endmodule
no_block1综合后RTL视图
4.非阻塞赋值形式2
module no_block2(clk,a,b,c);
input [2:0]a;
input clk;
output reg [2:0]b,c;
always@(posedge clk)
begin
c<=b;
b<=a;
end
endmodule
no_block2综合后RTL视图
在modelsim中仿真tb文件:
`timescale 1ns/1ns
module compare_tb;
reg [2:0]a;
reg clk;
wire [2:0]b1,b2,b3,b4,c1,c2,c3,c4;
block1 u0(
.clk(clk),
.a(a),
.b(b1),
.c(c1)
);
block2 u1(
.clk(clk),
.a(a),
.b(b2),
.c(c2)
);
no_block1 u2(
.clk(clk),
.a(a),
.b(b3),
.c(c3)
);
no_block2 u3(
.clk(clk),
.a(a),
.b(b4),
.c(c4)
);
initial begin
clk=0;
forever #10 clk=~clk;
end
initial begin
a=3'd1;
#100;
a=3'd3;
#100;
a=3'd6;
#100;
a=3'd7;
#200;
$stop;
end
endmodule
对于block1使用阻塞赋值建模,因为always语句@符号后敏感事件使用边沿触发,所以b,c都是D触发器输出。由于是阻塞赋值,a赋值给b后,语句c=b;也立即会执行。
对于block2也是用阻塞赋值,但是顺序颠倒,begin-end是顺序执行,首先执行c=b;b的值是就是进入always语句时的值,即上升沿到来前的值,综合后RTL视图如图所示。
对于no_block1使用非阻塞赋值,进入always语句后,会使用各个变量的原始值将表达是右边值计算后并暂存,语句结束后b,c同时被更新。c<=b;用的是b的前一个值。
对于no_block2非阻塞赋值,顺序颠倒后对综合生成的电路无影响。
因此,阻塞赋值语句对语句的顺序具有依赖性,用它对时序电路建模存在一定风险,所以对时序逻辑电路建议使用非阻塞赋值。