HomeFPGA from ScratchDay 18
DAY 18 · CLOCKING

PLLs & MMCMs — Generating Clocks on FPGA

By EcrioniX · Updated Jun 11, 2026

Your board has a single 100 MHz crystal. Your design needs 200 MHz for the processor, 25 MHz for VGA, and 12.288 MHz for audio. The PLL/MMCM hard block solves this — it synthesises multiple precise clocks from a single reference. This lesson explains the maths, shows you how to instantiate Xilinx MMCME2_BASE and PLLE2_BASE, and explains why you cannot usefully simulate PLLs behaviourally.

1. How a PLL works — VCO, M, D, O dividers

A Phase-Locked Loop (PLL) works by comparing the phase of an output-derived clock to the input reference and adjusting a Voltage-Controlled Oscillator (VCO) until they match. Three programmable dividers let you set the output frequency:

Frequency formula

Fvco = Fin × M / D
Fout = Fvco / O = Fin × M / (D × O)

Constraint: Fvco must be in the valid VCO range. For Xilinx 7-series: 600 MHz – 1200 MHz.
Example: 100 MHz in, 200 MHz out: D=1, M=10, O=5 → Fvco=1000 MHz ✓

2. PLL vs MMCM on Xilinx 7-series

FeaturePLLE2_BASEMMCME2_BASE
Output clocks67 (CLKOUT0–6)
Fractional dividerNoYes (CLKOUT0 only, M/D)
Phase step resolution45° steps~11 ps (fine phase shift)
Dynamic reconfigNo (BASE variant)No (BASE variant)
JitterLower for integer ratiosSlightly higher with fractional
Typical useSimple integer multiply/divideAudio, video, spread-spectrum

3. Why behavioural simulation doesn't model PLLs

The Xilinx unisim simulation model for MMCME2_BASE waits a fixed simulation time (a few hundred nanoseconds), then starts driving its output clocks at the correct frequency. It does not model:

For functional simulation, treat the PLL as a black box that produces the correct frequency after asserting LOCKED. Design your reset logic to hold all downstream logic in reset until LOCKED is high — this pattern works in both simulation and hardware.

4. Port table — clk_wiz_wrapper

PortDirWidthDescription
clk_inIN1Reference clock input (100 MHz from board oscillator)
resetIN1Active-high PLL reset. Assert briefly at startup then release.
clk_200OUT1200 MHz output clock (M=10, D=1, O=5)
clk_25OUT125 MHz output clock (M=10, D=1, O=40)
lockedOUT1High when PLL is locked. Use to release downstream resets.

5. clk_wiz_wrapper.v — MMCME2_BASE instantiation

clk_wiz_wrapper.v
// clk_wiz_wrapper.v — Xilinx MMCME2_BASE wrapper
// Generates 200 MHz and 25 MHz from a 100 MHz reference.
// Fvco = 100 * 10 / 1 = 1000 MHz (within 600-1200 MHz range)
// clk_200: Fvco / 5  = 200 MHz
// clk_25:  Fvco / 40 = 25 MHz
//
// In production, replace this with Vivado Clocking Wizard IP
// (IP Catalog → Clocking Wizard) which generates this instantiation
// automatically and includes proper UCF/XDC constraints.

module clk_wiz_wrapper (
    input  wire clk_in,    // 100 MHz input
    input  wire reset,     // active-high reset
    output wire clk_200,   // 200 MHz output
    output wire clk_25,    // 25 MHz output
    output wire locked     // PLL locked indicator
);

// Internal wires for MMCM outputs (unbuffered)
wire clk_200_int, clk_25_int;
wire clkfb_out, clkfb_in;

// ---- BUFG: global clock buffers ----
// Route PLL outputs through global clock buffers for low-skew distribution
BUFG buf_200 (.I(clk_200_int), .O(clk_200));
BUFG buf_25  (.I(clk_25_int),  .O(clk_25));

