在通信領域當中,經常會在芯片運行過程當中進行時鍾切換,特別是當芯片內部中有兩個時鍾源時,往往通過內部邏輯控制多路復用器來實現時鍾源的切換。
時鍾切換的分類:
第一種:第一種時兩個時鍾源的頻率呈倍數關系;
第二種:兩個時鍾源完全沒有關系,異步時鍾。
解決方法:
當兩個時鍾可能完全無關,也可能成倍數關系。當聽到要進行時鍾切換時,第一個想到的語法就是三目運算。完全合乎邏輯。但是在網上查閱資料的時候,發現原來是最爛的一種設計。
1 assign outclk = sel? clk0: clk1;
寫法不入眼……而且這樣寫的話,考慮的實際工程的問題太少了。肯定會產生毛刺,對搭建的整個系統是非常危險的,因為有些寄存器可能會捕獲到時鍾沿其他沒捕獲到,造成系統的不穩定。在此寫法上繼續升級。使用AND-OR型多路復用器邏輯進行簡單的時鍾切換。如下圖所示:
1 assign outclk = (clk1 & select) | (~select & clk0);
從圖中可以看出,如果當Select信號發生改變時,信號源正好處於高電平的時刻,那么就會產生毛刺。從而影響后續的電路。仿真一下電路可以看出來效果。實現的代碼:
1 // ********************************************************************************* 2 // Project Name : 3 // weixin : li15226499835 4 // Website : https://www.cnblogs.com/lgy-gdeu/ 5 // Create Time : 2020// 6 // File Name : .v 7 // Module Name : 8 // Abstract : 9 // editor : sublime text 3 10 // ********************************************************************************* 11 // Modification History: 12 // Date By Version Change Description 13 // ----------------------------------------------------------------------- 14 // 2020// Liguoyong 1.0 Original 15 // 16 // ********************************************************************************* 17 `timescale 1ns/1ns 18 module first_glitch_free( 19 //system signals 20 input wire sclk , 21 input wire rst_n , 22 //others 23 input wire clk_1 , 24 input wire clk_2 , 25 input wire select , 26 output wire out_clk 27 28 29 ); 30 31 //============================================================================= 32 //**************************** Main Code ******************************* 33 //============================================================================= 34 35 assign out_clk = (select & sclk)|(~select & clk_2); 36 37 38 endmodule
tb測試的激勵文件:
1 // ********************************************************************************* 2 // Project Name : 3 // weixin : li15226499835 4 // Website : https://www.cnblogs.com/lgy-gdeu/ 5 // Create Time : 2020// 6 // File Name : .v 7 // Module Name : 8 // Abstract : 9 // editor : sublime text 3 10 // ********************************************************************************* 11 // Modification History: 12 // Date By Version Change Description 13 // ----------------------------------------------------------------------- 14 // 2020// Liguoyong 1.0 Original 15 // 16 // ********************************************************************************* 17 `timescale 1ns/1ns 18 19 module first_glitch_free_tb; 20 21 reg sclk ; 22 reg tb_clk_1 ; 23 reg tb_clk_2 ; 24 reg tb_rst_n ; 25 reg tb_select ; 26 wire tb_out_clk ; 27 28 initial begin 29 tb_rst_n = 0; 30 sclk = 1; 31 #100 32 tb_rst_n = 1; 33 tb_select = 0; 34 #487 35 tb_select = 1; 36 #2000 37 $finish; 38 end 39 40 always #10 sclk = ~sclk ; 41 42 43 //============================================================================= 44 //**************************** Main Code ******************************* 45 //============================================================================= 46 47 48 always @(posedge sclk or negedge tb_rst_n )begin 49 if(!tb_rst_n) 50 tb_clk_1 <= 0; 51 else 52 tb_clk_1 <= ~tb_clk_1 ; 53 end 54 55 always @(posedge tb_clk_1 or negedge tb_rst_n)begin 56 if(!tb_rst_n) 57 tb_clk_2 <= 0; 58 else 59 tb_clk_2 <= ~tb_clk_2; 60 end 61 wire tb_clk_3 ; 62 assign tb_clk_3 = ~tb_clk_2; 63 //例化 64 first_glitch_free first_glitch_free_inst( 65 //system signals 66 .sclk (sclk ) , 67 .clk_1 (tb_clk_1) , 68 .clk_2 (tb_clk_3) , 69 .rst_n (tb_rst_n) , 70 //output 71 .select (tb_select), 72 .out_clk (tb_out_clk) 73 74 75 ); 76 77 endmodule
仿真圖:
避免毛刺的方法繼續往下看,下圖針對的是兩個時鍾源頻率成倍數關系。在每個時鍾源的選擇路徑中插入一個下降沿觸發的D觸發器,這樣可以保證上面的情況被避免,確保在切換時鍾源時,即使任意時鍾處於高電平,也不會引起輸出的變換,時鍾源切換時,這個反饋能保證一個時鍾被完全取消選擇后,輸出傳播另一個時鍾,從而避免產生任何毛刺。
這個電路有三個時序路徑需要考慮,SELECT到兩個觸發器的任何一個,DFF0到DFF1,DFF1到DFF0,這三條路徑上的輸入信號與時鍾邊沿同時發生變化,都可能會引起亞穩態,所以需要將觸發器的觸發邊沿和SELECT信號的變換邊沿分開,這可以通過時序約束來實現,因為這兩個時鍾是呈倍數的關系。芯片在啟動的時候,兩個觸發器都應該處於0狀態。
代碼:

