目录
- 过程赋值概述
- Verilog 中的赋值类型
- 阻塞赋值(Blocking Assignment)
- 非阻塞赋值(Non-blocking Assignment)
- 阻塞赋值与非阻塞赋值的区别
- 赋值语句应用实例
- 参考资料
过程赋值概述
在 Verilog 中,赋值语句通常用于对信号或变量进行值的更新。在过程结构中,赋值是用来描述信号随时间的变化行为。过程赋值的类型主要有两种:阻塞赋值(Blocking Assignment)和非阻塞赋值(Non-blocking Assignment)。
- 阻塞赋值:是常见的赋值形式,按照顺序执行赋值,后续赋值操作会被阻塞直到当前赋值完成。
- 非阻塞赋值:允许赋值语句并行执行,赋值的更新会在当前仿真时间段结束后生效。
Verilog 中的赋值类型
阻塞赋值(Blocking Assignment)
阻塞赋值使用 =
符号进行,赋值语句会按顺序执行。当前赋值语句会阻塞后续赋值的执行,直到赋值完成。
语法:
variable = expression;
- 执行顺序:按顺序执行,每个赋值会立即生效,后续赋值会等当前赋值完成后才执行。
示例:
module blocking_example;
reg a, b, c;
initial begin
a = 0; // 阻塞赋值:先给 a 赋值为 0
b = 1; // 阻塞赋值:接着给 b 赋值为 1
c = a & b; // 阻塞赋值:最后计算 c = a & b, 结果为 0
end
endmodule
在这个例子中,c
的值会在 a
和 b
都被赋值后才会计算。阻塞赋值按顺序执行,导致赋值结果严格按照代码中的顺序进行。
非阻塞赋值(Non-blocking Assignment)
非阻塞赋值使用 <=
符号进行,它允许多个赋值语句并行执行。赋值的更新会在当前时间段结束后生效,而不是立即生效。
语法:
variable <= expression;
- 执行顺序:赋值会被推迟到仿真时间片结束时应用,这意味着赋值的结果不会影响同一时间段内的后续赋值。
示例:
module non_blocking_example;
reg clk, a, b, c;
always @ (posedge clk) begin
a <= b; // 非阻塞赋值:a 的值在下一个时钟周期更新
b <= c; // 非阻塞赋值:b 的值也在下一个时钟周期更新
c <= a & b; // 非阻塞赋值:c 的值在下一个时钟周期更新
end
endmodule
在这个例子中,a
、b
和 c
的赋值是非阻塞的,因此它们会在同一时钟周期结束时更新。此时,c
的计算不会立即反映在下一次时钟周期,而是等待所有赋值都完成之后一起更新。
阻塞赋值与非阻塞赋值的区别
特性 | 阻塞赋值 (= ) | 非阻塞赋值 (<= ) |
---|---|---|
执行顺序 | 按顺序执行赋值,后续赋值在前一个赋值完成后才会执行。 | 赋值操作并行进行,结果在当前仿真时间段结束后更新。 |
适用场景 | 多用于组合逻辑和需要严格顺序的情况。 | 多用于时序逻辑,描述寄存器或时钟边沿触发的行为。 |
对其他信号的影响 | 当前赋值会立即影响后续赋值。 | 赋值结果不会立即生效,保持当前值直到下一个时间步。 |
赋值更新时机 | 赋值立即生效。 | 赋值会在当前仿真时间步结束后生效。 |
示例对比:
module blocking_vs_nonblocking;
reg clk, a, b, c;
always @ (posedge clk) begin
a = b; // 阻塞赋值
b = c; // 阻塞赋值
c = a & b; // 阻塞赋值
end
always @ (posedge clk) begin
a <= b; // 非阻塞赋值
b <= c; // 非阻塞赋值
c <= a & b; // 非阻塞赋值
end
endmodule
在阻塞赋值情况下:
a
会在当前时钟周期内立即更新为b
的值。b
会在当前时钟周期内立即更新为c
的值。c
的值会立即更新为a & b
的结果。
在非阻塞赋值情况下:
a
会在当前时钟周期结束后更新为b
的值。b
会在当前时钟周期结束后更新为c
的值。c
会在当前时钟周期结束后更新为a & b
的结果。
赋值语句应用实例
1. 使用阻塞赋值描述组合逻辑
module comb_logic_example(input a, b, output reg c);
always @ (a or b) begin
c = a & b; // 阻塞赋值:执行逻辑与运算
end
endmodule
2. 使用非阻塞赋值描述时序逻辑
module seq_logic_example(input clk, reset, output reg [3:0] counter);
always @ (posedge clk or posedge reset) begin
if (reset)
counter <= 4'b0000; // 非阻塞赋值:计数器重置
else
counter <= counter + 1; // 非阻塞赋值:计数器加 1
end
endmodule
在该例中,counter
的值会在时钟上升沿触发时更新,并且通过非阻塞赋值确保多个信号的更新不会相互阻塞。
发表回复