VHDL · Chapter 17.4 · FPGA-Oriented VHDL Design
Clocking Resources and Clock Management
Clocks on an FPGA do not run through ordinary logic; they travel on dedicated clocking resources built for the job. Global clock buffers drive low-skew clock trees that reach every flip-flop in a region nearly simultaneously, which is why clocks belong on these resources and never in the fabric. PLL and MMCM blocks generate the clocks a design needs, multiplying and dividing frequencies, shifting phase, deskewing, and filtering jitter, and you use them by instantiating the vendor primitive rather than building dividers in RTL. When part of a design must run slower you use a clock enable, not a divided clock, and any enable-based gating uses a dedicated buffer on the clock network. The rule is firm: clocks come from dedicated resources, and your RTL uses the clock plus enables. This lesson covers global buffers, PLL and MMCM clock generation, and clock-enable control.
Foundation14 min readVHDLFPGAClockingPLLMMCMClock Enable
1. Engineering intuition — clocks ride special rails
A clock must arrive at thousands of flip-flops at almost the same instant; route it through ordinary logic and routing and the skew would wreck timing. So FPGAs give clocks their own dedicated rails: low-skew global buffers that fan a clock out across a region, and clock-management blocks (PLL/MMCM) that make the clocks you need from an input reference. The discipline that follows is the one you have met repeatedly — never build clock behavior in the fabric. Need a different frequency? Ask a PLL/MMCM. Need part of the logic to run slower? Use a clock enable, not a divided clock. Need to "gate" a clock? Use enable-based gating on the dedicated network. Clocks are special signals on special hardware; your RTL uses them and modulates with enables.
2. Formal explanation — buffers, clock managers, and enables
-- DEDICATED clocking resources (NOT fabric logic):
-- GLOBAL CLOCK BUFFER (BUFG) : low-skew clock distribution tree → drives all FFs in a region.
-- PLL / MMCM : generate clocks from a reference — MULTIPLY/DIVIDE frequency,
-- PHASE-SHIFT, DESKEW, filter JITTER. Instantiate the PRIMITIVE/wizard.
-- BUFGCE : a global buffer with a clock enable → enable-based gating on the rails.
--
-- THE RULE:
-- • Get every clock from a PLL/MMCM + global buffer — do NOT build dividers/PLLs in RTL.
-- • Run "slower" logic with a CLOCK ENABLE on the real clock (7.5), not a divided clock.
-- • Never GATE / DIVIDE / MUX a clock in the fabric (15.4) — use enables / BUFGCE / dedicated mux.-- "Half-rate" behavior on the SINGLE real clock via an enable (no second clock):
process (clk) begin
if rising_edge(clk) then
if tick_en = '1' then q <= d; end if; -- updates only when enabled → "slower", one clock domain
end if;
end process;
-- tick_en is a normal signal from a counter; the clock itself is untouched.Dedicated resources carry and create clocks: global buffers (low-skew distribution), PLL/MMCM (generate/multiply/divide/phase/deskew — instantiated, not coded), and BUFGCE (enable-gated distribution). RTL uses the clock and modulates behavior with clock enables; it never builds clocks in fabric.
3. Production usage — generating and using clocks correctly
-- GENERATE clocks with a clock manager (instantiate the vendor primitive / use the wizard):
-- MMCM/PLL: ref 100 MHz → outputs 200 MHz (×2), 50 MHz (÷2), 100 MHz @ 90° phase, all deskewed.
-- (You instantiate it; you do NOT write a frequency divider in RTL.)
--
-- DISTRIBUTE each generated clock on a GLOBAL BUFFER (BUFG) so it reaches FFs with low skew.
--
-- CONTROL RATE / "gating" without breaking the clock:
-- • slower logic → clock ENABLE on the real clock (7.5) [one domain, no derived clock]
-- • disable a block→ BUFGCE (enable on the dedicated network) [not a logic-AND on the clock]
-- • select a clock → dedicated clock MUX primitive (BUFGMUX) [not a fabric mux]What hardware does this become? The clock manager is a hard PLL/MMCM primitive that produces clean, phase-controlled, deskewed clocks; each rides a global buffer tree to the flip-flops. Your RTL contributes flip-flops with clock enables — the enable decides when logic updates while the clock keeps running on its dedicated rails. Crucially, none of the dangerous fabric clocking (divided clocks, logic-gated clocks, fabric clock muxes) appears: rate control is an enable, gating is BUFGCE, clock selection is a dedicated BUFGMUX. This is what gives an FPGA design clean, low-skew, race-free clocking.
4. Structural interpretation — the clocking path
5. Why this is structural, not timing
FPGA clocking is an architecture concern — which dedicated resources carry and generate clocks, and how RTL connects to them — so the clocking-path diagram above is the right picture, not a waveform. The behavior of a clock-enabled register (its "slower" update) was already shown in Module 7.5; here the point is where clocks come from (PLL/MMCM, global buffers) and the structural rule that they never live in the fabric. That is design-time, resource-mapping knowledge, not a signal trace.
6. Debugging example — a divided/gated clock in the fabric
Expected: clean, low-skew clocking that meets timing. Observed: high clock skew, timing failures on
paths from a home-made clock, glitches, or the delta-race non-determinism from Module 15.4 — and the tool warns
about a clock on a non-clock (fabric) net. Root cause: a clock was built in the fabric — a divided
clock (clk_div <= not clk_div ...) or a logic-gated/muxed clock — instead of coming from a PLL/MMCM on a
global buffer, so it has skew, no jitter filtering, and races (15.4). Fix: generate every clock with a
clock manager and distribute it on a global buffer; for slower logic use a clock enable, for gating a
BUFGCE, and for selection a dedicated clock mux — never gate/divide/mux a clock in fabric logic.
Engineering takeaway: clocks belong on dedicated resources — generate them with PLL/MMCM on global buffers and
control rate with enables; a fabric-made (divided/gated) clock brings skew, races, and timing failures.
-- BUG: divided clock built in the fabric → skew, races, timing failure (15.4).
-- clk_div <= not clk_div when rising_edge(clk); process(clk_div) ...
-- FIX: one real clock (from PLL/MMCM on a BUFG) + a clock enable for slower behavior.
process (clk) begin if rising_edge(clk) then if tick_en='1' then q <= d; end if; end if; end process;7. Common mistakes & what to watch for
- Building clocks in fabric. Generate clocks with PLL/MMCM on global buffers; never write dividers/PLLs in RTL.
- Divided clocks for slower logic. Use a clock enable on the real clock (7.5), not a derived clock — avoids skew and races.
- Logic-gated/muxed clocks. Gate with BUFGCE and select with a dedicated clock mux (BUFGMUX), not fabric AND/mux.
- Ignoring clock regions/skew. Keep related logic in-region and on global buffers; cross-region skew costs timing.
- Not constraining generated clocks. Define every PLL/MMCM output clock in constraints (16.8) so timing is analyzed correctly.
8. Engineering insight & continuity
FPGA clocks come from dedicated resources: PLL/MMCM blocks generate them (multiply/divide/phase/deskew) and global buffers distribute them with low skew — instantiated as primitives, never built in RTL. Your logic uses the clock and controls rate with clock enables, gating with BUFGCE, selection with a dedicated mux; it never gates, divides, or muxes a clock in the fabric. Once a design has multiple clocks (from one or more managers), data passing between them faces a fundamental hazard — metastability — which is the subject of the next lesson, Clock Domain Crossing.