FPGA基础知识:深度剖析异步复位同步释放

在数字电路设计中,"异步复位,同步释放"是一种被广泛采用的、可靠的复位策略。它巧妙地结合了异步复位和同步复位的优点,有效规避了各自的缺点。

为什么要同步释放?

核心原因是为了避免在复位信号撤销(即"释放")时可能引发的亚稳态问题。
异步复位的优势与风险 :异步复位的好处是响应迅速,一旦复位信号有效,电路会立即进入复位状态,无需等待时钟边沿。然而,其风险恰恰在于"释放"阶段。如果复位信号的撤销(例如从低电平变为高电平)恰好发生在时钟有效边沿的建立时间(Setup Time)或保持时间(Hold Time)窗口内,目标寄存器就可能因违反时序要求而进入亚稳态 。

亚稳态的危害:处于亚稳态的寄存器输出既不是稳定的高电平也不是稳定的低电平,而是在一个中间状态震荡,并可能在一段时间后随机收敛到0或1。这个不确定的状态会传播到后续的逻辑电路中,导致系统状态混乱、状态机跑飞,甚至整个系统功能失效。

因此,"同步释放"的目的就是将复位信号的撤销动作与系统时钟对齐 ,确保所有寄存器都在一个确定的、安全的时钟边沿退出复位状态,从而彻底消除亚稳态风险。

"异步复位,同步释放"的原理可以概括为:复位生效时异步,复位撤销时同步。

异步生效 (Assert):当复位信号有效时(例如 rst_n 变为低电平),电路会立即被强制复位,这个过程不受时钟控制,保证了复位的即时性。

同步撤销 (De-assert):当复位信号无效时(例如 rst_n 变为高电平),电路并不会立即退出复位。相反,这个"释放"的动作会被目标时钟域的时钟信号采样,经过同步处理后,再驱动内部逻辑退出复位状态。

c 复制代码
module rst_sync (
    input      clk,          // 系统时钟
    input      async_rst_n,  // 外部异步复位信号,低电平有效
    output reg sys_rst_n     // 内部同步复位信号,低电平有效
);
    reg sync1, sync2; // 两级同步寄存器

    // 核心逻辑:异步复位,同步释放
    always @(posedge clk or negedge async_rst_n) begin
        if (!async_rst_n) begin
            // 异步复位路径:当外部复位有效时,两级寄存器立即清零
            sync1 <= 1'b0;
            sync2 <= 1'b0;
        end else begin
            // 同步释放路径:当外部复位无效时,在时钟驱动下传递'1'
            sync1 <= 1'b1;
            sync2 <= sync1;
        end
    end

    // 将第二级寄存器的输出作为最终的同步复位信号
    assign sys_rst_n = sync2;
将上述sys_rst_n连接到一个专用的BUFG(全局时钟缓冲器或复位分发模块)上。
endmodule

在系统设计中,直接将一个复位同步器输出的信号连接到所有模块,确实会导致扇出(Fanout)过大,进而引发驱动能力不足、信号延迟增加和复位偏移(Skew)严重等问题

为了解决上述问题,工业界的标准做法是构建一个分层的复位树。其核心思想是"分而治之",通过多级缓冲来平衡负载,确保复位信号能够均匀、同步地到达系统的每一个角落。

1.使用使用约束文件:你只需要在代码中保持简单的连接,然后在约束文件(.xdc, .sdc)中告诉工具:"这个信号的扇出不能超过 X"。

c 复制代码
// 顶层
wire rst_n_sys;
rst_sync u_sync(.clk(clk), .async_rst_n(rst_n_in), .sys_rst_n(rst_n_sys));

// 直接连接几十个模块,不用管扇出问题
genvar i;
generate
    for (i = 0; i < 50; i = i + 1) begin : gen_modules
        my_module u_mod (
            .clk(clk),
            .rst_n(rst_n_sys) // 工具会自动处理这里的扇出
        );
    end
endgenerate
# 告诉工具,rst_n_sys 的最大扇出不能超过 15
# 工具会自动计算,如果超过了,就会自动插入 Buffer
set_max_fanout 15 [get_nets rst_n_sys]

2.手动分层:如果不想依赖工具自动优化,或者为了代码的可读性,想显式地把复位信号分开,可以采用手动分组的方法。这比写复杂的"树"要简单得多。

c 复制代码
module top_system (
    input clk,
    input rst_n_in
);
    wire rst_n_root;
    
    // 1. 同步释放
    rst_sync u_sync (.clk(clk), .async_rst_n(rst_n_in), .sys_rst_n(rst_n_root));

    // 2. 手动分组:将 50 个模块分成 5 组,每组 10 个
    // 利用简单的 wire 赋值,综合工具通常会将其识别为需要隔离的 nets
    wire rst_n_group_0;
    wire rst_n_group_1;
    wire rst_n_group_2;
    wire rst_n_group_3;
    wire rst_n_group_4;

    // 这里的 assign 在物理综合时,工具可能会插入 Buffer,
    // 或者你可以显式实例化 BUFG/CLKBUF
    assign rst_n_group_0 = rst_n_root;
    assign rst_n_group_1 = rst_n_root;
    assign rst_n_group_2 = rst_n_root;
    assign rst_n_group_3 = rst_n_root;
    assign rst_n_group_4 = rst_n_root;

    // 3. 分配模块
    // 组 0
    my_module u_mod_0 (.rst_n(rst_n_group_0));
    my_module u_mod_1 (.rst_n(rst_n_group_0));
    // ... (组0的其他模块)

    // 组 1
    my_module u_mod_10 (.rst_n(rst_n_group_1));
    // ...
endmodule
相关推荐
szxinmai主板定制专家8 小时前
基于Zynq的高精度多通道数据采集卡完整解决方案(工业振动/高速采集/边缘传输)
fpga开发·zynq·数据采集卡
szxinmai主板定制专家10 小时前
基于TI AM62x+FPGA的24bit高精度数据采集卡设计(振动/风电/发动机监测)
人工智能·fpga开发·arm+fpga·rk3588+fpga
szxinmai主板定制专家13 小时前
基于 ARM+FPGA 雕刻机控制系统的设计
arm开发·人工智能·fpga开发·rk3576·半导体设备
吉他英雄一里1 天前
zynq入门教程
fpga开发·zynq
XMAIPC_Robot2 天前
RK3576/RK3588+FPGA+AI数据采集系统:实时性与边缘AI算力兼顾
人工智能·fpga开发·机器人·数据采集·rk3588+fpga·rk3576+fpga
156082072192 天前
JFMRFVU3P5G的bit正常,但烧录mcs程序后加载异常
fpga开发
狂奔蜗牛(bradley)2 天前
把 EtherCAT 初始化从 FPGA 搬到 ARM:命令通道的接口设计与11个坑
arm开发·人工智能·fpga开发·架构
女神下凡3 天前
芯参谋(37):EEPROM_电路设计指南
arm开发·单片机·嵌入式硬件·fpga开发·设计规范
szxinmai主板定制专家4 天前
工业视觉新思路:FPGA图像预处理+RK NPU推理,实现高速缺陷检测
人工智能·嵌入式硬件·fpga开发·rk3576+codesys
FPGA小徐5 天前
【硬件实战】立创 EDA 绘制 TF/SD 卡模块电路|SPI 模式原理图 + 阻抗匹配 + PCB 布局布线全教程
单片机·嵌入式硬件·fpga开发