1.阻塞赋值和非阻塞赋值
阻塞赋值的赋值号用"="表示,对应的电路结构往往与触发边沿没有关系,只与输入电平的变化有关系,它的操作可以认为是只有一个步骤的操作,即计算赋值号右边的语句并更新赋值号左边的语句,此时不允许有来自任何其他verilog语句的干扰,直到现行的赋值完成,才允许下一条的赋值语句执行
串行块(begin end)中,各条赋值语将以它们在顺序块中的排列次序依次执行
a = 1;
b = 2;
c = 3;
begin
a = b + 1; // a = 3
b = a + 2; // b = 5
c = a - 1; // c = 4
end
非阻塞赋值的赋值号用"<="表示,对应的电路结构往往与触发沿有关系,只有在触发沿的时刻才能进行非阻塞赋值;
非阻塞赋值操作可以看作是两个步骤的过程:在赋值开始时刻,计算赋值号右边的语句(所有赋值号右边的结果),在赋值结束时刻(end),更新赋值号左边的语句
在计算非阻塞赋值号右边的语句和更新赋值号左边语句期间,允许其他的verilog语句同时进行操作
非阻塞赋值只能用于寄存器类型变量进行赋值,因此只能用于initial语句和always语句,不允许用于连续赋值语句assign
a = 1;
b = 2;
c = 3;
begin // 开始 结束
a <= b + 1; // 三条语句并行执行 3 3
b <= a + 2; // 3 3
c <= a - 1; // 0 0
end
2.实践
2.1 阻塞赋值
module blocking(
input wire sys_clk,
input wire sys_rst_n,
input wire [1:0] in,
output reg [1:0] out
);
// 定义中间变量
reg [1:0] in_reg;
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
begin
in_reg = 2'b0;
out = 1'b0;
end
else
begin
in_reg = in;
out = in_reg;
end
end
endmodule
- 创建quartus工程,进行编译
`timescale 1ns/1ns
module tb_blocking();
reg sys_clk;
reg sys_rst_n;
reg [1:0] in;
wire [1:0] out;
// 初始化时钟和复位信号,输入信号
intial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
in <=2'b0;
#20;
sys_rst_in = 1'b1;
end
// 模拟时钟
initial begin
#10;
sys_clk = ~sys_clk;
end
always #10 in <= {$random} % 4; // 生成非负数0,1,2,3
blocking block_inst(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.in (in),
.out (out)
);
endmodule
2.2 非阻塞赋值
module nonblocking(
input wire sys_clk,
input wire sys_rst_n,
input wire [1:0] in,
output reg [1:0] out
);
// 定义中间变量
reg [1:0] in_reg;
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
begin
in_reg <= 2'b0;
out <= 1'b0;
end
else
begin
in_reg <= in;
out <= in_reg;
end
end
endmodule
- 当想要对想要的信号打两拍的时候,使用非阻塞赋值
- 时序逻辑电路使用非阻塞赋值,组合逻辑电路使用阻塞赋值
- always语句块实现组合逻辑,使用阻塞赋值,不能即使用阻塞赋值又使用非阻塞赋值
- 避免锁存器latch,使用锁存器的时候使用非阻塞赋值的方式
- 一个always语句块只对一个变量进行赋值