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结构如下:
在这里插入图片描述

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

1. Glitch Free技术介绍

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

方法一:

在这里插入图片描述

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

仿真结果图:
在这里插入图片描述
多时钟源的源码可以参考下面这篇文章:多是中源切换MUX

方法二:

在这里插入图片描述

`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

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

方法三:

在这里插入图片描述

`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 设计中,时钟复位机制是一个重要的组成部分,用于确保系统的正常启动和运行稳定性。复位信号的作用是对系统中的寄存器和其他逻辑单元进行初始化,使其进入已知的状态[^1]。 #### 复位的分类 复位可以分为两种主要类型:异步复位和同步复位。 - **异步复位**:复位信号独立于时钟工作,一旦检测到有效的复位脉冲,无论当前时钟周期如何,都会立即触发复位动作。这种类型的复位适用于快速恢复场景,但也可能引入亚稳态问题[^3]。 - **同步复位**:复位信号仅在时钟边沿有效,因此所有的复位操作都与时钟同步发生。这种方式能够减少由于复位引起的竞争冒险现象,但在某些情况下可能会延长复位时间。 #### 复位传播路径 复位信号通常通过专用网络在整个芯片上传播。为了防止复位释放过程中出现毛刺或者意外激活的情况,一般会采用两级或多级 D 触发器组成的同步链路来净化复位信号[^2]。 ```verilog module reset_synchronizer ( input wire clk, input wire async_reset_n, // 异步低电平有效复位输入 output reg sync_reset_n // 同步高电平有效复位输出 ); reg intermediate_reset; always @(posedge clk or negedge async_reset_n) begin if (!async_reset_n) begin intermediate_reset <= 1'b0; sync_reset_n <= 1'b0; end else begin intermediate_reset <= 1'b1; sync_reset_n <= intermediate_reset; end end endmodule ``` 上述代码展示了一个简单的双级同步化模块实现方法,它将外部异步复位转换成内部同步形式以供后续电路使用。 #### 故障排查技巧 当遇到与复位有关的问题时,可以从以下几个方面入手分析原因并解决问题: 1. 检查是否有足够的保持时间和建立时间为所有受影响的触发器提供稳定的复位条件; 2. 确认是否存在未预期到达目标位置前就被提前移除掉的有效复位脉宽不足情况; 3. 对比实际硬件行为同仿真模型预测结果之间差异找出潜在设计缺陷所在之处; ### 结论 综上所述,合理规划及时优化SOC项目里的时钟分配策略以及配套完善的复位管理方案对于提升整体性能表现至关重要。这不仅有助于降低功耗水平而且还能增强产品长期使用的可靠程度。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

摆渡沧桑

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值