FPGA 32 专题 阻塞和非阻塞状态的理解
写的不是很细致,过两天继续完善
block_nonblock.v 文件
module block_nonblock(
Clk ,
Rst_n,
a ,
b ,
c ,
out
);
input Clk ;
input Rst_n ;
input a ;
input b ;
input c ;
// out = a+b+c ;
// d = a+b ;
// out = d +c ;
output reg [1:0]out ;
reg [1:0]d ;
always@(posedge Clk or negedge Rst_n )
if(Rst_n == 1'b0)
out = 2'b0 ;
else begin
out <= a + b + c; //建议使用阻塞赋值
end
//非阻塞赋值 : 运算符: <= ,前后执行时【并行运算】,代码执行不分前后(结构时确定没有问题的(多条语句赋值不存在前后顺序),
//但是如果多条语句中的数据或者说变量存在关联,那么需要考虑的是逻辑结构的延时
//或者说是D触发器的延时问题导致的数据出现的错误)
//阻塞赋值 : 运算符: = ,执行语句【有先后顺寻】,存在延迟情况,存在不确定性(有的时候会出现问题)
/********* 非阻塞赋值 **********/
/* 方式1:
out <= a + b + c;
*/
/* 方式2:
d <= a + b ;
out <= a + b + c;
*/
/* 方式3:
out <= d + c;
d <= a + b ;
*/
/********* 阻塞赋值 **********/
/* 方式4: 非并行运算
d = a + b ;
out = d + c;
*/
/* 方式5: 非并行运算
out = d + c;
d = a + b ;
*/
// 这里可以通过仿真结果得到, 方式【4】和方式【1】得到的电路是一样的,也就是我们想要的效果
// 这里可以通过仿真结果得到, 方式【2】和方式【3】得到的电路是一样的。
// 这里可以通过仿真结果得到, 方式【4】和方式【5】得到的电路是【不一样】的,
// 但是电路输出结果会因为延时得到的结果会存在延时的数据错误,我们需要在设计的时候需要去避免
endmodule
1、阻塞赋值
阻塞赋值的实际电路:
always@(posedge Clk or negedge Rst_n )
if(Rst_n == 1'b0)
out = 2'b0 ;
else begin
//这里是阻塞赋值语句,有先后顺序,和C语言类似
d = a + b ;
out = d +c ;
end
2、阻塞赋值
always@(posedge Clk or negedge Rst_n )
if(Rst_n == 1'b0)
out = 2'b0 ;
else begin
//这里是阻塞赋值语句,有先后顺序,和C语言类似
out = d +c ;
d = a + b ;
end
3、非阻塞赋值
always@(posedge Clk or negedge Rst_n )
if(Rst_n == 1'b0)
out <= 2'b0 ;
else begin
//这里非阻塞赋值语句,代码无先后顺序
out <= d +c ;
d <= a + b ;
end
4、非阻塞赋值
always@(posedge Clk or negedge Rst_n )
if(Rst_n == 1'b0)
out <= 2'b0 ;
else begin
//这里非阻塞赋值语句,代码无先后顺序
d <= a + b ;
out <= d +c ;
end
可以发现: 非阻塞赋值( 代码3、代码 4、)中,代码前后顺序改变,内部生成的电路结构是保持一致的
阻塞赋值( 代码1、代码 2、)中,代码前后顺序改变,内部生成的电路结构是不同的**
非阻塞赋值【3、4】的仿真结果
只有当 下一个时钟上升沿到来的时候,可以看到 out 的结果才发生了变化 。
为了避免延时需要修改成如下所示的情况:
always@(posedge Clk or negedge Rst_n )
if(Rst_n == 1'b0)
out <= 2'b0 ;
else begin
//这里非阻塞赋值语句,代码无先后顺序
d <= a + b + c ;
end
这样出来的结果就不会有因为D触发器所导致的寄存,而最终导致输出结果的延时问题。
本次我们的主要目的是:
知道 非阻塞赋值不考虑语句的先后顺序,内部电路结构不发生改变
阻塞赋值考虑语句的先后顺序,内部会根据先后顺序得到不同的电路结构。
个人理解:
根据自己实际的想法编写就好,如果和C 语言的用法类似,也可以考虑使用阻塞赋值,不一定非要用非阻塞赋值做运算。
非阻塞如果是有多个语句执行,而且【中间存在交互的变量 如: d=a+b out= d+c, d就是中间变量】,那么势必在结果上的输出【out】 会带来时间上的延时。
block_nonblock_tb.v 文件
`timescale 1ns/1ns
`define clock_period 20
module block_nonblock_tb;
reg Clock;
reg Rst_n;
reg a,b,c;
wire [1:0]out;
block_nonblock block_nonblock0(Clock,Rst_n,a,b,c,out); //新的一种模块名称加载
initial Clock = 1; //时钟信号
always#(`clock_period/2) Clock = ~Clock;
initial begin
Rst_n = 1'b0;
a = 0;
b = 0;
c = 0;
#(`clock_period*200 + 1); //信号初始化 ,+1 避免和时钟信号对齐,仿真时更加接近实际的电路
Rst_n = 1'b1;
#(`clock_period*200);
a = 0 ; b = 0 ; c = 0;
#(`clock_period*200);
a = 0 ; b = 0 ; c = 1;
#(`clock_period*200);
a = 0 ; b = 1 ; c = 0;
#(`clock_period*200);
a = 0 ; b = 1 ; c = 1;
#(`clock_period*200);
a = 1 ; b = 0 ; c = 0;
#(`clock_period*200);
a = 1 ; b = 0 ; c = 1;
#(`clock_period*200);
a = 1 ; b = 1 ; c = 0;
#(`clock_period*200);
a = 1 ; b = 1 ; c = 1;
#(`clock_period*200);
#(`clock_period*200);
$stop;
end
endmodule