IC基础知识:时钟无毛刺切换

参考这篇文章:数字电路时钟无毛刺切换
因为直接用组合逻辑判断去切换时钟,会产生毛刺,如下图所示。
在这里插入图片描述
在这里插入图片描述

产生该毛刺的原因: sel没有在时钟跳边沿改变。因为我们一般是用clk上升沿采样数据,所以我们sel选择信号最好是在clk下降沿改变,可以让切换的时候,不会错过上升沿。

我理解的整体思路: 将en信号先经过打3拍(异步时钟要打三拍),然后经过一个ICG(integrate clock Gating)
ICG框图
在这里插入图片描述
作用:让sel同步于时钟并且在下降沿改变。

设计代码



module clock_switch(
        input                   s_rst_n                 ,       
        input                   s_clk_1                 ,       
        input                   s_clk_2                 ,       
        input                   s_clk_3                 ,       
        input [1:0]             i_clk_sel               ,//00: clk1, 01: clk2, 10/11: clk3       
        output                  o_clk
);


//========================================================================\
// =========== Define Parameter and Internal signals =========== 
//========================================================================/
wire                            clk1_sel                        ;       
reg                             clk1_sel_syn1                   ;       
reg                             clk1_sel_syn2                   ;       
reg                             clk1_sel_syn3                   ;    

wire                            clk2_sel                        ;       
reg                             clk2_sel_syn1                   ;       
reg                             clk2_sel_syn2                   ;       
reg                             clk2_sel_syn3                   ;       

wire                            clk3_sel                        ;       
reg                             clk3_sel_syn1                   ;       
reg                             clk3_sel_syn2                   ;       
reg                             clk3_sel_syn3                   ;       

reg                             clk1_sel_real                   ;       
reg                             clk2_sel_real                   ;       
reg                             clk3_sel_real                   ;       

assign clk1_sel = (i_clk_sel == 2'b00)? 1'b1: 1'b0;
assign clk2_sel = (i_clk_sel == 2'b01)? 1'b1: 1'b0;
assign clk3_sel = (i_clk_sel == 2'b10 || i_clk_sel == 2'b11)? 1'b1: 1'b0;

always  @(posedge s_clk_1 or negedge s_rst_n) begin
        if(s_rst_n == 1'b0) begin
            clk1_sel_syn1       <= 'd0            ;       
            clk1_sel_syn2       <= 'd0            ;       
            clk1_sel_syn3       <= 'd0            ;    
        end
        else begin
            clk1_sel_syn1       <= clk1_sel  & (~clk2_sel_syn3) & (~clk3_sel_syn3)       ;       
            clk1_sel_syn2       <= clk1_sel_syn1    ;       
            clk1_sel_syn3       <= clk1_sel_syn2    ;   
        end
                
end


always  @(posedge s_clk_2 or negedge s_rst_n) begin
        if(s_rst_n == 1'b0) begin
            clk2_sel_syn1       <= 'd0            ;       
            clk2_sel_syn2       <= 'd0            ;       
            clk2_sel_syn3       <= 'd0            ;    
        end
        else begin
            clk2_sel_syn1       <= clk2_sel & (~clk1_sel_syn3) & (~clk3_sel_syn3)        ;       
            clk2_sel_syn2       <= clk2_sel_syn1    ;       
            clk2_sel_syn3       <= clk2_sel_syn2    ;   
        end
                
end

always  @(posedge s_clk_3 or negedge s_rst_n) begin
        if(s_rst_n == 1'b0) begin
            clk3_sel_syn1       <= 'd0            ;       
            clk3_sel_syn2       <= 'd0            ;       
            clk3_sel_syn3       <= 'd0            ;    
        end
        else begin
            clk3_sel_syn1       <= clk3_sel  & (~clk1_sel_syn3) & (~clk2_sel_syn3)       ;       
            clk3_sel_syn2       <= clk3_sel_syn1    ;       
            clk3_sel_syn3       <= clk3_sel_syn2    ;   
        end
end



always  @(negedge s_clk_1 or negedge s_rst_n) begin
    if(s_rst_n == 1'b0)
         clk1_sel_real <= 'd0;
    else
         clk1_sel_real <= clk1_sel_syn3;
//         clk1_sel_real <= clk1_sel_syn2;
end

always  @(negedge s_clk_2 or negedge s_rst_n) begin
    if(s_rst_n == 1'b0)
         clk2_sel_real <= 'd0;
    else
         clk2_sel_real <= clk2_sel_syn3;
         //clk2_sel_real <= clk2_sel_syn2;
end

always  @(negedge s_clk_3 or negedge s_rst_n) begin
    if(s_rst_n == 1'b0)
         clk3_sel_real <= 'd0;
    else
         clk3_sel_real <= clk3_sel_syn3;
         //clk3_sel_real <= clk3_sel_syn2;
end
//验证了,只打两拍确实有问题
assign o_clk = (clk1_sel_real & s_clk_1) | (clk2_sel_real & s_clk_2) | (clk3_sel_real & s_clk_3);

endmodule

testbench 代码

`timescale      1ns/1ns

module clock_switch_tb();

reg                             s_rst_n                         ;       
reg                             s_clk_1                         ;       
reg                             s_clk_2                         ;       
reg                             s_clk_3                         ;       
reg  [1:0]                      i_clk_sel                       ;       
wire                            o_clk                           ;       

clock_switch  clock_switch_inst(
        .s_rst_n                (s_rst_n                ),
        .s_clk_1                (s_clk_1                ),
        .s_clk_2                (s_clk_2                ),
        .s_clk_3                (s_clk_3                ),
        .i_clk_sel              (i_clk_sel              ),
        .o_clk                  (o_clk                  )
);

always #5 s_clk_1 = ~s_clk_1;
always #10 s_clk_2 = ~s_clk_2;
always #20 s_clk_3 = ~s_clk_3;

initial begin
        s_rst_n     = 0                    ;       
        s_clk_1     = 0                    ;       
        s_clk_2     = 0                    ;       
        s_clk_3     = 0                    ;       
        i_clk_sel   = 0                    ;   
        #20;
        s_rst_n = 1;
        #200;
        i_clk_sel = 1;
        #200;
        i_clk_sel = 2;
        #200;        
        i_clk_sel = 3;
        #200;
        $finish;
end
//generate fsdb file
initial begin
	$fsdbDumpfile("clock_switch_tb.fsdb");
  	$fsdbDumpvars(0,clock_switch_tb);
end
endmodule

仿真波形
在这里插入图片描述
一般无毛刺切换,切换始终的时候,都会需要几个clock的缓冲。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值