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.
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:
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 ✓
| Feature | PLLE2_BASE | MMCME2_BASE |
|---|---|---|
| Output clocks | 6 | 7 (CLKOUT0–6) |
| Fractional divider | No | Yes (CLKOUT0 only, M/D) |
| Phase step resolution | 45° steps | ~11 ps (fine phase shift) |
| Dynamic reconfig | No (BASE variant) | No (BASE variant) |
| Jitter | Lower for integer ratios | Slightly higher with fractional |
| Typical use | Simple integer multiply/divide | Audio, video, spread-spectrum |
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.
| Port | Dir | Width | Description |
|---|---|---|---|
| clk_in | IN | 1 | Reference clock input (100 MHz from board oscillator) |
| reset | IN | 1 | Active-high PLL reset. Assert briefly at startup then release. |
| clk_200 | OUT | 1 | 200 MHz output clock (M=10, D=1, O=5) |
| clk_25 | OUT | 1 | 25 MHz output clock (M=10, D=1, O=40) |
| locked | OUT | 1 | High when PLL is locked. Use to release downstream resets. |
// 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
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.
clk_wiz_0.v wrapper + XDC constraintsclk_wiz_0 in your top module and gate resets with locked// 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
locked is assertedBoth 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.
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.
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 ✓