CDC设计实例

  • Mux sync
  • 门控单元:clock gating
  • 动态的时钟切换:glith free clock switch

mux sync

在这里插入图片描述
enable信号同步两拍,以保证信号的稳定。信号不打拍。enable信号到时,把信号同步过去。

ICG:Integrate Clock Gating Cell

  • 减少时钟功耗,clock和data的跳变的功耗叫做dynamic power,当数据不变时,需要将clock停住(gating),以减少功耗,可以用AND和OR gate,前者时0是enable,后者是1是enale
    在这里插入图片描述
    ICG在关断和打开的时候如果时机不对,会产生glitch(短时脉冲),为了避免这种情况,可在AND gate或OR gate前加上一级latch,保证enable信号只在时钟低电平或者高电平时才传到gate上去。
    在这里插入图片描述
    在这里插入图片描述
    Verilog Behavior Model
module cell_clock_gating(
	input 	TE,	//test enable which is used for test mode in DFT
	input 	E,	//enable
	input 	CP,	//clock
	output	Q	
);
	reg		E_lat;
	assign	E_or = E | TE;
	
	always @ (CP or E)	//latch
		if(!CP) begin
			E_lat <= E_or;
		end
	assign Q = E_lat & CP;
endmodule

Clock switch:glitch due to simple mux

在这里插入图片描述
时钟切换时会产生毛刺,合理的设计要使切换发生目标时钟的低电平处。

SoC系统中时钟切换应用场景

在这里插入图片描述
软件配置需要CPU去下达命令,所以当在切换CPU时钟的时候不适用软件配置切换
在这里插入图片描述

CPU动态切换时钟,并且不能出现glitch的方法

在这里插入图片描述

  1. 用打三拍的方式,使其他时钟提前关断,并且用ICG电路保证在时钟信号低电平时刻关断。
  2. 其他时钟关断后,载使用ICG使选中的时钟在低电平处释放。

毛刺消除

module glitch_free(
    output      clk_out,
    input [1:0] cgm_sel,
    input       clk_in0,
    input       clk_in1,
    input       clk_in2,
    input       rst_clk_n,
    input       icg_scan_mode,
    input       scan_dc_mode,
    input       clk_scan
);

reg in0_en_sync1, in0_en_sync2, in0_en_sync3; 
reg in1_en_sync1, in1_en_sync2, in1_en_sync3; 
reg in2_en_sync1, in2_en_sync2, in2_en_sync3; 

/*
 * 切换时钟模式选择
 */
assign clk_in0_scan = scan_dc_mode ? clk_scan : clk_in0;
assign clk_in1_scan = scan_dc_mode ? clk_scan : clk_in1;
assign clk_in2_scan = scan_dc_mode ? clk_scan : clk_in2;

/*
 * cgm_sel[1:0]选择时钟输入,in0_sel是选择信号
 */
