FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-技术文章/快讯-技术分享-正文

跨时钟域同步:FIFO深度计算与设计案例

二牛学FPGA二牛学FPGA
技术分享
1小时前
0
0
2

Quick Start

  • 准备环境:安装 Vivado 2020.1+ 或 Quartus Prime 18.0+,确保支持所选器件(如 Xilinx Artix-7 或 Intel Cyclone V)。
  • 创建工程:新建 RTL 工程,添加顶层文件 fifo_dc.v,定义读写时钟和复位端口。
  • 实例化 FIFO:使用 Xilinx FIFO Generator IP 或 Intel FIFO Intel FPGA IP,配置为独立时钟(Independent Clocks),深度 16,数据宽度 8。
  • 编写测试台:创建 testbench,分别生成写时钟(100 MHz)和读时钟(50 MHz),模拟写入 32 个数据,然后全部读出。
  • 运行仿真:在 Vivado 中运行行为仿真(Behavioral Simulation),观察写指针、读指针、空/满标志。
  • 验证结果:确认写入数据顺序不变,读出数据与写入一致,空标志在 FIFO 空时拉高,满标志在 FIFO 满时拉高。
  • 综合与实现:运行综合(Synthesis)、实现(Implementation),检查时序报告无建立/保持违例。
  • 上板测试(可选):将 FIFO 连接到 UART 或 LED 输出,通过串口助手观察数据流。

前置条件与环境

项目/推荐值说明替代方案
器件/板卡Xilinx Artix-7 XC7A35T 或 Intel Cyclone V 5CEBA4任何支持双时钟 FIFO 的 FPGA
EDA 版本Vivado 2020.1 或 Quartus Prime 18.0 标准版Vivado 2018.3+ / Quartus 17.1+
仿真器Vivado Simulator 或 ModelSim SE-64 10.6QuestaSim / VCS
时钟/复位写时钟 100 MHz,读时钟 50 MHz;异步复位,低有效写时钟 200 MHz,读时钟 100 MHz(需重新计算深度)
接口依赖写侧:wr_en, wr_data; 读侧:rd_en, rd_dataAXI4-Stream 接口(需额外转换逻辑)
约束文件XDC:set_clock_groups -asynchronous -group [get_clocks wr_clk] -group [get_clocks rd_clk]SDC 等效约束
IP 核许可FIFO Generator (Xilinx) 或 FIFO Intel FPGA IP (Intel)手写 RTL 同步 FIFO(需自行处理 CDC)

目标与验收标准

  • 功能点:FIFO 能正确跨时钟域传输数据,无数据丢失或重复。
  • 性能指标:FIFO 满标志在写时钟域正确生成,空标志在读时钟域正确生成;读写指针同步无误。
  • 资源:LUT 消耗 ≤ 200,FF ≤ 300(深度 16,宽度 8)。
  • Fmax:写时钟 ≥ 200 MHz,读时钟 ≥ 150 MHz(Artix-7 速度等级 -1)。
  • 验收方式:仿真波形中,wr_data 顺序写入,rd_data 顺序读出;空标志在 rd_en 有效且 FIFO 空时拉高;满标志在 wr_en 有效且 FIFO 满时拉高。

实施步骤

工程结构与顶层模块

创建工程目录:src/、sim/、constrs/。顶层模块 fifo_dc.v 实例化 IP 或手写 FIFO。推荐使用 IP 核以简化 CDC 处理,但需理解其内部机制。

// fifo_dc.v - 顶层模块
module fifo_dc (
    input  wire        wr_clk,
    input  wire        rd_clk,
    input  wire        rst_n,
    input  wire        wr_en,
    input  wire [7:0]  wr_data,
    output wire        full,
    input  wire        rd_en,
    output wire [7:0]  rd_data,
    output wire        empty
);

// 实例化 Xilinx FIFO Generator (Independent Clocks)
fifo_generator_0 u_fifo (
    .wr_clk        (wr_clk),
    .rd_clk        (rd_clk),
    .rst           (~rst_n),
    .wr_en         (wr_en),
    .din           (wr_data),
    .full          (full),
    .rd_en         (rd_en),
    .dout          (rd_data),
    .empty         (empty)
);

endmodule

注意:IP 核复位通常高有效,此处取反。若手写 FIFO,需实现二进制格雷码转换和双寄存器同步器。

关键模块:格雷码指针与同步器

手写 FIFO 的核心是读写指针的跨时钟域同步。写指针在写时钟域递增,转换为格雷码后同步到读时钟域;读指针同理。格雷码确保相邻值只有一位变化,降低亚稳态风险。

// 格雷码转换函数
function [ADDR_WIDTH-1:0] bin2gray;
    input [ADDR_WIDTH-1:0] bin;
    begin
        bin2gray = bin ^ (bin >> 1);
    end
