跳转到主要内容

FPGA触发器使用经验详解(一)

judy 提交于

文章来源:FPGA入门到精通

在FPGA设计中,触发器(Flip-Flop)是常用的时序元件。

合理使用触发器对于FPGA设计的稳定性、资源利用率以及时序收敛有很大帮助。

一、触发器基础回顾
触发器是FPGA中存储一位二进制数据的单元,在时钟边沿(通常是上升沿)采样输入数据并输出。

与锁存器不同,触发器是边沿敏感的,而锁存器是电平敏感的。

FPGA中的触发器通常还带有 复位(SR) 和 时钟使能(CE) 控制端。

二、核心设计建议详解
建议1:SR优先级高于CE,避免既复位又置位
解释:在描述带复位和使能的D触发器时,复位信号(SR)的优先级必须高于时钟使能(CE)。

同时,一个触发器不能同时具备异步置位和异步复位,否则会导致综合错误。

正确示例:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
module dff_sr_priority (
    input clk,
    input rst_n,      // 异步复位,低有效
    input ce,         // 时钟使能
    input d,
    output reg q
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)          // SR优先级最高
            q <= 1'b0;
        else if (ce)         // 仅在使能时采样
            q <= d;
    end
endmodule

错误示例(同时存在异步置位和复位):

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
// 错误:同一触发器既有异步置位又有异步复位
always @(posedge clk or negedge rst_n or posedge set) begin
    if (!rst_n)
        q <= 1'b0;
    else if (set)   // 某些FPGA架构不支持
        q <= 1'b1;
    else
        q <= d;
end

建议2:避免使用锁存器,转换为带使能的D触发器
解释:锁存器由组合逻辑中的条件不完整产生,会导致时序分析困难、毛刺敏感等问题。应始终使用边沿敏感的触发器。

错误示例(产生锁存器):

ounter(lineounter(lineounter(lineounter(lineounter(line
// 缺少else分支,综合出锁存器
always @(*) begin
    if (sel)
        q = d;
end

正确示例(转换为触发器):

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
module avoid_latch (
    input clk,
    input sel,
    input d,
    output reg q
);
    // 使用带时钟使能的触发器代替锁存器
    always @(posedge clk) begin
        if (sel)
            q <= d;
    end
endmodule

建议3:保持触发器时钟采样极性一致
解释:一个设计模块中不应混合使用上升沿和下降沿触发的触发器。

混合使用会引入额外的时钟缓冲器,增加时钟偏斜,使时序收敛困难。

错误示例(混合极性):

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
always @(posedge clk) begin  // 上升沿触发
    reg1 <= d1;
end

always @(negedge clk) begin  // 下降沿触发——不推荐混用
    reg2 <= d2;
end

正确示例(统一极性):

ounter(lineounter(lineounter(lineounter(lineounter(line
// 全部使用上升沿触发
always @(posedge clk) begin
    reg1 <= d1;
    reg2 <= d2;
end