学习新语法,争做新青年!咱就是说太上头了!!希望我坠得慢一点哈哈哈
verilog基础语法与应用 —— 阻塞=
和非阻塞<=
赋值
本节课通过实例来理解~~
所谓阻塞=
和非阻塞<=
赋值,都是在时序逻辑的语境中。umm话说,在操作系统中,我学过进程的阻塞和非阻塞等待,让我来探索一下它们之间有没有相通之处吧~
啊哦,感觉还是有点意思,其实写代码时候直接用结论就好了,但是~~ 大概知道为什么安心一些吗
1. 引入实验
block_nonblock.v
module block_nonblock(
Clk,
Reset_n,
a,
b,
c,
out
);
input Clk;
input Reset_n;
input a,b,c;
output reg [1:0] out;
reg [1:0] d;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n) begin
out <= 2'b0;
d <= 0;
end
else begin
d <= a+b;
out <= d+c;
end
endmodule
那如果我们把它拆开写,这是一样的~~
reg [1:0] d;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
d <= 0;
else
d <= a+b;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
out <= 2'b0;
else
out <= d+c;
它对应的电路图①如图所示 ——
这是否等价于如下代码呢?
out <= a + b + c;
它对应的电路图②如图所示 ——
思考在这两种情况下 ——
若此时,a = 1; b = 1; c = 1; 则d是多少?out是多少?
若此时,a = 0; b = 0; c = 1; 则d是多少?out是多少?
block_nonblock1.v
将非阻塞赋值<=
变为阻塞赋值=
module block_nonblock1(
Clk,
Reset_n,
a,
b,
c,
out
);
input Clk;
input Reset_n;
input a,b,c;
output reg [1:0] out;
reg [1:0] d;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n) begin
out = 0;
d = 0;
end
else begin
out = d + c;
d = a+b;
end
endmodule
我们把这个工程右键选做top,然后run synthesis ——
打开新世界,等价于① ——
2. 对比实验
block_nonblock2.v
我们只是调换两个语句的位置:
module block_nonblock2(
Clk,
Reset_n,
a,
b,
c,
out
);
input Clk;
input Reset_n;
input a,b,c;
output reg [1:0] out;
reg [1:0] d;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n) begin
out <= 0;
d <= 0;
end
else begin
d = a+b; //调换顺序
out = d + c;
end
endmodule
我们再把这个文件设置为顶层,分析综合,查看RTL图,就很不一样~
等价于②
所以,=
阻塞赋值时,代码顺序不同,会导致电路不一样,结果就会不同~
block_nonblock_tb.v
我们写仿真文件block_nonblock2_tb.v
`timescale 1ns/1ns
`define Clk_period 20
module block_nonblock2_tb();
reg Clk;
reg Reset_n;
reg a,b,c;
wire[1:0] out;
block_nonblock2 block_nonblock2_inst(
.Clk(Clk),
.Reset_n(Reset_n),
.a(a),
.b(b),
.c(c),
.out(out)
);
initial Clk = 1;
always#(`Clk_period/2) Clk = ~Clk;
initial begin
Reset_n = 1'b0;
a = 0;
b = 0;
c = 0;
#(`Clk_period*200 + 1)
Reset_n = 1'b1;
//每延迟一段时间,abc发生变化
#(`Clk_period*200);
a = 0; b = 0; c = 0;
#(`Clk_period*200);
a = 0; b = 0; c = 1;
#(`Clk_period*200);
a = 0; b = 1; c = 0;
#(`Clk_period*200);
a = 0; b = 1; c = 1;
#(`Clk_period*200);
a = 1; b = 0; c = 0;
#(`Clk_period*200);
a = 1; b = 0; c = 1;
#(`Clk_period*200);
a = 1; b = 1; c = 0;
#(`Clk_period*200);
a = 1; b = 1; c = 1;
#(`Clk_period*200);
$stop;
end
endmodule
我们分别对两个版本进行仿真,仔细观察 ——
非阻塞:
阻塞:
这主要和D触发器的电路有关。
3. 总结
阻塞赋值=
:调换代码,电路会发生变化;
非阻塞赋值<=
:无论怎样写怎样调换,电路完全一样;因此在时序逻辑中,我们一律使用非阻塞赋值。
把我们LED实验中,把
counter <= counter + 1'd1;
改成
counter = counter + 1
会有没有区别?若N = 24999
那么前者周期大概在500us;后者周期在500us-20ns