在 Verilog 中,xpm_cdc_handshake 是 Xilinx 参数化宏(XPM) 中的握手协议时钟域交叉(CDC)模块,用于安全地传递多比特数据 across clock domains。
一、概述
xpm_cdc_handshake 使用完整的握手协议(REQ/ACK)来确保多比特数据在跨时钟域时不会丢失或损坏。
二、基本语法
// Verilog 实例化 xpm_cdc_handshake #( .DEST_EXT_HSK(0), // 0-1 .DEST_SYNC_FF(2), // 范围:2-10 .INIT_SYNC_FF(0), // 0-1 .SIM_ASSERT_CHK(0), // 0-1 .SRC_SYNC_FF(2), // 范围:2-10 .WIDTH(8) // 范围:1-1024 ) xpm_cdc_handshake_inst ( .src_clk(src_clk), // 源时钟 .src_rst(src_rst), // 源复位 .dest_clk(dest_clk), // 目标时钟 .dest_rst(dest_rst), // 目标复位 .src_in(src_in), // 源数据输入 .src_send(src_send), // 源发送请求 .src_rcv(src_rcv), // 源接收确认(可选) .dest_req(dest_req), // 目标数据请求 .dest_ack(dest_ack), // 目标确认(可选) .dest_out(dest_out) // 目标数据输出 );
三、参数详解
1. 关键参数
-
WIDTH(必须): 数据宽度(1-1024 位) -
DEST_SYNC_FF(默认=2): 目标时钟域同步寄存器级数 -
SRC_SYNC_FF(默认=2): 源时钟域同步寄存器级数 -
DEST_EXT_HSK(默认=0): 是否使用外部握手信号
四、使用示例
示例 1:基本握手数据传输
module handshake_cdc_example ( input wire clk_a, input wire clk_b, input wire rst_a, input wire rst_b, input wire [31:0] data_a, input wire send_data, output wire [31:0] data_b, output wire data_valid ); xpm_cdc_handshake #( .WIDTH(32), // 32位数据 .DEST_SYNC_FF(2), // 2级同步 .SRC_SYNC_FF(2) ) handshake_cdc ( .src_clk(clk_a), .src_rst(rst_a), .src_in(data_a), .src_send(send_data), .src_rcv(), // 不连接可选信号 .dest_clk(clk_b), .dest_rst(rst_b), .dest_req(data_valid), // 数据有效标志 .dest_ack(1'b0), // 不使用外部确认 .dest_out(data_b) ); endmodule
示例 2:完整握手协议
module full_handshake_cdc ( input wire src_clk, input wire dest_clk, input wire src_rst, input wire dest_rst, input wire [63:0] src_data, input wire data_ready, output wire src_ready, // 源端准备好接收新数据 output wire [63:0] dest_data, output wire dest_valid, input wire dest_ready // 目标端准备好接收 ); xpm_cdc_handshake #( .WIDTH(64), .DEST_EXT_HSK(1), // 使用外部握手 .DEST_SYNC_FF(3) ) full_handshake ( .src_clk(src_clk), .src_rst(src_rst), .src_in(src_data), .src_send(data_ready), .src_rcv(src_ready), // 源端接收确认 .dest_clk(dest_clk), .dest_rst(dest_rst), .dest_req(dest_valid), .dest_ack(dest_ready), // 外部目标确认 .dest_out(dest_data) ); endmodule
五、握手协议流程
1. 基本模式(DEST_EXT_HSK = 0)
-
源端:设置
src_in和src_send=1 -
CDC:自动传输数据
-
目标端:
dest_req=1表示数据有效 -
CDC:自动产生确认,准备下一次传输
2. 外部握手模式(DEST_EXT_HSK = 1)
-
源端:设置
src_in和src_send=1 -
CDC:传输数据到目标端
-
目标端:
dest_req=1表示数据有效 -
目标应用:读取数据后设置
dest_ack=1 -
CDC:确认传回源端,
src_rcv=1
六、应用场景
1. 配置寄存器跨时钟域
module config_reg_cdc ( input wire cfg_clk, input wire sys_clk, input wire rst, input wire [15:0] cfg_data, input wire cfg_write, output wire cfg_ready, output wire [15:0] sys_cfg, output wire sys_cfg_valid ); xpm_cdc_handshake #( .WIDTH(16), .DEST_SYNC_FF(2) ) cfg_transfer ( .src_clk(cfg_clk), .src_rst(rst), .src_in(cfg_data), .src_send(cfg_write), .src_rcv(cfg_ready), .dest_clk(sys_clk), .dest_rst(rst), .dest_req(sys_cfg_valid), .dest_ack(1'b0), .dest_out(sys_cfg) ); endmodule
2. 数据包传输
module packet_transfer ( input wire tx_clk, input wire rx_clk, input wire rst, input wire [127:0] packet_data, input wire packet_valid, output wire tx_ready, output wire [127:0] rx_packet, output wire rx_valid, input wire rx_ready ); xpm_cdc_handshake #( .WIDTH(128), .DEST_EXT_HSK(1), // 使用外部握手控制流 .DEST_SYNC_FF(3) ) packet_cdc ( .src_clk(tx_clk), .src_rst(rst), .src_in(packet_data), .src_send(packet_valid), .src_rcv(tx_ready), .dest_clk(rx_clk), .dest_rst(rst), .dest_req(rx_valid), .dest_ack(rx_ready), .dest_out(rx_packet) ); endmodule
3. 命令字传递
module command_sync ( input wire ctrl_clk, input wire proc_clk, input wire rst_n, input wire [7:0] command, input wire cmd_valid, output wire ctrl_busy, output wire [7:0] proc_cmd, output wire proc_cmd_valid ); xpm_cdc_handshake #( .WIDTH(8), .DEST_SYNC_FF(2) ) cmd_sync ( .src_clk(ctrl_clk), .src_rst(~rst_n), .src_in(command), .src_send(cmd_valid), .src_rcv(ctrl_busy), .dest_clk(proc_clk), .dest_rst(~rst_n), .dest_req(proc_cmd_valid), .dest_ack(1'b0), .dest_out(proc_cmd) ); endmodule
4. 状态信息反馈
module status_feedback ( input wire proc_clk, input wire mon_clk, input wire rst, input wire [31:0] status_reg, input wire status_update, output wire proc_done, output wire [31:0] mon_status, output wire mon_status_valid ); xpm_cdc_handshake #( .WIDTH(32), .DEST_SYNC_FF(2) ) status_cdc ( .src_clk(proc_clk), .src_rst(rst), .src_in(status_reg), .src_send(status_update), .src_rcv(proc_done), .dest_clk(mon_clk), .dest_rst(rst), .dest_req(mon_status_valid), .dest_ack(1'b0), .dest_out(mon_status) ); endmodule
七、完整参数列表
xpm_cdc_handshake #( .DEST_EXT_HSK(0), // 目标外部握手使能 .DEST_SYNC_FF(2), // 目标同步寄存器级数 .INIT_SYNC_FF(0), // 同步寄存器初始值 .SIM_ASSERT_CHK(0), // 仿真断言检查 .SRC_SYNC_FF(2), // 源同步寄存器级数 .WIDTH(8) // 数据宽度 )
八、时序特性
1. 传输延迟
src_send=1 → [2-3 src_clk] → 数据传输 → [DEST_SYNC_FF dest_clk] → dest_req=1
2. 吞吐量
-
最大速率:受限于握手协议往返时间
-
典型性能:每 5-8 个时钟周期传输一次数据
九、在 Vivado 中的使用
1. 自动识别和优化
Vivado 能够识别 XPM CDC 模块并应用适当的时序约束。
2. 约束建议
# 设置异步时钟组
set_clock_groups -asynchronous \
-group [get_clocks src_clk] \
-group [get_clocks dest_clk]
# 如果需要,设置虚假路径
set_false_path -from [get_cells {xpm_cdc_handshake_inst/*src_ff_reg*}] \
-to [get_cells {xpm_cdc_handshake_inst/*dest_ff_reg*}]
十、优势
-
高可靠性:完整的握手协议确保数据完整性
-
灵活性:支持各种数据宽度和握手模式
-
流控制:内置背压机制防止数据丢失
-
易于使用:无需手动实现复杂的 CDC 逻辑
十一、注意事项
1. 正确用法
// 正确:等待 ready 信号再发送新数据
always @(posedge src_clk) begin
if (src_rst) begin
src_send <= 1'b0;
end else begin
if (new_data_ready && src_rcv) begin // 等待确认
src_in <= new_data;
src_send <= 1'b1;
end else begin
src_send <= 1'b0;
end
end
end
2. 错误用法
// 错误:连续发送,可能丢失数据 always @(posedge src_clk) begin src_send <= data_valid; // 可能在前一次传输未完成时发送 src_in <= current_data; end // 错误:忽略握手信号 assign src_send = always_send; // 不考虑目标端是否准备好
3. 复位考虑
// 推荐:使用适当的复位同步 xpm_cdc_handshake #(.WIDTH(32)) cdc_inst ( .src_clk(clk_a), .src_rst(rst_sync_a), // 同步到 src_clk 的复位 .dest_clk(clk_b), .dest_rst(rst_sync_b), // 同步到 dest_clk 的复位 // ... 其他信号 );
十二、相关 XPM CDC 模块
-
xpm_cdc_single: 单比特电平信号 CDC -
xpm_cdc_pulse: 单周期脉冲 CDC -
xpm_cdc_gray: 计数器格雷码 CDC -
xpm_cdc_array_single: 多比特数组 CDC(无握手)
xpm_cdc_handshake 是处理多比特数据跨时钟域传输的最安全方法,特别适用于配置数据、命令字和数据包传输等需要确保数据完整性的场景。
2536

被折叠的 条评论
为什么被折叠?



