(I'd post this in EE but it seems there are far more VHDL questions here...)
Background: I'm using the Xilinx Spartan-6LX9 FPGA with the Xilinx ISE 14.4 (webpack).
I stumbled upon the dreaded "PhysDesignRules:372 - Gated clock" warning today, and I see there's a LOT of discussion out there concerning that in general. The consensus seems to be to use one of the DCMs on the FPGA to do clock division but... my DCM doesn't appear to be capable of going from 32 MHz to 4.096 KHz (per the wizard it bottoms out at 5MHz based on 32MHz... and it seems absurd to try to chain multiple DCMs for this low-frequency purpose).
My current design uses clk_in to count up to a specified value (15265), resets that value to zero and toggles the clk_out bit (so I end up with a duty cycle of 50%, FWIW). It does the job, and I can easily use the rising edge of clk_out to drive the next stage of my design. It seems to work just fine, but... gated clock (even though it isn't in the range where clock skew would IMHO be very relevant). (Note: All clock tests are done using the rising_edge() function in processes sensitive to the given clock.)
So, my questions:
If we're talking about deriving a relatively slow clk_out from a much faster clk_in, is gating still considered bad? Or is this sort of "count to x and send a pulse" thing pretty typical for FPGAs to generate a "clock" in the KHz range and instead some other unnecessary side-effect may be triggering this warning instead?
Is there a better way to create a low KHz-range clock from a MHz-range master clock, keeping in mind that using multiple DCMs appears to be overkill here (if it's possible at all given the very low output frequency)? I realize the 50% duty cycle may be superfluous but assuming one clock in and not using the on-board DCMs how else would one perform major clock division with an FPGA?
Edit: Given the following (where CLK_MASTER is the 32 MHz input clock and CLK_SLOW is the desired slow-rate clock, and LOCAL_CLK_SLOW was a way to store the state of the clock for the whole duty-cycle thing), I learned that this configuration causes the warning:
architecture arch of clock is
constant CLK_MASTER_FREQ: natural := 32000000; -- time := 31.25 ns
constant CLK_SLOW_FREQ: natural := 2048;
constant MAX_COUNT: natural := CLK_MASTER_FREQ/CLK_SLOW_FREQ;
shared variable counter: natural := 0;
signal LOCAL_CLK_SLOW: STD_LOGIC := '0';
begin
clock_proc: process(CLK_MASTER)
begin
if rising_edge(CLK_MASTER) then
counter := counter + 1;
if (counter >= MAX_COUNT) then
counter := 0;
LOCAL_CLK_SLOW <= not LOCAL_CLK_SLOW;
CLK_SLOW <= LOCAL_CLK_SLOW;
end if;
end if;
end process;
end arch;
Whereas this configuration does NOT cause the warning:
architecture arch of clock is
constant CLK_MASTER_FREQ: natural := 32000000; -- time := 31.25 ns
constant CLK_SLOW_FREQ: natural := 2048;
constant MAX_COUNT: natural := CLK_MASTER_FREQ/CLK_SLOW_FREQ;
shared variable counter: natural := 0;
begin
clock_proc: process(CLK_MASTER)
begin
if rising_edge(CLK_MASTER) then
counter := counter + 1;
if (counter >= MAX_COUNT) then
counter := 0;
CLK_SLOW <= '1';
else
CLK_SLOW <= '0';
end if;
end if;
end process;
end arch;
So, in this case it was all for lack of an else (like I said, the 50% duty cycle was originally interesting but wasn't a requirement in the end, and the toggle of the "local" clock bit seemed quite clever at the time...) I was mostly on the right track it appears.
What's not clear to me at this point is why using a counter (which stores lots of bits) isn't causing warnings, but a stored-and-toggled output bit does cause warnings. Thoughts?