SOC设计——时钟切换的MUX设计 glitch free技术(一种防止毛刺产生的多路选择器设计)

SOC设计——时钟切换的MUX设计 glitch free技术(一种防止毛刺产生的多路选择器设计)

0. 为何需要时钟Glitch Free技术

在SOC的设计中,经常需要用到大量的时钟源的选择与切换,以及时钟的分频,其中对于时钟的切换就显得尤为重要,并且如何在切换时钟源的过程中消除毛刺(glitch)。对于时钟的分频技术后续会介绍。
我们首先看一下如果不适用glitch free技术,来看时钟源的切换对电路的影响。

glitch毛刺的产生的危害

对于一个时钟切换电路,输入两个异步时钟clk0、clk1,以及一个选择信号sel。我们直接使用2MUX就可以实现两个时钟源的切换,RTL代码也很简单:

assign clk_out = sel? clk1 :clk0;

其RTL结构如下:
SOC设计——时钟切换的MUX设计 glitch free技术(一种防止毛刺产生的多路选择器设计)_第1张图片

下面分析这个设计的问题:
因为我们的clk0,clk1是异步的关系,所以就存在 时钟切换会发生在任意时刻,也就会存在glitch的产生。当寄存器捕获到时钟沿其他没捕获到,极有可能造成系统的不稳定。下如下图所示:
SOC设计——时钟切换的MUX设计 glitch free技术(一种防止毛刺产生的多路选择器设计)_第2张图片
仿真的结果也可以看到有glitch毛刺的产生,如果被寄存器捕捉到,传播到下一级的电路,会产生不稳定的状态。
在这里插入图片描述

1. Glitch Free技术介绍

对于需要无缝切换时钟源,我们需要解决的问题有:
1.异步切换信号的跨时钟域同步问题,即可以用到异步复位,同步释放电路。
2.同步后的切换信号与时钟信号的逻辑设计。

方法一:

SOC设计——时钟切换的MUX设计 glitch free技术(一种防止毛刺产生的多路选择器设计)_第3张图片

module stsoc_gf_ckmux 
(
    input                                    rstn        ,
    input   [          1:0]   				 i_clk       ,
    input     								 sel         ,
    output                                   o_clk
);

  wire [1:0]  src_clk_lb, clk_en ;
  reg  [1:0]  n_en_reg           ;
  reg  [1:0]  n_en_reg_dly       ;
  wire [1:0]  sync_clken_out     ;

  wire [1:0]  src_clk_inv        ;

  wire [1:0]  out_clk_and        ;

  genvar index;
  generate for(index=0;index<2;index=index+1)
  
	assign  src_clk_lb[index]  =  i_clk[index];
	assign  src_clk_inv[index] =  i_clk[index];
	
	//sync 三拍 
    stsoc_sync_l3 sync_clk_en (
       .ck   (src_clk_lb[0]),
       .clb  (rstn),
       .d    (clk_en[0]),
       .o    (sync_clken_out[0])
     );

	//sync 三拍
     stsoc_sync_l3 sync_clk_en (
       .ck   (src_clk_lb[1]),
       .clb  (rstn),
       .d    (clk_en[1]),
       .o    (sync_clken_out[1])
     );
 
      always @(posedge src_clk_inv[index] or negedge rstn)
        if(!rstn)
        begin
              n_en_reg[0]     <= 1'b1  ;
              n_en_reg_dly[0] <= 1'b1  ;

              n_en_reg[1]     <= 1'b0     ;
              n_en_reg_dly[1] <= 1'b0     ;    
        end
        else
          begin
            n_en_reg[index]     <= sync_clken_out[index]  ;
            n_en_reg_dly[index] <= n_en_reg[index] ;
          end

 endgenerate
 
    assign clk_en[0] = ~sel & (!n_en_reg_dly[1]) ;
    assign clk_en[1] =  sel & (!n_en_reg_dly[0]) ;
     
	//and gate
	assign  out_clk_and[0] = n_en_reg[0] & i_clk[0];
	assign  out_clk_and[1] = n_en_reg[1] & i_clk[1];
    
    //or gate
	assign  o_clk = out_clk_and[0] | out_clk_and[1];
