电子说
原理如下图(为了方便简洁,去掉了rst_n)
波形是这样的
代码就是根据电路图写的
1 /////////////////////////////////////////////////////////////////////////////////////////// 2 // DATE : Wed Jun 6 23:31:57 CST 2012 3 /////////////////////////////////////////////////////////////////////////////////////////// 4 module clk_sw( 5 input wire clk_a 6 , input wire clk_b 7 , input wire rst_n 8 , input wire sel 9 , output wire clk_o 10 ); 11 /////////////////////////////////////////////////////////////////////////////////////////// 12 // variable declaration 13 reg clk_a_en ; 14 reg clk_b_en ; 15 /////////////////////////////////////////////////////////////////////////////////////////// 16 // logic 17 always @(posedge clk_a or negedge rst_n) begin 18 if(~rst_n) clk_a_en <= 1'b0 ; 19 else clk_a_en <= ~sel & ~clk_b_en ; 20 end 21 always @(posedge clk_b or negedge rst_n) begin 22 if(~rst_n) clk_b_en <= 1'b0 ; 23 else clk_b_en <= sel & ~clk_a_en ; 24 end 25 assign clk_o = (clk_a & clk_a_en) | (clk_b & clk_b_en) ; 26 /////////////////////////////////////////////////////////////////////////////////////////// 27 28 endmodule // CREATED by poiu_elab@1207 29 30 ///////////////////////////////////////////////////////////////////////////////////////////
testbench是这样的
1 /////////////////////////////////////////////////////////////////////////////////////////// 2 // DATE : Wed Jun 6 23:42:58 CST 2012 3 /////////////////////////////////////////////////////////////////////////////////////////// 4 `define CLK_A_CYCLE 23 5 `define CLK_B_CYCLE 47 6 module tb(); 7 /////////////////////////////////////////////////////////////////////////////////////////// 8 // variable declaration 9 reg clk_a ; 10 reg clk_b ; 11 reg rst_n ; 12 reg sel ; 13 wire clk_o ; 14 /////////////////////////////////////////////////////////////////////////////////////////// 15 // stimulation generation 16 initial forever #(`CLK_A_CYCLE/2) clk_a = ~clk_a; 17 initial forever #(`CLK_B_CYCLE/2) clk_b = ~clk_b; 18 initial begin 19 rst_n = 1'b0 ; 20 clk_a = 1'b1 ; 21 clk_b = 1'b1 ; 22 sel = 1'b0 ; 23 #500; 24 rst_n = 1'b1 ; 25 #500; 26 #({$random}%13+500); 27 sel = ~sel ; 28 #({$random}%23+500); 29 sel = ~sel ; 30 #({$random}%33+500); 31 sel = ~sel ; 32 #({$random}%43+500); 33 sel = ~sel ; 34 #({$random}%53+500); 35 sel = ~sel ; 36 #({$random}%63+500); 37 sel = ~sel ; 38 #({$random}%73+500); 39 sel = ~sel ; 40 #({$random}%83+500); 41 sel = ~sel ; 42 #({$random}%93+500); 43 sel = ~sel ; 44 #({$random}%13+500); 45 sel = ~sel ; 46 #({$random}%23+500); 47 sel = ~sel ; 48 #({$random}%33+500); 49 sel = ~sel ; 50 #({$random}%43+500); 51 sel = ~sel ; 52 #({$random}%53+500); 53 sel = ~sel ; 54 #({$random}%63+500); 55 sel = ~sel ; 56 #({$random}%73+500); 57 sel = ~sel ; 58 #({$random}%83+500); 59 sel = ~sel ; 60 #({$random}%93+500); 61 sel = ~sel ; 62 #5000; 63 $stop; 64 end 65 /////////////////////////////////////////////////////////////////////////////////////////// 66 // module instaniation 67 clk_sw u_clk_sw( 68 .clk_a ( clk_a ) 69 , .clk_b ( clk_b ) 70 , .rst_n ( rst_n ) 71 , .sel ( sel ) 72 , .clk_o ( clk_o ) 73 ); 74 /////////////////////////////////////////////////////////////////////////////////////////// 75 76 endmodule // CREATED by poiu_elab@1207 77 78 ///////////////////////////////////////////////////////////////////////////////////////////
这里的核心就是你的sel发生翻转的时候,首先肯定是在本时钟域内的clk_en会先变低(invalid),之后才会使得另外时钟域内的clk_en变高(valid),这时另外一个时钟域内的时钟才能和clk_en相与输出。
简而言之,比如一开始是clk_a有效,clk_out为clk_a,sel翻转后,clk_a_en在clk_a的时钟域内先关断(拉低),使得clk_out持续拉低,clk_a_en变低后,clk_b_en在clk_b的时钟域内才能被拉高有效,这时同步的clk_b_en信号与clk_b相与就能使得clk_out成功切换到clk_b了。
原理就是这样,其中clk_a_en和clk_b_en不会同时有效就避免了时钟切换的时候窄脉冲及毛刺的生成,但是我觉得由于是组合逻辑输出的时钟总归还是会有一些缺点和不足的。不知道有没有什么更好的办法。
编辑:hfy
全部0条评论
快来发表一下你的评论吧 !