fpga系列 HDL: 竞争和冒险 02

竞争和冒险

在 Verilog 设计中,竞争(race conditions)和冒险(hazards)是数字电路设计中不期望出现的现象,它们会影响电路的正确性。了解并解决竞争和冒险问题对于确保电路稳定运行非常重要。

竞争(Race Condition)

  • 竞争是指多个信号或触发器在同一时刻更新时,由于不同路径的延迟差异导致的未定义行为。在 Verilog 中,竞争通常出现在时序电路中,如在使用触发器和寄存器的场合。例如:

冒险(Hazards)

  • 冒险是指由于信号延迟或逻辑实现方式导致电路在特定条件下短暂地输出错误逻辑值,通常分为两类:

  • 静态冒险(Static Hazard):输入变化时输出短暂地产生错误的尖峰或抖动。比如,一个函数期望在某个输入变化时输出保持1,但由于路径延迟问题,输出短暂变成了0,这就是静态1冒险。

  • 动态冒险(Dynamic Hazard):当输入发生快速变化时,输出产生不止一次的错误跳变。这在多级逻辑电路中较常见,且难以完全消除。

示例

1. 当两个或多个触发器在相同时钟上运行,但它们的输入信号的延迟不同,这可能导致逻辑错误。

  • 输出应恒为0,错误由 Δ t 1 \Delta t_1 Δt1造成
Layer 1
  • 解决竞争问题的方法:小心设计触发器,减少路径之间的延迟差异。
    • 适当的冗余设计:通过在逻辑表达式中添加冗余项,减少由于延迟造成的错误。
        BC
       00  01  11  10
      +----------------
    0 |  1   1   0   0
 A    |
    1 |  0   1   1   0
  • Y = A ′ B ′ + A C Y = A'B' + AC Y=AB+AC中,当 B ′ = 1 且 C = 1 B'=1且C=1 B=1C=1时,存在竞争,为了消除竞争冒险,可以引入一个额外的冗余项,使得表达式为: Y = A ′ B ′ + A C + B ′ C Y = A'B' + AC + B'C Y=AB+AC+BC。 VHDL 代码逻辑:
module my_logic (
    input wire A,
    input wire B,
    input wire C,
    output wire Y
);
    assign Y = (~A & ~B) | (A & C) | (~B & C);
endmodule
  • 冗余项由表达式中原有的一部分项目组成,如下图所示 A ′ B ′ = m 0 + m 1 A'B'=m_0+m_1 AB=m0+m1, A C = m 5 + m 7 AC=m_5+m_7 AC=m5+m7,再加一个 m 1 + m 5 m_1+m_5 m1+m5即B’C,不会改变原来的值,且会消除竞争现象,当 B ′ = 1 且 C = 1 B'=1且C=1 B=1C=1时,保持输出为1。

在这里插入图片描述

2.在组合逻辑中,当两个或多个语句同时发生时,当语句执行顺序改变时,最终谁先更新可能会影响下一级的逻辑电平,从而导致不可预知的输出。

  • 以下代码中,由于两个 always 块都是由同一个事件(时钟上升沿)触发,Verilog 模拟器中的调度程序在一个时钟周期内可能会先执行其中一个块。如果首先执行 y1 = y2; 的赋值,y1 将取 y2 的先前值;但如果先执行 y2 = y1;,y2 将取 y1 的先前值。这种不确定性可能导致振荡行为在不同的仿真运行中变化,或者在不同的模拟器实现中表现不同。
module fbosc1 (y1, y2, clk, rst);
  output reg y1, y2;
  input      clk, rst;

  always @(posedge clk or posedge rst)
    if (rst) y1 = 0;  // reset
    else     y1 = y2;
  
  always @(posedge clk or posedge rst)
    if (rst) y2 = 1;  // preset
    else     y2 = y1;
endmodule
  • 解决竞争问题的方法: 如果是组合逻辑,可以用额外的寄存器进行延时匹配,确保所有信号在相同时间点更新。使用非阻塞赋值 (<=) 来确保逻辑的同步更新(但是非阻塞赋值所取值为上一个状态的值)。
module fbosc1 (y1, y2, clk, rst);
  output reg y1, y2;
  input      clk, rst;

  always @(posedge clk or posedge rst)
    if (rst) y1 <= 0;  // reset
    else     y1 <= y2;
  
  always @(posedge clk or posedge rst)
    if (rst) y2 <= 1;  // preset
    else     y2 <= y1;
endmodule

3.在关键信号通路上使用触发器,确保输出稳定。

  • 以下为一个异步时钟信号async_in经过两级D触发器后被同步成同步信号sync_out,这样可以减少亚稳态的发生,从而确保输出信号的稳定性。
module sync_stabilizer (
    input wire clk,           // 时钟信号
    input wire async_in,      // 异步输入信号
    output reg sync_out       // 同步输出信号
);

    // 中间级信号,用于锁存第一级触发器的输出
    reg sync_stage1;

    // 第一阶段触发器:将异步信号锁存到第一级触发器中
    always @(posedge clk) begin
        sync_stage1 <= async_in;
    end

    // 第二阶段触发器:将第一级触发器的输出锁存到同步输出
    always @(posedge clk) begin
        sync_out <= sync_stage1;
    end

endmodule
  • 这个模块在关键路径上使用了触发器,以确保输出信号的稳定性。代码中两个异步时钟信号signal_asignal_b经过两级D触发器后被同步成同步信号sync_out
module stable_logic_with_ff
    (
      input             clk,
      input             rstn,
      input             signal_a,
      input             signal_b,
      output reg        output_flag
    );

    reg signal_a_ff;  // 用于存储信号 a 的触发器
    reg signal_b_ff;  // 用于存储信号 b 的触发器

    // 在时钟上升沿捕获输入信号
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            signal_a_ff <= 1'b0;
            signal_b_ff <= 1'b0;
        end
        else begin
            signal_a_ff <= signal_a;  // 捕获 signal_a
            signal_b_ff <= signal_b;  // 捕获 signal_b
        end
    end

    wire condition = signal_a_ff & signal_b_ff;  // 使用触发器的输出进行组合逻辑

    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            output_flag <= 1'b0;
        end
        else begin
            output_flag <= condition;  // 使用稳定的信号
        end
    end 

endmodule

CG

猜你喜欢

转载自blog.csdn.net/ResumeProject/article/details/143238628
HDL