Verilog 時鐘切換

2022-05-20 14:36 更新

隨著各種應用場景的限制,芯片在運行時往往需要在不同的應用下切換不同的時鐘源,例如低功耗和高性能模式就分別需要低頻率和高頻率的時鐘。兩個時鐘源有可能是同源且同步的,也有可能是不相關的。直接使用選擇邏輯進行時鐘切換大概率會導致分頻時鐘信號出現(xiàn)毛刺現(xiàn)象,所以時鐘切換邏輯也需要進行特殊的處理。

時鐘切換問題

直接采用選擇邏輯對時鐘進行切換的電路圖如下所示。


假如時鐘選擇信號 sel_clk1 與兩個時鐘都是異步的,那么時鐘切換時刻就是任意的。假如時鐘由 clk1 切換到 clk2,且切換時刻為 clk1 輸出電平為高的時候,此時立即切換時鐘就會導致輸出時鐘出現(xiàn)毛刺(glitch)。波形示意圖如下:


時鐘切換方案

在兩個電平相反的時候切換時鐘,肯定有毛刺;電平相同的時候,即使不產(chǎn)生毛刺,時鐘切換后的第一個時鐘的周期或占空比也不是理想的。所以,為避免毛刺的產(chǎn)生,需要在兩個時鐘都為低電平的時候進行時鐘切換。

一種典型的時鐘切換電路如下所示。

該電路利用時鐘下降沿對時鐘選擇信號 sel_clk1 進行緩存。同時一個時鐘選擇信號對另一個時鐘進行反饋控制,保證同一時刻只能有一路時鐘有效。最后采用"或操作"將兩路時鐘合并,完成時鐘切換的過程。


采用上述電路完成時鐘切換(clk1->clk2)的波形示意圖如下所示。

由圖可知,clk1 向 clk2 切換時,先關閉 clk1, 然后打開 clk2。由于時鐘選擇信號被同步到時鐘下降沿,所以切換過程中不會出現(xiàn)毛刺。


clk2 向 clk1 切換的波形示意圖如下所示。


考慮到選擇信號有可能是異步信號,需要在時鐘選擇信號的緩存觸發(fā)器之前加兩級觸發(fā)器進行同步處理,來減少亞穩(wěn)態(tài)的傳播,結(jié)構(gòu)圖如下。該時鐘切換電路更具有普遍性。


時鐘切換設計

普遍且安全的時鐘切換邏輯描述如下。

module clk_switch(
    input               rstn ,
    input               clk1,
    input               clk2,
    input               sel_clk1 , // 1 clk1, 0 clk2
    output              clk_out
    );

   reg [2:0]            sel_clk1_r ;
   reg [1:0]            sel_clk1_neg_r ;
   reg [2:0]            sel_clk2_r ;
   reg [1:0]            sel_clk2_neg_r ;

   //使用3拍緩存,同步另一個時鐘控制信號與本時鐘控制信號的"與"邏輯操作
   always @(posedge clk1 or negedge rstn) begin
      if (!rstn) begin
         sel_clk1_r     <= 3'b111 ; //注意默認值
      end
      else begin
         //sel clk1, and not sel clk2
         sel_clk1_r     <= {sel_clk1_r[1:0], sel_clk1 & (!sel_clk2_neg_r[1])} ;
      end
   end

   //在下降沿,使用2拍緩存時鐘選擇信號
   always @(negedge clk1 or negedge rstn) begin
      if (!rstn) begin
         sel_clk1_neg_r <= 2'b11 ; //注意默認值
      end
      else begin
         sel_clk1_neg_r <= {sel_clk1_neg_r[0], sel_clk1_r[2]} ;
      end
   end

   //使用3拍緩存,同步另一個時鐘控制信號與本時鐘控制信號的"與"邏輯操作
   always @(posedge clk2 or negedge rstn) begin
      if (!rstn) begin
         sel_clk2_r     <= 3'b0 ; //注意默認值
      end
      else begin
         //sel clk2, and not sel clk1
         sel_clk2_r     <= {sel_clk2_r[1:0], !sel_clk1 & (!sel_clk1_neg_r[1])} ;
      end
   end

   //在下降沿,使用2拍緩存時鐘選擇信號
   always @(negedge clk2 or negedge rstn) begin
      if (!rstn) begin
         sel_clk2_neg_r <= 2'b0 ; //注意默認值
      end
      else begin
         sel_clk2_neg_r <= {sel_clk2_neg_r[0], sel_clk2_r[2]} ;
      end
   end

   //時鐘邏輯運算時,一般使用特定的工藝單元庫。
   //這里用 Verilog 自帶的邏輯門單元代替
   wire clk1_gate, clk2_gate ;
   and (clk1_gate, clk1, sel_clk1_neg_r[1]) ;
   and (clk2_gate, clk2, sel_clk2_neg_r[1]) ;
   or  (clk_out, clk1_gate, clk2_gate) ;

endmodule

testbench 描述如下,主要產(chǎn)生異步時鐘的選擇信號。

`timescale 1ns/1ps
module test ;
   reg          clk_100mhz, clk_200mhz ;
   reg          rstn ;
   reg          sel ;
   wire         clk_out ;

   always #(2.5)    clk_200mhz  = ~clk_200mhz ;
   always @(posedge clk_200mhz)
                    clk_100mhz  = #1 ~clk_100mhz ;

   initial begin
      clk_100mhz  = 0 ;
      clk_200mhz  = 0 ;
      rstn        = 0 ;
      sel         = 1 ;
      #11 rstn    = 1 ;
      #36.2 sel   = ~sel ;
      #119.7 sel   = ~sel ;
   end

   clk_switch u_clk_switch(
     .rstn      (rstn),
     .clk1      (clk_100mhz),
     .clk2      (clk_200mhz),
     .sel_clk1  (sel),
     .clk_out   (clk_out));

   initial begin
      forever begin
         #100;
         if ($time >= 10000)  $finish ;
      end
   end

endmodule

仿真結(jié)果如下,可見時鐘相互切換時沒有產(chǎn)生毛刺,但是存在延遲。


點擊這里下載源碼


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號