// ---- MMCME2_BASE instantiation ----
MMCME2_BASE #(
    // Input clock
    .CLKIN1_PERIOD   (10.0),     // 100 MHz = 10 ns period

    // VCO configuration: Fvco = 100 * 10 / 1 = 1000 MHz
    .CLKFBOUT_MULT_F (10.0),     // M = 10 (VCO multiply)
    .DIVCLK_DIVIDE   (1),        // D = 1  (input divider)

    // Output 0: 200 MHz (Fvco / 5)
    .CLKOUT0_DIVIDE_F(5.0),
    .CLKOUT0_PHASE   (0.0),
    .CLKOUT0_DUTY_CYCLE(0.5),

    // Output 1: 25 MHz (Fvco / 40)
    .CLKOUT1_DIVIDE  (40),
    .CLKOUT1_PHASE   (0.0),
    .CLKOUT1_DUTY_CYCLE(0.5),

    // Unused outputs disabled
    .CLKOUT2_DIVIDE  (1),
    .CLKOUT3_DIVIDE  (1),
    .CLKOUT4_DIVIDE  (1),
    .CLKOUT5_DIVIDE  (1),
    .CLKOUT6_DIVIDE  (1),

    .BANDWIDTH       ("OPTIMIZED"),
    .STARTUP_WAIT    ("FALSE"),
    .REF_JITTER1     (0.010)     // expected input jitter in UI (10 ps)
) mmcm_inst (
    // Inputs
    .CLKIN1   (clk_in),
    .RST      (reset),
    .PWRDWN   (1'b0),

    // Feedback (use internal feedback for simplicity)
    .CLKFBOUT (clkfb_out),
    .CLKFBIN  (clkfb_out),  // internal feedback loop

    // Outputs
    .CLKOUT0  (clk_200_int),
    .CLKOUT1  (clk_25_int),
    .CLKOUT0B (),
    .CLKOUT1B (),
    .CLKOUT2  (),
    .CLKOUT2B (),
    .CLKOUT3  (),
    .CLKOUT3B (),
    .CLKOUT4  (),
    .CLKOUT5  (),
    .CLKOUT6  (),
    .CLKFBOUTB(),

    // Status
    .LOCKED   (locked)
);

endmodule

6. Using Vivado Clock Wizard IP (recommended workflow)

In real projects, use the Clocking Wizard IP rather than instantiating MMCM primitives directly. The wizard validates your frequency targets, computes optimal M/D/O values, and generates XDC constraints automatically.

  1. Open Vivado IP Catalog → Search "Clocking Wizard"
  2. Set input frequency (100 MHz), enable output clocks, enter target frequencies
  3. The tool computes M/D/O and reports achieved frequency and jitter
  4. Generate → Vivado creates clk_wiz_0.v wrapper + XDC constraints
  5. Instantiate clk_wiz_0 in your top module and gate resets with locked

7. Reset sequencing with locked

top_with_pll.v (snippet)
// Pattern: hold all logic in reset until PLL is locked
// Always use this — glitches during PLL lock-up corrupt state machines

module top (
    input  wire sys_clk,    // 100 MHz board clock
    input  wire sys_rst_n   // active-low board reset button
);

wire clk_200, clk_25, locked;
wire pll_rst = ~sys_rst_n;

clk_wiz_wrapper pll (
    .clk_in  (sys_clk),
    .reset   (pll_rst),
    .clk_200 (clk_200),
    .clk_25  (clk_25),
    .locked  (locked)
);

// Synchronous reset derived from locked signal
// Logic only runs when PLL is stable
reg rst_200_r1, rst_200;
always @(posedge clk_200) begin
    rst_200_r1 <= ~locked;
    rst_200    <= rst_200_r1;   // 2-stage sync for safe CDC
end

// Your 200 MHz logic here, reset with rst_200
// ...

endmodule

Key Takeaways

Frequently Asked Questions

What is the difference between PLL and MMCM?

Both generate derived clocks. The MMCM (Mixed-Mode Clock Manager) supports fractional dividers, fine phase shift (~11 ps resolution), and more output ports. The PLLE2 has lower jitter for integer ratios. Use MMCM via Clock Wizard for most designs; PLLE2 for lowest-jitter integer applications.

Why can't you simulate PLLs behaviourally?

PLLs are analogue circuits. Behavioural simulation cannot model VCO lock time, phase noise, or jitter — it just starts the output clock after a fixed simulation delay. Design your reset sequencing to wait for locked — this pattern works in both simulation and hardware.

How do you calculate PLL output frequency?

Fout = Fin × M / (D × O). Choose M and D to put Fvco in the valid range (600–1200 MHz for 7-series), then choose O for the desired output. Example: 100 MHz → 25 MHz: D=1, M=10, O=40 → Fvco=1000 MHz ✓

← Previous
Day 17: Clock Domain Crossing