PLL_ChargePumpPLL

PLL_ChargePumpPLL : A charge-pump phase-locked loop (PLL)

A phase-locked loop (PLL) is a feedback system that generates an output clock of which phase is aligned with that of the input clock. In particular, a charge-pump phase-locked loop (CP-PLL) is a PLL that uses a charge-pump-based loop filter, which has a pole located at DC and can achieve a zero static phase error regardless of the input frequency.

This CP-PLL model is composed of a linear phase-frequency detector (PFD), a charge-pump loop filter, a voltage-controlled oscillator (VCO), and a frequency divider. The PFD compares the phases of the input clock in and feedback clock fb and expresses their error using the pulsewidth difference of the up and dn outputs. The charge-pump loop filter then adjusts the control voltage vc in response to this error. And the VCO generates a set of multiphase clocks out of which frequency and phase are controlled by vc. When a frequency divider with a dividing ratio of N is present in the feedback path, the PLL generates an N-times higher-frequency output clocks out than the input clock in.

Input/Output Terminals

Name I/O Type Description
out[7:0] output xbit output clocks
in input xbit input clock

Parameters

Name Type Default Description
Iup real 100e-6 charge-pump up current
Idn real 100e-6 charge-pump down current
Vinit real 0.5 initial control voltage
Rs real 20e3 loop-filter series resistance
Cs real 0.79e-12 loop-filter series capacitance
Cp real 79e-15 loop-filter shunt capacitance

List of Children Cells

BLK_ChargePumpLoopFilter : A loop filter for charge-pump PLL
DIV_ProgDividerSyncRetimer : A programmable frequency divider with a synchronous retimer
OSC_LinearVCO8O : A voltage-controlled oscillator (VCO) with a linear V-to-f characteristic and 8 outputs
PDC_LinearPFD : A linear phase-frequency detector (PFD)

List of Testbenches

tb_check_lock : A testbench for checking the locking behavior of a PLL
tb_meas_freqstep : A testbench for measuring the frequency step response of a PLL
tb_meas_jhist : A testbench for measuring the jitter histogram of a PLL output clock
tb_meas_jtran : A testbench for measuring the jitter transfer characteristics of a PLL
tb_meas_phasestep : A testbench for measuring the phase step response of a PLL
tb_meas_phnoise_cpmismatch : A testbench for measuring the reference spurs of a PLL due to charge pump current mismatch

tb_check_lock : A testbench for checking the locking behavior of a PLL

This testbench checks if a phase-locked loop (PLL) can successfully acquire a lock by simulating its locking transient. The testbench applies a fixed-frequency reference clock to the PLL, of which initial frequency starts from a value far from the desired lock position. The frequency and phase trajectories of the PLL output clock indicate whether the PLL has the capability of acquiring the correct lock when it is started from the said initial condition.

`include "xmodel.h"

module tb_check_lock();	

    parameter real freq_ref = 2.0e9;    // reference clock frequency 

    xbit clk_ref;                       // reference clock
    xbit [7:0] clk_out;                 // output clock
    xbit clk_out0;                      // alias for clk_out[0]

    // DUT phase-locked loop
    PLL_ChargePumpPLL  DUT (.in(clk_ref), .out(clk_out));

    // reference clock generator
    clk_gen #(.freq(freq_ref))  clk_gen(clk_ref);
    
    // probing
    initial begin
        $xmodel_dumpfile();
        $xmodel_dumpvars("level=", 2);
    end
    assign clk_out0 = clk_out[0];
    probe_freq  fq_out(clk_out0);
    probe_phase #(.freq(8*freq_ref)) ph_out(clk_out0);

endmodule

Simulation Results

Figure. locking transients of the output clock’s frequency and phase.

steady-state waveforms of the input and output clocks

Figure. steady-state waveforms of the input and output clocks.

tb_meas_freqstep : A testbench for measuring the frequency step response of a PLL

This testbench measures the response of a PLL to a step change in its input clock frequency. Once the PLL acquires a lock, the testbench applies a step change in its input clock frequency using the step_gen and freq_to_clk primitives. The responses in the output clock frequency and phase indicate the loop bandwidth and stability of the PLL.

`include "xmodel.h"

