引言
多时钟域的设计中,CDC处理的场景还是蛮多的。单比特信号在CDC时,为保证信号采样的安全性,降低亚稳态,必须要对信号做同步处理。CDC从时钟的快慢关系来说分为两种case:快到慢、慢到快。对于脉冲型的控制信号,在以上两种case中都需要满足如下条件才能保证控制信号CDC的安全性:
源端控制信号的脉冲宽度>1.5倍目的端时钟周期 (即 "三时钟沿" 要求)。
一般建议以上条件中1.5增大为2。
在设计同步器时需要注意,源端控制信号必须为寄存器输出。否则组合逻辑的毛刺可能会影响目的端的采样。
CBB设计源码
这个功能相对来说比较简单,就不扯框图和原理了,直接上代码。
cpp
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// ________ ________ ________
// |\ ____\ |\ __ \ |\ __ \
// \ \ \___| \ \ \|\ /_ \ \ \|\ /_
// \ \ \ \ \ __ \ \ \ __ \
// \ \ \____ \ \ \|\ \ \ \ \|\ \
// \ \_______\ \ \_______\ \ \_______\
// \|_______| \|_______| \|_______|
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// CBB Module Name :CBB_PULSE_SYNCHRONIZER
// CBB Created Date :2024-08-02
// CBB Module Function:单比特脉冲信号跨时钟域处理
// Usage Limitation :
// Author :在路上-正出发
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
`timescale 1ns/1ps
module CBB_PULSE_SYNCHRONIZER #(
// ---- parameter define
parameter P_EXTEN_EN = "ENABLE", //"ENABLE" or "DISABLE"
parameter P_EXTEN_MULT = 3, //2 or larger
parameter P_SYNC_STAGE = 2, //2 or larger
parameter P_PULSE_WIDTH = "CARE-1" //"CARE-1" or "NOTCARE"
)(
// ---- port define
input i_clk_src,
input i_rstn_src,
input i_pulse_src,//must be register output(source clk)
input i_clk_dst,
input i_rstn_dst,
output o_pulse_dst
);
reg [P_EXTEN_MULT-2:0] r_pluse_src_dly;
reg r_pulse_exten;
reg [P_SYNC_STAGE-1:0] r_pulse_sync;
generate
if(P_EXTEN_EN == "ENABLE")
begin
if(P_EXTEN_MULT <= 2)
begin
always @(posedge i_clk_src or negedge i_rstn_src) begin : proc_pulse_exten1
if(~i_rstn_src) begin
r_pluse_src_dly <= {(P_EXTEN_MULT-1){1'b0}};
end else begin
r_pluse_src_dly <= {i_pulse_src};
end
end
always @(posedge i_clk_src or negedge i_rstn_src) begin : proc_pulse_exten2
if(~i_rstn_src) begin
r_pulse_exten <= 1'b0;
end else begin
r_pulse_exten <= |{r_pluse_src_dly,i_pulse_src};
end
end
always @(posedge i_clk_dst or negedge i_rstn_dst) begin : proc_pulse_sync
if(~i_rstn_dst) begin
r_pulse_sync <= {(P_SYNC_STAGE){1'b0}};
end else begin
r_pulse_sync <= {r_pulse_sync[P_SYNC_STAGE-2:0],r_pulse_exten};
end
end
end
else
begin
always @(posedge i_clk_src or negedge i_rstn_src) begin : proc_pulse_exten
if(~i_rstn_src) begin
r_pluse_src_dly <= {(P_EXTEN_MULT-1){1'b0}};
end else begin
r_pluse_src_dly <= {r_pluse_src_dly[P_EXTEN_MULT-3:0],i_pulse_src};
end
end
always @(posedge i_clk_src or negedge i_rstn_src) begin : proc_pulse_exten2
if(~i_rstn_src) begin
r_pulse_exten <= 1'b0;
end else begin
r_pulse_exten <= |{r_pluse_src_dly,i_pulse_src};
end
end
always @(posedge i_clk_dst or negedge i_rstn_dst) begin : proc_pulse_sync
if(~i_rstn_dst) begin
r_pulse_sync <= {(P_SYNC_STAGE){1'b0}};
end else begin
r_pulse_sync <= {r_pulse_sync[P_SYNC_STAGE-2:0],r_pulse_exten};
end
end
end
end
else
begin
always @(posedge i_clk_dst or negedge i_rstn_dst) begin : proc_pulse_sync
if(~i_rstn_dst) begin
r_pulse_sync <= {(P_SYNC_STAGE){1'b0}};
end else begin
r_pulse_sync <= {r_pulse_sync[P_SYNC_STAGE-2:0],i_pulse_src};
end
end
end
endgenerate
generate
if(P_PULSE_WIDTH == "CARE-1")
begin
assign o_pulse_dst = r_pulse_sync[P_SYNC_STAGE-2] & (~r_pulse_sync[P_SYNC_STAGE-1]);
end
else
begin
assign o_pulse_dst = r_pulse_sync[P_SYNC_STAGE-1];
end
endgenerate
endmodule
CBB使用说明
P_EXTEN_EN:需要进行脉冲展宽时,将使能开关打开;
P_EXTEN_MULT:表示脉冲在源时钟域被展宽的倍数,这个倍数需要使用者根据上述1.5或2倍关系折算。
P_SYNC_STAGE:表示目的时钟域打拍的级数。
P_PULSE_WIDTH:"CARE-1"表示,目的侧时钟域输出的脉冲宽度为1个时钟周期;"NOTCARE"则表示目的侧打拍直接输出,不取边沿。
【注意】输入信号i_pulse_src必须为寄存器输出。
CBB验证
CASE1:快--->慢(使能脉冲展宽,3倍)
CASE2:慢--->快(不使能脉冲展宽)
验证代码
cpp
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// ________ ________ ________
// |\ ____\ |\ __ \ |\ __ \
// \ \ \___| \ \ \|\ /_ \ \ \|\ /_
// \ \ \ \ \ __ \ \ \ __ \
// \ \ \____ \ \ \|\ \ \ \ \|\ \
// \ \_______\ \ \_______\ \ \_______\
// \|_______| \|_______| \|_______|
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// CBB Module Name :TB_PULSE_SYNCHRONIZER
// CBB Created Date :2024-08-03
// CBB Module Function:
// Usage Limitation :
// Author :在路上-正出发
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
`timescale 1ns/1ps
// `define TC_FAST_2_LOW
`define TC_LOW_2_FAST
module TB_PULSE_SYNCHRONIZER ();
// ---- parameter define
parameter P_EXTEN_EN = "DISABLE"; //"ENABLE" or "DISABLE"
parameter P_EXTEN_MULT = 3; //2 or larger
parameter P_SYNC_STAGE = 2; //2 or larger
parameter P_PULSE_WIDTH = "CARE-1"; //"CARE-1" or "NOTCARE"
// ---- port define
reg i_clk_src;
reg i_rstn_src;
reg i_pulse_src;//must be register output(source clk)
reg i_clk_dst;
reg i_rstn_dst;
wire o_pulse_dst;
// 产生时钟
`ifdef TC_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 TC_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_pulse_src = 1'b0;
#100;
i_rstn_dst = 1'b1;
i_rstn_src = 1'b1;
#50;
@(posedge i_clk_src)
i_pulse_src <= 1'b1;
@(posedge i_clk_src)
i_pulse_src <= 1'b0;
@(negedge o_pulse_dst);
#200;
$finish;
end
CBB_PULSE_SYNCHRONIZER #(
.P_EXTEN_EN(P_EXTEN_EN),
.P_EXTEN_MULT(P_EXTEN_MULT),
.P_SYNC_STAGE(P_SYNC_STAGE),
.P_PULSE_WIDTH(P_PULSE_WIDTH)
) U_CBB_PULSE_SYNCHRONIZER (
.i_clk_src (i_clk_src),
.i_rstn_src (i_rstn_src),
.i_pulse_src (i_pulse_src),
.i_clk_dst (i_clk_dst),
.i_rstn_dst (i_rstn_dst),
.o_pulse_dst (o_pulse_dst)
);
endmodule
CBB电路综合
使能脉冲展宽
源时钟域下,控制信号经多拍延迟,源信号与延迟信号经过或门输出,输出的信号在源时钟域寄存输出,目的测时钟域对展宽的信号做打拍处理,取上升沿输出。