@[toc]s
阻塞赋值、非阻塞赋值傻x行为大赏
关于阻塞赋值和非阻塞赋值的问题,记录一下
1、组合逻辑对同一个变量赋值
module experiment(
input clk,
input rst_n,
input [15:0] data_in
);
/****************************** 实验1:组合逻辑用阻塞赋值,可以对同一个变量赋值 ************************/
reg [3:0] mem1 [0:3];
reg [3:0] mem2 [0:3];
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
for(i=0;i<4;i=i+1)
mem1[i] <= 'b0;
end
else
begin
for(i=0;i<4;i=i+1)
mem1[i] <= i+1;
end
end
integer i,j;
always@(*)
begin
j = 0;
for(i=0;i<4;i=i+1)
if(mem1[i]>1)
begin
mem2[j] = mem1[i]; // 如果这里是非阻塞赋值,则只会执行最后一次的赋值结果;如果是阻塞赋值,则会等待前一个赋值完成再赋值另外一个。虽然是对同一个变量j赋值,但是有先后顺序,不会出错
j=j+1;
end
end
/*
// 上面的循环实际电路时循环体展开
if(mem1[0]>1)
begin
mem2[j] = mem1[0];
j=j+1;
end
if(mem1[1]>1)
begin
mem2[j] = mem1[1];
j=j+1;
end
……
*/
/****************************** 实验2:实验1变体 ************************/
/*
integer i;
reg [3:0] j [3:0];
always@(*)
begin
for(i=0;i<4;i=i+1)
if(mem1[i]>1)
begin
mem2[j[i]] = mem1[i];
j[i+1]=j[i]+1; // 这里虽然不是对同一个变量赋值,但当前变量的值也是要依赖于前一个值的,所以只有阻塞赋值时是正确的
end
else
j[i+1] = j[i];
end
// 上面的循环实际电路时循环体展开
if(mem1[0]>1)
begin
mem2[j] <= mem1[0];
j[1]=j[0]+1;
end
else
j[1] = j[0];
if(mem1[1]>1)
begin
mem2[j] <= mem1[1];
j[2]=j[1]+1;
end
else
j[2] = j[1];
……
*/
endmodule
综上所述:
- 组合逻辑就用阻塞赋值,不要瞎用非阻塞赋值
- 组合逻辑中可以对同一个变量赋值(前提是你知道自己的代码结果是怎样的,否则最好不要用)
2、参考实验
参考:https://www.cnblogs.com/wkl7123/p/4131671.html
2.1
module experiment():
reg [3:0] a=0;
reg [3:0] b=0;
reg clk=0;
always@(clk)
begin
a<=a+3;
b<=b+1;
end
always@(b)
begin
a<=a+2;
end
always #10 clk=~clk;
endmodule
实验说明:
reg [3:0] a=0;
reg [3:0] b=0;
reg clk=0;
用非阻塞赋值
实验仿真:
瞎猜原因:
只有初始化的时候有顺序:
a=0,a,b无变化
b=0,always@(b)触发,a<=a+2=2
clk=0, always@(clk)触发,a<=a+3=5,b<=b+1=1,后面的 a=a+2不再执行是因为clk触发导致b变化,但是用的非阻塞赋值,上面和下面同时赋值,由于clk在前,所以后面的没有再执行
2.2
module experiment():
reg [3:0] a=0;
reg [3:0] b=0;
reg clk=0;
always@(clk)
begin
a=a+3;
b=b+1;
end
always@(b)
begin
a=a+2;
end
always #10 clk=~clk;
endmodule
实验说明:
reg [3:0] a=0;
reg [3:0] b=0;
reg clk=0;
用阻塞赋值
仿真结果
瞎猜原因:
a=0,a,b无变化
b=0,a=a+2=2
clk=0, a=a+3=5,b=b+1=1,always@(b)触发,a=a+2.后面的 a=a+2会执行是因为clk触发导致b变化,always@(b)用阻塞赋值,等上面的赋值完后面再赋值,由于clk在前,所以always@(clk) 先执行,always@(b) 后执行
2.3
module experiment():
reg clk=0;
reg [3:0] a=0;
reg [3:0] b=0;
always@(clk)
begin
a<=a+3;
b<=b+1;
end
always@(b)
begin
a<=a+2;
end
always #10 clk=~clk;
endmodule
实验说明:
reg clk=0;
reg [3:0] a=0;
reg [3:0] b=0;
用非阻塞赋值
仿真结果
2.4
module experiment():
reg clk=0;
reg [3:0] a=0;
reg [3:0] b=0;
always@(clk)
begin
a=a+3;
b=b+1;
end
always@(b)
begin
a=a+2;
end
always #10 clk=~clk;
endmodule
实验说明:
reg clk=0;
reg [3:0] a=0;
reg [3:0] b=0;
用阻塞赋值
仿真结果
说明
上面的原因纯属瞎猜,实际原因可能和仿真时不同语句执行顺序有关,不同的语句在仿真的不同区中执行,导致结果差异。
欢迎各位大佬批斗发表感言