1 // ********************************************************************************* 2 // Project Name : 3 // weixin : li15226499835 4 // Website : https://www.cnblogs.com/lgy-gdeu/ 5 // Create Time : 2020// 6 // File Name : .v 7 // Module Name : 8 // Abstract : 9 // editor : sublime text 3 10 // ********************************************************************************* 11 // Modification History: 12 // Date By Version Change Description 13 // ----------------------------------------------------------------------- 14 // 2020// Liguoyong 1.0 Original 15 // 16 // ********************************************************************************* 17 `timescale 1ns/1ns 18 module first_glitch_free( 19 //system signals 20 input wire sclk , 21 input wire rst_n , 22 //others 23 input wire clk_1 , 24 input wire clk_2 , 25 input wire select , 26 output wire out_clk 27 28 29 ); 30 //============================================================================= 31 //**************************** Main Code ******************************* 32 //============================================================================= 33 reg out_clk1; 34 reg out_clk2; 35 36 //============================================================================= 37 //**************************** Main Code ******************************* 38 //============================================================================= 39 40 //assign out_clk = (select & sclk)|(~select & clk_2); 41 //out_clk1 42 always @(posedge sclk or negedge rst_n)begin 43 if(!rst_n) 44 out_clk1 <= 0; 45 else 46 out_clk1 <= ~out_clk2 & ~select; 47 end 48 //out_clk2 49 always @(posedge sclk or negedge rst_n)begin 50 if(!rst_n) 51 out_clk2 <= 0; 52 else 53 out_clk2 <= select&~out_clk1 ; 54 end 55 56 //out_clk 57 assign out_clk = (clk_2&out_clk2)|(clk_1&out_clk1); 58 59 60 endmodule
tb測試文件

1 // ********************************************************************************* 2 // Project Name : 3 // weixin : li15226499835 4 // Website : https://www.cnblogs.com/lgy-gdeu/ 5 // Create Time : 2020// 6 // File Name : .v 7 // Module Name : 8 // Abstract : 9 // editor : sublime text 3 10 // ********************************************************************************* 11 // Modification History: 12 // Date By Version Change Description 13 // ----------------------------------------------------------------------- 14 // 2020// Liguoyong 1.0 Original 15 // 16 // ********************************************************************************* 17 `timescale 1ns/1ns 18 19 module first_glitch_free_tb; 20 21 reg sclk ; 22 reg tb_clk_1 ; 23 reg tb_clk_2 ; 24 reg tb_rst_n ; 25 reg tb_select ; 26 wire tb_out_clk ; 27 wire tb_clk_3 ; 28 initial begin 29 tb_rst_n = 0; 30 sclk = 1; 31 #100 32 tb_rst_n = 1; 33 tb_select = 0; 34 #487 35 tb_select = 1; 36 #2000 37 $finish; 38 end 39 40 always #10 sclk = ~sclk ; 41 42 //============================================================================= 43 //**************************** Main Code ******************************* 44 //============================================================================= 45 46 47 always @(posedge sclk or negedge tb_rst_n )begin 48 if(!tb_rst_n) 49 tb_clk_1 <= 0; 50 else 51 tb_clk_1 <= ~tb_clk_1 ; 52 end 53 54 always @(posedge tb_clk_1 or negedge tb_rst_n)begin 55 if(!tb_rst_n) 56 tb_clk_2 <= 0; 57 else 58 tb_clk_2 <= ~tb_clk_2; 59 end 60 61 62 assign tb_clk_3 = ~tb_clk_2; 63 //例化 64 first_glitch_free first_glitch_free_inst( 65 //system signals 66 .sclk (sclk ) , 67 .clk_1 (tb_clk_1) , 68 .clk_2 (tb_clk_2) , 69 .rst_n (tb_rst_n) , 70 //output 71 .select (tb_select) , 72 .out_clk (tb_out_clk) 73 74 75 ); 76 77 endmodule
仿真圖形:
第二種方法是針對兩個異步時鍾源的切換,這個方法是在第一種方法的基礎上,在選擇路徑上再插入一個上升沿觸發D觸發器,這是為了針對對兩個異步時鍾源產生的反饋信號以及異步信號SELECT,對選擇信號進行同步處理,這樣即使是兩個異步的時鍾源進行切換,也可以避免亞穩態的產生。
仿真代碼:

