xilinx/MMCM/DRP/使用

 

 

//------------------------------------------------------------------------------------------
//   ____  ____
//  /   /\/   /
// /___/  \  /
// \   \   \/    锟? Copyright 2019 Xilinx, Inc. All rights reserved.
//  \   \        This file contains confidential and proprietary information of Xilinx, Inc.
//  /   /        and is protected under U.S. and international copyright and other
// /___/   /\    intellectual property laws.
// \   \  /  \
//  \___\/\___\
//
//-------------------------------------------------------------------------------------------
// Device:              7-Series
// Author:              Tatsukawa, Kruger, Defossez
// Entity Name:         top_mmcme2
// Purpose:             This is a basic demonstration of the MMCM_DRP
//                      connectivity to the MMCM_ADV.
// Tools:               Vivado_2019.1 or newer
// Limitations:
//
// Vendor:              Xilinx Inc.
// Version:             1.40
// Filename:            top_mmcme2.v
// Date Created:        30-Jul-2014
// Date Last Modified:  25-Jun-2019
//-------------------------------------------------------------------------------------------
// Disclaimer:
//        This disclaimer is not a license and does not grant any rights to the materials
//        distributed herewith. Except as otherwise provided in a valid license issued to you
//        by Xilinx, and to the maximum extent permitted by applicable law: (1) THESE MATERIALS
//        ARE MADE AVAILABLE "AS IS" AND WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL
//        WARRANTIES AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED
//        TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR
//        PURPOSE; and (2) Xilinx shall not be liable (whether in contract or tort, including
//        negligence, or under any other theory of liability) for any loss or damage of any
//        kind or nature related to, arising under or in connection with these materials,
//        including for any direct, or any indirect, special, incidental, or consequential
//        loss or damage (including loss of data, profits, goodwill, or any type of loss or
//        damage suffered as a result of any action brought by a third party) even if such
//        damage or loss was reasonably foreseeable or Xilinx had been advised of the
//        possibility of the same.
//
// CRITICAL APPLICATIONS
//        Xilinx products are not designed or intended to be fail-safe, or for use in any
//        application requiring fail-safe performance, such as life-support or safety devices
//        or systems, Class III medical devices, nuclear facilities, applications related to
//        the deployment of airbags, or any other applications that could lead to death,
//        personal injury, or severe property or environmental damage (individually and
//        collectively, "Critical Applications"). Customer assumes the sole risk and
//        liability of any use of Xilinx products in Critical Applications, subject only to
//        applicable laws and regulations governing limitations on product liability.
//
// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE AT ALL TIMES.
//
// Contact:    e-mail  hotline@xilinx.com        phone   + 1 800 255 7778
//-------------------------------------------------------------------------------------------
// Revision History:
//  Rev: 30-Apr-2014 - Tatsukawa
//      Initial code release
//  Rev: 25-Jun-2019 - Defossez
//      Add possibility to register the LOCKED signal.
//-------------------------------------------------------------------------------------------
//
`timescale 1ps/1ps
//
//-------------------------------------------------------------------------------------------
// Entity pin description
//-------------------------------------------------------------------------------------------
// Inputs
//      SSTEP:      Start a reconfiguration. It should only be pulsed for one clock cycle.
//      STATE:      Determines which state the MMCM_ADV will be reconfigured to. A value
//                  of 0 correlates to state 1, and a value of 1 correlates to state 2.
//      RST:        RST will reset the entire reference design including the MMCM_ADV.
//      CLKIN:      Clock for the MMCM_ADV CLKIN as well as the clock for the MMCM_DRP module
//      SRDY:       Pulses for one clock cycle after the MMCM_ADV is locked and the
//                  MMCM_DRP module is ready to start another re-configuration.
// Outputs
//      LOCKED_OUT: MMCM is locked after configuration or reconfiguration.
//      CLK0OUT:    These are the clock outputs from the MMCM_ADV.
//      CLK1OUT:    These are the clock outputs from the MMCM_ADV.
//      CLK2OUT:    These are the clock outputs from the MMCM_ADV.
//      CLK3OUT:    These are the clock outputs from the MMCM_ADV.
//      CLK4OUT:    These are the clock outputs from the MMCM_ADV.
//      CLK5OUT:    These are the clock outputs from the MMCM_ADV.
//      CLK6OUT:    These are the clock outputs from the MMCM_ADV.
//-------------------------------------------------------------------------------------------
module top_mmcme2
    (
        input    SSTEP,
        input [1:0]   STATE,
        input    RST,
        input    CLKIN,
        output   SRDY,
         output      LOCKED_OUT,
        output   CLK0OUT,
        output   CLK1OUT,
        output   CLK2OUT,
        output   CLK3OUT,
        output   CLK4OUT,
        output   CLK5OUT,
        output   CLK6OUT
    );
//-------------------------------------------------------------------------------------------
// These signals are used as direct connections between the MMCM_ADV and the
// MMCM_DRP.
(* mark_debug = "true" *) wire [15:0]    di;
(* mark_debug = "true" *) wire [6:0]     daddr;
(* mark_debug = "true" *) wire [15:0]    dout;
(* mark_debug = "true" *) wire           den;
(* mark_debug = "true" *) wire           dwe;
wire            dclk;
wire            rst_mmcm;
wire            drdy;
reg                current_state;
reg [7:0]        sstep_int ;
reg                init_drp_state = 1;
// These signals are used for the BUFG's necessary for the design.
wire            CLKIN_ibuf;
wire            clkin_bufgout;
wire            clkfb_bufgout;
wire            clkfb_bufgin;
wire            clk0_bufgin;
wire            clk0_bufgout;
wire            clk1_bufgin;
wire            clk1_bufgout;
wire            clk2_bufgin;
wire            clk2_bufgout;
wire            clk3_bufgin;
wire            clk3_bufgout;
wire            clk4_bufgin;
wire            clk4_bufgout;
wire            clk5_bufgin;
wire            clk5_bufgout;
wire            clk6_bufgin;
wire            clk6_bufgout;
wire            LOCKED;
//-------------------------------------------------------------------------------------------
assign CLKIN_ibuf = CLKIN;
//
BUFG BUFG_IN    (.O (clkin_bufgout),    .I (CLKIN_ibuf));
BUFG BUFG_FB    (.O (clkfb_bufgout),    .I (clkfb_bufgin));
BUFG BUFG_CLK0  (.O (CLK0OUT),     .I (clk0_bufgin));
BUFG BUFG_CLK1  (.O (clk1_bufgout),     .I (clk1_bufgin));
BUFG BUFG_CLK2  (.O (clk2_bufgout),     .I (clk2_bufgin));
BUFG BUFG_CLK3  (.O (clk3_bufgout),     .I (clk3_bufgin));
BUFG BUFG_CLK4  (.O (clk4_bufgout),     .I (clk4_bufgin));
BUFG BUFG_CLK5  (.O (clk5_bufgout),     .I (clk5_bufgin));
BUFG BUFG_CLK6  (.O (clk6_bufgout),     .I (clk6_bufgin));
//
// ODDR registers used to output clocks
// ODDR ODDR_CLK0 (.Q(CLK0OUT), .C(clk0_bufgout), .CE(1'b1), .D1(1'b1), .D2(1'b0), .R(RST), .S(1'b0));
ODDR ODDR_CLK1 (.Q(CLK1OUT), .C(clk1_bufgout), .CE(1'b1), .D1(1'b1), .D2(1'b0), .R(RST), .S(1'b0));
ODDR ODDR_CLK2 (.Q(CLK2OUT), .C(clk2_bufgout), .CE(1'b1), .D1(1'b1), .D2(1'b0), .R(RST), .S(1'b0));
ODDR ODDR_CLK3 (.Q(CLK3OUT), .C(clk3_bufgout), .CE(1'b1), .D1(1'b1), .D2(1'b0), .R(RST), .S(1'b0));
ODDR ODDR_CLK4 (.Q(CLK4OUT), .C(clk4_bufgout), .CE(1'b1), .D1(1'b1), .D2(1'b0), .R(RST), .S(1'b0));
ODDR ODDR_CLK5 (.Q(CLK5OUT), .C(clk5_bufgout), .CE(1'b1), .D1(1'b1), .D2(1'b0), .R(RST), .S(1'b0));
ODDR ODDR_CLK6 (.Q(CLK6OUT), .C(clk6_bufgout), .CE(1'b1), .D1(1'b1), .D2(1'b0), .R(RST), .S(1'b0));
//
// MMCM_ADV that reconfiguration will take place on
//
//  BANDWIDTH:              : "HIGH", "LOW" or "OPTIMIZED"
//  DIVCLK_DIVIDE           : Value from 1 to 106
//  CLKFBOUT_MULT_F         : Value from 2 to 64
//  CLKFBOUT_PHASE          :
//  CLKFBOUT_USE_FINE_PS    : "TRUE" or "FALSE",
//  CLKIN1_PERIOD           : Value from 0.968 to 100.000. Set the period (ns) of input clocks
//  REF_JITTER1             :
//  CLKIN2_PERIOD           :
//  REF_JITTER2             :
//  CLKOUT parameters:
//  DIVIDE                  : Value from 1 to 128
//  DUTY_CYCLE              : 0.01 to 0.99 - This is dependent on the divide value.
//  PHASE                   : 0.0 to 360.0 - This is dependent on the divide value.
//  USE_FINE_PS             : TRUE or FALSE
//  Misc parameters
//  COMPENSATION
//  STARTUP_WAIT
//  -------------------Fclkin 输入时钟频率
//  -------------------Fvco = (Fclkin * M) /D  ---- Fvco电压控制振荡器内部频率
//  -------------------Fout(x) = Fvco/O(x)     ---- O(x)--CLKOUTx 的分频系数
MMCME2_ADV #(
   .BANDWIDTH           ("OPTIMIZED"),
   .DIVCLK_DIVIDE       (1),  //D分频参数  输入时钟分频器(DIVCLK_DIVIDE)
   .CLKFBOUT_MULT_F     (6),//(3),  //M倍频参数  倍频因子(CLKFBOUT_MULT_F)
   .CLKFBOUT_PHASE      (0.0),
   .CLKFBOUT_USE_FINE_PS("FALSE"),
   .CLKIN1_PERIOD       (10.000),//(5.000), 
   .REF_JITTER1         (0.010),
   .CLKIN2_PERIOD       (10.000),
   .REF_JITTER2         (0.010),
   .CLKOUT0_DIVIDE_F    (24),//(24),//CLKOUTx 的分频系数
   .CLKOUT0_DUTY_CYCLE  (0.5),
   .CLKOUT0_PHASE       (0.0),
   .CLKOUT0_USE_FINE_PS ("FALSE"),
   .CLKOUT1_DIVIDE      (6), //
   .CLKOUT1_DUTY_CYCLE  (0.5),
   .CLKOUT1_PHASE       (0.0),
   .CLKOUT1_USE_FINE_PS ("FALSE"),
   .CLKOUT2_DIVIDE      (6),
   .CLKOUT2_DUTY_CYCLE  (0.5),
   .CLKOUT2_PHASE       (0.0),
   .CLKOUT2_USE_FINE_PS ("FALSE"),
   .CLKOUT3_DIVIDE      (6),
   .CLKOUT3_DUTY_CYCLE  (0.5),
   .CLKOUT3_PHASE       (0.0),
   .CLKOUT3_USE_FINE_PS ("FALSE"),
   .CLKOUT4_DIVIDE      (6),
   .CLKOUT4_DUTY_CYCLE  (0.5),
   .CLKOUT4_PHASE       (0.0),
   .CLKOUT4_USE_FINE_PS ("FALSE"),
   .CLKOUT4_CASCADE     ("FALSE"),
   .CLKOUT5_DIVIDE      (6),
   .CLKOUT5_DUTY_CYCLE  (0.5),
   .CLKOUT5_PHASE       (0.0),
   .CLKOUT5_USE_FINE_PS ("FALSE"),
   .CLKOUT6_DIVIDE      (6),
   .CLKOUT6_DUTY_CYCLE  (0.5),
   .CLKOUT6_PHASE       (0.0),
   .CLKOUT6_USE_FINE_PS ("FALSE"),
   .COMPENSATION        ("ZHOLD"),
   .STARTUP_WAIT        ("FALSE")
) mmcme2_test_inst (
   .CLKFBOUT            (clkfb_bufgin),
   .CLKFBOUTB           (),
   .CLKFBSTOPPED        (),
   .CLKINSTOPPED        (),
   .CLKOUT0             (clk0_bufgin),
   .CLKOUT0B            (),
   .CLKOUT1             (clk1_bufgin),
   .CLKOUT1B            (),
   .CLKOUT2             (clk2_bufgin),
   .CLKOUT2B            (),
   .CLKOUT3             (clk3_bufgin),
   .CLKOUT3B            (),
   .CLKOUT4             (clk4_bufgin),
   .CLKOUT5             (clk5_bufgin),
   .CLKOUT6             (clk6_bufgin),
   .DO                  (dout),
   .DRDY                (drdy),
   .DADDR               (daddr),
   .DCLK                (dclk),
   .DEN                 (den),
   .DI                  (di),
   .DWE                 (dwe),
   .LOCKED              (LOCKED),
   .CLKFBIN             (clkfb_bufgout),
   .CLKIN1              (clkin_bufgout),
   .CLKIN2              (),
   .CLKINSEL            (1'b1),
   .PSDONE              (),
   .PSCLK               (1'b0),
   .PSEN                (1'b0),
   .PSINCDEC            (1'b0),
   .PWRDWN              (1'b0),
   .RST                 (rst_mmcm)
);
// MMCM_DRP instance that will perform the reconfiguration operations
mmcme2_drp #(
    // Register the LOCKED signal with teh MMCME3_ADV input clock.
    // The LOCKED_IN (LOCKED from the MMCME3_ADV) is fed into a register and then
    // passed the LOCKED_OUT when REGISTER_LOCKED is set to "Reg" or when set to
    // "NoReg" LOCKED_IN is just passed on to LOCKED_OUT without being registered.
    .REGISTER_LOCKED       ("Reg"),
    // Use the registered LOCKED signal from the MMCME3 also for the DRP state machine.
    .USE_REG_LOCKED        ("No"),
    // Possible combination of above two parameters:
    // | REGISTER_LOCKED | USE_REG_LOCKED |                                            |
    // |-----------------|----------------|--------------------------------------------|
    // |      "NoReg"    |     "No"       | LOCKED is just passed through mmcme3_drp   |
    // |                 |                | and is used as is with the state machine   |
    // |      "NoReg"    |     "Yes"      | NOT ALLOWED                                |
    // |       "Reg"     |     "No"       | LOCKED is registered but the unregistered  |
    // |                 |                | version is used for the state machine.     |
    // |       "Reg"     |     "Yes"      | LOCKED is registered and the registered    |
    // |                 |                | version is also used by the state machine. |
    //
    //***********************************************************************
    // State 1 Parameters - These are for the first reconfiguration state.
    //***********************************************************************
    // Set the multiply to 6.0 with 0 deg phase offset, optimized bandwidth, input divide of 1
    .S1_CLKFBOUT_MULT(2),
    .S1_CLKFBOUT_PHASE(000_000),
    .S1_CLKFBOUT_FRAC(000),
    .S1_CLKFBOUT_FRAC_EN(0),
    .S1_BANDWIDTH("OPTIMIZED"),
    .S1_DIVCLK_DIVIDE(2),
    // Set clockout0 to a divide of 6.0 (unity gain), 0 deg phase offset, 50/50 duty cycle
    .S1_CLKOUT0_DIVIDE(4),//(8),
    .S1_CLKOUT0_PHASE(000_000),
    .S1_CLKOUT0_DUTY(50000),
    .S1_CLKOUT0_FRAC(000),
    .S1_CLKOUT0_FRAC_EN(0),
    // Set clockout 1 to a divide of 1, 0 deg phase offset, 50/50 duty cycle
    .S1_CLKOUT1_DIVIDE(1),
    .S1_CLKOUT1_PHASE(000_000),
    .S1_CLKOUT1_DUTY(50000),
    // Set clockout 2 to a divide of 2, 0 deg phase offset, 50/50 duty cycle
    .S1_CLKOUT2_DIVIDE(2),
    .S1_CLKOUT2_PHASE(000_000),
    .S1_CLKOUT2_DUTY(50000),
    // Set clockout 3 to a divide of 3, 0 deg phase offset, 50/50 duty cycle
    .S1_CLKOUT3_DIVIDE(3),
    .S1_CLKOUT3_PHASE(000_000),
    .S1_CLKOUT3_DUTY(50000),
    // Set clockout 4 to a divide of 4, 0 deg phase offset, 50/50 duty cycle
    .S1_CLKOUT4_DIVIDE(4),
    .S1_CLKOUT4_PHASE(000_000),
    .S1_CLKOUT4_DUTY(50000),
    // Set clockout 5 to a divide of 5, 0 deg phase offset, 50/50 duty cycle
    .S1_CLKOUT5_DIVIDE(5),
    .S1_CLKOUT5_PHASE(000_000),
    .S1_CLKOUT5_DUTY(50000),
    // Set clockout 6 to a divide of 10, 0 deg phase offset, 50/50 duty cycle
    .S1_CLKOUT6_DIVIDE(10),
    .S1_CLKOUT6_PHASE(000_000),
    .S1_CLKOUT6_DUTY(50000),
    //***********************************************************************
    // State 2 Parameters - These are for the second reconfiguration state.
    //***********************************************************************
    .S2_CLKFBOUT_MULT(2),
    .S2_CLKFBOUT_PHASE(000_000),
    .S2_CLKFBOUT_FRAC(000),
    .S2_CLKFBOUT_FRAC_EN(0),
    .S2_BANDWIDTH("OPTIMIZED"),
    .S2_DIVCLK_DIVIDE(2),
    // Set clockout 0 to a divide of 4.750, 0 deg phase offset, 50/50 duty cycle
    .S2_CLKOUT0_DIVIDE(2),//(4),
    .S2_CLKOUT0_PHASE(000_000),
    .S2_CLKOUT0_DUTY(50000),
    .S2_CLKOUT0_FRAC(000),
    .S2_CLKOUT0_FRAC_EN(0),
    // Set clockout 1 to a divide of 1, 45.0 deg phase offset, 50/50 duty cycle
    .S2_CLKOUT1_DIVIDE(1),
    .S2_CLKOUT1_PHASE(045_000),
    .S2_CLKOUT1_DUTY(50000),
    // Set clock out 0 to a divide of 1, 90.0 deg phase offset, 50/50 duty cycle
    .S2_CLKOUT2_DIVIDE(1),
    .S2_CLKOUT2_PHASE(090_000),
    .S2_CLKOUT2_DUTY(90000),
    // Set clockout3 to a divide of 1, 135.0 deg phase offset, 50/50 duty cycle
    .S2_CLKOUT3_DIVIDE(1),
    .S2_CLKOUT3_PHASE(135_000),
    .S2_CLKOUT3_DUTY(50000),
    // Set clockout4 to a divide of 1, 180.0 deg phase offset, 50/50 duty cycle
    .S2_CLKOUT4_DIVIDE(1),
    .S2_CLKOUT4_PHASE(180_000),
    .S2_CLKOUT4_DUTY(50000),
    // Set clockout5 to a divide of 1, 225.0 deg phase offset, 50/50 duty cycle
    .S2_CLKOUT5_DIVIDE(1),
    .S2_CLKOUT5_PHASE(225_000),
    .S2_CLKOUT5_DUTY(50000),
    // Set clockout6 to a divide of 1, 270.0 deg phase offset, 50/50 duty cycle
    .S2_CLKOUT6_DIVIDE(1),
    .S2_CLKOUT6_PHASE(270_000),
    .S2_CLKOUT6_DUTY(50000),
    //***********************************************************************
    // State 2 Parameters - These are for the second reconfiguration state.
    //***********************************************************************
    .S3_CLKFBOUT_MULT(2),
    .S3_CLKFBOUT_PHASE(000_000),
    .S3_CLKFBOUT_FRAC(000),
    .S3_CLKFBOUT_FRAC_EN(0),
    .S3_BANDWIDTH("OPTIMIZED"),
    .S3_DIVCLK_DIVIDE(2),
    // Set clockout 0 to a divide of 4.750, 0 deg phase offset, 50/50 duty cycle
    .S3_CLKOUT0_DIVIDE(1),//(2),
    .S3_CLKOUT0_PHASE(000_000),
    .S3_CLKOUT0_DUTY(50000),
    .S3_CLKOUT0_FRAC(000),
    .S3_CLKOUT0_FRAC_EN(0),
    // Set clockout 1 to a divide of 1, 45.0 deg phase offset, 50/50 duty cycle
    .S3_CLKOUT1_DIVIDE(1),
    .S3_CLKOUT1_PHASE(045_000),
    .S3_CLKOUT1_DUTY(50000),
    // Set clock out 0 to a divide of 1, 90.0 deg phase offset, 50/50 duty cycle
    .S3_CLKOUT2_DIVIDE(1),
    .S3_CLKOUT2_PHASE(090_000),
    .S3_CLKOUT2_DUTY(90000),
    // Set clockout3 to a divide of 1, 135.0 deg phase offset, 50/50 duty cycle
    .S3_CLKOUT3_DIVIDE(1),
    .S3_CLKOUT3_PHASE(135_000),
    .S3_CLKOUT3_DUTY(50000),
    // Set clockout4 to a divide of 1, 180.0 deg phase offset, 50/50 duty cycle
    .S3_CLKOUT4_DIVIDE(1),
    .S3_CLKOUT4_PHASE(180_000),
    .S3_CLKOUT4_DUTY(50000),
    // Set clockout5 to a divide of 1, 225.0 deg phase offset, 50/50 duty cycle
    .S3_CLKOUT5_DIVIDE(1),
    .S3_CLKOUT5_PHASE(225_000),
    .S3_CLKOUT5_DUTY(50000),
    // Set clockout6 to a divide of 1, 270.0 deg phase offset, 50/50 duty cycle
    .S3_CLKOUT6_DIVIDE(1),
    .S3_CLKOUT6_PHASE(270_000),
    .S3_CLKOUT6_DUTY(50000)
) mmcme2_drp_inst (
    .SADDR              (STATE),
    .SEN                (sstep_int[0]),
    .RST                (RST),
    .SRDY               (SRDY),
    .SCLK               (clkin_bufgout),
    .DO                 (dout),
    .DRDY               (drdy),
    .LOCK_REG_CLK_IN    (clkin_bufgout),
    .LOCKED_IN          (LOCKED),
    .DWE                (dwe),
    .DEN                (den),
    .DADDR              (daddr),
    .DI                 (di),
    .DCLK               (dclk),
    .RST_MMCM           (rst_mmcm),
    .LOCKED_OUT         (LOCKED_OUT)
);
   //***********************************************************************
   // Additional STATE and SSTEP logic for push buttons and switches
   //***********************************************************************
// The following logic is not required but is being used to allow the DRP
// circuitry work more effectively with boards that use toggle switches or
// buttons that may not adhere to the single clock requirement.
//
// Only start DRP after initial lock and when STATE has changed
always @ (posedge clkin_bufgout or posedge SSTEP)
    if (SSTEP) sstep_int <=  8'h80;
    else sstep_int <= {1'b0, sstep_int[7:1]};
//
//-------------------------------------------------------------------------------------------
endmodule
top_mmcme2

 

//-------------------------------------------------------------------------------------------
//   ____  ____
//  /   /\/   /
// /___/  \  /
// \   \   \/    锟? Copyright 2019 Xilinx, Inc. All rights reserved.
//  \   \        This file contains confidential and proprietary information of Xilinx, Inc.
//  /   /        and is protected under U.S. and international copyright and other
// /___/   /\    intellectual property laws.
// \   \  /  \
//  \___\/\___\
//
//-------------------------------------------------------------------------------------------
// Device:              7_Series
// Author:              Tatsukawa, Kruger, Ribbing, Defossez
// Entity Name:         mmcme2_drp
// Purpose:             This calls the DRP register calculation functions and
//                      provides a state machine to perform MMCM reconfiguration
//                      based on the calculated values stored in a initialized
//                      ROM.
//                      7-Series MMCM is called:            MMCME2
//                          Ultrascale MMCM is called:      MMCME3
//                          UltrascalePlus MMCM is called:  MMCME4
//                      MMCME3 attributes
//                          CLKINx_PERIOD:      0.968 to 100.000 (x = 1 or 2)
//                          REF_JITTERx:        0.001 to 0.999 (x = 1 or 2)
//                          BANDWIDTH:          LOW, HIGH, OPTIMIZED and POSTCRC
//                          COMPENSATION:       AUTO, ZHOLD, EXTERNAL, INTERNAL and BUF_IN
//                          DIVCLK_DIVIDE:      1 to 106
//                          CLKFBOUT_MULT_F:    2 to 64
//                          CLKFBOUT_PHASE:     -360 to 360
//                          CLKOUTn_DIVIDE:     1 to 128 (n = 0 to 6)
//                          CLKOUTn_PHASE:      -360 to 360 (n = 0 to 6)
//                          CLKOUTn_DUTY_CYCLE: 0.01 to 0.99 (n = 0 to 6)
//
// Tools:               Vivado_2019.1 or newer
// Limitations:         None
//
// Vendor:              Xilinx Inc.
// Version:             1.40
// Filename:            mmcme3_drp.v
// Date Created:        22-Oct-2014
// Date Last Modified:  25-Jun-2019
//-------------------------------------------------------------------------------------------
// Disclaimer:
//        This disclaimer is not a license and does not grant any rights to the materials
//        distributed herewith. Except as otherwise provided in a valid license issued to you
//        by Xilinx, and to the maximum extent permitted by applicable law: (1) THESE MATERIALS
//        ARE MADE AVAILABLE "AS IS" AND WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL
//        WARRANTIES AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED
//        TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR
//        PURPOSE; and (2) Xilinx shall not be liable (whether in contract or tort, including
//        negligence, or under any other theory of liability) for any loss or damage of any
//        kind or nature related to, arising under or in connection with these materials,
//        including for any direct, or any indirect, special, incidental, or consequential
//        loss or damage (including loss of data, profits, goodwill, or any type of loss or
//        damage suffered as a result of any action brought by a third party) even if such
//        damage or loss was reasonably foreseeable or Xilinx had been advised of the
//        possibility of the same.
//
// CRITICAL APPLICATIONS
//        Xilinx products are not designed or intended to be fail-safe, or for use in any
//        application requiring fail-safe performance, such as life-support or safety devices
//        or systems, Class III medical devices, nuclear facilities, applications related to
//        the deployment of airbags, or any other applications that could lead to death,
//        personal injury, or severe property or environmental damage (individually and
//        collectively, "Critical Applications"). Customer assumes the sole risk and
//        liability of any use of Xilinx products in Critical Applications, subject only to
//        applicable laws and regulations governing limitations on product liability.
//
// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE AT ALL TIMES.
//
// Contact:    e-mail  hotline@xilinx.com        phone   + 1 800 255 7778
//-------------------------------------------------------------------------------------------
// Revision History:
//  Rev: 13-Jan-2011 - Tatsukawa
//      Updated ROM[18,41] LOCKED bitmask to 16'HFC00
//  Rev: 30-May-2013 - Tatsukawa
//      Adding Fractional support for CLKFBOUT_MULT_F, CLKOUT0_DIVIDE_F
//  Rev: 30-Apr-2014 - Tatsukawa
//      For fractional multiply changed order to enable fractional
//      before the multiply is applied to prevent false VCO DRCs
//      (e.g. DADDR 7'h15 must be set before updating 7'h14)
//  Rev: 24-Oct-2014 - Ribbing
//      Parameters have been added to clarify Reg1/Reg2/Shared registers
//  Rev: 08-Jun-2015 - Kruger
//      WAIT_LOCK update
//  Rev: 02-May-2016 - Kruger
//      Reordering FRAC_EN bits DADDR(7'h09, 7'h15)
//      Registers before frac settings (7'h08, 7'h14)
//  Rev: 19-Sep-2018 - Defossez
//      Updated comments of BANDWIDTH.
//      Corrected some typos.
//  Rev: 25-Jun-2019 - Defossez
//      Adding registering possibility for LOCKE signal.
//-------------------------------------------------------------------------------------------
//
`timescale 1ps/1ps
//
module mmcme2_drp
    #(
        // Register the LOCKED signal with teh MMCME3_ADV input clock.
        // The LOCKED_IN (LOCKED from the MMCME3_ADV) is fed into a register and then
        // passed the LOCKED_OUT when REGISTER_LOCKED is set to "Reg" or when set to
        // "NoReg" LOCKED_IN is just passed on to LOCKED_OUT without being registered.
        parameter REGISTER_LOCKED       = "Reg",
        // Use the registered LOCKED signal from the MMCME3 also for the DRP state machine.
        parameter USE_REG_LOCKED        = "No",
        // Possible/allowed combinations of above two parameters:
        // | REGISTER_LOCKED | USE_REG_LOCKED |                                            |
        // |-----------------|----------------|--------------------------------------------|
        // |      "NoReg"    |     "No"       | LOCKED is just passed through mmcme3_drp   |
        // |                 |                | and is used as is with the state machine   |
        // |      "NoReg"    |     "Yes"      | NOT ALLOWED                                |
        // |       "Reg"     |     "No"       | LOCKED is registered but the unregistered  |
        // |                 |                | version is used for the state machine.     |
        // |       "Reg"     |     "Yes"      | LOCKED is registered and the registered    |
        // |                 |                | version is also used by the state machine. |
        //
        //***********************************************************************
        // State 1 Parameters - These are for the first reconfiguration state.
        //***********************************************************************
        //
        // These parameters have an effect on the feedback path. A change on
        // these parameters will effect all of the clock outputs.
        //
        // The parameters are composed of:
        //    _MULT: This can be from 2 to 64. It has an effect on the VCO
        //          frequency which consequently, effects all of the clock
        //          outputs.
        //    _PHASE: This is the phase multiplied by 1000. For example if
        //          a phase of 24.567 deg was desired the input value would be
        //          24567. The range for the phase is from -360000 to 360000.
        //    _FRAC: This can be from 0 to 875. This represents the fractional
        //          divide multiplied by 1000.
        //          M = _MULT + _FRAC / 1000
        //          e.g. M=8.125
        //               _MULT = 8
        //               _FRAC = 125
        //    _FRAC_EN: This indicates fractional divide has been enabled. If 1
        //          then the fractional divide algorithm will be used to calculate
        //          register settings. If 0 then default calculation to be used.
        parameter S1_CLKFBOUT_MULT          = 5,
        parameter S1_CLKFBOUT_PHASE         = 0,
        parameter S1_CLKFBOUT_FRAC          = 125,
        parameter S1_CLKFBOUT_FRAC_EN       = 1,
        //
        // The bandwidth parameter effects the phase error and the jitter filter
        // capability of the MMCM. For more information on this parameter see the
        // Device user guide.
        // Possible values are: "LOW", "LOW_SS", "HIGH" and "OPTIMIZED"
        parameter S1_BANDWIDTH              = "LOW",
        //
        // The divclk parameter allows the input clock to be divided before it
        // reaches the phase and frequency comparator. This can be set between
        // 1 and 128.
        parameter S1_DIVCLK_DIVIDE          = 1,

        // The following parameters describe the configuration that each clock
        // output should have once the reconfiguration for state one has
        // completed.
        //
        // The parameters are composed of:
        //    _DIVIDE: This can be from 1 to 128
        //    _PHASE: This is the phase multiplied by 1000. For example if
        //          a phase of 24.567 deg was desired the input value would be
        //          24567. The range for the phase is from -360000 to 360000.
        //    _DUTY: This is the duty cycle multiplied by 100,000.  For example if
        //          a duty cycle of .24567 was desired the input would be
        //          24567.
        //
        parameter S1_CLKOUT0_DIVIDE         = 1,
        parameter S1_CLKOUT0_PHASE          = 0,
        parameter S1_CLKOUT0_DUTY           = 50000,
        parameter S1_CLKOUT0_FRAC          = 125,
        parameter S1_CLKOUT0_FRAC_EN       = 1,
        //
        parameter S1_CLKOUT1_DIVIDE         = 1,
        parameter S1_CLKOUT1_PHASE          = 0,
        parameter S1_CLKOUT1_DUTY           = 50000,
        //
        parameter S1_CLKOUT2_DIVIDE         = 1,
        parameter S1_CLKOUT2_PHASE          = 0,
        parameter S1_CLKOUT2_DUTY           = 50000,
        //
        parameter S1_CLKOUT3_DIVIDE         = 1,
        parameter S1_CLKOUT3_PHASE          = 0,
        parameter S1_CLKOUT3_DUTY           = 50000,
        //
        parameter S1_CLKOUT4_DIVIDE         = 1,
        parameter S1_CLKOUT4_PHASE          = 0,
        parameter S1_CLKOUT4_DUTY           = 50000,
        //
        parameter S1_CLKOUT5_DIVIDE         = 1,
        parameter S1_CLKOUT5_PHASE          = 0,
        parameter S1_CLKOUT5_DUTY           = 50000,
        //
        parameter S1_CLKOUT6_DIVIDE         = 1,
        parameter S1_CLKOUT6_PHASE          = 0,
        parameter S1_CLKOUT6_DUTY           = 50000,
        //
        //***********************************************************************
        // State 2 Parameters - These are for the second reconfiguration state.
        //***********************************************************************
        //
        // These parameters have an effect on the feedback path. A change on
        // these parameters will effect all of the clock outputs.
        //
        // The parameters are composed of:
        //    _MULT: This can be from 2 to 64. It has an effect on the VCO
        //          frequency which consequently, effects all of the clock
        //          outputs.
        //    _PHASE: This is the phase multiplied by 1000. For example if
        //          a phase of 24.567 deg was desired the input value would be
        //          24567.  The range for the phase is from -360000 to 360000.
        //    _FRAC: This can be from 0 to 875. This represents the fractional
        //          divide multiplied by 1000.
        //          M = _MULT + _FRAC / 1000
        //          e.g. M=8.125
        //               _MULT = 8
        //               _FRAC = 125
        //    _FRAC_EN: This indicates fractional divide has been enabled. If 1
        //          then the fractional divide algorithm will be used to calculate
        //          register settings. If 0 then default calculation to be used.
        parameter S2_CLKFBOUT_MULT          = 1,
        parameter S2_CLKFBOUT_PHASE         = 0,
        parameter S2_CLKFBOUT_FRAC          = 125,
        parameter S2_CLKFBOUT_FRAC_EN       = 1,
        //
        // The bandwidth parameter effects the phase error and the jitter filter
        // capability of the MMCM. For more information on this parameter see the
        // Device user guide.
        // Possible values are: "LOW", "LOW_SS", "HIGH" and "OPTIMIZED"
        parameter S2_BANDWIDTH              = "LOW",
        //
        // The divclk parameter allows the input clock to be divided before it
        // reaches the phase and frequency comparator. This can be set between
        // 1 and 128.
        parameter S2_DIVCLK_DIVIDE          = 1,
        //
        // The following parameters describe the configuration that each clock
        // output should have once the reconfiguration for state one has
        // completed.
        //
        // The parameters are composed of:
        //    _DIVIDE: This can be from 1 to 128
        //    _PHASE: This is the phase multiplied by 1000. For example if
        //          a phase of 24.567 deg was desired the input value would be
        //          24567. The range for the phase is from -360000 to 360000
        //    _DUTY: This is the duty cycle multiplied by 100,000. For example if
        //          a duty cycle of .24567 was desired the input would be
        //          24567.
        //
        parameter S2_CLKOUT0_DIVIDE         = 1,
        parameter S2_CLKOUT0_PHASE          = 0,
        parameter S2_CLKOUT0_DUTY           = 50000,
        parameter S2_CLKOUT0_FRAC          = 125,
        parameter S2_CLKOUT0_FRAC_EN       = 1,
        //
        parameter S2_CLKOUT1_DIVIDE         = 2,
        parameter S2_CLKOUT1_PHASE          = 0,
        parameter S2_CLKOUT1_DUTY           = 50000,
        //
        parameter S2_CLKOUT2_DIVIDE         = 3,
        parameter S2_CLKOUT2_PHASE          = 0,
        parameter S2_CLKOUT2_DUTY           = 50000,
        //
        parameter S2_CLKOUT3_DIVIDE         = 4,
        parameter S2_CLKOUT3_PHASE          = 0,
        parameter S2_CLKOUT3_DUTY           = 50000,
        //
        parameter S2_CLKOUT4_DIVIDE         = 5,
        parameter S2_CLKOUT4_PHASE          = 0,
        parameter S2_CLKOUT4_DUTY           = 50000,
        //
        parameter S2_CLKOUT5_DIVIDE         = 5,
        parameter S2_CLKOUT5_PHASE          = 0,
        parameter S2_CLKOUT5_DUTY           = 50000,
        //
        parameter S2_CLKOUT6_DIVIDE         = 5,
        parameter S2_CLKOUT6_PHASE          = -90,
        parameter S2_CLKOUT6_DUTY           = 50000,
        //
        //***********************************************************************
        // State 2 Parameters - These are for the second reconfiguration state.
        //***********************************************************************
        //
        // These parameters have an effect on the feedback path. A change on
        // these parameters will effect all of the clock outputs.
        //
        // The parameters are composed of:
        //    _MULT: This can be from 2 to 64. It has an effect on the VCO
        //          frequency which consequently, effects all of the clock
        //          outputs.
        //    _PHASE: This is the phase multiplied by 1000. For example if
        //          a phase of 24.567 deg was desired the input value would be
        //          24567.  The range for the phase is from -360000 to 360000.
        //    _FRAC: This can be from 0 to 875. This represents the fractional
        //          divide multiplied by 1000.
        //          M = _MULT + _FRAC / 1000
        //          e.g. M=8.125
        //               _MULT = 8
        //               _FRAC = 125
        //    _FRAC_EN: This indicates fractional divide has been enabled. If 1
        //          then the fractional divide algorithm will be used to calculate
        //          register settings. If 0 then default calculation to be used.
        parameter S3_CLKFBOUT_MULT          = 1,
        parameter S3_CLKFBOUT_PHASE         = 0,
        parameter S3_CLKFBOUT_FRAC          = 125,
        parameter S3_CLKFBOUT_FRAC_EN       = 1,
        //
        // The bandwidth parameter effects the phase error and the jitter filter
        // capability of the MMCM. For more information on this parameter see the
        // Device user guide.
        // Possible values are: "LOW", "LOW_SS", "HIGH" and "OPTIMIZED"
        parameter S3_BANDWIDTH              = "LOW",
        //
        // The divclk parameter allows the input clock to be divided before it
        // reaches the phase and frequency comparator. This can be set between
        // 1 and 128.
        parameter S3_DIVCLK_DIVIDE          = 1,
        //
        // The following parameters describe the configuration that each clock
        // output should have once the reconfiguration for state one has
        // completed.
        //
        // The parameters are composed of:
        //    _DIVIDE: This can be from 1 to 128
        //    _PHASE: This is the phase multiplied by 1000. For example if
        //          a phase of 24.567 deg was desired the input value would be
        //          24567. The range for the phase is from -360000 to 360000
        //    _DUTY: This is the duty cycle multiplied by 100,000. For example if
        //          a duty cycle of .24567 was desired the input would be
        //          24567.
        //
        parameter S3_CLKOUT0_DIVIDE         = 1,
        parameter S3_CLKOUT0_PHASE          = 0,
        parameter S3_CLKOUT0_DUTY           = 50000,
        parameter S3_CLKOUT0_FRAC          = 125,
        parameter S3_CLKOUT0_FRAC_EN       = 1,
        //
        parameter S3_CLKOUT1_DIVIDE         = 2,
        parameter S3_CLKOUT1_PHASE          = 0,
        parameter S3_CLKOUT1_DUTY           = 50000,
        //
        parameter S3_CLKOUT2_DIVIDE         = 3,
        parameter S3_CLKOUT2_PHASE          = 0,
        parameter S3_CLKOUT2_DUTY           = 50000,
        //
        parameter S3_CLKOUT3_DIVIDE         = 4,
        parameter S3_CLKOUT3_PHASE          = 0,
        parameter S3_CLKOUT3_DUTY           = 50000,
        //
        parameter S3_CLKOUT4_DIVIDE         = 5,
        parameter S3_CLKOUT4_PHASE          = 0,
        parameter S3_CLKOUT4_DUTY           = 50000,
        //
        parameter S3_CLKOUT5_DIVIDE         = 5,
        parameter S3_CLKOUT5_PHASE          = 0,
        parameter S3_CLKOUT5_DUTY           = 50000,
        //
        parameter S3_CLKOUT6_DIVIDE         = 5,
        parameter S3_CLKOUT6_PHASE          = -90,
        parameter S3_CLKOUT6_DUTY           = 50000
    ) (
        // These signals are controlled by user logic interface and are covered
        // in more detail within the XAPP.
        input       [1:0] SADDR,
        input             SEN,
        input             SCLK,
        input             RST,
        output reg        SRDY,
        //
        // These signals are to be connected to the MMCM_ADV by port name.
        // Their use matches the MMCM port description in the Device User Guide.
        input      [15:0] DO,
        input             DRDY,
        input             LOCK_REG_CLK_IN,
        input             LOCKED_IN,
        output reg        DWE,
        output reg        DEN,
        output reg [6:0]  DADDR,
        output reg [15:0] DI,
        output            DCLK,
        output reg        RST_MMCM,
        output            LOCKED_OUT
    );
