[Cryptech-Commits] [core/platform/alpha] 01/07: New Alpha platform with three clocks: * 45 MHz (aka "io_clk") is the I/O clock for the FMC bus * 90 MHz (aka "sys_clk") is the system clock for all the cores * 180 MHz (aka "core_clk") is the high-speed clock for high-performance cores

git at cryptech.is git at cryptech.is
Thu Jan 23 09:01:32 UTC 2020


This is an automated email from the git hooks/post-receive script.

meisterpaul1 at yandex.ru pushed a commit to branch fmc_clk_core
in repository core/platform/alpha.

commit 18c0a8e73bacd2ccbb9089d7aa220290e95dcb76
Author: Pavel V. Shatov (Meister) <meisterpaul1 at yandex.ru>
AuthorDate: Tue Jan 21 15:36:05 2020 +0300

    New Alpha platform with three clocks:
     *  45 MHz (aka "io_clk") is the I/O clock for the FMC bus
     *  90 MHz (aka "sys_clk") is the system clock for all the cores
     * 180 MHz (aka "core_clk") is the high-speed clock for high-performance cores
---
 rtl/alpha_clkmgr.v     | 182 ++++++++++++++++-----------------
 rtl/alpha_fmc_top.v    | 272 ++++++++++++++++++++++++-------------------------
 rtl/clkmgr_mmcm.v      | 241 ++++++++++++++++++++-----------------------
 rtl/clkmgr_mmcm_ctrl.v | 117 +++++++++++++++++++++
 rtl/clkmgr_reset_gen.v |  69 +++++++++++++
 5 files changed, 518 insertions(+), 363 deletions(-)

diff --git a/rtl/alpha_clkmgr.v b/rtl/alpha_clkmgr.v
index 5c4099e..0f5f912 100644
--- a/rtl/alpha_clkmgr.v
+++ b/rtl/alpha_clkmgr.v
@@ -7,7 +7,7 @@
 //
 //
 // Author: Pavel Shatov
-// Copyright (c) 2016, 2018 NORDUnet A/S All rights reserved.
+// Copyright (c) 2016, 2018-2019 NORDUnet A/S All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions
@@ -38,101 +38,101 @@
 //======================================================================
 
 module alpha_clkmgr
-  (
-   input wire  fmc_clk,         // signal from clock pin
-
-   output wire sys_clk,         // buffered system clock output
-   output wire sys_rst_n        // system reset output (async set, sync clear, active-low)
-   );
-
-
-   //
-   // Settings
-   //
-	
-	/*
-	 * fmc_clk is 90 MHz, sys_clk is also 90 MHz routed through an MMCM.
-	 *
-	 * VCO frequency is 1080 MHz.
-	 *
-	 */
-   localparam CLK_OUT_MUL   = 12.0;
-   localparam CLK_OUT_DIV   = 12.0;
-   localparam CLK_OUT_PHI   = 45.0;
+(
+    input wire  fmc_clk,    // signal from clock pin
 
+    output wire io_clk,     // buffered i/o clock
+    output wire sys_clk,    // buffered system clock output
+    output wire sys_rst_n,  // system reset output (async set, sync clear, active-low)
+    output wire core_clk    // buffered high speed core clock
+);
 
