跳转到内容
新建笔记

06. 时序逻辑与阻塞/非阻塞赋值

时序逻辑用寄存器保存过去的信息。同步设计中,绝大多数状态只在指定时钟沿更新。

组合逻辑和时序逻辑

reg q;
always @(posedge clk) begin
q <= d;
end

posedge clk 表示上升沿触发。每个上升沿到来时,触发器采样 d;随后 q 更新并保持到下一个有效边沿。

同步高有效复位:

always @(posedge clk) begin
if (rst)
q <= 1'b0;
else
q <= d;
end

只有时钟上升沿才检查 rst。

异步低有效复位:

always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 1'b0;
else
q <= d;
end

rst_n 下降沿可立即让寄存器复位,不必等待时钟。解除异步复位通常需要遵守器件和工程的同步释放策略,避免恢复/撤除时间问题。不要凭个人习惯混用复位极性和风格,应遵循项目约定与目标器件建议。

非阻塞赋值为什么适合寄存器

跳转到“非阻塞赋值为什么适合寄存器”

阻塞与非阻塞更新时间

非阻塞赋值的直观模型:

  1. 在时钟沿读取所有右值旧状态;
  2. 安排左值更新;
  3. 当前过程计算结束后统一提交。
always @(posedge clk) begin
stage1 <= data_in;
stage2 <= stage1;
stage3 <= stage2;
end

这会生成三级流水线,每个周期数据前进一步。若错误使用阻塞赋值,仿真中同一块后句可能读到刚更新的新值,三个阶段会像被“穿透”,不再表达预期流水行为。

module counter #(
parameter WIDTH = 8
) (
input wire clk,
input wire rst_n,
input wire enable,
output reg [WIDTH-1:0] count
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
count <= {WIDTH{1'b0}};
else if (enable)
count <= count + 1'b1;
end
endmodule

enable=0 时没有 else 是否会产生锁存器?不会。这个块是带时钟的时序过程,未赋值明确表示触发器保持当前状态,正是需要的行为。

module pulse_counter #(
parameter WIDTH = 8,
parameter [WIDTH-1:0] LIMIT = 8'd99
) (
input wire clk,
input wire rst_n,
output reg [WIDTH-1:0] count,
output reg tick
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
count <= {WIDTH{1'b0}};
tick <= 1'b0;
end else begin
tick <= 1'b0;
if (count == LIMIT) begin
count <= {WIDTH{1'b0}};
tick <= 1'b1;
end else begin
count <= count + 1'b1;
end
end
end
endmodule

每个正常周期先安排 tick <= 0,到终值时再安排 tick <= 1。同一过程块中,同一寄存器最后执行的非阻塞赋值获胜,因此 tick 只保持一个周期。

一个寄存器只由一个时序过程驱动

跳转到“一个寄存器只由一个时序过程驱动”

不要这样写:

always @(posedge clk)
if (set) flag <= 1'b1;
always @(posedge clk)
if (clear) flag <= 1'b0;

flag 有两个过程驱动,优先级不明确,也通常无法综合为普通单个触发器。合并到同一块并明确优先级:

always @(posedge clk) begin
if (clear)
flag <= 1'b0;
else if (set)
flag <= 1'b1;
end

避免用普通逻辑随意生成门控时钟:

assign gated_clk = clk & enable; // 可能产生毛刺和时钟偏斜

优先使用时钟使能:

always @(posedge clk) begin
if (enable)
q <= d;
end

需要真正门控时钟时,应使用目标器件的专用时钟资源和规范流程。

综合后的寄存器之间存在组合路径:

源寄存器 Q → 组合逻辑 → 目标寄存器 D

时钟周期必须容纳时钟到 Q 延迟、组合逻辑延迟、布线延迟和建立时间。代码功能正确但组合路径太长,仍可能无法在目标频率运行。优化方法包括减少逻辑级数、增加流水级、使用专用资源和正确约束时钟。

  • 是否只在一个时钟边沿更新;
  • 是否统一使用非阻塞赋值;
  • 复位极性、同步/异步语义是否一致;
  • 复位是否给所有必要状态确定值;
  • 一个寄存器是否只有一个过程驱动;
  • 位宽是否足够,终值是否可达;
  • 跨时钟域信号是否经过专门同步设计。
  1. 写一个带同步高有效复位和使能的 8 位寄存器。
  2. 写一个 4 位循环计数器,从 0 数到 9 后回到 0。
  3. 用三个寄存器实现三级延迟,预测输入脉冲经过几个时钟到达输出。
  4. 解释为什么时钟过程缺少 else 是保持寄存器,而组合过程缺少 else 会推导锁存器。

上一篇:组合逻辑 · 返回目录 · 下一篇:条件、循环与 generate