//----------------------------------------------------------------------------------------
    //
    wire        IntLocked;
    wire        IntRstMmcm;
    //
    // 100 ps delay for behavioral simulations
    localparam  TCQ = 100;

    // Make sure the memory is implemented as distributed
    (* rom_style = "distributed" *)
    //
    // ROM of:  39 bit word 64 words deep
    reg [38:0]  rom [63:0];
    reg [5:0]   rom_addr;
    reg [38:0]  rom_do;
    reg         next_srdy;
    reg [5:0]   next_rom_addr;
    reg [6:0]   next_daddr;
    reg         next_dwe;
    reg         next_den;
    reg         next_rst_mmcm;
    reg [15:0]  next_di;
    //
    // Insert a register in LOCKED or not depending on the value given to the parameters
    // REGISTER_LOCKED. When REGISTER_LOCKED is set to "Reg" insert a register, when set
    // to "NoReg" don't insert a register but just pass the LOCKED signal from input to
    // output.
    // Use or not, under USE_REG_LOCKED parameter control, the registered version of the
    // LOCKED signal for the DRP state machine.
    // Possible/allowed combinations of the two LOCKED related parameters:
    //
    // | REGISTER_LOCKED | USE_REG_LOCKED |                                            |
    // |-----------------|----------------|--------------------------------------------|
    // |      "NoReg"    |     "No"       | LOCKED is just passed through mmcme3_drp   |
    // |                 |                | and is used as is with the state machine   |
    // |      "NoReg"    |     "Yes"      | NOT ALLOWED                                |
    // |       "Reg"     |     "No"       | LOCKED is registered but the unregistered  |
    // |                 |                | version is used for the state machine.     |
    // |       "Reg"     |     "Yes"      | LOCKED is registered and the registered    |
    // |                 |                | version is also used by the state machine. |
    //
    generate
        if (REGISTER_LOCKED == "NoReg" && USE_REG_LOCKED == "No") begin
            assign LOCKED_OUT = LOCKED_IN;
            assign IntLocked = LOCKED_IN;
        end else if (REGISTER_LOCKED == "Reg" && USE_REG_LOCKED == "No") begin
            FDRE #(
                .INIT           (0),
                .IS_C_INVERTED  (0),
                .IS_D_INVERTED  (0),
                .IS_R_INVERTED  (0)
            ) mmcme3_drp_I_Fdrp (
                .D      (LOCKED_IN),
                .CE     (1'b1),
                .R      (IntRstMmcm),
                .C      (LOCK_REG_CLK_IN),
                .Q      (LOCKED_OUT)
            );
            //
            assign IntLocked = LOCKED_IN;
        end else if (REGISTER_LOCKED == "Reg" && USE_REG_LOCKED == "Yes") begin
            FDRE #(
                .INIT           (0),
                .IS_C_INVERTED  (0),
                .IS_D_INVERTED  (0),
                .IS_R_INVERTED  (0)
            ) mmcme3_drp_I_Fdrp (
                .D  (LOCKED_IN),
                .CE (1'b1),
                .R  (IntRstMmcm),
                .C  (LOCK_REG_CLK_IN),
                .Q  (LOCKED_OUT)
            );
            //
            assign IntLocked = LOCKED_OUT;
        end
    endgenerate

    // Integer used to initialize remainder of unused ROM
    integer     ii;

    // Pass SCLK to DCLK for the MMCM
    assign DCLK = SCLK;
     assign IntRstMmcm = RST_MMCM;

    // Include the MMCM reconfiguration functions.  This contains the constant
    // functions that are used in the calculations below.  This file is
    // required.
    `include "mmcme2_drp_func.h"

    //**************************************************************************
    // State 1 Calculations
    //**************************************************************************
    // Please see header for information.
    localparam [37:0] S1_CLKFBOUT       =
       mmcm_count_calc(S1_CLKFBOUT_MULT, S1_CLKFBOUT_PHASE, 50000);

    localparam [37:0] S1_CLKFBOUT_FRAC_CALC       =
       mmcm_frac_count_calc(S1_CLKFBOUT_MULT, S1_CLKFBOUT_PHASE, 50000, S1_CLKFBOUT_FRAC);

    localparam [9:0]  S1_DIGITAL_FILT   =
       mmcm_filter_lookup(S1_CLKFBOUT_MULT, S1_BANDWIDTH);

    localparam [39:0] S1_LOCK           =
       mmcm_lock_lookup(S1_CLKFBOUT_MULT);

    localparam [37:0] S1_DIVCLK         =
       mmcm_count_calc(S1_DIVCLK_DIVIDE, 0, 50000);

    localparam [37:0] S1_CLKOUT0        =
       mmcm_count_calc(S1_CLKOUT0_DIVIDE, S1_CLKOUT0_PHASE, S1_CLKOUT0_DUTY);
       localparam [15:0] S1_CLKOUT0_REG1        = S1_CLKOUT0[15:0]; //See log file for 16 bit reporting of the register
       localparam [15:0] S1_CLKOUT0_REG2        = S1_CLKOUT0[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S1_CLKOUT0_FRAC_CALC        =
       mmcm_frac_count_calc(S1_CLKOUT0_DIVIDE, S1_CLKOUT0_PHASE, 50000, S1_CLKOUT0_FRAC);
        localparam [15:0] S1_CLKOUT0_FRAC_REG1        = S1_CLKOUT0_FRAC_CALC[15:0];  //See log file for 16 bit reporting of the register
        localparam [15:0] S1_CLKOUT0_FRAC_REG2        = S1_CLKOUT0_FRAC_CALC[31:16];  //See log file for 16 bit reporting of the register
        localparam [5:0] S1_CLKOUT0_FRAC_REGSHARED        = S1_CLKOUT0_FRAC_CALC[37:32];  //See log file for 16 bit reporting of the register

    localparam [37:0] S1_CLKOUT1        =
       mmcm_count_calc(S1_CLKOUT1_DIVIDE, S1_CLKOUT1_PHASE, S1_CLKOUT1_DUTY);
        localparam [15:0] S1_CLKOUT1_REG1        = S1_CLKOUT1[15:0];  //See log file for 16 bit reporting of the register
        localparam [15:0] S1_CLKOUT1_REG2        = S1_CLKOUT1[31:16];  //See log file for 16 bit reporting of the register

    localparam [37:0] S1_CLKOUT2        =
       mmcm_count_calc(S1_CLKOUT2_DIVIDE, S1_CLKOUT2_PHASE, S1_CLKOUT2_DUTY);
       localparam [15:0] S1_CLKOUT2_REG1        = S1_CLKOUT2[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S1_CLKOUT2_REG2        = S1_CLKOUT2[31:16];  //See log file for 16 bit reporting of the register

    localparam [37:0] S1_CLKOUT3        =
       mmcm_count_calc(S1_CLKOUT3_DIVIDE, S1_CLKOUT3_PHASE, S1_CLKOUT3_DUTY);
       localparam [15:0] S1_CLKOUT3_REG1        = S1_CLKOUT3[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S1_CLKOUT3_REG2        = S1_CLKOUT3[31:16];  //See log file for 16 bit reporting of the register

    localparam [37:0] S1_CLKOUT4        =
       mmcm_count_calc(S1_CLKOUT4_DIVIDE, S1_CLKOUT4_PHASE, S1_CLKOUT4_DUTY);
       localparam [15:0] S1_CLKOUT4_REG1        = S1_CLKOUT4[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S1_CLKOUT4_REG2        = S1_CLKOUT4[31:16];  //See log file for 16 bit reporting of the register

    localparam [37:0] S1_CLKOUT5        =
       mmcm_count_calc(S1_CLKOUT5_DIVIDE, S1_CLKOUT5_PHASE, S1_CLKOUT5_DUTY);
       localparam [15:0] S1_CLKOUT5_REG1        = S1_CLKOUT5[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S1_CLKOUT5_REG2        = S1_CLKOUT5[31:16];  //See log file for 16 bit reporting of the register

    localparam [37:0] S1_CLKOUT6        =
       mmcm_count_calc(S1_CLKOUT6_DIVIDE, S1_CLKOUT6_PHASE, S1_CLKOUT6_DUTY);
       localparam [15:0] S1_CLKOUT6_REG1        = S1_CLKOUT6[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S1_CLKOUT6_REG2        = S1_CLKOUT6[31:16]; //See log file for 16 bit reporting of the register

    //**************************************************************************
    // State 2 Calculations
    //**************************************************************************
    localparam [37:0] S2_CLKFBOUT       =
       mmcm_count_calc(S2_CLKFBOUT_MULT, S2_CLKFBOUT_PHASE, 50000);

    localparam [37:0] S2_CLKFBOUT_FRAC_CALC       =
       mmcm_frac_count_calc(S2_CLKFBOUT_MULT, S2_CLKFBOUT_PHASE, 50000, S2_CLKFBOUT_FRAC);

    localparam [9:0] S2_DIGITAL_FILT    =
       mmcm_filter_lookup(S2_CLKFBOUT_MULT, S2_BANDWIDTH);

    localparam [39:0] S2_LOCK           =
       mmcm_lock_lookup(S2_CLKFBOUT_MULT);

    localparam [37:0] S2_DIVCLK         =
       mmcm_count_calc(S2_DIVCLK_DIVIDE, 0, 50000);

    localparam [37:0] S2_CLKOUT0        =
       mmcm_count_calc(S2_CLKOUT0_DIVIDE, S2_CLKOUT0_PHASE, S2_CLKOUT0_DUTY);
       localparam [15:0] S2_CLKOUT0_REG1        = S2_CLKOUT0[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S2_CLKOUT0_REG2        = S2_CLKOUT0[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S2_CLKOUT0_FRAC_CALC        =
       mmcm_frac_count_calc(S2_CLKOUT0_DIVIDE, S2_CLKOUT0_PHASE, 50000, S2_CLKOUT0_FRAC);
       localparam [15:0] S2_CLKOUT0_FRAC_CALC_REG1        = S2_CLKOUT0_FRAC_CALC[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S2_CLKOUT0_FRAC_CALC_REG2        = S2_CLKOUT0_FRAC_CALC[31:16]; //See log file for 16 bit reporting of the register
       localparam [15:0] S2_CLKOUT0_FRAC_CALC_REGSHARED        = S2_CLKOUT0_FRAC_CALC[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S2_CLKOUT1        =
       mmcm_count_calc(S2_CLKOUT1_DIVIDE, S2_CLKOUT1_PHASE, S2_CLKOUT1_DUTY);
       localparam [15:0] S2_CLKOUT1_REG1        = S2_CLKOUT1[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S2_CLKOUT1_REG2        = S2_CLKOUT1[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S2_CLKOUT2        =
       mmcm_count_calc(S2_CLKOUT2_DIVIDE, S2_CLKOUT2_PHASE, S2_CLKOUT2_DUTY);
       localparam [15:0] S2_CLKOUT2_REG1        = S2_CLKOUT2[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S2_CLKOUT2_REG2        = S2_CLKOUT2[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S2_CLKOUT3        =
       mmcm_count_calc(S2_CLKOUT3_DIVIDE, S2_CLKOUT3_PHASE, S2_CLKOUT3_DUTY);
       localparam [15:0] S2_CLKOUT3_REG1        = S2_CLKOUT3[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S2_CLKOUT3_REG2        = S2_CLKOUT3[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S2_CLKOUT4        =
       mmcm_count_calc(S2_CLKOUT4_DIVIDE, S2_CLKOUT4_PHASE, S2_CLKOUT4_DUTY);
       localparam [15:0] S2_CLKOUT4_REG1        = S2_CLKOUT4[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S2_CLKOUT4_REG2        = S2_CLKOUT4[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S2_CLKOUT5        =
       mmcm_count_calc(S2_CLKOUT5_DIVIDE, S2_CLKOUT5_PHASE, S2_CLKOUT5_DUTY);
       localparam [15:0] S2_CLKOUT5_REG1        = S2_CLKOUT5[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S2_CLKOUT5_REG2        = S2_CLKOUT5[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S2_CLKOUT6        =
       mmcm_count_calc(S2_CLKOUT6_DIVIDE, S2_CLKOUT6_PHASE, S2_CLKOUT6_DUTY);
       localparam [15:0] S2_CLKOUT6_REG1        = S2_CLKOUT6[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S2_CLKOUT6_REG2        = S2_CLKOUT6[31:16]; //See log file for 16 bit reporting of the register

    //**************************************************************************
    // State 2 Calculations
    //**************************************************************************
    localparam [37:0] S3_CLKFBOUT       =
       mmcm_count_calc(S3_CLKFBOUT_MULT, S3_CLKFBOUT_PHASE, 50000);

    localparam [37:0] S3_CLKFBOUT_FRAC_CALC       =
       mmcm_frac_count_calc(S3_CLKFBOUT_MULT, S3_CLKFBOUT_PHASE, 50000, S3_CLKFBOUT_FRAC);

    localparam [9:0] S3_DIGITAL_FILT    =
       mmcm_filter_lookup(S3_CLKFBOUT_MULT, S3_BANDWIDTH);

    localparam [39:0] S3_LOCK           =
       mmcm_lock_lookup(S3_CLKFBOUT_MULT);

    localparam [37:0] S3_DIVCLK         =
       mmcm_count_calc(S3_DIVCLK_DIVIDE, 0, 50000);

    localparam [37:0] S3_CLKOUT0        =
       mmcm_count_calc(S3_CLKOUT0_DIVIDE, S3_CLKOUT0_PHASE, S3_CLKOUT0_DUTY);
       localparam [15:0] S3_CLKOUT0_REG1        = S3_CLKOUT0[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S3_CLKOUT0_REG2        = S3_CLKOUT0[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S3_CLKOUT0_FRAC_CALC        =
       mmcm_frac_count_calc(S3_CLKOUT0_DIVIDE, S3_CLKOUT0_PHASE, 50000, S3_CLKOUT0_FRAC);
       localparam [15:0] S3_CLKOUT0_FRAC_CALC_REG1        = S3_CLKOUT0_FRAC_CALC[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S3_CLKOUT0_FRAC_CALC_REG2        = S3_CLKOUT0_FRAC_CALC[31:16]; //See log file for 16 bit reporting of the register
       localparam [15:0] S3_CLKOUT0_FRAC_CALC_REGSHARED        = S3_CLKOUT0_FRAC_CALC[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S3_CLKOUT1        =
       mmcm_count_calc(S3_CLKOUT1_DIVIDE, S3_CLKOUT1_PHASE, S3_CLKOUT1_DUTY);
       localparam [15:0] S3_CLKOUT1_REG1        = S3_CLKOUT1[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S3_CLKOUT1_REG2        = S3_CLKOUT1[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S3_CLKOUT2        =
       mmcm_count_calc(S3_CLKOUT2_DIVIDE, S3_CLKOUT2_PHASE, S3_CLKOUT2_DUTY);
       localparam [15:0] S3_CLKOUT2_REG1        = S3_CLKOUT2[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S3_CLKOUT2_REG2        = S3_CLKOUT2[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S3_CLKOUT3        =
       mmcm_count_calc(S3_CLKOUT3_DIVIDE, S3_CLKOUT3_PHASE, S3_CLKOUT3_DUTY);
       localparam [15:0] S3_CLKOUT3_REG1        = S3_CLKOUT3[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S3_CLKOUT3_REG2        = S3_CLKOUT3[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S3_CLKOUT4        =
       mmcm_count_calc(S3_CLKOUT4_DIVIDE, S3_CLKOUT4_PHASE, S3_CLKOUT4_DUTY);
       localparam [15:0] S3_CLKOUT4_REG1        = S3_CLKOUT4[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S3_CLKOUT4_REG2        = S3_CLKOUT4[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S3_CLKOUT5        =
       mmcm_count_calc(S3_CLKOUT5_DIVIDE, S3_CLKOUT5_PHASE, S3_CLKOUT5_DUTY);
       localparam [15:0] S3_CLKOUT5_REG1        = S3_CLKOUT5[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S3_CLKOUT5_REG2        = S3_CLKOUT5[31:16]; //See log file for 16 bit reporting of the register

    localparam [37:0] S3_CLKOUT6        =
       mmcm_count_calc(S3_CLKOUT6_DIVIDE, S3_CLKOUT6_PHASE, S3_CLKOUT6_DUTY);
       localparam [15:0] S3_CLKOUT6_REG1        = S3_CLKOUT6[15:0];  //See log file for 16 bit reporting of the register
       localparam [15:0] S3_CLKOUT6_REG2        = S3_CLKOUT6[31:16]; //See log file for 16 bit reporting of the register

    initial begin
       // rom entries contain (in order) the address, a bitmask, and a bitset
       //***********************************************************************
       // State 1 Initialization
       //***********************************************************************

       // Store the power bits
       rom[0] = {7'h28, 16'h0000, 16'hFFFF};

       // Store CLKOUT0 divide and phase
       rom[1]  = (S1_CLKOUT0_FRAC_EN == 0) ?
                         {7'h09, 16'h8000, S1_CLKOUT0[31:16]}:
                         {7'h09, 16'h8000, S1_CLKOUT0_FRAC_CALC[31:16]};
       rom[2]  = (S1_CLKOUT0_FRAC_EN == 0) ?
                         {7'h08, 16'h1000, S1_CLKOUT0[15:0]}:
                         {7'h08, 16'h1000, S1_CLKOUT0_FRAC_CALC[15:0]};

       // Store the input divider
       rom[3] = {7'h16, 16'hC000, {2'h0, S1_DIVCLK[23:22], S1_DIVCLK[11:0]} };

       // Store the feedback divide and phase
       rom[4] = (S1_CLKFBOUT_FRAC_EN == 0) ?
                 {7'h14, 16'h1000, S1_CLKFBOUT[15:0]}:
                 {7'h14, 16'h1000, S1_CLKFBOUT_FRAC_CALC[15:0]};
       rom[5] = (S1_CLKFBOUT_FRAC_EN == 0) ?
                 {7'h15, 16'h8000, S1_CLKFBOUT[31:16]}:
                 {7'h15, 16'h8000, S1_CLKFBOUT_FRAC_CALC[31:16]};

       // Store the lock settings
       rom[6] = {7'h18, 16'hFC00, {6'h00, S1_LOCK[29:20]} };
       rom[7] = {7'h19, 16'h8000, {1'b0 , S1_LOCK[34:30], S1_LOCK[9:0]} };
       rom[8] = {7'h1A, 16'h8000, {1'b0 , S1_LOCK[39:35], S1_LOCK[19:10]} };

       // Store the filter settings
       rom[9] = {7'h4E, 16'h66FF,
                 S1_DIGITAL_FILT[9], 2'h0, S1_DIGITAL_FILT[8:7], 2'h0,
                 S1_DIGITAL_FILT[6], 8'h00 };
       rom[10] = {7'h4F, 16'h666F,
                 S1_DIGITAL_FILT[5], 2'h0, S1_DIGITAL_FILT[4:3], 2'h0,
                 S1_DIGITAL_FILT[2:1], 2'h0, S1_DIGITAL_FILT[0], 4'h0 };

       //***********************************************************************
       // State 2 Initialization
       //***********************************************************************

       // Store the power bits
       rom[11] = {7'h28, 16'h0000, 16'hFFFF};

       // Store CLKOUT0 divide and phase
       rom[12] = (S2_CLKOUT0_FRAC_EN == 0) ?
                 {7'h09, 16'h8000, S2_CLKOUT0[31:16]}:
                 {7'h09, 16'h8000, S2_CLKOUT0_FRAC_CALC[31:16]};
       rom[13] = (S2_CLKOUT0_FRAC_EN == 0) ?
                 {7'h08, 16'h1000, S2_CLKOUT0[15:0]}:
                 {7'h08, 16'h1000, S2_CLKOUT0_FRAC_CALC[15:0]};

       // Store the input divider
       rom[14] = {7'h16, 16'hC000, {2'h0, S2_DIVCLK[23:22], S2_DIVCLK[11:0]} };

       // Store the feedback divide and phase
       rom[15] = (S2_CLKFBOUT_FRAC_EN == 0) ?
                 {7'h14, 16'h1000, S2_CLKFBOUT[15:0]}:
                 {7'h14, 16'h1000, S2_CLKFBOUT_FRAC_CALC[15:0]};
       rom[16] = (S2_CLKFBOUT_FRAC_EN == 0) ?
                 {7'h15, 16'h8000, S2_CLKFBOUT[31:16]}:
                 {7'h15, 16'h8000, S2_CLKFBOUT_FRAC_CALC[31:16]};

       // Store the lock settings
       rom[17] = {7'h18, 16'hFC00, {6'h00, S2_LOCK[29:20]} };
       rom[18] = {7'h19, 16'h8000, {1'b0 , S2_LOCK[34:30], S2_LOCK[9:0]} };
       rom[19] = {7'h1A, 16'h8000, {1'b0 , S2_LOCK[39:35], S2_LOCK[19:10]} };

       // Store the filter settings
       rom[20] = {7'h4E, 16'h66FF,
                 S2_DIGITAL_FILT[9], 2'h0, S2_DIGITAL_FILT[8:7], 2'h0,
                 S2_DIGITAL_FILT[6], 8'h00 };
       rom[21] = {7'h4F, 16'h666F,
                 S2_DIGITAL_FILT[5], 2'h0, S2_DIGITAL_FILT[4:3], 2'h0,
                 S2_DIGITAL_FILT[2:1], 2'h0, S2_DIGITAL_FILT[0], 4'h0 };

       //***********************************************************************
       // State 2 Initialization
       //***********************************************************************

       // Store the power bits
       rom[22] = {7'h28, 16'h0000, 16'hFFFF};

       // Store CLKOUT0 divide and phase
       rom[23] = (S3_CLKOUT0_FRAC_EN == 0) ?
                 {7'h09, 16'h8000, S3_CLKOUT0[31:16]}:
                 {7'h09, 16'h8000, S3_CLKOUT0_FRAC_CALC[31:16]};
       rom[24] = (S3_CLKOUT0_FRAC_EN == 0) ?
                 {7'h08, 16'h1000, S3_CLKOUT0[15:0]}:
                 {7'h08, 16'h1000, S3_CLKOUT0_FRAC_CALC[15:0]};

       // Store the input divider
       rom[25] = {7'h16, 16'hC000, {2'h0, S3_DIVCLK[23:22], S3_DIVCLK[11:0]} };

       // Store the feedback divide and phase
       rom[26] = (S3_CLKFBOUT_FRAC_EN == 0) ?
                 {7'h14, 16'h1000, S3_CLKFBOUT[15:0]}:
                 {7'h14, 16'h1000, S3_CLKFBOUT_FRAC_CALC[15:0]};
       rom[27] = (S3_CLKFBOUT_FRAC_EN == 0) ?
                 {7'h15, 16'h8000, S3_CLKFBOUT[31:16]}:
                 {7'h15, 16'h8000, S3_CLKFBOUT_FRAC_CALC[31:16]};

       // Store the lock settings
       rom[28] = {7'h18, 16'hFC00, {6'h00, S3_LOCK[29:20]} };
       rom[29] = {7'h19, 16'h8000, {1'b0 , S3_LOCK[34:30], S3_LOCK[9:0]} };
       rom[30] = {7'h1A, 16'h8000, {1'b0 , S3_LOCK[39:35], S3_LOCK[19:10]} };

       // Store the filter settings
       rom[31] = {7'h4E, 16'h66FF,
                 S3_DIGITAL_FILT[9], 2'h0, S3_DIGITAL_FILT[8:7], 2'h0,
                 S3_DIGITAL_FILT[6], 8'h00 };
       rom[32] = {7'h4F, 16'h666F,
                 S3_DIGITAL_FILT[5], 2'h0, S3_DIGITAL_FILT[4:3], 2'h0,
                 S3_DIGITAL_FILT[2:1], 2'h0, S3_DIGITAL_FILT[0], 4'h0 };

       // Initialize the rest of the ROM
       rom[33] = {7'h28,32'h0000_0000};
       for(ii = 34; ii < 64; ii = ii +1) begin
          rom[ii] = 0;
       end
    end

    // Output the initialized rom value based on rom_addr each clock cycle
    always @(posedge SCLK) begin
       rom_do<= #TCQ rom[rom_addr];
    end

    //**************************************************************************
    // Everything below is associated whith the state machine that is used to
    // Read/Modify/Write to the MMCM.
    //**************************************************************************

    // State Definitions
    localparam RESTART      = 4'h1;
    localparam WAIT_LOCK    = 4'h2;
    localparam WAIT_SEN     = 4'h3;
    localparam ADDRESS      = 4'h4;
    localparam WAIT_A_DRDY  = 4'h5;
    localparam BITMASK      = 4'h6;
    localparam BITSET       = 4'h7;
    localparam WRITE        = 4'h8;
    localparam WAIT_DRDY    = 4'h9;

    // State sync
    reg [3:0]  current_state   = RESTART;
    reg [3:0]  next_state      = RESTART;

    // These variables are used to keep track of the number of iterations that
    //    each state takes to reconfigure.
    // STATE_COUNT_CONST is used to reset the counters and should match the
    //    number of registers necessary to reconfigure each state.
    localparam STATE_COUNT_CONST  = 11;
    reg [4:0] state_count         = STATE_COUNT_CONST;
    reg [4:0] next_state_count    = STATE_COUNT_CONST;

    // This block assigns the next register value from the state machine below
    always @(posedge SCLK) begin
       DADDR       <= #TCQ next_daddr;
       DWE         <= #TCQ next_dwe;
       DEN         <= #TCQ next_den;
       RST_MMCM    <= #TCQ next_rst_mmcm;
       DI          <= #TCQ next_di;

       SRDY        <= #TCQ next_srdy;

       rom_addr    <= #TCQ next_rom_addr;
       state_count <= #TCQ next_state_count;
    end

    // This block assigns the next state, reset is syncronous.
    always @(posedge SCLK) begin
       if(RST) begin
          current_state <= #TCQ RESTART;
       end else begin
          current_state <= #TCQ next_state;
       end
    end

    always @* begin
       // Setup the default values
       next_srdy         = 1'b0;
       next_daddr        = DADDR;
       next_dwe          = 1'b0;
       next_den          = 1'b0;
       next_rst_mmcm     = RST_MMCM;
       next_di           = DI;
       next_rom_addr     = rom_addr;
       next_state_count  = state_count;

       case (current_state)
          // If RST is asserted reset the machine
          RESTART: begin
             next_daddr     = 7'h00;
             next_di        = 16'h0000;
             next_rom_addr  = 6'h00;
             next_rst_mmcm  = 1'b1;
             next_state     = WAIT_LOCK;
          end

          // Waits for the MMCM to assert IntLocked - once it does asserts SRDY
          WAIT_LOCK: begin
             // Make sure reset is de-asserted
             next_rst_mmcm   = 1'b0;
             // Reset the number of registers left to write for the next
             // reconfiguration event.
             next_state_count = STATE_COUNT_CONST ;
             next_rom_addr = SADDR * STATE_COUNT_CONST;

             if(IntLocked) begin
                // MMCM is IntLocked, go on to wait for the SEN signal
                next_state  = WAIT_SEN;
                // Assert SRDY to indicate that the reconfiguration module is
                // ready
                next_srdy   = 1'b1;
             end else begin
                // Keep waiting, IntLocked has not asserted yet
                next_state  = WAIT_LOCK;
             end
          end

          // Wait for the next SEN pulse and set the ROM addr appropriately
          //    based on SADDR
          WAIT_SEN: begin
             next_rom_addr = SADDR * STATE_COUNT_CONST;
             if (SEN) begin
                next_rom_addr = SADDR * STATE_COUNT_CONST;
                // Go on to address the MMCM
                next_state = ADDRESS;
             end else begin
                // Keep waiting for SEN to be asserted
                next_state = WAIT_SEN;
             end
          end

          // Set the address on the MMCM and assert DEN to read the value
          ADDRESS: begin
             // Reset the DCM through the reconfiguration
             next_rst_mmcm  = 1'b1;
             // Enable a read from the MMCM and set the MMCM address
             next_den       = 1'b1;
             next_daddr     = rom_do[38:32];

             // Wait for the data to be ready
             next_state     = WAIT_A_DRDY;
          end

          // Wait for DRDY to assert after addressing the MMCM
          WAIT_A_DRDY: begin
             if (DRDY) begin
                // Data is ready, mask out the bits to save
                next_state = BITMASK;
             end else begin
                // Keep waiting till data is ready
                next_state = WAIT_A_DRDY;
             end
          end

          // Zero out the bits that are not set in the mask stored in rom
          BITMASK: begin
             // Do the mask
             next_di     = rom_do[31:16] & DO;
             // Go on to set the bits
             next_state  = BITSET;
          end

          // After the input is masked, OR the bits with calculated value in rom
          BITSET: begin
             // Set the bits that need to be assigned
             next_di           = rom_do[15:0] | DI;
             // Set the next address to read from ROM
             next_rom_addr     = rom_addr + 1'b1;
             // Go on to write the data to the MMCM
             next_state        = WRITE;
          end

          // DI is setup so assert DWE, DEN, and RST_MMCM.  Subtract one from the
          //    state count and go to wait for DRDY.
          WRITE: begin
             // Set WE and EN on MMCM
             next_dwe          = 1'b1;
             next_den          = 1'b1;

             // Decrement the number of registers left to write
             next_state_count  = state_count - 1'b1;
             // Wait for the write to complete
             next_state        = WAIT_DRDY;
          end

          // Wait for DRDY to assert from the MMCM.  If the state count is not 0
          //    jump to ADDRESS (continue reconfiguration).  If state count is
          //    0 wait for lock.
          WAIT_DRDY: begin
             if(DRDY) begin
                // Write is complete
                if(state_count > 0) begin
                   // If there are more registers to write keep going
                   next_state  = ADDRESS;
                end else begin
                   // There are no more registers to write so wait for the MMCM
                   // to lock
                   next_state  = WAIT_LOCK;
                end
             end else begin
                // Keep waiting for write to complete
                next_state     = WAIT_DRDY;
             end
          end

          // If in an unknown state reset the machine
          default: begin
             next_state = RESTART;
          end
       endcase
    end
endmodule
mmcme2_drp

 

 

 

 

image

 

image

 

老师,您好,可以给我讲讲xilinx mmcm 这个框图嘛,原理,我作为一名fpga工程师如何使用drp功能;文件如上,然后有一个问题, top_mmcme2.v文件中.S1_DIVCLK_DIVIDE(2),是啥意思,谢谢您

你好!很高兴为你解答。作为FPGA工程师,理解MMCM(Mixed-Mode Clock Manager)和DRP(Dynamic Reconfiguration Port)是进阶的必备技能。我们分三部分来回答:框图原理、代码中的参数含义、以及如何使用DRP功能。

一、 Xilinx MMCM 框图原理详解
你提供的图片是Xilinx 7系列FPGA中MMCM的经典结构图。我们可以把它看作一个“频率合成工厂”,流程如下:

输入与预分频(D):

左侧 CLKIN1/2 是外部晶振或时钟输入。

进入 D 触发器(实际上是分频器),对应参数 DIVCLK_DIVIDE。

作用:如果输入时钟频率太高,先除以D,降低频率,以便后续电路处理。

公式:FPFD=FCLKIN/DFPFD​=FCLKIN​/D

鉴频鉴相器(PFD)与电荷泵(CP)、环路滤波器(LF):

PFD 比较 CLKFB(反馈时钟)和经过D分频后的时钟的相位差。

输出误差信号,控制VCO(压控振荡器)的频率。

压控振荡器(VCO)与倍频(M):

这是核心。VCO输出高频时钟。

反馈路径上的 M(CLKFBOUT_MULT_F)是倍频系数。

核心公式:FVCO=FCLKIN×MDFVCO​=FCLKIN​×DM​

注意:VCO的频率必须在芯片规定的范围内(例如 600MHz - 1200MHz),否则MMCM无法锁定(Lock)。

输出分频(O0 - O6):

VCO产生的高频信号,经过右侧的 O0 到 O6 分频器输出。

每个输出通道都可以独立设置分频系数(CLKOUTx_DIVIDE)和相位(Phase)。

输出公式:FOUTx=FVCOOxFOUTx​=Ox​FVCO​​

总结:MMCM就像一个齿轮箱,输入频率先被D除,再被M乘,最后被O除,得到你想要的频率。

二、 关于 .S1_DIVCLK_DIVIDE(2) 的问题
在 top_mmcme2.v 文件中,这行代码的含义是:

这是配置“状态1(State 1)”下的输入时钟分频系数(D)= 2。

具体解释:

S1:代表 State 1。你的代码支持动态重配置(DRP),可以在不同状态间切换。这里定义的是第一种配置方案。

DIVCLK_DIVIDE:对应框图中最左边的 D。

值为 2:意味着输入的时钟频率会被除以 2。

结合你的代码看:

输入时钟 CLKIN_PERIOD 设为 10.000 ns,即 100 MHz。

在 mmcme2_drp 模块中,S1_CLKFBOUT_MULT 设为 2(倍频 M=2)。

那么 VCO 的频率计算为:FVCO=100MHz×22=100MHzFVCO​=100MHz×22​=100MHz。

如果 S1_DIVCLK_DIVIDE(2) 改成 1,那么 FVCO=100MHz×21=200MHzFVCO​=100MHz×12​=200MHz。

为什么设为2?
通常是为了满足VCO的工作频率范围,或者为了得到特定的输出频率。如果你的输入时钟很高(比如 500MHz),D必须设大一点,否则VCO会超频。

三、 FPGA工程师如何使用 DRP 功能
DRP(Dynamic Reconfiguration Port)允许你在FPGA运行过程中,动态修改MMCM的配置参数(如倍频M、分频D、输出分频O、相位等),而不需要重新烧录比特流。

1. 核心文件解析
你提供的代码包含三个关键部分:

mmcme2_drp.v:DRP状态机。它负责读取ROM中的配置数据,并通过DRP接口写入MMCM。

mmcme2_drp_func.h:计算函数。它把用户设置的参数(如M=2, D=2)转换成MMCM寄存器能识别的二进制值(Bitmask)。

top_mmcme2.v:顶层模块。它实例化了MMCME2_ADV(硬核)和mmcme2_drp(控制器),并连接了DRP信号。

2. 使用步骤(基于你的代码)
你的代码设计了一个多状态重配置的机制。

Step 1: 定义状态参数
在 mmcme2_drp 实例化时,你会看到 S1_, S2_, S3_ 开头的参数。

S1_...:第一种配置(例如:100MHz输入,输出50MHz)。

S2_...:第二种配置(例如:100MHz输入,输出200MHz)。

S3_...:第三种配置。

Step 2: 触发重配置
在 top_mmcme2.v 的端口有 input SSTEP 和 input [1:0] STATE。

STATE:选择你要切换到哪一组参数(0对应S1,1对应S2,2对应S3)。

SSTEP:给一个脉冲(上升沿),启动重配置过程。

Step 3: 内部工作流程

你改变 STATE 引脚的值。

给 SSTEP 一个脉冲。

mmcme2_drp 模块检测到 SSTEP,开始工作。

它根据 STATE 选择对应的 ROM 地址段(比如 S2 的地址)。

它通过 DADDR, DI, DEN, DWE 信号,将新配置写入 MMCME2_ADV。

写入完成后,MMCM会暂时失锁(LOST LOCK),然后重新锁定(LOCKED)。

SRDY 信号拉高,表示重配置完成。

3. 注意事项(避坑指南)
时钟切换风险:在重配置过程中,输出时钟会不稳定甚至停止。如果你的系统依赖这个时钟运行逻辑,必须设计好时钟切换电路(BUFGMUX),在DRP操作期间切换到备用时钟(如晶振直连),等待 LOCKED 信号再次变高后,再切回来。

VCO频率范围:无论你怎么重配置,计算出的 FVCOFVCO​ 必须满足芯片手册要求(7系列通常是 600MHz - 1200MHz)。否则MMCM无法锁定。

复位:重配置期间,RST_MMCM 信号会被拉高,这是正常的,为了重置MMCM内部状态。

总结:你图中的红框 .S1_DIVCLK_DIVIDE(2) 只是定义了第一套配置方案中的输入分频系数。要使用DRP,你只需要在外部改变 STATE 并触发 SSTEP,剩下的寄存器计算和写入由 mmcme2_drp.v 自动完成。

 

posted on 2026-10-10 17:49  taylorrrrrrrrrr  阅读(9)  评论(0)    收藏  举报