Let’s say we want to be able to switch dynamically between two (or more) clocks. In the Virtex FPGAs we have a primitive which allows us to do just this, it’s called the BUFGCTRL. The BUFGCTRL is a global clock buffer (like BUFG) which has two clock inputs and a series of control inputs that allow you to select between the two clocks. The great thing about the BUFGCTRL is that it allows you to switch between clocks “glitch free”.
If you have two clock inputs and you want to switch between them without glitches at the output, use this code:
BufGCtrlMux_l : BUFGCTRL
generic map (
INIT_OUT => 0,
PRESELECT_I0 => FALSE,
PRESELECT_I1 => FALSE)
port map (
O => ClkOutputMux,
CE0 => not ClkSel,
CE1 => ClkSel,
I0 => ClkInput0,
I1 => ClkInput1,
IGNORE0 => '0',
IGNORE1 => '0',
S0 => '1', -- Clock select0 input
S1 => '1' -- Clock select1 input
);
One problem with using the BUFGCTRL in “glitch free” configuration is that it requires that both clocks be running at all times. If the selected clock suddenly drops out, you will not be able to switch to the other clock. If for example, your clocks come from external sources that come and go, you will not be able to use the BUFGCTRL in “glitch free” configuration and instead you will have to use it in asynchronous mode. In this mode, you can switch between the clocks as you like and it will never get locked into one or the other.
Use this code for the asynchronous clock MUX if you don’t care about glitch free operation:
BufGCtrlMux_l : BUFGCTRL
generic map (
INIT_OUT => 0,
PRESELECT_I0 => FALSE,
PRESELECT_I1 => FALSE)
port map (
O => ClkOutputMux,
CE0 => '1',
CE1 => '1',
I0 => ClkInput0,
I1 => ClkInput1,
IGNORE0 => '1',
IGNORE1 => '1',
S0 => not ClkSel, -- Clock select0 input
S1 => ClkSel -- Clock select1 input
);
What if you have four clocks to choose from? Well you can use 3 BUFGCTRLs to implement a 4-to-1 clock multiplexer. Obviously, your select signal becomes a 2-bit signal. Use this code for a 4-input asynchronous clock MUX:
BufGCtrlMuxA_l : BUFGCTRL
generic map (
INIT_OUT => 0,
PRESELECT_I0 => FALSE,
PRESELECT_I1 => FALSE)
port map (
O => ClkOutputMuxA,
CE0 => '1',
CE1 => '1',
I0 => ClkInput0,
I1 => ClkInput1,
IGNORE0 => '1',
IGNORE1 => '1',
S0 => not ClkSel(0), -- Clock select0 input
S1 => ClkSel(0) -- Clock select1 input
);
BufGCtrlMuxB_l : BUFGCTRL
generic map (
INIT_OUT => 0,
PRESELECT_I0 => FALSE,
PRESELECT_I1 => FALSE)
port map (
O => ClkOutputMuxB,
CE0 => '1',
CE1 => '1',
I0 => ClkInput2,
I1 => ClkInput3,
IGNORE0 => '1',
IGNORE1 => '1',
S0 => not ClkSel(0), -- Clock select0 input
S1 => ClkSel(0) -- Clock select1 input
);
BufGCtrlMux_l : BUFGCTRL
generic map (
INIT_OUT => 0,
PRESELECT_I0 => FALSE,
PRESELECT_I1 => FALSE)
port map (
O => ClkOutputMux,
CE0 => '1',
CE1 => '1',
I0 => ClkOutputMuxA,
I1 => ClkOutputMuxB,
IGNORE0 => '1',
IGNORE1 => '1',
S0 => not ClkSel(1), -- Clock select0 input
S1 => ClkSel(1) -- Clock select1 input
);
This example assumes that you have the following signals declared somewhere!
signal ClkOutputMuxA : std_logic;
signal ClkOutputMuxB : std_logic;
signal ClkOutputMux : std_logic;
signal ClkInput0 : std_logic;
signal ClkInput1 : std_logic;
signal ClkInput2 : std_logic;
signal ClkInput3 : std_logic;
signal ClkSel : std_logic_vector(1 downto 0);
Remember that the BUFGCTRL is a global clock buffer, and you only have a limited number of these in any Virtex device, so be aware of the limitation on your device. For more information on BUFG and BUFGCTRL, read the Clocking Resources User Guide for your specific FPGA device.