Search code examples
timevhdlclockfpgaxilinx-ise

Gated Clock in Clock Divider for a Square Wave


I recently have been designing a clock divider for my system - which I redesigned, and now has an asynchronous reset, which generates a synchronous reset for the rest of the system. To do this, I followed the answers & advice to my own question and used a clock enable to toggle an output, thus generating clock with a 50% duty cycle (which is desired).

However, this has thrown up the error when generating the bitstream of PhysDesignRules:372 - Gated clock. Clock net ... is sourced by a combinatorial pin. This is not good design practice. Use the CE pin to control the loading of data into the flip-flop.

Reading into this question about using the clock enable, it appears when creating a clock enable is correct, however, because I need a square wave (and not just a 1/200MHz pulse), and thus using the enable to toggle another signal, it appears in this question that this is an intentional gated clock.

So my questions are; is this gated clock warning significant? Both in simulation, and on an oscilloscope it appears to function correctly (so I'm inclined to ignore it), but am I storing problems for later? Is there a way of getting a very slow 50% duty cycle pulse without a gated clock?

I've put my code below!

Thanks very much (especially to the handful of people who have collectively given a lot of time to my recent non-stop questions)

David

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library UNISIM;
use UNISIM.VComponents.all;

ENTITY CLK_DIVIDER IS
    GENERIC(INPUT_FREQ : INTEGER;
            OUT1_FREQ  : INTEGER;
            OUT2_FREQ  : INTEGER
    );
    PORT(SYSCLK      : IN  STD_LOGIC;
         RESET_N     : IN  STD_LOGIC;
         RESET_N_OUT : OUT STD_LOGIC;
         OUT1        : OUT STD_LOGIC;
         OUT2        : OUT STD_LOGIC);
END CLK_DIVIDER;

architecture Behavioral of Clk_Divider is
    constant divider1 : integer   := INPUT_FREQ / OUT1_FREQ / 2;
    constant divider2 : integer   := INPUT_FREQ / OUT2_FREQ / 2;
    signal counter1   : integer   := 0;
    signal counter2   : integer   := 0;
    signal output1    : std_logic := '0';
    signal output2    : std_logic := '0';
    signal reset      : boolean;
begin
    reset_proc : process(RESET_N, SYSCLK)
        variable cycles        : integer := 0;
        variable reset_counter : integer := 0;
    begin
        if rising_edge(SYSCLK) then
            if cycles < 2 then
                if reset_counter >= divider1 then
                    cycles        := cycles + 1;
                    reset_counter := 0;
                else
                    reset_counter := reset_counter + 1;
                end if;
                reset <= true;
            else
                reset <= false;
            end if;
        end if;
        if RESET_N = '0' then
            cycles        := 0;
            reset_counter := 0;
            reset         <= true;
        end if;
    end process;

    output1_proc : process(SYSCLK)
    begin
        if rising_edge(SYSCLK) then
            if counter1 >= divider1 - 1 then
                output1  <= not output1;
                counter1 <= 0;
            else
                counter1 <= counter1 + 1;
            end if;
            if RESET_N = '0' then
                counter1 <= 0;
                output1  <= '1';
            end if;
        end if;
    end process;

    output2_proc : process(SYSCLK)
    begin
        if rising_edge(SYSCLK) then
            if counter2 >= divider2 - 1 then
                output2  <= not output2;
                counter2 <= 0;
            else
                counter2 <= counter2 + 1;
            end if;
            if RESET_N = '0' then
                counter2 <= 0;
                output2  <= '1';
            end if;
        end if;
    end process;

    OUT1        <= output1;
    OUT2        <= output2;
    RESET_N_OUT <= '0' when reset else '1';

end Behavioral;

Solution

  • The comments suggest, that the clock-divider is instantiated in a larger design. If you want to use the generated clock there, you must add a BUFG between signal output2 and the output out2 like this:

    out2_bufg : BUFG port map(I => output2, O => out2);
    

    The component BUFG is defined in the library unisim.vcomponents. Same applies to output out1.

    The BUFG ensures, that the generated clock is distributed using a clock-tree, so that the clock signal arrives at all destination flip-flops at the same time. This minimizes hold-time violations and gives more room for the setup of data signals.

    If you still get the warning/error, then you combined the generated clock signal with another signal elsewhere in the larger design.