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

FPGA跨时钟域同步:基于双寄存器握手协议的Verilog实现指南

FPGA小白FPGA小白
技术分享
2天前
0
0
9

Quick Start

  1. 准备开发环境:安装 Vivado 或 Quartus(推荐 Vivado 2019.1 及以上版本)。
  2. 新建工程:选择目标器件,例如 Xilinx Artix-7 XC7A35T。
  3. 创建顶层模块:编写 top.v,包含两个时钟域(clk_aclk_b)及复位信号。
  4. 编写双寄存器同步器模块:实现 sync_2ff.v(代码详见“实施步骤”)。
  5. 编写握手控制模块:实现 handshake.v,完成请求-应答逻辑。
  6. 编写 testbench:模拟跨时钟域数据传输,运行仿真。
  7. 观察仿真波形:确认 data_out 稳定输出,无毛刺或亚稳态传播。
  8. 综合实现:检查时序报告,确保无跨时钟域路径违例。
  9. 上板验证:通过 LED 或 UART 观察数据正确性。

前置条件

项目推荐值说明替代方案
器件/板卡Xilinx Artix-7 (XC7A35T)主流 FPGA,资源充足Altera Cyclone IV / Lattice ECP5
EDA 版本Vivado 2020.1支持异步约束语法Quartus Prime 18.0+
仿真器Vivado Simulator / ModelSim用于功能仿真和时序仿真Verilator(仅功能仿真)
时钟/复位clk_a = 50MHz, clk_b = 75MHz异步时钟,频率不同任意频率差,但需满足 setup/hold
接口依赖无特殊外设仅需 GPIO 或 UART 观察逻辑分析仪(上板调试)
约束文件XDC(Vivado)必须添加 set_false_path 或 set_clock_groupsSDC(Quartus)

目标与验收标准

  • 功能点:实现从 clk_a 域到 clk_b 域的单比特或少量多比特数据可靠传输,无亚稳态传播。
  • 性能指标:握手延迟不超过 3 个 clk_b 周期(从请求到应答)。
  • 资源消耗双寄存器同步器占用约 2 个触发器,握手控制约 4-6 个触发器。
  • 验收方式:仿真波形中 data_out 在握手完成后稳定,且与 data_in 一致;时序分析报告无跨时钟域违例。

实施步骤

工程结构

project/
├── rtl/
│   ├── top.v
│   ├── sync_2ff.v
│   └── handshake.v
├── sim/
│   └── tb_top.v
├── constraints/
│   └── top.xdc
└── scripts/
    └── run.tcl

顶层模块 top.v

顶层模块实例化 handshakesync_2ff,其中 handshake 内部调用 sync_2ff 同步请求和应答信号。

关键模块:双寄存器同步器

module sync_2ff (
    input wire clk_dst,
    input wire rst_n,
    input wire async_in,
    output wire sync_out
);

reg sync_reg1, sync_reg2;

always @(posedge clk_dst or negedge rst_n) begin
    if (!rst_n) begin
        sync_reg1 <= 1'b0;
        sync_reg2 <= 1'b0;
    end else begin
        sync_reg1 <= async_in;
        sync_reg2 <= sync_reg1;
    end
end

assign sync_out = sync_reg2;

endmodule

机制说明:两级触发器串联,第一级可能产生亚稳态,但经过一个时钟周期后,第二级捕获到稳定值。该结构将亚稳态概率降低至可忽略水平,是跨时钟域同步的基础单元。

关键模块:握手控制

握手协议通过请求-应答机制确保数据可靠传输。发送域(clk_a)拉高请求信号,接收域(clk_b)同步后采样数据,并拉高应答信号。发送域检测到应答后,拉低请求,完成一次传输。

module handshake (
    input wire clk_a,
    input wire clk_b,
    input wire rst_n,
    input wire [7:0] data_in,
    input wire req_in,
    output wire ack_out,
    output reg [7:0] data_out
);

wire req_sync, ack_sync;
reg req_a, ack_b;

// 同步请求到 clk_b 域
sync_2ff u_sync_req (
    .clk_dst(clk_b),
    .rst_n(rst_n),
    .async_in(req_a),
    .sync_out(req_sync)
);

// 同步应答到 clk_a 域
sync_2ff u_sync_ack (
    .clk_dst(clk_a),
    .rst_n(rst_n),
    .async_in(ack_b),
    .sync_out(ack_sync)
);

// clk_a 域:请求生成
always @(posedge clk_a or negedge rst_n) begin
    if (!rst_n)
        req_a <= 1'b0;
    else if (req_in && !ack_sync)
        req_a <= 1'b1;
    else if (ack_sync)
        req_a <= 1'b0;
end