module tb_meas_freqstep();	

    parameter real freq_ref = 2.0e9;        // reference frequency 
    parameter real freq_step = 200e6;       // frequency step amount
    parameter real step_delay = 100e-9;     // frequency step delay

    xreal   freq_in;                        // input frequency
    xbit    clk_ref;                        // reference clock
    xbit    [7:0] clk_out;                  // output clock
    xbit    clk_out0;                       // alias for clk_out0

    // DUT phase-locked loop
    PLL_ChargePumpPLL  DUT (.in(clk_ref), .out(clk_out));

    // frequency step generator
    step_gen    #(.init_value(freq_ref), .change(freq_step), .delay(step_delay))
                freq_gen(freq_in);
    freq_to_clk clk_gen(.in(freq_in), .out(clk_ref));

    // probing
    initial begin
        $xmodel_dumpfile();
        $xmodel_dumpvars("level=", 2);
    end
    
    assign clk_out0 = clk_out[0];
    probe_freq  fq_out(clk_out0);
    probe_freq  fq_in(clk_ref);

endmodule

Simulation Results

frequency step response of the PLL

Figure. frequency step response of the PLL.

tb_meas_jhist : A testbench for measuring the jitter histogram of a PLL output clock

This testbench measures the jitter histogram and phase noise spectrum of the output clock of a phase-locked loop (PLL). The testbench first lets the PLL acquire a lock by applying a fixed-frequency clock input and waiting for the PLL responses to settle. Then it collects the output clock transitions and analyzes the jitter histogram and phase noise spectrum. The jitter histogram shows the probability density function of the clock edge position and the phase noise spectrum shows the frequency content of the jitter or phase noise. The jitter and phase noise of a PLL output clock can be contributed by the noise from the input clock and internal components.

`include "xmodel.h"

module tb_meas_jhist();	

    parameter real freq_ref = 2.0e9;    // reference clock frequency 
    parameter real RJ_rms = 10e-12;     // reference clock random jitter (RMS)
    parameter real t_lock = 200e-9;     // time required for PLL to lock

    xbit clk_ref;                       // reference clock
    xbit [7:0] clk_out;                 // output clock
    xbit clk_out0;                      // alias for clk_out0

    // DUT phase-locked loop
    PLL_ChargePumpPLL  DUT(.in(clk_ref), .out(clk_out));

    // reference clock generator
    clk_gen     #(.freq(freq_ref), .RJ_rms(RJ_rms))
                clk_gen(clk_ref);

    // probing
    assign clk_out0 = clk_out[0];
    probe_xbit  #(.start(t_lock)) probe_out(clk_out0);
    
endmodule

Simulation Results

jitter histogram of PLL output clock

Figure. jitter histogram of PLL output clock.

phase noise spectrum of PLL output clock

Figure. phase noise spectrum of PLL output clock.

tb_meas_jtran : A testbench for measuring the jitter transfer characteristics of a PLL

This testbench measures the jitter transfer characteristics of a phase-locked loop (PLL). The testbench measures the jitter transfer function at each frequency by applying a sinusoidal jitter to the input clock using a clk_gen primitive and measuring the magnitude and phase of the resulting sinusoidal response in the output clock phase. The jtran.py script repeats this measurement while sweeping the sinusoidal jitter frequency and constructs the overall jitter transfer function of the PLL.

`include "xmodel.h"

module tb_meas_jtran();	
	  
    parameter real ref_freq = @ref_freq;    // input clock frequency 
    parameter real SJ_amp = @sj_amp;        // input sinusoidal jitter amplitude in UI
    parameter real SJ_freq = @sj_freq;      // input sinusoidal jitter frequency in Hz
    parameter real t_lock = @t_lock;        // initial simulation time (PLL locking time) 

    xbit clk_ref;                           // reference clock
    xbit [7:0] clk_out;                     // output clock
    xbit clk_out0;                          // alias for clk_out[0]

    // charge-pump phase-locked loop
    PLL_ChargePumpPLL   #(.Iup(100e-6), .Idn(100e-6),
                  .Rs(20e3), .Cs(790e-15), .Cp(79e-15), .Vinit(0.4))
                cp_pll(.in(clk_ref),.out(clk_out));

    // reference clock generator with sinusoidal jitter
    clk_gen     #(.freq(ref_freq), .SJ_amp(SJ_amp), .SJ_freq(SJ_freq))
                clk_gen(clk_ref);

    // probing
    assign clk_out0 = clk_out[0];
    probe_phase #(.freq(ref_freq*8), .start(t_lock), .phase_wrap(0))  
                probe_phase(clk_out0);

