本文深入解析 Xilinx 7-series FPGA 的触发器(FF)架构、复位设计的最佳实践,以及如何正确实现"异步置位、同步释放"的复位同步器。


1. 7-series Slice 中的 FF 架构

1.1 Slice 基本结构

Xilinx 7-series(Artix-7、Kintex-7、Virtex-7)的 CLB(Configurable Logic Block)包含两个 Slice,每个 Slice 包含:

┌─────────────────────────────────────────────────────────────┐
  
│                         SLICE                               │
  
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐        │
  
│  │  LUT_A  │  │  LUT_B  │  │  LUT_C  │  │  LUT_D  │        │  4 × 6-LUT
  
│  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘        │
  
│       │            │            │            │              │
  
│  ┌────▼────┐  ┌────▼────┐  ┌────▼────┐  ┌────▼────┐        │
  
│  │  FF_A   │  │  FF_B   │  │  FF_C   │  │  FF_D   │        │  4 × FF(上层)
  
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘        │
  
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐        │
  
│  │  FF_A2  │  │  FF_B2  │  │  FF_C2  │  │  FF_D2  │        │  4 × FF(下层)
  
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘        │
  
│                                                             │
  
│  + Carry Chain (CARRY4) + Wide MUX + 其他控制逻辑          │
  
└─────────────────────────────────────────────────────────────┘
  

关键点:每个 Slice 有 8 个 FF,物理结构相同,功能通过配置决定。

1.2 FF 的控制信号

每个 FF 有以下控制端口:

端口名称说明
CClock时钟输入
DData数据输入
QOutput数据输出
CEClock Enable时钟使能(高有效)
SRSet/Reset置位/复位控制

重要限制:同一 Slice 内的 8 个 FF 共享以下控制信号:

共享信号限制
CLK必须同时钟
CE必须同使能
SR必须同复位信号
SR 极性必须同为同步或异步
SR 功能必须同为置位或复位

这意味着:不能在同一 Slice 内混用 FDRE 和 FDPE

1.3 FF 的四种配置模式

通过配置 SR 端的功能,同一物理 FF 可以实现四种不同行为:

原语名称全称SR 功能复位类型复位后状态
FDREFF + sync Reset + CE同步复位同步Q = 0
FDSEFF + sync Set + CE同步置位同步Q = 1
FDCEFF + async Clear + CE异步清零异步Q = 0
FDPEFF + async Preset + CE异步置位异步Q = 1

2. RTL 写法与综合结果对照

2.1 综合器如何推断 FF 类型

综合器根据 always 块的敏感列表和代码结构推断 FF 类型:

同步复位 → FDRE / FDSE

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 复位到 0 → FDRE
  
always @(posedge clk) begin
  
    if (rst)
  
        q <= 1'b0;
  
    else
  
        q <= d;
  
end
  

  
// 复位到 1 → FDSE
  
always @(posedge clk) begin
  
    if (rst)
  
        q <= 1'b1;
  
    else
  
        q <= d;
  
end
  

异步复位 → FDCE / FDPE

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 异步复位到 0 → FDCE
  
always @(posedge clk or posedge rst) begin  // 注意:敏感列表包含 rst
  
    if (rst)
  
        q <= 1'b0;
  
    else
  
        q <= d;
  
end
  

  
// 异步复位到 1 → FDPE
  
always @(posedge clk or posedge rst) begin
  
    if (rst)
  
        q <= 1'b1;
  
    else
  
        q <= d;
  
end
  

无复位 → FDRE(SR 悬空)

1
2
3
4
5
6
always @(posedge clk) begin
  
    q <= d;
  
end
  

2.2 综合对照表

RTL 写法敏感列表复位条件推断原语
同步复位到 0posedge clkif (rst) q <= 0FDRE
同步复位到 1posedge clkif (rst) q <= 1FDSE
异步复位到 0posedge clk or posedge rstif (rst) q <= 0FDCE
异步复位到 1posedge clk or posedge rstif (rst) q <= 1FDPE
无复位posedge clkFDRE

3. 同步复位 vs 异步复位:如何选择

3.1 Xilinx 官方推荐