assign in0_sel = (cgm_sel[1:0] == 2'b00);
assign in1_sel = (cgm_sel[1:0] == 2'b01);
assign in2_sel = (cgm_sel[1:0] == 2'b10 || (cgm_sel[1:0] == 2'b11));

/*********************************使能信号的转变**********************************/
// 三级同步器中每一级都是0,表示该时钟不被使用,有一个是1,表示正在切换至或正
// 正在使用
assign in0_used = in0_sel | in0_en_sync1 | in0_en_sync2 | in0_en_sync3;
assign in1_used = in1_sel | in1_en_sync1 | in1_en_sync2 | in1_en_sync3;
assign in2_used = in2_sel | in2_en_sync1 | in2_en_sync2 | in2_en_sync3;

// inx_en信号转变后,时钟信号至少在本时钟2.5个周期后完成停止或起振。
// 因此转变目标时钟要在inx_en转变的3个时钟周期后发生起振。
assign in0_en = ~in1_used & ~in2_used;
assign in1_en = ~in0_used & ~in2_used;
assign in2_en = ~in0_used & ~in1_used;
/*********************************************************************************/

/*
 *ICG使能信号,打三拍处理
 */
always @(posedge clk_in0_scan or negedge rst_clk_n) begin
    if(!rst_clk_n) begin
        in0_en_sync1 <= 1'b0;
        in0_en_sync2 <= 1'b0;
        in0_en_sync3 <= 1'b0;
    end
    else begin
        in0_en_sync1 <= in0_en;
        in0_en_sync2 <= in0_en_sync1;
        in0_en_sync3 <= in0_en_sync2;
    end
end

always @(posedge clk_in1_scan or negedge rst_clk_n) begin
    if(!rst_clk_n) begin
        in1_en_sync1 <= 1'b0;
        in1_en_sync2 <= 1'b0;
        in1_en_sync3 <= 1'b0;
    end
    else begin
        in1_en_sync1 <= in1_en;
        in1_en_sync2 <= in1_en_sync1;
        in1_en_sync3 <= in1_en_sync2;
    end
end


always @(posedge clk_in2_scan or negedge rst_clk_n) begin
    if(!rst_clk_n) begin
        in2_en_sync1 <= 1'b0;
        in2_en_sync2 <= 1'b0;
        in2_en_sync3 <= 1'b0;
    end
    else begin
        in2_en_sync1 <= in2_en;
        in2_en_sync2 <= in2_en_sync1;
        in2_en_sync3 <= in2_en_sync2;
    end
end

assign ind_in0 = in0_en_sync2;
assign ind_in1 = in1_en_sync2;
assign ind_in2 = in2_en_sync2;

/*
 * 打三拍处理后的使能信号接入ICG模块
 */
cell_clock_gating u_clk_gate_out0(
    .TE (icg_scan_mode),
    .E  (ind_in0),
    .CP (clk_in0),
    .Q  (clk_out0)
);
assign ind_in1_scan = -scan_dc_mode && ind_in1;

cell_clock_gating u_clk_gate_out1(
    .TE (1'b0),
    .E  (ind_in1_scan),
    .CP (clk_in1),
    .Q  (clk_out1)
);
assign ind_in2_scan = -scan_dc_mode && ind_in2;

cell_clock_gating u_clk_gate_out2(
    .TE (1'b0),
    .E  (ind_in2_scan),
    .CP (clk_in2),
    .Q  (clk_out2)
);
assign clk_out = clk_out0 | clk_out1 | clk_out2;

endmodule

testbench

module glitch_free_tb();

    reg clk_in0;        //输出clk1
    reg clk_in1;        //输出clk1
    reg clk_in2;        //输出clk2
    reg clk_scan;       
    reg scan_dc_mode;
    reg icg_scan_mode;  
    reg rst_clk_n = 0;
    reg [1:0] clk_in0;

    initial begin
        clk_in0   = 0;
        clk_in1   = 0;
        clk_in2   = 0;
        rst_clk_n = 0;
        clk_scan  = 0;
        icg_scan_mode = 0;

        scan_dc_mode = 1;

        #200
        rst_clk_n = 1;
        cgm_sel   = 0;
        repeat(50) @(posedge clk_in2);  //clk2输出50个周期后,切换clk
        cgm_sel = 1;
        repeat(50) @(posedge clk_in2);
        cgm_sel = 2;
        repeat(50) @(posedge clk_in2);
        icg_scan_mode = 1;
        scan_dc_mode = 0;
        sgm_sel = 0;
        repeat(1000) @(posedge clk_in0);
        
        icg_scan_mode = 0;
        scan_dc_mode = 1;
        cgm_sel = 2;
        repeat(1000) @(posedge clk_in0);
        $finish;
    end

    initial begin
        $fsdbDumpfile("glitch_free_tb.fsdb");//将名为glitch_free_tb.fsdb的fsdb波形文件dump下来
        $fsdbDumpvars;
    end

    always #20   clk_in0 = ~clk_in0;    //clk0周期为40个时间单位
    always #70   clk_in1 = ~clk_in1;    //clk1周期为140个时间单位
    always #110  clk_in2 = ~clk_in2;    //clk2周期为220个时间单位
    always #1000 clk_scan = ~clk_scan;  //clk_scan周期为2000个时间单位

    glitch_free u_glitch_free(
        .clk_out    (clk_out),
        .cgm_sel	(cgm_sel),
        .clk_in0	(clk_in0),
        .clk_in1	(clk_in1),
        .clk_in2	(clk_in2),
        .rst_clk_n	(rst_clk_n),
        .icg_scan_mode	(icg_scan_mode),
        .scan_dc_mode	(scan_dc_mode),
        .clk_scan	(clk_scan)
    );

endmodule

仿真

在这里插入图片描述
dve对应的波形文件叫vpd文件
verdi对应的波形文件叫fsdb文件

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值