endmodule

仿真结果图:
SOC设计——时钟切换的MUX设计 glitch free技术(一种防止毛刺产生的多路选择器设计)_第4张图片
多时钟源的源码可以参考下面这篇文章:多是中源切换MUX

方法二:

SOC设计——时钟切换的MUX设计 glitch free技术(一种防止毛刺产生的多路选择器设计)_第5张图片

`timescale 1ns/100ps

module clk_switch ( 
  out_clk,	 // Outputs
  clk_a, clk_b, select   // Inputs
  );
	input clk_a;
  	input clk_b;
 	input select; 	
	output out_clk;
	
	wire   out_clk;
	reg q1,q2,q3,q4;
	wire or_one, or_two,or_three,or_four;
	
	always @ (posedge clk_a)
	begin
	   if (clk_a == 1'b1)
	   begin
	      q1 <= q4;
	      q3 <= or_one;
	   end
	end
	
	always @ (posedge clk_b)
	begin
	   if (clk_b == 1'b1)
	   begin
	       q2 <= q3;
	       q4 <= or_two;
	   end
	end
	
	assign or_one   = (!q1) | (!select);
	assign or_two   = (!q2) | (select);
	
	assign or_three = (q3)  | (clk_a);
	assign or_four  = (q4)  | (clk_b);
	
	assign out_clk  = or_three & or_four;

endmodule

测试文件:

module  clk_switch_tb;
reg clk_a,clk_b;
reg select;
wire  out_clk;
 
clk_switch  clk_switch(clk_a,clk_b,select,out_clk);
 
initial begin
  clk_a = 0;
  forever #50 clk_a = !clk_a;
end
initial begin
  clk_b = 0;
  forever #10 clk_b = !clk_b;
end
 
initial begin
  select  = 0;
  #1000;
  select  = 1;
  #1000;
  select  = 0;
  #1000;
  select  = 1;
  #1000;
  $finish;
end
 
endmodule

仿真结果图:
在这里插入图片描述

方法三:

SOC设计——时钟切换的MUX设计 glitch free技术(一种防止毛刺产生的多路选择器设计)_第6张图片

`timescale  1ns/10ps
module  clock_mux (
    // OUTPUTs
    //=========
    output         clk_out,        // Clock output
 
    // INPUTs
    //=========
    input          clk_in0,        // Clock input 0
    input          clk_in1,        // Clock input 1
    input          reset,            // Reset
    input          select_in       // Clock selection
);
//----------------------------------------
//  Regs declare
//----------------------------------------
 
	reg   dff0a,dff0b;
	reg   dff1a,dff1b;
	 
	wire  clk_in0_inv = ~clk_in0;
	wire  clk_in1_inv = ~clk_in1;
 
//----------------------------------------
//  clk_in0 path
//----------------------------------------
 
// negedge of clk_in0
	always @(posedge clk_in0_inv or posedge reset)
	  if(reset)   
	  	dff0a <=  1'b1;
	  else      
	  	dff0a <=  !select_in & !dff1b;
	 
	always @(posedge clk_in0 or posedge reset)
	  if(reset)   
	  	dff0b <=  1'b1;
	  else      
	  	dff0b <=  dff0a;
	 
	wire  clk_in0_gate  = ~(~clk_in0 & dff0b);
 
//----------------------------------------
//  clk_in1 path
//----------------------------------------
// negedge of clk_in1
	always @(posedge clk_in1_inv or posedge reset)
	  if(reset)   
	  	dff1a <=  1'b0;
	  else      
	  	dff1a <=  select_in & !dff0b;
	 
	always @(posedge clk_in1 or posedge reset)
	  if(reset)   
	  	dff1b <=  1'b0;
	  else      
	  	dff1b <=  dff1a;
	 
	wire  clk_in1_gate  = ~(~clk_in1 & dff1b);
 
//-----------------------
//  clock mux out
//-----------------------
	assign  clk_out = clk_in0_gate & clk_in1_gate;
	 
endmodule

欢迎关注下面公众号,每周精选一篇原创文章!!!
在这里插入图片描述

你可能感兴趣的:(SOC设计,Verilog语言,时钟树)