blob: 20ca430fe44c393573511b06d221c581e023f093 [file] [log] [blame]
//
// 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