// | |
// Switch between two clock sources. | |
// In this design the output clock stays LOW between switching clocks. | |
// After a reset clk1 is selected. | |
// sel_clk2 is assumed to have a high/low duration of at least 2 clock | |
// periods of the slowest of clk1 or clk2. | |
// (If the above rule is not followed, certain pathological patterns of | |
// sel_clk2 against the input clocks will produce low period violations) | |
// | |
// | |
// Design by G.J. van Loo, FenLogic Ltd, 3-January-2017. | |
// | |
// This program is free software. It comes without any guarantees or | |
// warranty to the extent permitted by applicable law. Although the | |
// author has attempted to find and correct any bugs in this free software | |
// program, the author is not responsible for any damage or losses of any | |
// kind caused by the use or misuse of the program. You can redistribute | |
// the program and or modify it in any form without obligations, but the | |
// author would appreciated if the credits stays in. | |
// | |
module clock_mux | |
( | |
input clk1, // Clock 1 supposed to be faster | |
input clk2, // Clock 2 supposed to be slower | |
input reset_n, // System reset | |
input sel_clk2, // Select clock2 when high | |
output clk1or2 // Selected clock | |
); | |
reg [1:0] meta1_off,sync1_off; | |
reg [1:0] meta1_on, sync1_on; | |
reg [1:0] meta2_off,sync2_off; | |
reg [1:0] meta2_on, sync2_on; | |
always @(posedge clk1 or negedge reset_n) | |
begin | |
if (!reset_n) | |
begin | |
meta1_off <= 1'b0; | |
sync1_off <= 1'b0; | |
meta1_on <= 1'b1; | |
sync1_on <= 1'b1; | |
end | |
else | |
begin | |
// Switch off when not selected | |
meta1_off <= sel_clk2; | |
sync1_off <= meta1_off; | |
// Switch on when other clock (clk2) is off | |
meta1_on <= sync2_off; | |
sync1_on <= meta1_on; | |
end | |
end | |
always @(posedge clk2 or negedge reset_n) | |
begin | |
if (!reset_n) | |
begin | |
meta2_off <= 1'b1; | |
sync2_off <= 1'b1; | |
meta2_on <= 1'b0; | |
sync2_on <= 1'b0; | |
end | |
else | |
begin | |
// Switch off when not selected | |
meta2_off <= ~sel_clk2; | |
sync2_off <= meta2_off; | |
// Switch on when other clock (clk1) is off | |
meta2_on <= sync1_off; | |
sync2_on <= meta2_on; | |
end | |
end | |
assign clk1or2 = (clk1 & ~sync1_off & sync1_on ) | | |
(clk2 & ~sync2_off & sync2_on ); | |
endmodule // clock_rnux | |