赞
踩
本文以Xilinx提供的xpm_cdc代码为例,整理处理跨时钟域数据传输的常见方法。
Xilinx定义了多个宏定义代替描述触发器行为的always块,列举如下
宏名称 | 含义 |
---|---|
XPM_XSRREG | 带同步复位/置位的同步寄存器 |
XPM_XSRREGEN | 带同步复位/置位和使能的寄存器 |
XPM_XARREG | 带异步复位/置位和使能的寄存器 |
// Define Xilinx Synchronous Register. Only to be used by xpm_cdc_* modules. `define XPM_XSRREG(clk, reset_p, q, d, rstval) \ always @(posedge clk) begin \ if (reset_p == 1'b1) \ q <= rstval; \ else \ q <= d; \ end // Define Xilinx Synchronous Register with Enable. Only to be used by xpm_cdc_* modules. `define XPM_XSRREGEN(clk, reset_p, q, d, en, rstval) \ always @(posedge clk) begin \ if (reset_p == 1'b1) \ q <= rstval; \ else \ if (en == 1'b1) \ q <= d; \ end // Define Xilinx Asynchronous Register. Only to be used by xpm_cdc_* modules. `define XPM_XARREG(clk, reset_p, q, d, rstval) \ always @(posedge clk or posedge reset_p) \ begin \ if (reset_p == 1'b1) \ q <= rstval; \ else \ q <= d; \ end
cdc_single使用多个寄存器构成寄存器同步链的方式进行跨时钟域同步,这种方式适合于单比特数据的同步。使用该原语时需要注意:
- 为了保证不存在漏采脉冲信号,Xilinx规定用户逻辑需要保证每次源时钟脉冲(数据变化)至少为两个目的时钟周期。
可调参数 | 功能 |
---|---|
DEST_SYNC_FF | 可设置为大于2的值,用于设置目的时钟域的同步寄存器级数 |
SRC_INPUT_REG | 可设置为0或1,在不为0时,会在源时钟域添加一级XPM_XSRREG寄存器采样src_in |
module xpm_cdc_single #( // Module parameters parameter integer DEST_SYNC_FF = 4, parameter integer INIT_SYNC_FF = 0, parameter integer SIM_ASSERT_CHK = 0, parameter integer SRC_INPUT_REG = 1, parameter integer VERSION = 0 ) ( // Module ports input wire src_clk, input wire src_in, input wire dest_clk, output wire dest_out ); // Set Asynchronous Register property on synchronizers (* XPM_CDC = "SINGLE", ASYNC_REG = "TRUE" *) reg [DEST_SYNC_FF-1:0] syncstages_ff; reg src_ff; wire src_inqual; wire async_path_bit; assign dest_out = syncstages_ff[DEST_SYNC_FF-1]; assign async_path_bit = src_inqual; // Virtual mux: Register at input optional. generate if (SRC_INPUT_REG) begin : extra_inreg assign src_inqual = src_ff; end : extra_inreg else begin : no_extra_inreg assign src_inqual = src_in; end : no_extra_inreg endgenerate // Instantiate Xilinx Synchronous Register `XPM_XSRREG(src_clk , 1'b0, src_ff, src_in, 1'b0) `XPM_XSRREG(dest_clk, 1'b0, syncstages_ff, { syncstages_ff[DEST_SYNC_FF-2:0], async_path_bit} , {DEST_SYNC_FF{1'b0}}) endmodule : xpm_cdc_single # 单比特伪路径 set_false_path -to [get_cells syncstages_ff_reg[0][*]]
通过格雷码方式传输多位宽连续变化数据(相邻变化范围不超过1),比较适合用作计数器的同步(如异步FIFO中)。使用该原语时需要注意:
1.为了保证不存在漏采脉冲信号,Xilinx规定用户逻辑需要保证每次源时钟脉冲(数据变化)至少为两个目的时钟周期。
2. 为了保证数据的正确性,源时钟域发出的新数据需要是由旧数据加1或减1得到的。
可调参数 | 功能 |
---|---|
DEST_SYNC_FF | 可设置为大于2的值,用于设置目的时钟域的同步寄存器级数 |
REG_OUTPUT | 可设置为0或1,在不为0时,会在源时钟域添加一级XPM_XSRREG寄存器采样src_in_bin的格雷码结果 |
WIDTH | 待同步数据位宽 |
module xpm_cdc_gray #( // Module parameters parameter integer DEST_SYNC_FF = 4, parameter integer INIT_SYNC_FF = 0, parameter integer REG_OUTPUT = 0, parameter integer SIM_ASSERT_CHK = 0, parameter integer SIM_LOSSLESS_GRAY_CHK = 0, parameter integer VERSION = 0, parameter integer WIDTH = 2 ) ( // Module ports input wire src_clk, input wire [WIDTH-1:0] src_in_bin, input wire dest_clk, output wire [WIDTH-1:0] dest_out_bin ); // Set Asynchronous Register property on synchronizers (* XPM_CDC = "GRAY", ASYNC_REG = "TRUE" *) reg [WIDTH-1:0] dest_graysync_ff [DEST_SYNC_FF-1:0]; `ifdef XPM_CDC_BHVSIM_ONLY if (INIT_SYNC_FF == 1) begin always @(glblGSR_xpmcdc) if (glblGSR_xpmcdc) force dest_graysync_ff = '{default:(0)}; else release dest_graysync_ff; end `endif wire [WIDTH-1:0] gray_enc; reg [WIDTH-1:0] binval; reg [WIDTH-1:0] src_gray_ff; wire [WIDTH-1:0] synco_gray; wire [WIDTH-1:0] async_path; reg [WIDTH-1:0] dest_out_bin_ff; always @(posedge dest_clk) begin dest_graysync_ff[0] <= async_path; // @2 for (int syncstage = 1; syncstage < DEST_SYNC_FF ;syncstage = syncstage + 1) dest_graysync_ff[syncstage] <= dest_graysync_ff [syncstage-1]; end assign async_path = src_gray_ff; // @1 assign synco_gray = dest_graysync_ff[DEST_SYNC_FF-1]; assign gray_enc = src_in_bin ^ {1'b0, src_in_bin[WIDTH-1:1]}; // Convert gray code back to binary always_comb begin binval[WIDTH-1] = synco_gray[WIDTH-1]; for (int j = WIDTH - 2; j >= 0; j = j - 1) binval[j] = binval[j+1] ^ synco_gray[j]; end generate if(REG_OUTPUT) begin : reg_out assign dest_out_bin = dest_out_bin_ff; end : reg_out else begin : comb_out assign dest_out_bin = binval; end : comb_out endgenerate // Instantiate Xilinx Synchronous Register `XPM_XSRREG(src_clk, 1'b0, src_gray_ff, gray_enc, {WIDTH{1'b0}}) `XPM_XSRREG(dest_clk, 1'b0, dest_out_bin_ff, binval, {WIDTH{1'b0}}) endmodule : xpm_cdc_gray # 保证格雷码各位传输的最大路径延迟小于一个源时钟周期 set_max_delay -from [get_cells src_gray_ff_reg*] -to [get_cells dest_graysync_ff_reg[0]*] $src_clk_period -datapath_only # 保证格雷码各位传输的偏斜不超过一个时钟周期 set_bus_skew -from [get_cells src_gray_ff_reg*] -to [get_cells dest_graysync_ff_reg[0]*] [expr min ($src_clk_period, $dest_clk_period)]
具有握手信号的跨时钟域传输,源时钟域通过src_send发起新的传输,通过src_rcv信号确认传输结束,目的时钟域通过dest_req得知出现新的传输,通过dest_ack信号确认传输。这种方式不需要使用存储资源进行同步,适合传输多位宽非连续的数据。使用该原语时需要注意:
- 对于源时钟域逻辑而言,在目的时钟域确认握手结束前不能发起新的传输,即每次src_send拉高都需要等到src_rcv拉低后一个周期再进行
- 对于源时钟域逻辑而言,在目的时钟域未确认握手时需要持续等待,即每次src_send拉低都需要等到src_rcv拉高后一个周期再进行
- 对于目的时钟域逻辑而言,在源时钟域未发起握手时不能发起新的确认,即每次dest_ack拉高都需要dest_req拉高后一个周期进行
- 对于目的时钟域逻辑而言,在源时钟域未确认握手时需要持续等待,即每次dest_ack拉低都需要等到dest_req拉低后一个周期再进行
可调参数 | 功能 |
---|---|
DEST_EXT_HSK | 可设置为0和1,当为1时启用dest_ack信号由用户逻辑在需要确认时确认握手,为0时由系统自行通过dest_req确认握手 |
DEST_SYNC_FF | 可设置为大于2的值,用于设置握手信号在目的时钟域的同步寄存器级数 |
SRC_SYNC_FF | 可设置为大于2的值,用于设置握手信号在源时钟域的同步寄存器级数 |
WIDTH | 待同步数据位宽 |
module xpm_cdc_handshake #( // Module parameters parameter integer DEST_EXT_HSK = 1, parameter integer DEST_SYNC_FF = 4, parameter integer INIT_SYNC_FF = 0, parameter integer SIM_ASSERT_CHK = 0, parameter integer SRC_SYNC_FF = 4, parameter integer VERSION = 0, parameter integer WIDTH = 1 ) ( // Module ports input wire src_clk, input wire [WIDTH-1:0] src_in, input wire src_send, output wire src_rcv, input wire dest_clk, output wire [WIDTH-1:0] dest_out, output wire dest_req, input wire dest_ack ); // ------------------------------------------------------------------------------------------------------------------- // Local parameter definitions // ------------------------------------------------------------------------------------------------------------------- // Set Asynchronous Register property on synchronizers (* XPM_CDC = "HANDSHAKE" *) reg [WIDTH-1:0] dest_hsdata_ff; // ------------------------------------------------------------------------------------------------------------------- // Simulation only variable and signal assignment // ------------------------------------------------------------------------------------------------------------------- // We can do set max delay between source and dest. // For option with no input register, we have to create a smart constraint // for set max delay. reg [WIDTH-1:0] src_hsdata_ff; wire dest_req_nxt; reg dest_req_ff; (* DIRECT_ENABLE = "yes" *) wire dest_hsdata_en; wire dest_req_ext_nxt; reg dest_req_ext_ff; wire [WIDTH-1:0] src_hsdata_nxt; wire [WIDTH-1:0] dest_hsdata_nxt; wire [WIDTH-1:0] src_data_src; wire dest_req_sync; wire dest_ack_sync_in; reg src_sendd_ff; wire src_sendd_nxt; // ------------------------------------------------------------------------------------------------------------------- // xpm_cdc_single instantiation // ------------------------------------------------------------------------------------------------------------------- xpm_cdc_single # ( .DEST_SYNC_FF (DEST_SYNC_FF ), .INIT_SYNC_FF (INIT_SYNC_FF ), .SRC_INPUT_REG (0 ), .VERSION (VERSION ) ) xpm_cdc_single_src2dest_inst ( .src_clk (src_clk ), .dest_clk (dest_clk ), .src_in (src_sendd_ff ), .dest_out (dest_req_sync ) ); //src_data is always registered once assign src_data_src = src_hsdata_ff; assign src_hsdata_nxt = (src_sendd_ff == 1'b0) ? src_in : src_hsdata_ff; assign dest_hsdata_nxt = src_data_src; assign dest_out = dest_hsdata_ff; assign dest_req_nxt = dest_req_sync; assign dest_hsdata_en = ~dest_req_ff && dest_req_sync; assign src_sendd_nxt = src_send; // ------------------------------------------------------------------------------------------------------------------- // xpm_cdc_single instantiation // ------------------------------------------------------------------------------------------------------------------- xpm_cdc_single # ( .DEST_SYNC_FF (SRC_SYNC_FF ), .INIT_SYNC_FF (INIT_SYNC_FF ), .SRC_INPUT_REG (0 ), .VERSION (VERSION ) ) xpm_cdc_single_dest2src_inst ( .src_clk (dest_clk ), .dest_clk (src_clk ), .src_in (dest_ack_sync_in), .dest_out (src_rcv ) ); generate if(DEST_EXT_HSK) begin : ext_desthsk assign dest_ack_sync_in = dest_ack; assign dest_req_ext_nxt = dest_req_sync ; end : ext_desthsk else begin : internal_desthsk assign dest_ack_sync_in = dest_req_ff; assign dest_req_ext_nxt = dest_req_sync & ~dest_req_ff; end : internal_desthsk endgenerate assign dest_req = dest_req_ext_ff; // Instantiate Xilinx Synchronous Register `XPM_XSRREG(src_clk, 1'b0, src_sendd_ff, src_sendd_nxt, 1'b0) `XPM_XSRREG(src_clk, 1'b0, src_hsdata_ff, src_hsdata_nxt, {WIDTH{1'b0}}) `XPM_XSRREGEN(dest_clk, 1'b0, dest_hsdata_ff, dest_hsdata_nxt, dest_hsdata_en ,{WIDTH{1'b0}}) `XPM_XSRREG(dest_clk, 1'b0, dest_req_ff, dest_req_nxt, 1'b0) `XPM_XSRREG(dest_clk, 1'b0, dest_req_ext_ff, dest_req_ext_nxt, 1'b0) endmodule : xpm_cdc_handshake # 在数据位宽小于100时控制最大延时、偏斜为多周期路径 if {$xpm_cdc_hs_width <= 100} { set_max_delay -from [get_cells src_hsdata_ff_reg*] -to [get_cells dest_hsdata_ff_reg*] [expr {$dest_clk_period * $xpm_cdc_hs_num_s2d_dsync_ff}] -datapath_only set_bus_skew -from [get_cells src_hsdata_ff_reg*] -to [get_cells dest_hsdata_ff_reg*] [expr {$dest_clk_period * $xpm_cdc_hs_num_s2d_dsync_ff}] } else { set_max_delay -from [get_cells src_hsdata_ff_reg*] -to [get_cells dest_hsdata_ff_reg*] [expr min ($src_clk_period, $dest_clk_period)] -datapath_only }
本原语用于脉冲信号的跨时钟域传输,使用该原语时需要注意:
- 复位期间不能传输脉冲信号,即src_rst或dest_rst有效期间src_pulse不能拉高
可调参数 | 功能 |
---|---|
DEST_SYNC_FF | 可设置为大于2的值,用于设置握手信号在目的时钟域的同步寄存器级数 |
REG_OUTPUT | 0或1,使用额外1级触发器同步目的时钟域输出脉冲 |
RST_USED | 0或1,1启用复位引脚 |
module xpm_cdc_pulse #( parameter integer DEST_SYNC_FF = 4, parameter integer INIT_SYNC_FF = 0, parameter integer REG_OUTPUT = 0, parameter integer RST_USED = 1, parameter integer SIM_ASSERT_CHK = 0, parameter integer VERSION = 0 ) ( input wire src_clk, input wire src_pulse, input wire dest_clk, input wire src_rst, input wire dest_rst, output wire dest_pulse ); // If toggle flop is not initialized,then it can be un-known forever. // It is assumed that there is no loss of coverage either way. // For edge detect, we would want the logic to be more controlled. reg src_level_ff = 1'b0; reg src_in_ff; wire src_level_nxt; wire src_edge_det; wire src_sync_in; wire dest_sync_out; wire dest_event_nxt; reg dest_event_ff; wire dest_sync_qual; wire src_rst_qual; wire dest_rst_qual; wire dest_pulse_int; reg dest_pulse_ff; //Assignments assign src_edge_det = src_pulse & ~src_in_ff; // 上升沿 assign src_level_nxt = src_level_ff ^ src_edge_det; // 有上升沿且src_level_ff为低电平 或 无上升沿且src_level_ff为高电平,将脉冲信号转换为电平信号 assign src_sync_in = src_level_ff; // 同步电平信号源时钟域 assign dest_event_nxt = dest_sync_qual; assign dest_pulse_int = dest_sync_qual ^ dest_event_ff; // 电平信号转脉冲信号 assign dest_sync_qual = dest_sync_out & ~dest_rst_qual; generate if(RST_USED) begin : use_rst assign src_rst_qual = src_rst; assign dest_rst_qual = dest_rst; end : use_rst else begin : no_rst assign src_rst_qual = 1'b0; assign dest_rst_qual = 1'b0; end : no_rst endgenerate generate if(REG_OUTPUT) begin : reg_out assign dest_pulse = dest_pulse_ff; end : reg_out else begin : comb_out assign dest_pulse = dest_pulse_int; end : comb_out endgenerate xpm_cdc_single # ( .DEST_SYNC_FF (DEST_SYNC_FF ), .INIT_SYNC_FF (INIT_SYNC_FF ), .SRC_INPUT_REG (0 ), .VERSION (VERSION ) ) xpm_cdc_single_inst ( .src_clk (src_clk ), .dest_clk (dest_clk ), .src_in (src_sync_in ), .dest_out (dest_sync_out ) ); // Instantiate Xilinx Synchronous Register `XPM_XSRREG(src_clk, src_rst_qual, src_in_ff, src_pulse, 1'b0) `XPM_XSRREG(src_clk, src_rst_qual, src_level_ff, src_level_nxt, 1'b0) `XPM_XSRREG(dest_clk, dest_rst_qual, dest_event_ff, dest_event_nxt, 1'b0) `XPM_XSRREG(dest_clk, dest_rst_qual, dest_pulse_ff, dest_pulse_int, 1'b0) endmodule : xpm_cdc_pulse
该原语对多位宽数据进行同步,用于实现多个xpm_cdc_single的功能。该原语需要注意:
- 输入数据宽度需要保证能在目的时钟域有效沿采样至少两次
可调参数 | 功能 |
---|---|
DEST_SYNC_FF | 可设置为大于2的值,用于设置握手信号在目的时钟域的同步寄存器级数 |
SRC_INPUT_REG | 0或1,使用额外1级触发器采样源时钟域的输入数据 |
WIDTH | 待同步数据位宽 |
module xpm_cdc_array_single # ( parameter integer DEST_SYNC_FF = 4, parameter integer INIT_SYNC_FF = 0, parameter integer SIM_ASSERT_CHK = 0, parameter integer SRC_INPUT_REG = 1, parameter integer VERSION = 0, parameter integer WIDTH = 2 ) ( input wire src_clk, input wire [WIDTH-1:0] src_in, input wire dest_clk, output wire [WIDTH-1:0] dest_out ); (* XPM_CDC = "ARRAY_SINGLE", ASYNC_REG = "TRUE" *) reg [WIDTH-1:0] syncstages_ff [DEST_SYNC_FF-1:0]; // ------------------------------------------------------------------------------------------------------------------- // Simulation only variable and signal assignment // ------------------------------------------------------------------------------------------------------------------- reg [WIDTH-1:0] src_ff; wire [WIDTH-1:0] src_inqual; wire [WIDTH-1:0] async_path_bit; assign dest_out = syncstages_ff[DEST_SYNC_FF-1]; always @(posedge dest_clk) begin syncstages_ff[0] <= async_path_bit; for (int syncstage = 1; syncstage < DEST_SYNC_FF ;syncstage = syncstage + 1) syncstages_ff[syncstage] <= syncstages_ff [syncstage-1]; end assign async_path_bit = src_inqual; // Virtual mux: Register at input optional. generate if (SRC_INPUT_REG) begin : extra_inreg assign src_inqual = src_ff; end : extra_inreg else begin : no_extra_inreg assign src_inqual = src_in; end : no_extra_inreg endgenerate genvar vara_i; generate // Instantiate Xilinx Synchronous Register `XPM_XSRREG(src_clk, 1'b0, src_ff, src_in, {WIDTH{1'b0}}) endgenerate endmodule : xpm_cdc_array_single # 单比特伪路径 set_false_path -to [get_cells syncstages_ff_reg[0][*]]
该原语用于同步复位信号的跨时钟域同步,类似xpm_cdc_single的功能。该原语需要注意:
- 输入复位信号宽度需要保证能在目的时钟域有效沿采样至少两次
可调参数 | 功能 |
---|---|
DEST_SYNC_FF | 可设置为大于2的值,用于设置握手信号在目的时钟域的同步寄存器级数 |
INIT | 用于设置同步寄存器默认值 |
module xpm_cdc_sync_rst # ( parameter integer DEST_SYNC_FF = 4, parameter integer INIT = 1, parameter integer INIT_SYNC_FF = 0, parameter integer SIM_ASSERT_CHK = 0, parameter integer VERSION = 0 ) ( input wire src_rst, input wire dest_clk, output wire dest_rst ); // Define local parameter for settings localparam DEF_VAL = (INIT == 1) ? 1'b1 : 1'b0; // Set asynchronous register property on synchronizers and initialize register with INIT value (* XPM_CDC = "SYNC_RST", ASYNC_REG = "TRUE" *) reg [DEST_SYNC_FF-1:0] syncstages_ff = {DEST_SYNC_FF{DEF_VAL}}; // ------------------------------------------------------------------------------------------------------------------- // Simulation only variable and signal assignment // ------------------------------------------------------------------------------------------------------------------- wire async_path_bit; assign dest_rst = syncstages_ff[DEST_SYNC_FF-1]; assign async_path_bit = src_rst; // Instantiate Xilinx Synchronous Register `XPM_XSRREG(dest_clk, 1'b0, syncstages_ff, { syncstages_ff[DEST_SYNC_FF-2:0], async_path_bit}, {DEST_SYNC_FF{1'b0}}) endmodule : xpm_cdc_sync_rst # 单比特伪路径 set_false_path -to [get_cells syncstages_ff_reg[0]]
该原语用于异步复位信号的跨时钟域同步,类似xpm_cdc_sync_rst的功能。
可调参数 | 功能 |
---|---|
DEST_SYNC_FF | 可设置为大于2的值,用于设置握手信号在目的时钟域的同步寄存器级数 |
RST_ACTIVE_HIGH | 0或1,分别代表低电平有效异步复位、高电平有效异步复位 |
module xpm_cdc_async_rst # ( parameter integer DEST_SYNC_FF = 4, parameter integer INIT_SYNC_FF = 0, parameter integer RST_ACTIVE_HIGH = 0, parameter integer VERSION = 0 ) ( input wire src_arst, input wire dest_clk, output wire dest_arst ); // ------------------------------------------------------------------------------------------------------------------- // Local parameter definitions // ------------------------------------------------------------------------------------------------------------------- // Define local parameter for settings localparam DEF_VAL = (RST_ACTIVE_HIGH == 1) ? 1'b0 : 1'b1; localparam INV_DEF_VAL = (RST_ACTIVE_HIGH == 0) ? 1'b0 : 1'b1; // Set asynchronous register property on synchronizers and initialize register with default value (* XPM_CDC = "ASYNC_RST", ASYNC_REG = "TRUE" *) reg [DEST_SYNC_FF-1:0] arststages_ff = {DEST_SYNC_FF{DEF_VAL}}; // ------------------------------------------------------------------------------------------------------------------- // Simulation only variable and signal assignment // ------------------------------------------------------------------------------------------------------------------- wire async_path_bit; wire reset_pol; wire reset_polo; assign reset_polo = arststages_ff[DEST_SYNC_FF-1]; assign async_path_bit = (RST_ACTIVE_HIGH == 1) ? 1'b0 : 1'b1; assign reset_pol = src_arst ^ ~RST_ACTIVE_HIGH; assign dest_arst = reset_polo; // Instantiate Xilinx Asynchronous Clear Register `XPM_XARREG(dest_clk, reset_pol, arststages_ff, { arststages_ff[DEST_SYNC_FF-2:0], async_path_bit}, {DEST_SYNC_FF{INV_DEF_VAL}}) endmodule : xpm_cdc_async_rst # 单比特伪路径 set_false_path -through [get_ports -no_traverse src_arst]
该原语功能类似与xpm_cdc_handshake,不同之处在于实现了一个深度为1的FIFO,并采用AXIS valid-ready握手的方式实现跨时钟域低延时传输。
可调参数 | 功能 |
---|---|
DEST_EXT_HSK | 可设置为0和1,当为1时启用dest_ack信号由用户逻辑在需要确认时确认握手,为0时由系统自行通过dest_req确认握手 |
DEST_SYNC_FF | 可设置为大于2的值,用于设置握手信号在目的时钟域的同步寄存器级数 |
SRC_SYNC_FF | 可设置为大于2的值,用于设置握手信号在源时钟域的同步寄存器级数 |
WIDTH | 待同步数据位宽 |
module xpm_cdc_low_latency_handshake #( // Module parameters parameter integer DEST_EXT_HSK = 1, parameter integer DEST_SYNC_FF = 4, parameter integer INIT_SYNC_FF = 0, parameter integer SIM_ASSERT_CHK = 0, parameter integer SRC_SYNC_FF = 4, parameter integer VERSION = 0, parameter integer WIDTH = 1 ) ( // Module ports input wire src_clk, input wire [WIDTH-1:0] src_in, input wire src_valid, output wire src_ready, input wire dest_clk, output wire [WIDTH-1:0] dest_out, output wire dest_valid, input wire dest_ready ); // ------------------------------------------------------------------------------------------------------------------- // Local parameter definitions // ------------------------------------------------------------------------------------------------------------------- // Set Asynchronous Register property on synchronizers (* XPM_CDC = "LOW_LATENCY_HANDSHAKE" *) reg [WIDTH-1:0] dest_hsdata_ff; // ------------------------------------------------------------------------------------------------------------------- // Simulation only variable and signal assignment // ------------------------------------------------------------------------------------------------------------------- reg [WIDTH-1:0] src_hsdata_ff; wire src_valid_nxt; wire src_count_nxt; reg src_count_ff = 1'b0; wire src_count_sync_ff; (* DIRECT_ENABLE = "yes" *) wire dest_hsdata_ff_en; reg dest_valid_ext_ff; wire dest_valid_nxt; wire dest_ready_in; wire dest_ready_nxt; wire dest_count_nxt; wire dest_count_eq; reg dest_count_ff = 1'b0; wire dest_count_sync_ff; wire src_count_eq; wire src_ready_nxt; reg src_ready_ext_ff; assign src_valid_nxt = src_valid && src_ready; assign src_count_nxt = (src_valid_nxt == 1'b1) ? (src_count_ff+1'b1) : src_count_ff; assign dest_ready_nxt = dest_valid_ext_ff && dest_ready_in ; assign dest_count_nxt = (dest_ready_nxt == 1'b1) ? (dest_count_ff+1'b1) : dest_count_ff; assign dest_count_eq = (src_count_sync_ff == dest_count_ff) ? 1'b1 : 1'b0; assign dest_hsdata_ff_en = !dest_count_eq && !dest_valid_ext_ff; assign dest_valid_nxt = !dest_count_eq && !dest_ready_nxt; assign dest_valid = dest_valid_ext_ff; assign src_count_eq = (src_count_ff == dest_count_sync_ff) ? 1'b1 : 1'b0; assign src_ready_nxt = src_count_eq && !src_valid_nxt; assign src_ready = src_ready_ext_ff; assign dest_out = dest_hsdata_ff; generate if(DEST_EXT_HSK) begin : ext_desthsk assign dest_ready_in = dest_ready; end : ext_desthsk else begin : internal_desthsk assign dest_ready_in = 1'b1; end : internal_desthsk endgenerate //Instantiate Xilinx Synchronous Register `XPM_XSRREGEN(src_clk, 1'b0, src_hsdata_ff, src_in, src_valid_nxt ,{WIDTH{1'b0}}) `XPM_XSRREGEN(dest_clk, 1'b0, dest_hsdata_ff, src_hsdata_ff, dest_hsdata_ff_en,{WIDTH{1'b0}}) `XPM_XSRREG(src_clk, 1'b0, src_count_ff, src_count_nxt, 1'b0) `XPM_XSRREG(dest_clk, 1'b0, dest_count_ff, dest_count_nxt, 1'b0) `XPM_XSRREG(dest_clk, 1'b0, dest_valid_ext_ff, dest_valid_nxt, 1'b0) `XPM_XSRREG(src_clk, 1'b0, src_ready_ext_ff, src_ready_nxt, 1'b0) // ------------------------------------------------------------------------------------------------------------------- // xpm_cdc_single instantiation // ------------------------------------------------------------------------------------------------------------------- xpm_cdc_single # ( .DEST_SYNC_FF (DEST_SYNC_FF ), .INIT_SYNC_FF (INIT_SYNC_FF ), .SRC_INPUT_REG (0 ), .SIM_ASSERT_CHK (SIM_ASSERT_CHK), .VERSION (VERSION ) ) xpm_cdc_single_src2dest_inst ( .src_clk (src_clk ), .dest_clk (dest_clk ), .src_in (src_count_ff ), .dest_out (src_count_sync_ff ) ); // ------------------------------------------------------------------------------------------------------------------- // xpm_cdc_single instantiation // ------------------------------------------------------------------------------------------------------------------- xpm_cdc_single # ( .DEST_SYNC_FF (SRC_SYNC_FF ), .INIT_SYNC_FF (INIT_SYNC_FF ), .SRC_INPUT_REG (0 ), .SIM_ASSERT_CHK (SIM_ASSERT_CHK), .VERSION (VERSION ) ) xpm_cdc_single_dest2src_inst ( .src_clk (dest_clk ), .dest_clk (src_clk ), .src_in (dest_count_ff ), .dest_out (dest_count_sync_ff ) ); endmodule : xpm_cdc_low_latency_handshake # 在数据位宽小于100时控制最大延时、偏斜为多周期路径 if {$xpm_cdc_hs_width <= 100} { set_max_delay -from [get_cells src_hsdata_ff_reg*] -to [get_cells dest_hsdata_ff_reg*] [expr {$dest_clk_period * $xpm_cdc_hs_num_s2d_dsync_ff}] -datapath_only set_bus_skew -from [get_cells src_hsdata_ff_reg*] -to [get_cells dest_hsdata_ff_reg*] [expr {$dest_clk_period * $xpm_cdc_hs_num_s2d_dsync_ff}] } else { set_max_delay -from [get_cells src_hsdata_ff_reg*] -to [get_cells dest_hsdata_ff_reg*] [expr min ($src_clk_period, $dest_clk_period)] -datapath_only }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。