引言
多比特数据CDC没有单比特那么简单,并不是单纯打拍就可以,因为存在多条数据路径,路径之间的延迟不一致就导致数据同步出错。对于很高数据速率的多比特数据CDC选择异步FIFO/RAM,对于数据速率很低的多比特数据直接选择DMUX会更简单一些。
DMUX解决多比特数据CDC其实是依赖于数据的有效信号。因此数据的有效信号和数据信号在被目的时钟域安全采样之前必须维持稳定。在实际的设计中可能出现这种时序,即数据的有效信号仅维持一个时钟周期的时间(下图case1)而数据信号在下一个数据到来之前维持稳定。这就涉及到对脉冲的展宽问题(快到慢时钟域)。上一篇设计的单比特信号CDC可以直接用来处理有效信号仅维持一个时钟周期的情况【Verilog-CBB】开发与验证(2)——单比特信号CDC同步器-CSDN博客。
数据有效信号和数据的时序关系case1:
对于case1需要做特殊的CDC处理,特别是快到慢,需要做脉冲展宽。
数据有效信号和数据的时序关系case2:
对于case2,有效信号持续时间若大于目的侧时钟周期的1.5倍,则可以放心直接打两拍CDC
设计框图
其中 CBB_PULSE_SYNCHRONIZER 模块 为上一篇设计的单比特信号CDC处理模块。MUX在不选通时进行数据保持,降低了多比特数据的toggle rate,降低了动态功耗。
CBB设计源码
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// ________ ________ ________
// |\ ____\ |\ __ \ |\ __ \
// \ \ \___| \ \ \|\ /_ \ \ \|\ /_
// \ \ \ \ \ __ \ \ \ __ \
// \ \ \____ \ \ \|\ \ \ \ \|\ \
// \ \_______\ \ \_______\ \ \_______\
// \|_______| \|_______| \|_______|
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// CBB Module Name :CBB_DMUX
// CBB Created Date :2024-08-04
// CBB Module Function:多比特数据CDC的DMUX方案
// Usage Limitation :
// Author :在路上-正出发
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
`timescale 1ns/1ps
module CBB_DMUX #(
// ---- parameter define
parameter P_TIMING_MODE = "DATA_VALID-ALIGN",//"DATA_VALID-1" or "DATA_VALID-ALIGN"
parameter P_SYNC_STAGE = 2,
parameter P_DATA_WIDTH = 16
)(
// ---- port define
input i_clk_src,
input i_rstn_src,
input i_valid_src,//must be register output(source clk)
input [P_DATA_WIDTH-1:0] i_data_src, //must be register output(source clk)
input i_clk_dst,
input i_rstn_dst,
output o_valid_dst,
output [P_DATA_WIDTH-1:0] o_data_dst
);
// ---- parameter define
localparam LP_EXTEN_EN = (P_TIMING_MODE == "DATA_VALID-1") ? "ENABLE" : "DISABLE";
localparam LP_EXTEN_MULT = 3;
localparam LP_SYNC_STAGE = P_SYNC_STAGE;
localparam LP_PULSE_WIDTH = "CARE-1";
wire w_valid_dst;
reg r_valid_dst;
reg [P_DATA_WIDTH-1:0] r_data_dst;
always @(posedge i_clk_dst or negedge i_rstn_dst) begin : proc_valid_sync
if(~i_rstn_dst) begin
r_valid_dst <= 1'b0;
end else begin
r_valid_dst <= w_valid_dst;
end
end
always @(posedge i_clk_dst or negedge i_rstn_dst) begin : proc_data_sync
if(~i_rstn_dst) begin
r_data_dst <= {(P_DATA_WIDTH){1'b0}};
end else if(w_valid_dst)begin
r_data_dst <= i_data_src;
end
end
assign o_valid_dst = r_valid_dst;
assign o_data_dst = r_data_dst;
CBB_PULSE_SYNCHRONIZER #(
.P_EXTEN_EN (LP_EXTEN_EN),
.P_EXTEN_MULT (LP_EXTEN_MULT),
.P_SYNC_STAGE (LP_SYNC_STAGE),
.P_PULSE_WIDTH(LP_PULSE_WIDTH)
) U_CBB_PULSE_SYNCHRONIZER (
.i_clk_src (i_clk_src),
.i_rstn_src (i_rstn_src),
.i_pulse_src (i_valid_src),
.i_clk_dst (i_clk_dst),
.i_rstn_dst (i_rstn_dst),
.o_pulse_dst (w_valid_dst)
);
endmodule
使用说明
参数:P_TIMING_MODE表示,源端输入的数据有效信号持续时间类型,DATA_VALID-1表示与case1时序关系一致;DATA_VALID-ALIGN表示与case2时序关系一致。
建议,使用者应判断输入的数据有效信号能否被目的时钟域安全采样,若可以则配置该参数为DATA_VALID-ALIGN;否则请配置为DATA_VALID-1。
模块的本地参数LP_PULSE_WIDTH表示,目的侧时钟域输出的有效信号宽度,“CARE-1”表示有效信号宽度为1个时钟周期(取上升沿),“NOTCARE”表示数据有效信号宽度不取边沿,直接将CDC打拍结果输出。(详见上一篇CBB设计说明)
CBB验证
CASE1:快到慢,源端输入数据有效信号宽度为1
CASE2:快到慢, 源端输入数据有效信号宽度可以被目的侧安全采样
CASE2:慢到快
验证代码参考
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// ________ ________ ________
// |\ ____\ |\ __ \ |\ __ \
// \ \ \___| \ \ \|\ /_ \ \ \|\ /_
// \ \ \ \ \ __ \ \ \ __ \
// \ \ \____ \ \ \|\ \ \ \ \|\ \
// \ \_______\ \ \_______\ \ \_______\
// \|_______| \|_______| \|_______|
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// CBB Module Name :TB_DMUX
// CBB Created Date :2024-08-04
// CBB Module Function:
// Usage Limitation :
// Author :在路上-正出发
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
`timescale 1ns/1ps
// `define CLK_CASE_FAST_2_LOW
`define CLK_CASE_LOW_2_FAST
module TB_DMUX();
parameter P_TIMING_MODE = "DATA_VALID-ALIGN";//"DATA_VALID-1" or "DATA_VALID-ALIGN"
parameter P_SYNC_STAGE = 2;
parameter P_DATA_WIDTH = 16;
// ---- port define
reg i_clk_src;
reg i_rstn_src;
reg i_valid_src;//must be register output(source clk)
reg [P_DATA_WIDTH-1:0] i_data_src; //must be register output(source clk)
reg i_clk_dst;
reg i_rstn_dst;
wire o_valid_dst;
wire [P_DATA_WIDTH-1:0] o_data_dst;
// 产生时钟
`ifdef CLK_CASE_FAST_2_LOW
initial i_clk_src = 1'b0;
always #5 i_clk_src = ~i_clk_src;
initial i_clk_dst = 1'b0;
always #10 i_clk_dst = ~i_clk_dst;
`endif
`ifdef CLK_CASE_LOW_2_FAST
initial i_clk_src = 1'b0;
always #10 i_clk_src = ~i_clk_src;
initial i_clk_dst = 1'b0;
always #5 i_clk_dst = ~i_clk_dst;
`endif
//
initial
begin
i_rstn_src = 1'b0;
i_rstn_dst = 1'b0;
i_valid_src = 1'b0;
i_data_src = {P_DATA_WIDTH{1'b0}};
#100;
i_rstn_dst = 1'b1;
i_rstn_src = 1'b1;
#50;
repeat(10)
begin
begin
if(P_TIMING_MODE == "DATA_VALID-1")
begin
@(posedge i_clk_src)
i_valid_src <= 1'b1;
i_data_src <= $random() % 2**16;
@(posedge i_clk_src)
i_valid_src <= 1'b0;
@(negedge o_valid_dst);
end
else
begin
@(posedge i_clk_src)
i_valid_src <= 1'b1;
i_data_src <= $random() % 2**16;
repeat(20) @(posedge i_clk_dst);
@(posedge i_clk_src)
i_valid_src <= 1'b0;
end
end
#500;
end
$finish;
end
CBB_DMUX #(
.P_TIMING_MODE(P_TIMING_MODE),
.P_SYNC_STAGE(P_SYNC_STAGE),
.P_DATA_WIDTH(P_DATA_WIDTH)
) U_CBB_DMUX (
.i_clk_src (i_clk_src),
.i_rstn_src (i_rstn_src),
.i_valid_src (i_valid_src),
.i_data_src (i_data_src),
.i_clk_dst (i_clk_dst),
.i_rstn_dst (i_rstn_dst),
.o_valid_dst (o_valid_dst),
.o_data_dst (o_data_dst)
);
endmodule
CBB综合
使能脉冲展宽
综合结果与预期一致。
不使能脉冲展宽
综合结果与预期一致。