【Verilog-CBB】开发与验证(3)——多比特数据CDC DMUX



引言

多比特数据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综合

使能脉冲展宽

 综合结果与预期一致。

不使能脉冲展宽 

  综合结果与预期一致。

  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在路上-正出发

哈哈,多少是个心意

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值