endmodule

Simulation Results

jitter transfer function of the PLL

Figure. jitter transfer function of the PLL.

tb_meas_phasestep : A testbench for measuring the phase step response of a PLL

This testbench measures the response of a PLL to a step change in its input clock phase. Once the PLL acquires a lock, the testbench applies a step change in its input clock phase using the step_gen and phase_to_clk primitives. The responses in the output clock frequency and phase indicate the loop bandwidth and stability of the PLL.

`include "xmodel.h"

module tb_meas_phasestep();	

    parameter real freq_ref = 2.0e9;        // reference frequency 
    parameter real phase_step = 0.1*M_PI;   // phase step amount
    parameter real step_delay = 100e-9;     // phase step delay

    xreal phase_ref;                        // reference phase
    xbit clk_ref;                           // reference clock
    xbit [7:0] clk_out;                     // output clock
    xbit clk_out0;                          // alias for clk_out0

    // DUT phase-locked loop
    PLL_ChargePumpPLL      DUT(.in(clk_ref), .out(clk_out));

    // phase step generator
    step_gen        #(.init_value(0.0), .change(phase_step), .delay(step_delay))
                    phase_gen(phase_ref);
    phase_to_clk    #(.freq(freq_ref)) clk_gen(.in(phase_ref), .out(clk_ref));

    // probing
    initial begin
        $xmodel_dumpfile();
        $xmodel_dumpvars("level=", 2);
    end
    
    assign clk_out0 = clk_out[0];
    probe_freq      fq_out(clk_out0);
    probe_phase     #(.freq(freq_ref*8), .phase_wrap(0)) ph_out(clk_out0);
    probe_phase     #(.freq(freq_ref)) ph_ref(clk_ref);

endmodule

Simulation Results

phase step response of the PLL

Figure. phase step response of the PLL.

tb_meas_phnoise_cpmismatch : A testbench for measuring the reference spurs of a PLL due to charge pump current mismatch

This testbench measures the phase noise spectrum of a phase-locked loop (PLL) when its charge pump has a mismatch between the up and down currents Iup and Idn. Such current mismatch may cause periodic disturbance on the control voltage, resulting in the periodic jitter in the output clock and the reference spurs in the phase noise spectrum. The testbench setup is identical to the testbench for measuring the jitter histogram, first letting the PLL acquire a lock to a fixed-frequency clock input and collecting the output clock transitions to analyze the phase noise spectrum. Reference spurs are spurious tones observed in the phase noise spectrum at frequency offsets equal to the integer multiples of the reference frequency.

`include "xmodel.h"

module tb_meas_phnoise_cpmismatch();	

    parameter real freq_ref = 2.0e9;    // reference clock frequency 
    parameter real t_lock = 200e-9;     // time required for PLL to lock

    xbit clk_ref;                       // reference clock
    xbit [7:0] clk_out;                 // output clock
    xbit clk_out0;                      // alias for clk_out0
    
    // DUT phase-locked loop
    PLL_ChargePumpPLL  #(.Iup(100e-6), .Idn(200e-6))
                DUT(.in(clk_ref), .out(clk_out));

    // reference clock generator
    clk_gen     #(.freq(freq_ref)) clk_gen(clk_ref);

    // probing
    initial begin
        $xmodel_dumpfile();
        $xmodel_dumpvars("level=", 1, DUT);
    end
    
    assign clk_out0 = clk_out[0];
    probe_xbit  #(.start(t_lock)) probe_out(clk_out0);
    probe_freq  fq_out(clk_out0);
    probe_phase #(.freq(8*freq_ref)) ph_out(clk_out0);
    
endmodule

Simulation Results

phase noise spectrum of the PLL output clock

Figure. phase noise spectrum of the PLL output clock.