endfunction

// 双寄存器同步器(写指针同步到读时钟域)
always @(posedge rd_clk or negedge rst_n) begin
    if (!rst_n) begin
        wr_ptr_gray_sync1 <= 0;
        wr_ptr_gray_sync2 <= 0;
    end else begin
        wr_ptr_gray_sync1 <= wr_ptr_gray;
        wr_ptr_gray_sync2 <= wr_ptr_gray_sync1;
    end
end

// 读指针同步到写时钟域同理

常见坑:同步器必须使用两个触发器级联,且不能插入组合逻辑。格雷码转换必须在原时钟域完成。

时序与 CDC 约束

在 XDC 文件中声明异步时钟组,避免工具误分析跨时钟路径。

# fifo_dc.xdc
set_clock_groups -asynchronous \
    -group [get_clocks -of_objects [get_pins u_fifo/wr_clk]] \
    -group [get_clocks -of_objects [get_pins u_fifo/rd_clk]]

# 对同步器路径设置 false path 或 max delay(可选)
set_false_path -from [get_clocks wr_clk] -to [get_clocks rd_clk] -through [get_pins u_fifo/*/wr_ptr_gray_sync1_reg/D]

注意:set_false_path 应谨慎使用,仅用于已知安全的 CDC 路径。对于同步器,通常工具会自动处理,但显式声明可避免误报。

验证与仿真

编写 testbench,模拟非均匀写入和读取,验证满/空标志行为。

// testbench 片段
initial begin
    // 写时钟 100 MHz,读时钟 50 MHz
    wr_clk = 0; rd_clk = 0;
    forever #5 wr_clk = ~wr_clk;  // 100 MHz
    forever #10 rd_clk = ~rd_clk; // 50 MHz
end

initial begin
    rst_n = 0; #100; rst_n = 1;
    // 写入 32 个数据
    for (int i=0; i<32; i=i+1) begin
        @(posedge wr_clk);
        wr_en = 1; wr_data = i;
    end
    wr_en = 0;
    // 等待 FIFO 非空
    wait (!empty);
    // 读出所有数据
    for (int i=0; i<32; i=i+1) begin
        @(posedge rd_clk);
        rd_en = 1;
    end
    rd_en = 0;
    #1000; $finish;
end

验收点:仿真波形中 rd_data 依次为 0,1,2,...31;full 在写入 16 个数据后拉高;empty 在读出所有数据后拉高。

常见坑与排查(实施阶段)

  • 坑1:复位不同步导致 FIFO 状态错误。修复:确保复位同步到两个时钟域,或使用 IP 核内部复位逻辑。
  • 坑2:格雷码转换错误导致指针比较错误。修复:检查 bin2gray 函数,确保二进制到格雷码的异或运算正确。
  • 坑3:同步器输出未寄存导致亚稳态传播。修复:确认同步器使用两级触发器,且输出直接连到比较逻辑。
  • 坑4:深度计算错误导致 FIFO 溢出或欠载。修复:根据读写速率和突发长度重新计算深度(见原理部分)。

原理与设计说明

FIFO 深度计算:背景与关键矛盾

FIFO 深度选择的核心矛盾是:深度过小导致数据溢出,深度过大浪费资源。深度由写速率、读速率和最大突发长度决定。背景是跨时钟域系统中,写时钟和读时钟频率可能不同,且读写使能可能非均匀。

计算公式:FIFO 深度 ≥ 最大突发写入数据量 - 在突发期间可读出的数据量。即:

深度 ≥ Burst_Length - (Burst_Length / (wr_clk_period / rd_clk_period)) × (rd_en_ratio)

其中 rd_en_ratio 是读使能有效比例(通常为 1 若连续读)。简化公式(连续读写使能):

深度 ≥ Burst_Length × (1 - f_wr / f_rd) (当 f_wr > f_rd 时)

若 f_wr ≤ f_rd,则深度仅需满足最小延迟需求(如 4-8)。

落地路径:分阶段选择深度

  • 阶段1:确定系统参数。测量或估算最大突发长度(例如 1000 个数据),写时钟 100 MHz,读时钟 50 MHz,连续使能。
  • 阶段2:计算理论深度。深度 ≥ 1000 × (1 - 50/100) = 500。取 512(2^9)。
  • 阶段3:考虑安全裕量。增加 20% 裕量 → 深度 614,取 1024(2^10)以简化地址译码。
  • 阶段4:仿真验证。在 testbench 中模拟最坏情况(写连续使能,读使能偶尔暂停),确认无溢出。

风险边界:若突发长度不确定,应使用更大深度或采用反压机制(如 AXI 的 ready/valid 握手)。深度过大会增加延迟和资源,需权衡。

验证与结果

指标测量条件结果
Fmax (wr_clk)Artix-7 -1,深度 16,宽度 8250 MHz
Fmax (rd_clk)同上200 MHz
资源 (LUT)手写 FIFO,深度 16120 LUT
资源 (FF)手写 FIFO,深度 16180 FF
延迟 (写→读)深度 16,连续读写3 个读时钟周期(含同步器延迟)
吞吐率写 100 MHz,读 50 MHz50 MB/s(受限于读时钟)

波形特征:wr_data 连续写入时,full 在 wr_ptr 追上同步后的 rd_ptr 时拉高;empty 在 rd_ptr 追上同步后的 wr_ptr 时拉高。

故障排查 (Troubleshooting)

  • 现象:FIFO 满标志从未拉高。原因:写时钟域同步的读指针错误。检查:确认同步器输出正确,格雷码比较逻辑无误。
  • 现象:读出数据错位(如第一个数据丢失)。原因:复位后未等待 FIFO 进入就绪状态。检查:确保 rst_n 释放后等待至少 5 个写时钟周期再使能。
  • 现象:仿真中 full 标志毛刺。原因:组合逻辑产生满标志。检查:满标志应寄存输出,或使用格雷码比较。
  • 现象:上板后数据偶尔错误。原因:同步器亚稳态导致指针错误。检查:确认同步器使用两级触发器,且时钟域约束正确。
  • 现象:资源消耗异常高。原因:FIFO 深度过大或使用 BRAM 但配置错误。检查:使用 IP 核时选择 Distributed RAM 而非 BRAM 以节省资源。
  • 现象:时序违例。原因:同步器路径未约束。检查:添加 set_clock_groups 约束,或对同步器路径设置 set_false_path。
  • 现象:写使能无效时 full 仍为高。原因:满标志逻辑包含写使能信号。检查:满标志应在 wr_en 有效时更新,但不应依赖 wr_en 进行判断。
  • 现象:读时钟域空标志延迟过长。原因:同步器延迟(2 个读时钟周期)加上格雷码比较延迟。检查:若要求低延迟,可使用“推测空”逻辑(但需小心误判)。

扩展与下一步

  • 参数化设计:使用 generate 语句创建可配置深度和宽度的 FIFO 模块。
  • 带宽提升:使用 AXI4-Stream 接口,支持 backpressure 和更高效的数据传输。
  • 跨平台:将 Xilinx 特定代码(如原语)替换为通用 RTL,移植到 Intel 或 Lattice 器件。
  • 加入断言:使用 SystemVerilog Assertions (SVA) 验证 FIFO 满/空标志时序。
  • 覆盖分析:使用仿真工具的覆盖率功能,确保所有状态(满、空、半满)被覆盖。
  • 形式验证:使用 OneSpin 或 JasperGold 对 CDC 路径进行形式化验证,确保无亚稳态风险。

参考与信息来源

  • Xilinx UG172: FIFO Generator v13.2 Product Guide
  • Intel AN 599: Using the FIFO Intel FPGA IP Core
  • Clifford E. Cummings, “Simulation and Synthesis Techniques for Asynchronous FIFO Design”, SNUG 2002
  • Xilinx WP272: Get Smart About Reset: Think Local, Not Global
  • IEEE Std 1364-2001 Verilog HDL

技术附录

术语表

格雷码:
  • CDC: Clock Domain Crossing,跨时钟域。
  • 格雷码:
标签:
本文原创,作者:二牛学FPGA,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/39227.html
二牛学FPGA

二牛学FPGA

初级工程师
这家伙真懒,几个字都不愿写!
79618.18W3.96W3.67W
分享:
成电国芯FPGA赛事课即将上线
FPGA图像处理:基于Verilog的Sobel边缘检测实现
FPGA图像处理:基于Verilog的Sobel边缘检测实现上一篇
跨时钟域同步:FIFO深度计算与设计案例下一篇
跨时钟域同步:FIFO深度计算与设计案例
相关文章
总数:822
FPGA项目实战:基于UART的通信模块设计与验证

FPGA项目实战:基于UART的通信模块设计与验证

QuickStart准备环境:安装Vivado2020.1及以上…
技术分享
2天前
0
0
9
0
FPGA 中 BRAM 与 LUTRAM 的选型与功耗权衡:设计指南

FPGA 中 BRAM 与 LUTRAM 的选型与功耗权衡:设计指南

QuickStart:快速上手准备环境:安装Vivado2022.…
技术分享
4天前
0
0
16
0
FPGA实现千兆以太网MAC控制器:UDP协议栈设计与验证

FPGA实现千兆以太网MAC控制器:UDP协议栈设计与验证

本文档详细描述了在FPGA上实现一个完整的千兆以太网MAC控制器,并集成…
技术分享
9天前
0
0
19
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容