1 // ********************************************************************************* 2 // Project Name : 3 // weixin : li15226499835 4 // Website : https://www.cnblogs.com/lgy-gdeu/ 5 // Create Time : 2020// 6 // File Name : .v 7 // Module Name : 8 // Abstract : 9 // editor : sublime text 3 10 // ********************************************************************************* 11 // Modification History: 12 // Date By Version Change Description 13 // ----------------------------------------------------------------------- 14 // 2020// Liguoyong 1.0 Original 15 // 16 // ********************************************************************************* 17 `timescale 1ns/1ns 18 module first_glitch_free( 19 //system signals 20 input wire sclk , 21 input wire rst_n , 22 //others 23 input wire clk_1 , 24 input wire clk_2 , 25 input wire select , 26 output wire out_clk 27 28 29 ); 30 //============================================================================= 31 //**************************** Main Code ******************************* 32 //============================================================================= 33 reg out_clk1; 34 reg out_clk1_r; 35 reg out_clk2; 36 reg out_clk2_r; 37 38 //============================================================================= 39 //**************************** Main Code ******************************* 40 //============================================================================= 41 42 //assign out_clk = (select & sclk)|(~select & clk_2); 43 //out_clk1 44 always @(posedge sclk or negedge rst_n)begin 45 if(!rst_n) 46 out_clk1 <= 0; 47 else 48 out_clk1 <= ~out_clk2 & ~select; 49 end 50 51 //out_clk1_r 52 always @(posedge sclk or negedge rst_n)begin 53 if(!rst_n) 54 out_clk1_r <= 0; 55 else 56 out_clk1_r <= out_clk1; 57 end 58 59 //out_clk2 60 always @(posedge sclk or negedge rst_n)begin 61 if(!rst_n) 62 out_clk2 <= 0; 63 else 64 out_clk2 <= select&~out_clk1 ; 65 end 66 67 //out_clk2_r 68 always @(posedge sclk or negedge rst_n)begin 69 if(!rst_n) 70 out_clk2_r <= 0; 71 else 72 out_clk2_r <= out_clk2; 73 end 74 75 //out_clk 76 assign out_clk = (clk_2&out_clk2_r)|(clk_1&out_clk1_r); 77 78 79 endmodule
tb激勵代碼

1 // ********************************************************************************* 2 // Project Name : 3 // weixin : li15226499835 4 // Website : https://www.cnblogs.com/lgy-gdeu/ 5 // Create Time : 2020// 6 // File Name : .v 7 // Module Name : 8 // Abstract : 9 // editor : sublime text 3 10 // ********************************************************************************* 11 // Modification History: 12 // Date By Version Change Description 13 // ----------------------------------------------------------------------- 14 // 2020// Liguoyong 1.0 Original 15 // 16 // ********************************************************************************* 17 `timescale 1ns/1ns 18 19 module first_glitch_free_tb; 20 21 reg sclk ; 22 reg tb_clk_1 ; 23 reg tb_clk_2 ; 24 reg tb_rst_n ; 25 reg tb_select ; 26 wire tb_out_clk ; 27 wire tb_clk_3 ; 28 initial begin 29 tb_rst_n = 0; 30 sclk = 1; 31 #100 32 tb_rst_n = 1; 33 tb_select = 0; 34 #487 35 tb_select = 1; 36 #2000 37 $finish; 38 end 39 40 always #10 sclk = ~sclk ; 41 42 //============================================================================= 43 //**************************** Main Code ******************************* 44 //============================================================================= 45 46 47 always @(posedge sclk or negedge tb_rst_n )begin 48 if(!tb_rst_n) 49 tb_clk_1 <= 0; 50 else 51 tb_clk_1 <= ~tb_clk_1 ; 52 end 53 54 always @(posedge tb_clk_1 or negedge tb_rst_n)begin 55 if(!tb_rst_n) 56 tb_clk_2 <= 0; 57 else 58 tb_clk_2 <= ~tb_clk_2; 59 end 60 61 62 assign tb_clk_3 = ~tb_clk_2; 63 //例化 64 first_glitch_free first_glitch_free_inst( 65 //system signals 66 .sclk (sclk ) , 67 .clk_1 (tb_clk_1) , 68 .clk_2 (tb_clk_2) , 69 .rst_n (tb_rst_n) , 70 //output 71 .select (tb_select) , 72 .out_clk (tb_out_clk) 73 74 75 ); 76 77 endmodule
仿真波形
參考文獻:https://www.eetimes.com/techniques-to-make-clock-switching-glitch-free/
多多指教。點頭致謝!