Xilinx 7-series 复位设计与 FF 原语深度指南
本文深入解析 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 包含:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| ┌─────────────────────────────────────────────────────────────┐
│ 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 有以下控制端口:
| 端口 | 名称 | 说明 |
|---|
| C | Clock | 时钟输入 |
| D | Data | 数据输入 |
| Q | Output | 数据输出 |
| CE | Clock Enable | 时钟使能(高有效) |
| SR | Set/Reset | 置位/复位控制 |
重要限制:同一 Slice 内的 8 个 FF 共享以下控制信号:
| 共享信号 | 限制 |
|---|
| CLK | 必须同时钟 |
| CE | 必须同使能 |
| SR | 必须同复位信号 |
| SR 极性 | 必须同为同步或异步 |
| SR 功能 | 必须同为置位或复位 |
这意味着:不能在同一 Slice 内混用 FDRE 和 FDPE。
1.3 FF 的四种配置模式
通过配置 SR 端的功能,同一物理 FF 可以实现四种不同行为:
| 原语名称 | 全称 | SR 功能 | 复位类型 | 复位后状态 |
|---|
| FDRE | FF + sync Reset + CE | 同步复位 | 同步 | Q = 0 |
| FDSE | FF + sync Set + CE | 同步置位 | 同步 | Q = 1 |
| FDCE | FF + async Clear + CE | 异步清零 | 异步 | Q = 0 |
| FDPE | FF + 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
| // 复位到 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
| // 异步复位到 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
| always @(posedge clk) begin
q <= d;
end
|
2.2 综合对照表
| RTL 写法 | 敏感列表 | 复位条件 | 推断原语 |
|---|
| 同步复位到 0 | posedge clk | if (rst) q <= 0 | FDRE |
| 同步复位到 1 | posedge clk | if (rst) q <= 1 | FDSE |
| 异步复位到 0 | posedge clk or posedge rst | if (rst) q <= 0 | FDCE |
| 异步复位到 1 | posedge clk or posedge rst | if (rst) q <= 1 | FDPE |
| 无复位 | posedge clk | 无 | FDRE |
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
| // 控制逻辑:同步复位
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 为什么需要复位同步器
当复位信号来自外部(按钮、另一个时钟域),它相对于本时钟域是异步的。如果直接使用:
1
2
3
4
5
| ┌───────┐
rst_in ─┤ FF ├─ q ← 复位释放时刻随机,可能在时钟边沿附近
└───┬───┘
│
clk
|
问题:复位释放时刻不确定,可能违反 FF 的 recovery/removal 时间,导致亚稳态。
4.2 解决方案:异步置位、同步释放
1
2
3
4
5
6
7
8
9
10
11
12
| 异步置位(立即生效)
│
rst_in ───────────────────┼───────────────────────┐
▼ ▼
┌──────────┐ ┌──────────┐
0 ───►│ FDPE │──► sync0 ──►│ FDPE │──► sync1 ──► rst_out
│ (PRE) │ │ (PRE) │
└────┬─────┘ └────┬─────┘
│ │
clk clk
│
同步释放(等时钟沿)
|
工作原理:
| 阶段 | 行为 |
|---|
| 复位置位 | rst_in=1 → PRE 端立即置位 → sync0=1、sync1=1 → rst_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
| // 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
| // 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 亚稳态恢复概率
亚稳态恢复概率是指数衰减的:
- 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
| // ❌ 错误:综合结果不可控
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
| // ❌ 错误:CDC 同步器不应有复位
FDRE u_sync (.R(rst), .D(din), .Q(dout));
|
问题:复位信号本身可能是跨时钟域的,引入新的 CDC 问题。
正确做法:.R(1'b0)。
7.3 错误:异步复位信号直接使用
1
2
3
4
| // ❌ 错误:直接使用外部异步复位
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 类型相同 |
参考文献
- Xilinx WP272: Get Smart About Reset: Think Local, Not Global
- Xilinx UG953: Vivado Design Suite 7 Series FPGA and Zynq-7000 SoC Libraries Guide
- Xilinx XAPP495: Designing Robust CDC Structures
- Xilinx UG474: 7 Series FPGAs Configurable Logic Block User Guide