隨著各種應用場景的限制,芯片在運行時往往需要在不同的應用下切換不同的時鐘源,例如低功耗和高性能模式就分別需要低頻率和高頻率的時鐘。兩個時鐘源有可能是同源且同步的,也有可能是不相關的。直接使用選擇邏輯進行時鐘切換大概率會導致分頻時鐘信號出現毛刺現象,所以時鐘切換邏輯也需要進行特殊的處理。
時鐘切換問題
直接采用選擇邏輯對時鐘進行切換的電路圖如下所示。
假如時鐘選擇信號 sel_clk1 與兩個時鐘都是異步的,那么時鐘切換時刻就是任意的。假如時鐘由 clk1 切換到 clk2,且切換時刻為 clk1 輸出電平為高的時候,此時立即切換時鐘就會導致輸出時鐘出現毛刺(glitch)。波形示意圖如下:
時鐘切換方案
在兩個電平相反的時候切換時鐘,肯定有毛刺;電平相同的時候,即使不產生毛刺,時鐘切換后的第一個時鐘的周期或占空比也不是理想的。所以,為避免毛刺的產生,需要在兩個時鐘都為低電平的時候進行時鐘切換。
一種典型的時鐘切換電路如下所示。
該電路利用時鐘下降沿對時鐘選擇信號 sel_clk1 進行緩存。同時一個時鐘選擇信號對另一個時鐘進行反饋控制,保證同一時刻只能有一路時鐘有效。最后采用"或操作"將兩路時鐘合并,完成時鐘切換的過程。
采用上述電路完成時鐘切換(clk1->clk2)的波形示意圖如下所示。
由圖可知,clk1 向 clk2 切換時,先關閉 clk1, 然后打開 clk2。由于時鐘選擇信號被同步到時鐘下降沿,所以切換過程中不會出現毛刺。
clk2 向 clk1 切換的波形示意圖如下所示。
考慮到選擇信號有可能是異步信號,需要在時鐘選擇信號的緩存觸發器之前加兩級觸發器進行同步處理,來減少亞穩態的傳播,結構圖如下。該時鐘切換電路更具有普遍性。
時鐘切換設計
普遍且安全的時鐘切換邏輯描述如下。
實例
module?clk_switch(input?? ? ? ? ? ? ? rstn?,input?? ? ? ? ? ? ? clk1,input?? ? ? ? ? ? ? clk2,input?? ? ? ? ? ? ? sel_clk1?,?// 1 clk1, 0 clk2output?? ? ? ? ? ? ?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)?beginif?(!rstn)?beginsel_clk1_r ? ??<=?3'b111?;?//注意默認值endelse?begin//sel clk1, and not sel clk2sel_clk1_r ? ??<=?{sel_clk1_r[1:0],?sel_clk1?&?(!sel_clk2_neg_r[1])}?;endend//在下降沿,使用2拍緩存時鐘選擇信號always?@(negedge?clk1?or?negedge?rstn)?beginif?(!rstn)?beginsel_clk1_neg_r?<=?2'b11?;?//注意默認值endelse?beginsel_clk1_neg_r?<=?{sel_clk1_neg_r[0],?sel_clk1_r[2]}?;endend//使用3拍緩存,同步另一個時鐘控制信號與本時鐘控制信號的"與"邏輯操作always?@(posedge?clk2?or?negedge?rstn)?beginif?(!rstn)?beginsel_clk2_r ? ??<=?3'b0?;?//注意默認值endelse?begin//sel clk2, and not sel clk1sel_clk2_r ? ??<=?{sel_clk2_r[1:0],?!sel_clk1?&?(!sel_clk1_neg_r[1])}?;endend//在下降沿,使用2拍緩存時鐘選擇信號always?@(negedge?clk2?or?negedge?rstn)?beginif?(!rstn)?beginsel_clk2_neg_r?<=?2'b0?;?//注意默認值endelse?beginsel_clk2_neg_r?<=?{sel_clk2_neg_r[0],?sel_clk2_r[2]}?;endend//時鐘邏輯運算時,一般使用特定的工藝單元庫。//這里用 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 描述如下,主要產生異步時鐘的選擇信號。
實例
`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?beginclk_100mhz ?=?0?;clk_200mhz ?=?0?;rstn ? ? ? ?=?0?;sel ? ? ? ??=?1?;#11?rstn ? ?=?1?;#36.2?sel ??=?~sel?;#119.7?sel ??=?~sel?;endclk_switch u_clk_switch(.rstn ? ? ?(rstn),.clk1 ? ? ?(clk_100mhz),.clk2 ? ? ?(clk_200mhz),.sel_clk1 ?(sel),.clk_out ??(clk_out));initial?beginforever?begin#100;if?($time?>=?10000)??$finish?;endendendmodule
仿真結果如下,可見時鐘相互切換時沒有產生毛刺,但是存在延遲。