Xilinx DDR3 MIG Series – Clock Architecture for DDR3 Controllers

Contents of this section

1. Clock architecture of ddr3 controller
1. PLL input clock - system clock system_clk
2. PLL output clock - sync_pulse, mem_refclk, freq_refclk, input clock of MMCM1
3. Input clock and output clock of MMCM1
4. Input clock and output clock of MMCM2

1. Clock architecture of ddr3 controller
For FPGA development, when calling IP or transplanting functional modules, the first thing to understand is the clock architecture of the module.
How to design the clock architecture is crucial, and secondly, some excellent design ideas can be used as a reference.
According to ug586_7Series_MIS, we can understand generally all clock architectures, and the manual provides specific clock design methods. Afterwards, each clock will be analyzed to understand the functions and uses of the corresponding clock.
As can be seen from the clock diagram, the PHY design uses one PLL and two MMCMs (the corresponding MMCM1 needs to be in the same bank as the PLL to compensate for the insertion delay).
Fix the PLL and MMCM1 in the same Bank through position constraints. This method can be used to solve timing optimization. By fixing Position constraints ensure that the two clock shews are almost consistent through wiring.

1. PLL input clock – system clock system_clk
In the corresponding position in the IP generation interface, there are three options: Differential, Single-Ended, and No buffer.
Selecting differential or single-ended will consume bufg. If the clock input at the top level has already passed through bufg, using No buffer here can save a bufg resource.
What needs to be noted here is: the selection of input clock frequency needs to be consistent with the hardware design. This series of courses uses a single-ended clock 200M, and the configuration is as follows:
There is also a small bug, which is a display bug in vivado and does not save the Input Clock period we set.
When transplanting other people’s projects, you need to pay attention to this. There are two ways. The first way can be to confirm the clock provided by the hardware, but generally this is the 200m clock generated by the FPGA developer through the PLL at the top level. The other way can Confirm through the xdc constraint file of the MIG IP of the old project.


Let’s look specifically at the code generation module and see how it corresponds?
In the mig_7series_v4_2_clk_ibuf.v module, different configuration settings are achieved through parameterized SYSCKL_TYPE and generate if function blocks.
This method is worth learning from and can be used in projects to be compatible with different designs. From the code below, only no buffer does not occupy clock resources.

2. PLL output clock-sync_pulse, mem_refclk, freq_refclk, input clock of MMCM1
There are four main uses for the PLL output: generating clocks for internal (FPGA) logic, generating clocks for write path (output) I/O logic, generating clocks for read path (input) and delayed I/O logic. Clock, generates the clock used for IDELAY reference clock.
Note: The top-level parameters that finally take effect are passed layer by layer to the underlying modules.

//********************************************** ****************************
   // The following parameters are multiplier and divisor factors for PLLE2.
   // Based on the selected design frequency these parameters vary.
   //************************************************ ***************************
   parameter CLKIN_PERIOD = 5000, // Input Clock Period
   parameter CLKFBOUT_MULT = 8, // write PLL VCO multiplier
   parameter DIVCLK_DIVIDE = 1, // write PLL VCO divisor
   parameter CLKOUT0_PHASE = 337.5, // Phase for PLL output clock (CLKOUT0)
   parameter CLKOUT0_DIVIDE = 2, // VCO output divisor for PLL output clock (CLKOUT0)
   parameter CLKOUT1_DIVIDE = 2, // VCO output divisor for PLL output clock (CLKOUT1)
   parameter CLKOUT2_DIVIDE = 32, // VCO output divisor for PLL output clock (CLKOUT2)
   parameter CLKOUT3_DIVIDE = 8, // VCO output divisor for PLL output clock (CLKOUT3)
   parameter MMCM_VCO = 800, // Max Freq (MHz) of MMCM VCO
   parameter MMCM_MULT_F = 4, // write MMCM VCO multiplier
   parameter MMCM_DIVCLK_DIVIDE = 1, // write MMCM VCO divisor


(1)sync_pulse
Manual requirements: sync_pulse must be 1/16 of the mem_refclk frequency, and the duty cycle must be 1/16 or 6.25%.
CLK_OUT2 of PLLE2_ADV is a synchronization pulse, and the input clock is 5000ps=5ns, which is 200M

 localparam real CLKIN1_PERIOD_NS = CLKIN_PERIOD / 1000.0;
  localparam CLKOUT4_DIVIDE = 2 * CLKOUT1_DIVIDE;
  localparam integer VCO_PERIOD
             = (CLKIN1_PERIOD_NS * DIVCLK_DIVIDE * 1000) / CLKFBOUT_MULT;
  localparam CLKOUT0_PERIOD = VCO_PERIOD * CLKOUT0_DIVIDE;
  localparam CLKOUT1_PERIOD = VCO_PERIOD * CLKOUT1_DIVIDE;
  localparam CLKOUT2_PERIOD = VCO_PERIOD * CLKOUT2_DIVIDE;
  localparam CLKOUT3_PERIOD = VCO_PERIOD * CLKOUT3_DIVIDE;
  localparam CLKOUT4_PERIOD = VCO_PERIOD * CLKOUT4_DIVIDE;
  localparam CLKOUT4_PHASE = (SIMULATION == "TRUE") ? 22.5 : 168.75;
  localparam real CLKOUT3_PERIOD_NS = CLKOUT3_PERIOD / 1000.0;
  localparam real CLKOUT4_PERIOD_NS = CLKOUT4_PERIOD / 1000.0;

