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
//------------------------------------------------------------------------------------------- // ____ ____ // / /\/ / // /___/ \ / // \ \ \/ 锟? 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


老师,您好,可以给我讲讲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=OxFVCO
总结: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) 收藏 举报
浙公网安备 33010602011771号