// clk_b 域:应答与数据采样
always @(posedge clk_b or negedge rst_n) begin
    if (!rst_n) begin
        ack_b <= 1'b0;
        data_out <= 8'b0;
    end else if (req_sync && !ack_b) begin
        data_out <= data_in;
        ack_b <= 1'b1;
    end else if (!req_sync) begin
        ack_b <= 1'b0;
    end
end

assign ack_out = ack_sync;

endmodule

风险边界:握手协议适用于数据变化频率低于握手周期的情况。若数据在握手期间多次变化,可能导致数据丢失或错误。多比特数据建议使用 FIFO 或 DMUX 结构。

约束文件(top.xdc)

# 对跨时钟域路径设置 false path
set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]
set_false_path -from [get_clocks clk_b] -to [get_clocks clk_a]

原因:跨时钟域路径无需时序收敛,因为同步器本身容忍亚稳态。若不设置 false path,工具可能报时序违例,影响综合结果。

验证结果

仿真波形应显示:

  • req_a 拉高后,经过 2-3 个 clk_b 周期,req_sync 变为高电平。
  • ack_b 拉高后,再经 2-3 个 clk_a 周期,ack_out 变为高电平。
  • data_outack_b 拉高时更新,并保持稳定直到下一次握手。
  • 无毛刺或不定态(X)传播到 data_out

时序分析报告应无跨时钟域违例(若已正确设置 false path)。

排障指南

  • 仿真中出现 X 态:检查复位信号是否在仿真开始时有效,且所有触发器正确初始化。
  • 握手不完成:确认请求和应答同步路径正确,且握手状态机无死锁。可增加超时计数器辅助调试。
  • 时序违例:确保约束文件已添加 false path,且时钟定义正确。若仍有违例,检查是否误将同步器内部路径包含在时序分析中。
  • 数据错误:对于多比特数据,确认握手期间数据保持稳定。若数据变化快,考虑使用格雷码或 FIFO。

扩展阅读

  • 多比特同步:可使用握手协议传输多比特数据,但需保证数据在握手期间不变。更高效方案是异步 FIFO。
  • 格雷码:适用于连续变化的多比特数据(如计数器),每次只变化一位,降低亚稳态风险。
  • DMUX 结构:通过使能信号同步后,用多路选择器选择数据,适合少量多比特传输。
  • 异步 FIFO:最通用的跨时钟域数据传输方案,适用于任意位宽和速率。

参考文档

  • Xilinx UG949: Vivado Design Suite User Guide - Using Constraints
  • Clifford E. Cummings: “Synthesis and Scripting Techniques for Designing Multi-Asynchronous Clock Designs”
  • Altera AN 433: Constraining and Analyzing Source-Synchronous Interfaces

附录:完整 testbench 示例

module tb_top;

reg clk_a, clk_b, rst_n;
reg [7:0] data_in;
reg req_in;
wire ack_out;
wire [7:0] data_out;

// 时钟生成
always #10 clk_a = ~clk_a; // 50MHz
always #6.667 clk_b = ~clk_b; // 75MHz

initial begin
    clk_a = 0; clk_b = 0; rst_n = 0;
    data_in = 8'hA5; req_in = 0;
    #100 rst_n = 1;
    #50 req_in = 1;
    #100 req_in = 0;
    #500 $finish;
end

top u_top (
    .clk_a(clk_a),
    .clk_b(clk_b),
    .rst_n(rst_n),
    .data_in(data_in),
    .req_in(req_in),
    .ack_out(ack_out),
    .data_out(data_out)
);

endmodule
标签:
本文原创,作者:FPGA小白,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/40458.html
FPGA小白

FPGA小白

初级工程师
成电国芯®的讲师哦,专业FPGA已有10年。
36220.98W7.21W34.38W
分享:
成电国芯FPGA赛事课即将上线
FPGA学习路线:从零基础到项目实战的三个月计划
FPGA学习路线:从零基础到项目实战的三个月计划上一篇
Vivado时序约束实战指南:基于Tcl脚本的自动化路径优化与验证下一篇
Vivado时序约束实战指南:基于Tcl脚本的自动化路径优化与验证
相关文章
总数:944
FPGA在边缘计算中的低延迟UDP包处理加速器设计与实现指南

FPGA在边缘计算中的低延迟UDP包处理加速器设计与实现指南

QuickStart:快速上手本指南将带你从零搭建一个基于FPGA的1…
技术分享
10天前
0
0
31
0
2026年FPGA原型验证在Chiplet系统级验证中的关键作用与流程

2026年FPGA原型验证在Chiplet系统级验证中的关键作用与流程

随着Chiplet(芯粒)技术成为高性能计算与异构集成的主流,系统级验证…
技术分享
14天前
0
0
38
0
FPGA实现千兆以太网MAC控制器:UDP协议栈设计与验证

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

本文档提供基于FPGA的千兆以太网MAC控制器与UDP协议栈的完整实现与…
技术分享
14天前
0
0
27
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容