VCO_PERIOD=(CLKIN1_PERIOD_NS * DIVCLK_DIVIDE * 1000) / CLKFBOUT_MULT
=(5000/100011000)/8=625ps
Clock period of sync_pulse: CLKOUT2_PERIOD = VCO_PERIOD * CLKOUT2_DIVIDE=62532=20000ps=20ns
Clock period of mem_refclk: CLKOUT1_PERIOD = VCO_PERIOD * CLKOUT1_DIVIDE=625
2=1250ps
The clock frequency of sync_pulse is 1/16 of mem_refclk. Observing the simulation results, it is true that the total cycle is 1250ps + 18750ps=20ns, and the duty cycle is 1250ps/20000ps=1/16.

(2) The clock cycle of mem_refclk is 1250ps and the clock frequency is 800M
The one corresponding to 800M here is Clock Period

(3) The clock cycle of freq_refclk is 79ps + 1171ps = 1250ps, and the clock frequency is 800M
(4) The clock cycle of pll_clk3_out is 1250ps + 3671ps + 79ps = 5000ps, and the clock frequency is 200M, which is mainly used for the input of MMCM1.

3. Input clock and output clock of MMCM1
(1) The input clock of MMCM1 comes from pll_clk3, which is 200M clock
(2) The output clock used inside the FPGA is clk, that is, PHY_Clk in the figure, which comes from CLKFBOUT of MMCM1.
(3)MMCM Phase shift clok is mmcm_ps_clk=1250ps + 3671ps + 79ps + 1171ps + 3829ps=10ns
4. Input clock and output clock of MMCM2
The input clock of MMCM2 can also be configured through the UI interface.
There will also be bugs here, choose to set up the system clock.

The code function is implemented in the mig_7series_v4_2_iodelay_ctrl.v module, which mainly involves IDELAYCTRL, so a reference clock needs to be introduced.
Introduction in the manual: For DDR3 design, the generation of IDELAY reference clock requires an MMCM2. If the design frequency is >667 MHz, the IDELAY reference clock is 300 MHz or 400MHz (depending on the FPGA speed grade). MIG instantiates a MMCM2 for 300 MHz and 400 MHz clock generation.

## FPGA Family: ZYNQ
## FPGA Part: XC7Z100-FFG900
## Speedgrade: -2
## Design Entry: VERILOG
## Frequency: 800 MHz
## Time Period: 1250 ps
   parameter STARVE_LIMIT = 2, // # = 2,3,4.
   parameter REF_CLK_MMCM_IODELAY_CTRL = "TRUE",

