阻塞:在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句;
非阻塞:当前语句的执行不会阻塞下一语句的执行,等式右边会在当前进程开始时更新,并在当前进程结束时对等式左边赋值。(这里的“进程”指的是,所有always块在当前时钟沿并行运行一次)
阻塞赋值语句是完全完成一条语句后,才执行下一次语句;非阻塞赋值语句是所有赋值语句同时进行。
如图,共有6个阻塞和非阻塞赋值,在功能性上(不考虑物理层面的延时),使用阻塞赋值的信号,不管其控制信号是由阻塞赋值还是非阻塞赋值得到的,均与控制信号在同一时刻跳变,即无延时。使用非阻塞赋值的信号,如果其控制信号是由阻塞赋值得到的,且正好在触发点(即上升沿处),则其与其控制信号在同一时刻跳变,即无延时;如果其控制信号是由非阻塞赋值得到的,不管是否正在处于出发点,则其都会比其控制信号慢一拍,即有延时。
控制信号由阻塞赋值得到的,受其控制的信号最快可以与其在同一时刻跳变;(无延时)
控制信号有非阻塞赋值得到的,受其控制的信号分两种情况得到:
- 由阻塞赋值得到,受其控制的信号最快可以与其在同一时刻跳变(无延时);
- 由非阻塞赋值得到,受其控制的信号最快只能在下一拍作出响应(有延时)。
实验代码
block_AND_non_block.v
module block_AND_non_block(
input clk,
input rst_n,
input flag,
input in,
output block_out1,
output block_out2,
output block_out3,
output reg non_block_out1,
output reg non_block_out2,
output reg non_block_out3
);
assign block_out1 = (flag) ? in : 1'b0;
assign block_out2 = (non_block_out1) ? in : 1'b0;
assign block_out3 = (non_block_out2) ? in : 1'b0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n) begin
non_block_out1 <= 1'b0;
end else if(flag) begin
non_block_out1 <= in;
end else
non_block_out1 <= 1'b0;
end
always@(posedge clk or negedge clk or negedge rst_n)begin
if(!rst_n) begin
non_block_out2 <= 1'b0;
end else if (non_block_out1) begin
non_block_out2 <= in;
end else
non_block_out2 <= 1'b0;
end
always@(posedge clk or negedge clk or negedge rst_n)begin
if(!rst_n) begin
non_block_out3 <= 1'b0;
end else if (non_block_out2) begin
non_block_out3 <= in;
end else
non_block_out3 <= 1'b0;
end
endmodule
测试代码
block_AND_non_block_tb.v
`timescale 1ns/1ns
module block_AND_non_block_tb();
reg clk;
reg rst_n;
reg flag;
reg in;
wire block_out1;
wire block_out2;
wire block_out3;
wire non_block_out1;
wire non_block_out2;
wire non_block_out3;
block_AND_non_block uu1(
.clk(clk),
.rst_n(rst_n),
.flag(flag),
.in(in),
.block_out1(block_out1),
.block_out2(block_out2),
.block_out3(block_out3),
.non_block_out1(non_block_out1),
.non_block_out2(non_block_out2),
.non_block_out3(non_block_out3)
);
initial begin
clk = 1'b0;
rst_n = 1'b0;
in = 1'b0;
flag = 1'b0;
#10
rst_n = 1'b1;
#20
flag = 1'b1;
in = 1'b1;
#20
in = 1'b1;
#20
in = 1'b0;
#20
in = 1'b1;
#20
in = 1'b0;
flag = 1'b0;
#20
in = 1'b1;
#100
$stop;
end
always #10 clk = ~clk;
endmodule