-   //
-   // Wrapper for Xilinx-specific MMCM (Mixed Mode Clock Manager) primitive.
-   //
-
-   wire        gclk_int;        // buffered input clock
-   wire        mmcm_reset;      // reset input
-   wire        mmcm_locked;     // output clock valid
-   wire        gclk_missing;    // input clock stopped
-
-   clkmgr_mmcm #
-     (
-			.CLK_OUT_MUL (CLK_OUT_MUL),	// 2..64
-			.CLK_OUT_DIV (CLK_OUT_DIV),	// 1..128
-			.CLK_OUT_PHI (CLK_OUT_PHI)	// 0.0..360.0
-      )
-   mmcm
-     (
-      .gclk_in                  (fmc_clk),
-      .reset_in                 (mmcm_reset),
-
-      .gclk_out                 (gclk_int),
-      .gclk_missing_out         (gclk_missing),
-
-      .clk_out                  (sys_clk),
-      .clk_valid_out            (mmcm_locked)
-      );
-      		
-
-
-   //
-   // MMCM Reset Logic
-   //
-
-   /* MMCM should be reset on power-up and when the input clock is stopped.
-	 * Note that MMCM requires active-high reset, so the shift register is
-	 * preloaded with 1's and then gradually filled with 0's.
-    */
-
-   reg [15: 0] mmcm_rst_shreg    = {16{1'b1}};   // 16-bit shift register
-
-   always @(posedge gclk_int or posedge gclk_missing)
-     //
-     if (gclk_missing == 1'b1)
-       mmcm_rst_shreg    <= {16{1'b1}};
-     else
-       mmcm_rst_shreg    <= {mmcm_rst_shreg[14:0], 1'b0};
-
-   assign mmcm_reset = mmcm_rst_shreg[15];
-
-
-   //
-   // System Reset Logic
-   //
-
-   /* System reset is asserted for 16 cycles whenever MMCM aquires lock. Note
-    * that system reset is active-low, so the shift register is preloaded with
-    * 0's and gradually filled with 1's.
-    */
-
-   reg [15: 0] sys_rst_shreg    = {16{1'b0}};   // 16-bit shift register
-
-   always @(posedge sys_clk or posedge gclk_missing or negedge mmcm_locked)
-     //
-     if ((gclk_missing == 1'b1) || (mmcm_locked == 1'b0))
-       sys_rst_shreg    <= {16{1'b0}};
-     else if (mmcm_locked == 1'b1)
-       sys_rst_shreg    <= {sys_rst_shreg[14:0], 1'b1};
-
-   assign sys_rst_n = sys_rst_shreg[15];
+
+    //
+    // Parameters
+    //
+    parameter integer CLK_CORE_MULT = 4;
+    
+
+    //
+    // STARTUPE2
+    //
+    wire cfg_mclk;  // 65 MHz (+/- 50%) internal oscillator
+    wire cfg_eos;   // end-of-startup flag
+    
+    STARTUPE2 #
+    (
+        .SIM_CCLK_FREQ  (0.0),    // config clock frequency for simulation
+        .PROG_USR       ("FALSE") // only used with encrypted bitstreams
+    )
+    STARTUPE2_inst
+    (
+        .CLK        (1'b0),     // no external clock
+        .CFGCLK     (),         // config clock (unused)
+        .CFGMCLK    (cfg_mclk), // config clock
+        .EOS        (cfg_eos),  // end-of-startup flag
+
+        .USRCCLKO   (1'b0),     // custom clock for configuration memory access (unused)
+        .USRCCLKTS  (1'b0),     // UG470 recommends this to be held low
+        .USRDONEO   (1'b1),     // custom value to drive onto DONE pin (unused)
+        .USRDONETS  (1'b1),     // tri-state DONE pin (unused)
+
+        .GSR        (1'b0),     // UG470 recommends hardwiring this low
+        .GTS        (1'b0),     // UG470 recommends this to be tied low
+        
+        .PREQ       (),         // unused when PROG_USR is disabled
+        .PACK       (1'b0),     // only used when PROG_USR is enabled
+
+        .KEYCLEARB  (1'b1)      // unused
+    );
+
+
+    //
+    // Wrapper for Xilinx-specific MMCM (Mixed Mode Clock Manager) primitive.
+    //
+    wire mmcm_reset;  // reset input
+    wire mmcm_locked; // output clock valid
+
+    clkmgr_mmcm #
+    (
+        .CLK_CORE_MULT(CLK_CORE_MULT)
+    )
+    mmcm_inst
+    (
+        .fmc_clk_in   (fmc_clk),
+        .rst_in       (mmcm_reset),
+
+        .io_clk_out   (io_clk),
+        .sys_clk_out  (sys_clk),
+        .core_clk_out (core_clk),
+        .locked_out   (mmcm_locked)
+    );
+
+    //
+    // MMCM Controller
+    //
+    clkmgr_mmcm_ctrl mmcm_ctrl_inst
+    (
+        .clk_in         (cfg_mclk),
+        .reset_n_in     (cfg_eos),
+        .locked_in      (mmcm_locked),
+        .reset_out      (mmcm_reset)
+    );
+    
+
+    //
+    // System Reset Logic
+    //
+    clkmgr_reset_gen #(.SHREG_WIDTH(16)) reset_gen_inst
+    (
+        .clk_in         (sys_clk),
+        .locked_in      (mmcm_locked),
+        .reset_n_out    (sys_rst_n)
+    );
 
 
 endmodule
+
 
 //======================================================================
 // EOF alpha_clkmgr.v
diff --git a/rtl/alpha_fmc_top.v b/rtl/alpha_fmc_top.v
index a07beee..09229b5 100644
--- a/rtl/alpha_fmc_top.v
+++ b/rtl/alpha_fmc_top.v
@@ -8,7 +8,7 @@
 //
 //
 // Author: Pavel Shatov
-// Copyright (c) 2016, 2018 NORDUnet A/S All rights reserved.
+// Copyright (c) 2016, 2018-2019 NORDUnet A/S All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions
@@ -38,147 +38,139 @@
 //
 //======================================================================
 
-`timescale 1ns / 1ps
-
 module alpha_fmc_top
-  (
-   input wire 	      gclk_pin, // 50 MHz
-
-   input wire 	      ct_noise, // cryptech avalanche noise circuit
-
-   input wire 	      fmc_clk, // clock
-   input wire [23: 0] fmc_a, // address
-   inout wire [31: 0] fmc_d, // data
-   input wire 	      fmc_ne1, // chip select
-   input wire 	      fmc_noe, // output enable
-   input wire 	      fmc_nwe, // write enable
-   input wire 	      fmc_nl, // latch enable
-   output wire 	      fmc_nwait,// wait
-
-   output wire 	      mkm_sclk,
-   output wire 	      mkm_cs_n,
-   input wire 	      mkm_do,
-   output wire 	      mkm_di,
-
-   output wire [3: 0] led_pins  // {red, yellow, green, blue}
-   );
-
-
-   //----------------------------------------------------------------
-   // Clock Manager
-   //
-   // Clock manager is used to buffer FMC_CLK and implement reset logic.
-   // ----------------------------------------------------------------
-   wire               sys_clk;		// system clock (90 MHz)
-   wire               sys_rst_n;	// active-low reset
-
-	alpha_clkmgr clkmgr
-	(
-		.fmc_clk		(fmc_clk),
-	
-		.sys_clk		(sys_clk),
-		.sys_rst_n		(sys_rst_n)
-	);
-
-
-
-   //----------------------------------------------------------------
-   // FMC Arbiter
-   //
-   // FMC arbiter handles FMC accesses.
-   //----------------------------------------------------------------
-
-   wire [23: 0]       sys_fmc_addr;     // address
-   wire               sys_fmc_wren;     // write enable
-   wire               sys_fmc_rden;     // read enable
-   wire [31: 0]       sys_fmc_dout;     // data output (from STM32 to FPGA)
-   wire [31: 0]       sys_fmc_din;      // data input (from FPGA to STM32)
-
-   fmc_arbiter #
-     (
-      .NUM_ADDR_BITS(24)        // change to 26 when Alpha is alive!
-      )
-   fmc
-     (
-      .fmc_a(fmc_a),
-      .fmc_d(fmc_d),
-      .fmc_ne1(fmc_ne1),
-      .fmc_nl(fmc_nl),
-      .fmc_nwe(fmc_nwe),
-      .fmc_noe(fmc_noe),
-      .fmc_nwait(fmc_nwait),
-
-      .sys_clk(sys_clk),
-
-      .sys_addr(sys_fmc_addr),
-      .sys_wr_en(sys_fmc_wren),
-      .sys_rd_en(sys_fmc_rden),
-      .sys_data_out(sys_fmc_dout),
-      .sys_data_in(sys_fmc_din)
-      );
-
-
-   //----------------------------------------------------------------
-   // LED Driver
-   //
-   // A simple utility LED driver that turns on the Alpha
-   // board LED when the FMC interface is active.
-   //----------------------------------------------------------------
-   fmc_indicator led
-     (
-      .sys_clk(sys_clk),
-      .sys_rst_n(sys_rst_n),
-      .fmc_active(sys_fmc_wren | sys_fmc_rden),
-      .led_out(led_pins[0])
-      );
-
-
-   //----------------------------------------------------------------
-   // Core Selector
-   //
-   // This multiplexer is used to map different types of cores, such as
-   // hashes, RNGs and ciphers to different regions (segments) of memory.
-   //----------------------------------------------------------------
-
-   // A note on byte-swapping:
-   // STM32 is little-endian, while the register interface here is
-   // big-endian. The software reads and writes 32-bit integer values,
-   // which means transmitting the least significant byte first. Up to
-   // now, we've been doing byte-swapping in software, which is
-   // inefficient, especially for bulk data transfer. So now we're doing
-   // the byte-swapping in hardware.
-
-   wire [31:0]        write_data;
-   assign write_data = {sys_fmc_dout[7:0], sys_fmc_dout[15:8], sys_fmc_dout[23:16], sys_fmc_dout[31:24]};
-
-   wire [31 : 0]      read_data;
-   assign sys_fmc_din = {read_data[7:0], read_data[15:8], read_data[23:16], read_data[31:24]};
-
-   core_selector cores
-     (
-      .sys_clk(sys_clk),
-      .sys_rst_n(sys_rst_n),
-
-      .sys_fmc_addr(sys_fmc_addr),
-      .sys_fmc_wr(sys_fmc_wren),
-      .sys_fmc_rd(sys_fmc_rden),
-      .sys_write_data(write_data),
-      .sys_read_data(read_data),
-
-      .noise(ct_noise),
-
-      .mkm_sclk(mkm_sclk),
-      .mkm_cs_n(mkm_cs_n),
-      .mkm_do(mkm_do),
-      .mkm_di(mkm_di)
-      );  
-
-
-   //
-   // Dummy assignment to bypass unconnected outpins pins check in BitGen
-   //
+(
+//  input  wire         gclk_pin, // 50 MHz
+
+    input  wire         ct_noise, // cryptech avalanche noise circuit
+
+    input  wire         fmc_clk, // clock
+    input  wire [23: 0] fmc_a, // address
+    inout  wire [31: 0] fmc_d, // data
+    input  wire         fmc_ne1, // chip select
+    input  wire         fmc_noe, // output enable
+    input  wire         fmc_nwe, // write enable
+    input  wire         fmc_nl, // latch enable
+    output wire         fmc_nwait,// wait
+
+    output wire         mkm_sclk,
+    output wire         mkm_cs_n,
+    input  wire         mkm_do,
+    output wire         mkm_di,
+
+    output wire [3: 0]  led_pins  // {red, yellow, green, blue}
+);
+
+
+    //----------------------------------------------------------------
+    // Clock Manager
+    //
+    // Clock manager is used to buffer FMC_CLK and implement reset logic.
+    // ----------------------------------------------------------------
+    wire io_clk;    // FMC I/O clock (45 MHz)
+    wire sys_clk;   // system clock (90 MHz)
+    wire sys_rst_n; // active-low system reset
+    wire core_clk;  // high-speed core clock (45*N MHz)
+
+    alpha_clkmgr #(.CLK_CORE_MULT(4)) clkmgr
+    (
+        .fmc_clk    (fmc_clk),
+    
+        .io_clk     (io_clk),
+        .sys_clk    (sys_clk),
+        .sys_rst_n  (sys_rst_n),
+        .core_clk   (core_clk)
+    );
+
+
+
+    //----------------------------------------------------------------
+    // FMC Arbiter
+    //
+    // FMC arbiter handles FMC accesses.
+    //----------------------------------------------------------------
+
+    wire [23: 0] sys_fmc_addr;  // address
+    wire         sys_fmc_wren;  // write enable
+    wire         sys_fmc_rden;  // read enable
+    wire [31: 0] sys_fmc_dout;  // data output (from STM32 to FPGA)
+    wire [31: 0] sys_fmc_din;   // data input (from FPGA to STM32)
+
+    fmc_arbiter #
+    (
+        .NUM_ADDR_BITS(24)      // change to 26 when Alpha is alive!
+    )
+    fmc
+    (
+        .fmc_a(fmc_a),
+        .fmc_d(fmc_d),
+        .fmc_ne1(fmc_ne1),
+        .fmc_nl(fmc_nl),
+        .fmc_nwe(fmc_nwe),
+        .fmc_noe(fmc_noe),
+        .fmc_nwait(fmc_nwait),
+
+        .sys_clk(sys_clk),
+        .io_clk(io_clk),
+
+        .sys_addr(sys_fmc_addr),
+        .sys_wr_en(sys_fmc_wren),
+        .sys_rd_en(sys_fmc_rden),
+        .sys_data_out(sys_fmc_dout),
+        .sys_data_in(sys_fmc_din)
+    );
+
+
+    //----------------------------------------------------------------
+    // LED Driver
+    //
+    // A simple utility LED driver that turns on the Alpha
+    // board LED when the FMC interface is active.
+    //----------------------------------------------------------------
+    fmc_indicator led
+    (
+        .sys_clk(sys_clk),
+        .sys_rst_n(sys_rst_n),
+        .fmc_active(sys_fmc_wren | sys_fmc_rden),
+        .led_out(led_pins[0])
+    );
+
+
+    //----------------------------------------------------------------
+    // Core Selector
+    //
+    // This multiplexer is used to map different types of cores, such as
+    // hashes, RNGs and ciphers to different regions (segments) of memory.
+    //----------------------------------------------------------------
+
+    core_selector cores
+    (
+        .sys_clk(sys_clk),
+        .sys_rst_n(sys_rst_n),
+        .core_clk(core_clk),
+
+        .sys_fmc_addr(sys_fmc_addr),
+        .sys_fmc_wr(sys_fmc_wren),
+        .sys_fmc_rd(sys_fmc_rden),
+        .sys_write_data(sys_fmc_dout),
+        .sys_read_data(sys_fmc_din),
+        .sys_error(),
+
+        .noise(ct_noise),
+
+        .mkm_sclk(mkm_sclk),
+        .mkm_cs_n(mkm_cs_n),
+        .mkm_do(mkm_do),
+        .mkm_di(mkm_di),
+        
+        .debug()
+    );
+
    
-   assign led_pins[3:1] = 3'b000;
+    //
+    // Dummy assignment to get past the unconnected outpins pins check in BitGen
+    //
+    assign led_pins[3:1] = 3'b000;
 
 
 endmodule
diff --git a/rtl/clkmgr_mmcm.v b/rtl/clkmgr_mmcm.v
index 03b0747..afb5716 100644
--- a/rtl/clkmgr_mmcm.v
+++ b/rtl/clkmgr_mmcm.v
@@ -1,12 +1,12 @@
 //======================================================================
 //
 // clkmgr_mmcm.v
-// ---------------
+// -------------
 // Xilinx MMCM primitive wrapper to avoid using Clocking Wizard IP core.
 //
 //
 // Author: Pavel Shatov
-// Copyright (c) 2016, 2018, NORDUnet A/S All rights reserved.
+// Copyright (c) 2019, NORDUnet A/S All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions
@@ -37,144 +37,121 @@
 //======================================================================
 
 module clkmgr_mmcm
-  (
-   input wire  gclk_in,
-   input wire  reset_in,
-  
-   output wire gclk_out,
-   output wire gclk_missing_out,
+(
+    input fmc_clk_in,
+    input rst_in,
+    
+    output io_clk_out,
+    output sys_clk_out,
+    output core_clk_out,
+    output locked_out
+);
 
-   output wire clk_out,
-   output wire clk_valid_out
-   );
-   
-   
-    //
-    // Parameters
-    //
-    parameter    CLK_OUT_MUL     = 12.0;    // multiply factor for output clock frequency (2..64)
-    parameter    CLK_OUT_DIV     = 12.0;    // divide factor for output clock frequency (1..128)
-    parameter	 CLK_OUT_PHI	 = 45.0;    // clock phase shift (0.0..360.0)
-   
-   
-   //
-   // IBUFG
-   //
- 
-   (* BUFFER_TYPE="NONE" *)
-	wire        gclk_in_ibufg;
-	
-	IBUFG IBUFG_gclk
-   (
-		.I (gclk_in),
-		.O	(gclk_in_ibufg)
-	);
-
-
-	//
-	// MMCME2_ADV
-	//
-	wire	mmcm_clkout0;
-	wire	mmcm_locked;
-	wire	mmcm_clkfbout;
-	wire	mmcm_clkfbout_bufg;
-	
-	MMCME2_ADV #
-	(
-		.CLKIN1_PERIOD        (11.111),
-		.REF_JITTER1          (0.010),
-
-		.STARTUP_WAIT         ("FALSE"),
-		.BANDWIDTH            ("OPTIMIZED"),
-		.COMPENSATION         ("ZHOLD"),
-
-		.DIVCLK_DIVIDE        (1),
-		
-		.CLKFBOUT_MULT_F      (CLK_OUT_MUL),
-		.CLKFBOUT_PHASE       (0.000),
-		.CLKFBOUT_USE_FINE_PS ("FALSE"),
-		
-		.CLKOUT0_DIVIDE_F     (CLK_OUT_DIV),
-		.CLKOUT0_PHASE        (CLK_OUT_PHI),
-		.CLKOUT0_USE_FINE_PS  ("FALSE"),
-		.CLKOUT0_DUTY_CYCLE   (0.500),
-		
-		.CLKOUT4_CASCADE      ("FALSE")
-	)
-	MMCME2_ADV_inst
-	(
-		.CLKIN1              (gclk_in_ibufg),
-		.CLKIN2              (1'b0),
-		.CLKINSEL            (1'b1),
+    parameter integer CLK_CORE_MULT = 4;
 
-		.CLKFBIN             (mmcm_clkfbout_bufg),
-		.CLKFBOUT            (mmcm_clkfbout),
-		.CLKFBOUTB           (),
-		
-		.CLKINSTOPPED        (gclk_missing_out),
-		.CLKFBSTOPPED        (),
+    function  integer lookup_vco_freq;
+        input integer core_mult;
+        case (core_mult)
+            2: lookup_vco_freq =  990;
+            3: lookup_vco_freq =  945;
+            4: lookup_vco_freq = 1080;
+            5: lookup_vco_freq =  900;
+            6: lookup_vco_freq = 1080;
+            7: lookup_vco_freq =  945;
+            8: lookup_vco_freq = 1080;
+        endcase
+    endfunction
+    
+    localparam real FMC_CLK_PERIOD_F = 22.222;
+    localparam real FB_PHASE_F       = 45.0;
+    localparam real SYS_FREQ_F       = 90.0;
+    
+    localparam integer VCO_FREQ  = lookup_vco_freq(CLK_CORE_MULT);
+    localparam integer IO_FREQ   = 45;
+    localparam integer CORE_FREQ = CLK_CORE_MULT * IO_FREQ;
 
-		.CLKOUT0             (mmcm_clkout0),
-		.CLKOUT0B            (),
-		
-		.CLKOUT1             (),
-		.CLKOUT1B            (),
-		
-		.CLKOUT2             (),
-		.CLKOUT2B            (),
-		
-		.CLKOUT3             (),
-		.CLKOUT3B            (),
-		
-		.CLKOUT4             (),
-		.CLKOUT5             (),
-		.CLKOUT6             (),
-		
-		.DCLK                (1'b0),
-		.DEN                 (1'b0),		
-		.DWE                 (1'b0),
-		.DADDR               (7'd0),
-		.DI                  (16'h0000),
-		.DO                  (),
-		.DRDY                (),
-		
-		.PSCLK               (1'b0),
-		.PSEN                (1'b0),
-		.PSINCDEC            (1'b0),
-		.PSDONE              (),
-		
-		.LOCKED              (mmcm_locked),
-		.PWRDWN              (1'b0),
-		.RST                 (reset_in)
-	);
+    localparam real VCO_FREQ_F = 1.0 * VCO_FREQ;
+    localparam real FMC_FREQ_F = 1.0 * IO_FREQ;
+    
+    localparam real FB_MULT_F  = VCO_FREQ_F / FMC_FREQ_F;
+    localparam real CLK0_DIV_F = VCO_FREQ_F / SYS_FREQ_F;
+    
+    localparam integer CLK1_DIV   = VCO_FREQ / IO_FREQ;
+    localparam integer CLK2_DIV   = VCO_FREQ / CORE_FREQ;
 
+    wire fmc_clk_ibufg;
+    IBUFG IBUFG_fmc_clk
+    (
+        .I(fmc_clk_in),
+        .O(fmc_clk_ibufg)
+    );
 
-	//
-	// Mapping
-	//
-	assign	gclk_out        = gclk_in_ibufg;
-	assign	clk_valid_out   = mmcm_locked;
-
-	
-	//
-	// BUFGs
-	//
-	BUFG BUFG_gclk
-   (
-		.I	(mmcm_clkout0),
-		.O	(clk_out)
+    wire mmcm_clkout0;
+    wire mmcm_clkout1;
+    wire mmcm_clkout2;
+    wire mmcm_clkfbin;
+    wire mmcm_clkfbout;
+    MMCME2_BASE #
+    (
+        .CLKIN1_PERIOD      (FMC_CLK_PERIOD_F),
+        .CLKFBOUT_MULT_F    (FB_MULT_F),
+        .CLKFBOUT_PHASE     (FB_PHASE_F),
+        .CLKOUT0_DIVIDE_F   (CLK0_DIV_F),
+        .CLKOUT1_DIVIDE     (CLK1_DIV),
+        .CLKOUT2_DIVIDE     (CLK2_DIV)
+    )
+    MMCME2_BASE_io_clk
+    (
+        .CLKIN1     (fmc_clk_ibufg),
+        .RST        (rst_in),
+        .PWRDWN     (1'b0),
+
+        .LOCKED     (locked_out),
+
+      
+        .CLKFBOUT   (mmcm_clkfbout),
+        .CLKFBOUTB  (),
+        .CLKFBIN    (mmcm_clkfbin),
+      
+        .CLKOUT0    (mmcm_clkout0),
+        .CLKOUT0B   (),
+        .CLKOUT1    (mmcm_clkout1),
+        .CLKOUT1B   (),
+        .CLKOUT2    (mmcm_clkout2),
+        .CLKOUT2B   (),
+        .CLKOUT3    (),
+        .CLKOUT3B   (),
+        .CLKOUT4    (),
+        .CLKOUT5    (),
+        .CLKOUT6    ()
     );
-
-	BUFG BUFG_feedback
-	(
-		.I	(mmcm_clkfbout),
-		.O	(mmcm_clkfbout_bufg)
-	);
-
-  
+
+    BUFG BUFG_clkfb
+    (
+        .I(mmcm_clkfbout),
+        .O(mmcm_clkfbin)
+    );
+
+    BUFG BUFG_clk_io
+    (
+        .I(mmcm_clkout0),
+        .O(sys_clk_out)
+    );
+    
+    BUFG BUFG_clk_sys
+    (
+        .I(mmcm_clkout1),
+        .O(io_clk_out)
+    );
+    
+    BUFG BUFG_clk_core
+    (
+        .I(mmcm_clkout2),
+        .O(core_clk_out)
+    );
 
 endmodule
 
 //======================================================================
-// EOF clkmgr_mmcm.v
+// EOF clkmgr_mmcm_io.v
 //======================================================================
diff --git a/rtl/clkmgr_mmcm_ctrl.v b/rtl/clkmgr_mmcm_ctrl.v
new file mode 100644
index 0000000..6d22291
--- /dev/null
+++ b/rtl/clkmgr_mmcm_ctrl.v
@@ -0,0 +1,117 @@
+//======================================================================
+//
+// clkmgr_mmcm_ctrl.v
+// ------------------
+// PLL reset generator and lock monitor.
+//
+//
+// Author: Pavel Shatov
+// Copyright (c) 2019, NORDUnet A/S All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// - Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+//   notice, this list of conditions and the following disclaimer in the
+//   documentation and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may
+//   be used to endorse or promote products derived from this software
+//   without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module clkmgr_mmcm_ctrl
+(
+    input  clk_in,
+    input  reset_n_in,
+    input  locked_in,
+    output reset_out
+);
+
+    //
+    // Timer Settings
+    //
+    localparam [13:0] tmr_zero = {14{1'b0}};
+    localparam [13:0] tmr_last = {14{1'b1}};
+    reg        [13:0] tmr      = tmr_zero;
+    wire       [13:0] tmr_next = tmr + 1'b1;
+    wire       [ 9:0] tmr_msb  = tmr[13:4];
+    
+    wire              tmr_about_to_wrap = tmr == tmr_last;
+    wire              tmr_msb_is_zero   = tmr_msb == 10'd0;
+    
+    //
+    // Lock Counting and Monitoring
+    //
+    reg  [1:0] pll_seen_locks      = 2'd0;
+    wire [1:0] pll_seen_locks_next = (pll_seen_locks < 2'd3) ? pll_seen_locks + 1'b1 : pll_seen_locks;
+
+    (* SHREG_EXTRACT="NO" *)
+    (* EQUIVALENT_REGISTER_REMOVAL="NO" *)
+    reg  [3:0] pll_stable_lock_shreg = 4'h0;
+    wire       pll_stable_lock = pll_stable_lock_shreg[3];
+        
+    wire pll_needs_reset = (pll_seen_locks != 2'd1) || !pll_stable_lock;
+
+    //
+    // Output Register
+    //
+    reg reset_out_r = 1'b1;
+    assign reset_out = reset_out_r;
+    
+    //
+    // Timer Increment/Wrap Logic
+    //
+    always @(posedge clk_in or negedge reset_n_in)
+        //
+        if (!reset_n_in)              tmr <= tmr_zero;
+        else begin
+            if (!tmr_about_to_wrap)   tmr <= tmr_next;
+            else if (pll_needs_reset) tmr <= tmr_zero;
+        end
+
+    //
+    // Lock Counter
+    //
+    always @(posedge locked_in or posedge reset_out)
+        //
+        if (reset_out) pll_seen_locks <= 2'd0;
+        else           pll_seen_locks <= pll_seen_locks_next;
+
+    //
+    // Lock Monitor
+    //
+    always @(posedge clk_in or negedge locked_in)
+        //
+        if (!locked_in) pll_stable_lock_shreg <= 4'h0;
+        else            pll_stable_lock_shreg <= {pll_stable_lock_shreg[2:0], 1'b1};
+
+    //
+    // Reset Generator
+    //
+    always @(posedge clk_in or negedge reset_n_in)
+        //
+        if (!reset_n_in) reset_out_r <= 1'b1;
+        else             reset_out_r <= tmr_msb_is_zero;
+
+endmodule
+
+//======================================================================
+// EOF clkmgr_mmcm_ctrl.v
+//======================================================================
diff --git a/rtl/clkmgr_reset_gen.v b/rtl/clkmgr_reset_gen.v
new file mode 100644
index 0000000..9cc4401
--- /dev/null
+++ b/rtl/clkmgr_reset_gen.v
@@ -0,0 +1,69 @@
+//======================================================================
+//
+// clkmgr_reset_gen.v
+// ------------------
+// System reset generator.
+//
+//
+// Author: Pavel Shatov
+// Copyright (c) 2019, NORDUnet A/S All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// - Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+//   notice, this list of conditions and the following disclaimer in the
+//   documentation and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may
+//   be used to endorse or promote products derived from this software
+//   without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module clkmgr_reset_gen
+(
+    input  clk_in,
+    input  locked_in,
+    output reset_n_out
+);
+
+    //
+    // Parameter
+    //
+    parameter integer SHREG_WIDTH = 16;
+
+    //
+    // Shift Register
+    //
+    (* SHREG_EXTRACT="NO" *)
+    (* EQUIVALENT_REGISTER_REMOVAL="NO" *)
+    reg [SHREG_WIDTH-1:0] sys_rst_shreg = {SHREG_WIDTH{1'b0}};
+
+    always @(posedge clk_in or negedge locked_in)
+        //
+        if (!locked_in) sys_rst_shreg <= {SHREG_WIDTH{1'b0}};
+        else            sys_rst_shreg <= {sys_rst_shreg[SHREG_WIDTH-2:0], 1'b1};
+
+    assign reset_n_out = sys_rst_shreg[SHREG_WIDTH-1];
+
+endmodule
+
+//======================================================================
+// EOF clkmgr_reset_gen.v
+//======================================================================



More information about the Commits mailing list