Xilinx WP272《Get Smart About Reset》明确推荐:同步复位优先。

3.2 对比分析

对比项同步复位异步复位
时序收敛✅ 复位信号被时序约束覆盖⚠️ 需要额外的 recovery/removal 约束
资源利用✅ 复位逻辑可合并进 LUT❌ 必须使用 SR 专用信号
仿真一致性✅ 敏感列表简单,不易出错⚠️ 敏感列表易漏写 or posedge rst
亚稳态风险✅ 无⚠️ 复位释放时可能亚稳态
时钟未起振时❌ 无法复位✅ 可以复位

3.3 最佳实践结论

场景推荐做法
普通逻辑(FSM、计数器)同步复位
数据通路(流水线寄存器)不加复位
复位同步器内部(第一级 FF)异步置位(FDPE)

3.4 推荐代码风格

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 控制逻辑:同步复位
  
always @(posedge i_clk) begin
  
    if (i_rst_p)
  
        r_state <= S_IDLE;
  
    else
  
        r_state <= r_next_state;
  
end
  

  
// 数据通路:不加复位
  
always @(posedge i_clk) begin
  
    r_data_d1 <= w_data_in;
  
    r_data_d2 <= r_data_d1;
  
end
  

4. 复位同步器:异步置位、同步释放

4.1 为什么需要复位同步器

当复位信号来自外部(按钮、另一个时钟域),它相对于本时钟域是异步的。如果直接使用:

        ┌───────┐
  
rst_in ─┤ FF    ├─ q    ← 复位释放时刻随机,可能在时钟边沿附近
  
        └───┬───┘
  
            │
  
           clk
  

问题:复位释放时刻不确定,可能违反 FF 的 recovery/removal 时间,导致亚稳态。

4.2 解决方案:异步置位、同步释放

                    异步置位(立即生效)
  
                          │
  
rst_in ───────────────────┼───────────────────────┐
  
                          ▼                       ▼
  
                    ┌──────────┐            ┌──────────┐
  
              0 ───►│  FDPE    │──► sync0 ──►│  FDPE    │──► sync1 ──► rst_out
  
                    │  (PRE)   │            │  (PRE)   │
  
                    └────┬─────┘            └────┬─────┘
  
                         │                       │
  
                        clk                     clk
  
                                                 │
  
                                          同步释放(等时钟沿)
  

工作原理

阶段行为
复位置位rst_in=1 → PRE 端立即置位 → sync0=1sync1=1rst_out=1(不等时钟)
复位释放rst_in=0 → PRE 释放 → D 端开始传递 0 → 经过 2-3 个时钟周期 → rst_out=0

4.3 为什么用 FDPE 而不是 FDCE

需求FDPE (Preset)FDCE (Clear)
异步置位到 1(高有效复位)✅ 直接支持❌ 只能清零
配合 rst_in 高有效✅ PRE 高有效需要取反

4.4 Xilinx 原语实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 3 级复位同步器:异步置位、同步释放
  
(*ASYNC_REG="TRUE", SHREG_EXTRACT="NO"*)
  
FDPE #(.INIT(1)) u_sync_r0 (.C(clk), .CE(1'b1), .PRE(rst_in), .D(1'b0   ), .Q(sync_r0));
  

  
(*ASYNC_REG="TRUE", SHREG_EXTRACT="NO"*)
  
FDPE #(.INIT(1)) u_sync_r1 (.C(clk), .CE(1'b1), .PRE(rst_in), .D(sync_r0), .Q(sync_r1));
  

  
(*ASYNC_REG="TRUE", SHREG_EXTRACT="NO"*)
  
FDPE #(.INIT(1)) u_sync_r2 (.C(clk), .CE(1'b1), .PRE(rst_in), .D(sync_r1), .Q(sync_r2));
  

  
assign rst_out = sync_r2;
  

关键属性

属性作用
ASYNC_REG="TRUE"告诉 Vivado 这是异步信号同步链,强制放在同一 Slice
SHREG_EXTRACT="NO"禁止综合成 SRL16,保持物理 FF 结构
.INIT(1)上电时 Q=1,保证上电复位

5. CDC 同步器:与复位同步器的区别

5.1 为什么 CDC 用 FDRE