// reference clock 300MHz and 400MHz generation with MMCM
  generate
    if (REF_CLK_MMCM_IODELAY_CTRL == "TRUE") begin: clk_ref_mmcm_gen
      MMCME2_ADV
      #(.BANDWIDTH ("HIGH"),
        .CLKOUT4_CASCADE ("FALSE"),
        .COMPENSATION ("INTERNAL"),
        .STARTUP_WAIT ("FALSE"),
        .DIVCLK_DIVIDE (1),
        .CLKFBOUT_MULT_F (6),
        .CLKFBOUT_PHASE (0.000),
        .CLKFBOUT_USE_FINE_PS ("FALSE"),
        .CLKOUT0_DIVIDE_F (4),
        .CLKOUT0_PHASE (0.000),
        .CLKOUT0_DUTY_CYCLE (0.500),
        .CLKOUT0_USE_FINE_PS ("FALSE"),
        .CLKOUT1_DIVIDE (3),
        .CLKOUT1_PHASE (0.000),
        .CLKOUT1_DUTY_CYCLE (0.500),
        .CLKOUT1_USE_FINE_PS ("FALSE"),
        .CLKIN1_PERIOD (5),
        .REF_JITTER1 (0.000))
      mmcm_i
        //Output clocks
       (.CLKFBOUT (mmcm_clkfbout),
        .CLKFBOUTB (),
        .CLKOUT0 (clk_ref_mmcm_300),
        .CLKOUT0B (),
        .CLKOUT1 (clk_ref_mmcm_400),
        .CLKOUT1B (),
        .CLKOUT2 (),
        .CLKOUT2B (),
        .CLKOUT3 (),
        .CLKOUT3B (),
        .CLKOUT4 (),
        .CLKOUT5 (),
        .CLKOUT6 (),
         //Input clock control
        .CLKFBIN (mmcm_clkfbout),
        .CLKIN1 (clk_ref_ibufg),
        .CLKIN2 (1'b0),
         // Tied to always select the primary input clock
        .CLKINSEL (1'b1),
        // Ports for dynamic reconfiguration
        .DADDR (7'h0),
        .DCLK (1'b0),
        .DEN (1'b0),
        .DI (16'h0),
        .DO(),
        .DRDY(),
        .DWE (1'b0),
        // Ports for dynamic phase shift
        .PSCLK (1'b0),
        .PSEN (1'b0),
        .PSINCDEC (1'b0),
        .PSDONE(),
        // Other control and status signals
        .LOCKED (mmcm_Locked),
        .CLKINSTOPPED (),
        .CLKFBSTOPPED (),
        .PWRDWN (1'b0),
        .RST (sys_rst_act_hi));
    end
  endgenerate

  generate
    if (REF_CLK_MMCM_IODELAY_CTRL == "TRUE") begin : clk_ref_300_400_en
      if(FPGA_SPEED_GRADE == 1) begin: clk_ref_300
        BUFG u_bufg_clk_ref_300
          (
           .O (clk_ref[1]),
           .I (clk_ref_mmcm_300)
           );
      end else if (FPGA_SPEED_GRADE == 2 || FPGA_SPEED_GRADE == 3) begin: clk_ref_400
        BUFG u_bufg_clk_ref_400
          (
           .O (clk_ref[1]),
           .I (clk_ref_mmcm_400)
           );
      end
    end
  endgenerate

  generate
    if ((REFCLK_TYPE == "DIFFERENTIAL") ||
        (REFCLK_TYPE == "SINGLE_ENDED") ||
        (REFCLK_TYPE == "USE_SYSTEM_CLOCK" & amp; & amp; SYSCLK_TYPE != "NO_BUFFER")) begin: clk_ref_200
      BUFG u_bufg_clk_ref
       (
        .O (clk_ref[0]),
        .I (clk_ref_ibufg)
        );
    end else begin: clk_ref_200_no_buffer
      assign clk_ref[0] = clk_ref_i;
    end
  endgenerate
  //************************************************ *****************
  //IDELAYCTRL reset
  // This assumes an external clock signal driving the IDELAYCTRL
  // blocks. Otherwise, if a PLL drives IDELAYCTRL, then the PLL
  // lock signal will need to be incorporated in this.
  //************************************************ *****************
  // Add PLL lock if PLL drives IDELAYCTRL in user design
  assign rst_tmp_idelay = sys_rst_act_hi;


  generate
    if (REF_CLK_MMCM_IODELAY_CTRL == "TRUE") begin: rst_ref_gen_1
      always @(posedge clk_ref[1] or posedge rst_tmp_idelay)
        if (rst_tmp_idelay)
          rst_ref_sync_r[1] <= #TCQ {RST_SYNC_NUM{1'b1}};
        else
          rst_ref_sync_r[1] <= #TCQ rst_ref_sync_r[1] << 1;
      assign rst_ref[1] = rst_ref_sync_r[1][RST_SYNC_NUM-1];
    end
  endgenerate

  always @(posedge clk_ref[0] or posedge rst_tmp_idelay)
    if (rst_tmp_idelay)
      rst_ref_sync_r[0] <= #TCQ {RST_SYNC_NUM{1'b1}};
    else
      rst_ref_sync_r[0] <= #TCQ rst_ref_sync_r[0] << 1;

  assign rst_ref[0] = rst_ref_sync_r[0][RST_SYNC_NUM-1];
  //************************************************ *****************
  generate
    if (REF_CLK_MMCM_IODELAY_CTRL == "TRUE") begin: idelayctrl_gen_1
      (*IODELAY_GROUP = IODELAY_GRP1 *) IDELAYCTRL u_idelayctrl_300_400
        (
         .RDY (iodelay_ctrl_rdy[1]),
         .REFCLK (clk_ref[1]),
         .RST (rst_ref[1])
         );
    end
  endgenerate
  (*IODELAY_GROUP = IODELAY_GRP0 *) IDELAYCTRL u_idelayctrl_200
    (
     .RDY (iodelay_ctrl_rdy[0]),
     .REFCLK (clk_ref[0]),
     .RST (rst_ref[0])
     );

The chip model is: XC7Z100-FFG900-2, the speed level is 2, and the reference clock used here is 400MHz.
The output clock can be observed through the simulation diagram:
Input clk_ref_i=3333ps + 1667ps=5000ps, clock frequency is 200M
Output clk_ref_mmcm_300=3333ps, clock frequency is 300M