CDC(跨时钟域)同步的是普通数据信号,不是复位:

需求对比复位同步器CDC 同步器
需要立即生效✅ 必须❌ 不需要
可以等时钟沿
需要异步控制端✅ PRE
应该被复位吗N/A❌ 不应该

5.2 CDC 同步器实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// CDC 同步器:纯数据通路,无复位
  
(*ASYNC_REG="TRUE", SHREG_EXTRACT="NO"*)
  
FDRE #(.INIT(0)) u_sync_r0 (.C(clk), .CE(1'b1), .R(1'b0), .D(din    ), .Q(sync_r0));
  

  
(*ASYNC_REG="TRUE", SHREG_EXTRACT="NO"*)
  
FDRE #(.INIT(0)) u_sync_r1 (.C(clk), .CE(1'b1), .R(1'b0), .D(sync_r0), .Q(sync_r1));
  

  
(*ASYNC_REG="TRUE", SHREG_EXTRACT="NO"*)
  
FDRE #(.INIT(0)) u_sync_r2 (.C(clk), .CE(1'b1), .R(1'b0), .D(sync_r1), .Q(sync_r2));
  

  
assign dout = sync_r2;
  

注意.R(1'b0) 表示不使用复位。如果 CDC 同步器带复位,复位信号本身又是跨时钟域的,会产生新的 CDC 问题。


6. 同步链级数:2 级、3 级还是 5 级?

6.1 亚稳态恢复概率

亚稳态恢复概率是指数衰减的:

P(亚稳态未恢复) ≈ e^(-t / τ)
  
  • 7-series FF 的 τ 约为 30~100ps
  • 一个时钟周期(@200MHz = 5ns)远大于 5τ
  • 第 2 级之后,亚稳态概率已可忽略

6.2 工业标准

级数适用场景常见于
2 级常规应用Xilinx XPM_CDC 默认
3 级高可靠性(航空、医疗)UG576 FIFO Generator
4+ 级极端保守通常过度设计

6.3 推荐

复位同步器和 CDC 同步器使用 3 级——既满足可靠性要求,又不过度消耗资源。


7. 常见错误与规避

7.1 错误:RTL 写复位同步器

1
2
3
4
5
6
7
8
// ❌ 错误:综合结果不可控
  
always @(posedge clk or posedge rst_in)
  
    if (rst_in) sync_r <= 1;
  
    else        sync_r <= sync_r_prev;
  

问题

  • 综合器可能用等效但不同的结构
  • ASYNC_REG 属性可能未正确应用
  • 综合器可能"优化"掉中间级

正确做法:显式使用 FDPE 原语。

7.2 错误:CDC 同步器带复位

1
2
3
4
// ❌ 错误:CDC 同步器不应有复位
  
FDRE u_sync (.R(rst), .D(din), .Q(dout));
  

问题:复位信号本身可能是跨时钟域的,引入新的 CDC 问题。

正确做法.R(1'b0)

7.3 错误:异步复位信号直接使用

1
2
3
4
5
6
7
8
// ❌ 错误:直接使用外部异步复位
  
always @(posedge clk or posedge btn_rst)
  
    if (btn_rst) r_data <= 0;
  
    else         r_data <= w_data;
  

问题btn_rst 释放时刻随机,可能导致亚稳态。

正确做法:先经过复位同步器。


8. 总结:复位设计检查清单

检查项要求
外部/异步复位源✅ 必须经过复位同步器
复位同步器✅ 使用 FDPE + ASYNC_REG
普通逻辑✅ 使用同步复位(或不复位)
数据通路✅ 不加复位
CDC 同步器✅ 使用 FDRE,.R(1'b0)
同步链级数✅ 3 级
Slice 内 FF 类型✅ 同一 Slice 内 FF 类型相同

参考文献

  1. Xilinx WP272: Get Smart About Reset: Think Local, Not Global
  2. Xilinx UG953: Vivado Design Suite 7 Series FPGA and Zynq-7000 SoC Libraries Guide
  3. Xilinx XAPP495: Designing Robust CDC Structures
  4. Xilinx UG474: 7 Series FPGAs Configurable Logic Block User Guide