clocks393.v 14.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*!
 * <b>Module:</b>clocks393
 * @file clocks393.v
 * @date 2015-07-17  
 * @author Andrey  Filippov   
 *
 * @brief Generating global clocks for x393 (excluding memcntrl and SATA)
 *
 * @copyright Copyright (c) 2015 Elphel, Inc .
 *
 * <b>License:</b>
12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * clocks393.v is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  clocks393.v is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/> .
25 26 27 28 29 30
 *
 * Additional permission under GNU GPL version 3 section 7:
 * If you modify this Program, or any covered work, by linking or combining it
 * with independent modules provided by the FPGA vendor only (this permission
 * does not extend to any 3-rd party modules, "soft cores" or macros) under
 * different license terms solely for the purpose of generating binary "bitstream"
31
 * files and/or simulating the code, the copyright holders of this Program give
32 33
 * you the right to distribute the covered work without those independent modules
 * as long as the source code for them is available from the FPGA vendor free of
Andrey Filippov's avatar
Andrey Filippov committed
34
 * charge, and there is no dependence on any encrypted modules for simulating of
35 36 37
 * the combined code. This permission applies to you if the distributed code
 * contains all the components and scripts required to completely simulate it
 * with at least one of the Free Software programs.
38
 */
39 40 41 42 43 44 45 46 47
`timescale 1ns/1ps

module  clocks393#(
        parameter CLK_ADDR =                  'h728, // ..'h729
        parameter CLK_MASK =                  'h7fe, //
        parameter CLK_STATUS_REG_ADDR =       'h3a,  //  
        parameter CLK_CNTRL =                 0,
        parameter CLK_STATUS =                1,
        
48 49 50
        parameter CLK_RESET =                'h0, // which clocks should stay reset after release of masrter reset {ff1,ff0,mem,sync,xclk,pclk,xclk}
        parameter CLK_PWDWN =                'h0, // which clocks should stay powered down  after release of masrter reset {sync,xclk,pclk,xclk}
        
51 52 53 54 55 56 57 58 59 60
        parameter CLKIN_PERIOD_AXIHP =        20, //ns >1.25, 600<Fvco<1200
        parameter DIVCLK_DIVIDE_AXIHP =       1,
        parameter CLKFBOUT_MULT_AXIHP =       18, // Fvco=Fclkin*CLKFBOUT_MULT_F/DIVCLK_DIVIDE, Fout=Fvco/CLKOUT#_DIVIDE
        parameter CLKOUT_DIV_AXIHP =           6,   // To get 150MHz for the reference clock
        parameter BUF_CLK1X_AXIHP =           "BUFG", // "BUFG", "BUFH", "BUFR", "NONE"
        
        parameter CLKIN_PERIOD_PCLK =         42, // 24MHz 
        parameter DIVCLK_DIVIDE_PCLK =         1,
        parameter CLKFBOUT_MULT_PCLK =        40, // 960 MHz
        parameter CLKOUT_DIV_PCLK =           10, // 96MHz 
61 62
        parameter BUF_CLK1X_PCLK =            "BUFG",
`ifdef USE_PCLK2X    
63 64 65
        parameter CLKOUT_DIV_PCLK2X =          5, // 192 MHz
        parameter PHASE_CLK2X_PCLK =           0.000, 
        parameter BUF_CLK1X_PCLK2X =          "BUFG",  
66
`endif        
Andrey Filippov's avatar
Andrey Filippov committed
67
        parameter CLKIN_PERIOD_XCLK =         20, // 50MHz 
68
        parameter DIVCLK_DIVIDE_XCLK =         1,
Andrey Filippov's avatar
Andrey Filippov committed
69
        parameter CLKFBOUT_MULT_XCLK =        20, // 50*20=1000 MHz
70 71 72
        parameter CLKOUT_DIV_XCLK =           10, // 100 MHz
        parameter BUF_CLK1X_XCLK =            "BUFG",
`ifdef  USE_XCLK2X     
73 74 75
        parameter CLKOUT_DIV_XCLK2X =          5, // 200 MHz
        parameter PHASE_CLK2X_XCLK =           0.000, 
        parameter BUF_CLK1X_XCLK2X =          "BUFG",  
76
`endif        
Andrey Filippov's avatar
Andrey Filippov committed
77
        parameter CLKIN_PERIOD_SYNC =         20, // 50MHz 
78
        parameter DIVCLK_DIVIDE_SYNC =         1,
Andrey Filippov's avatar
Andrey Filippov committed
79
        parameter CLKFBOUT_MULT_SYNC =        20, // 50*20=1000 MHz
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
        parameter CLKOUT_DIV_SYNC =           10, // 100 MHz 
        parameter BUF_CLK1X_SYNC =            "BUFG",
        
        parameter MEMCLK_CAPACITANCE =        "DONT_CARE",
        parameter MEMCLK_IBUF_LOW_PWR =       "TRUE",
        parameter MEMCLK_IOSTANDARD =         "DEFAULT",

        parameter FFCLK0_CAPACITANCE =        "DONT_CARE",
        parameter FFCLK0_DIFF_TERM =          "FALSE",
        parameter FFCLK0_IBUF_LOW_PWR =       "TRUE",
        parameter FFCLK0_IOSTANDARD =         "DEFAULT",
        
        parameter FFCLK1_CAPACITANCE =        "DONT_CARE",
        parameter FFCLK1_DIFF_TERM =          "FALSE",
        parameter FFCLK1_IBUF_LOW_PWR =       "TRUE",
        parameter FFCLK1_IOSTANDARD =         "DEFAULT"
        
)(
98
    input       async_rst, // always reset MMCM/PLL 
99
    input       mclk, // global clock, comes from the memory controller (uses aclk generated here)
Andrey Filippov's avatar
Andrey Filippov committed
100
    input       mrst,
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
    // command/status interface
    input                   [7:0] cmd_ad,       // byte-serial command address/data (up to 6 bytes: AL-AH-D0-D1-D2-D3 
    input                         cmd_stb,      // strobe (with first byte) for the command a/d
    output                  [7:0] status_ad,    // status address/data - up to 5 bytes: A - {seq,status[1:0]} - status[2:9] - status[10:17] - status[18:25]
    output                        status_rq,    // input request to send status downstream
    input                         status_start, // Acknowledge of the first status packet byte (address)
    input [3:0] fclk, // 4 clocks coming from the Zynq PS. Currently only [0] is used
    input       memclk_pad, // connected to external clock generator (VDD=1.5V)
    input       ffclk0p_pad, // differential clock (P) same power as sensors 0 and 1 (VCC_SENS01) 
    input       ffclk0n_pad, // differential clock (N) same power as sensors 0 and 1 (VCC_SENS01)
    input       ffclk1p_pad, // differential clock (P) same power as sensors 0 and 1 (VCC_SENS01) 
    input       ffclk1n_pad, // differential clock (N) same power as sensors 0 and 1 (VCC_SENS01)
    output      aclk,        // global clock 50 MHz (used for maxi0)
    output      hclk,        // global clock 150MHz (used for afi*, saxi*)
    output      pclk,        // global clock for sensors (now 96MHz), based on external clock generator
116
`ifdef USE_PCLK2X    
117
    output      pclk2x,      // global clock for sennors, 2x frequency (now 192MHz)
118
`endif
119
    output      xclk,        // global clock for compressor (now 100MHz) 
120
`ifdef  USE_XCLK2X     
121
    output      xclk2x,      // global clock for compressor, 2x frequency (now 200MHz)
122
`endif    
123
    output      sync_clk,    // global clock for camsync module (96 MHz for 353 compatibility - switch to 100MHz)?
124
    output      time_ref,     // non-global, just RTC (currently just mclk/8 = 25 MHz)
125 126 127 128 129
    input [1:0] extra_status, // just extra two status bits from the top module
    output      locked_sync_clk,
    output      locked_xclk,
    output      locked_pclk,
    output      locked_hclk
130 131 132 133 134 135 136 137 138 139 140 141
);
    wire         memclk;
    wire         ffclk0;
    wire         ffclk1;
    wire  [8:0] status_data;
    wire  [10:0] cmd_data;
    wire         cmd_we;
    wire   [0:0] cmd_a;
    
    wire         set_ctrl_w =   cmd_we & ((cmd_a  && CLK_MASK) == CLK_CNTRL);
    wire         set_status_w = cmd_we & ((cmd_a  && CLK_MASK) == CLK_STATUS);
    wire   [3:0] locked;
142 143
    reg    [6:0] reset_clk = CLK_RESET;
    reg    [3:0] pwrdwn_clk = CLK_PWDWN; 
144 145 146 147
    reg    [2:0] test_clk; // FF to test input clocks are running
    wire memclk_rst = reset_clk[4];
    wire ffclk0_rst = reset_clk[5];
    wire ffclk1_rst = reset_clk[6];
148 149 150 151 152 153

    assign locked_sync_clk = locked[3];
    assign locked_xclk =     locked[2];
    assign locked_pclk =     locked[1];
    assign locked_hclk =     locked[0];

Andrey Filippov's avatar
Andrey Filippov committed
154
    always @ (posedge mclk) begin
155
        if (mrst)            reset_clk <= CLK_RESET;
156 157
        else if (set_ctrl_w) reset_clk <= {cmd_data[10:8], cmd_data[3:0]};
         
158
        if (mrst)            pwrdwn_clk <= CLK_PWDWN;
159
        else if (set_ctrl_w) pwrdwn_clk <= cmd_data[7:4]; 
160
    end
161
    assign status_data = {test_clk, locked, extra_status};
162 163 164
    always @ (posedge memclk or posedge memclk_rst) if (async_rst || memclk_rst) test_clk[0] <= 0; else test_clk[0] <= ~test_clk[0];
    always @ (posedge ffclk0 or posedge ffclk0_rst) if (async_rst || ffclk0_rst) test_clk[1] <= 0; else test_clk[1] <= ~test_clk[1];
    always @ (posedge ffclk1 or posedge ffclk1_rst) if (async_rst || ffclk1_rst) test_clk[2] <= 0; else test_clk[2] <= ~test_clk[2];
165 166 167 168 169 170 171 172
    
    cmd_deser #(
        .ADDR       (CLK_ADDR),
        .ADDR_MASK  (CLK_MASK),
        .NUM_CYCLES (4),
        .ADDR_WIDTH (1),
        .DATA_WIDTH (11)
    ) cmd_deser_32bit_i (
Andrey Filippov's avatar
Andrey Filippov committed
173
        .rst        (1'b0),     // rst),      // input
174
        .clk        (mclk),     // input
Andrey Filippov's avatar
Andrey Filippov committed
175
        .srst       (mrst),     // input
176 177 178 179 180 181 182 183 184 185 186 187
        .ad         (cmd_ad),   // input[7:0] 
        .stb        (cmd_stb),  // input
        .addr       (cmd_a),    // output[3:0] 
        .data       (cmd_data), // output[31:0] 
        .we         (cmd_we)    // output
    );
 
    status_generate #(
        .STATUS_REG_ADDR     (CLK_STATUS_REG_ADDR),
        .PAYLOAD_BITS        (9),
        .REGISTER_STATUS     (0)
    ) status_generate_i (
Andrey Filippov's avatar
Andrey Filippov committed
188 189 190 191
        .rst           (1'b0),          // rst),      // input
        .clk           (mclk),          // input
        .srst          (mrst),          // input
        .we            (set_status_w),  // input
192
        .wd            (cmd_data[7:0]), // input[7:0] 
Andrey Filippov's avatar
Andrey Filippov committed
193 194 195 196
        .status        (status_data),   // input[14:0] 
        .ad            (status_ad),     // output[7:0] 
        .rq            (status_rq),     // output
        .start         (status_start)   // input
197 198 199 200 201 202 203 204 205 206 207 208
    );
    
    BUFG bufg_axi_aclk_i  (.O(aclk), .I(fclk[0]));

    dual_clock_source #(
        .CLKIN_PERIOD     (CLKIN_PERIOD_AXIHP),
        .DIVCLK_DIVIDE    (DIVCLK_DIVIDE_AXIHP),
        .CLKFBOUT_MULT    (CLKFBOUT_MULT_AXIHP),
        .CLKOUT_DIV_CLK1X (CLKOUT_DIV_AXIHP),
        .BUF_CLK1X        (BUF_CLK1X_AXIHP),
        .BUF_CLK2X        ("NONE")
    ) dual_clock_axihp_i (
209
        .rst              (async_rst || reset_clk[0]), // input
210 211 212 213 214 215 216 217 218 219 220 221
        .clk_in           (aclk),         // input
        .pwrdwn           (pwrdwn_clk[0]), // input
        .clk1x            (hclk), // output
        .clk2x            (), // output
        .locked           (locked[0]) // output
    );
    
    dual_clock_source #(
        .CLKIN_PERIOD     (CLKIN_PERIOD_PCLK),
        .DIVCLK_DIVIDE    (DIVCLK_DIVIDE_PCLK),
        .CLKFBOUT_MULT    (CLKFBOUT_MULT_PCLK),
        .CLKOUT_DIV_CLK1X (CLKOUT_DIV_PCLK),
222 223 224
        .BUF_CLK1X        (BUF_CLK1X_PCLK)
`ifdef USE_PCLK2X    
       ,.CLKOUT_DIV_CLK2X (CLKOUT_DIV_PCLK2X),
225 226
        .PHASE_CLK2X      (PHASE_CLK2X_PCLK),
        .BUF_CLK2X        (BUF_CLK1X_PCLK2X)
227 228 229
`else
       ,.BUF_CLK2X        ("NONE")
`endif        
230
    ) dual_clock_pclk_i (
231
        .rst              (async_rst || reset_clk[1]),     // input
232 233 234
        .clk_in           (ffclk0),           // input
        .pwrdwn           (pwrdwn_clk[1]),    // input
        .clk1x            (pclk),             // output
235
`ifdef USE_PCLK2X    
236
        .clk2x            (pclk2x),           // output
237 238 239
`else        
        .clk2x            (),                 // output not connected
`endif        
240 241 242 243 244 245 246 247
        .locked           (locked[1])         // output
    );
    
    dual_clock_source #(
        .CLKIN_PERIOD     (CLKIN_PERIOD_XCLK),
        .DIVCLK_DIVIDE    (DIVCLK_DIVIDE_XCLK),
        .CLKFBOUT_MULT    (CLKFBOUT_MULT_XCLK),
        .CLKOUT_DIV_CLK1X (CLKOUT_DIV_XCLK),
248 249
        .BUF_CLK1X        (BUF_CLK1X_XCLK),
`ifdef  USE_XCLK2X     
250 251 252
        .CLKOUT_DIV_CLK2X (CLKOUT_DIV_XCLK2X),
        .PHASE_CLK2X      (PHASE_CLK2X_XCLK),
        .BUF_CLK2X        (BUF_CLK1X_XCLK2X)
253 254 255
`else
        .BUF_CLK2X        ("NONE")
`endif        
256
    ) dual_clock_xclk_i (
257
        .rst              (async_rst || reset_clk[2]),     // input
258 259 260
        .clk_in           (aclk),             // input
        .pwrdwn           (pwrdwn_clk[2]),    // input
        .clk1x            (xclk),             // output
261
`ifdef  USE_XCLK2X     
262
        .clk2x            (xclk2x),           // output
263 264 265
`else
        .clk2x            (),                 // output
`endif        
266 267 268 269 270 271 272 273 274 275 276
        .locked           (locked[2])         // output
    );
    
    dual_clock_source #(
        .CLKIN_PERIOD     (CLKIN_PERIOD_SYNC),
        .DIVCLK_DIVIDE    (DIVCLK_DIVIDE_SYNC),
        .CLKFBOUT_MULT    (CLKFBOUT_MULT_SYNC),
        .CLKOUT_DIV_CLK1X (CLKOUT_DIV_SYNC),
        .BUF_CLK1X        (BUF_CLK1X_SYNC),
        .BUF_CLK2X        ("NONE")
    ) dual_clock_sync_clk_i (
277 278
        .rst              (async_rst || reset_clk[3]),     // input
        .clk_in           (aclk),             // input
279
        .pwrdwn           (pwrdwn_clk[3]),    // input
280 281
        .clk1x            (sync_clk),         // output
        .clk2x            (),                 // output
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
        .locked           (locked[3])         // output
    );
    

    ibuf_ibufg #(
        .CAPACITANCE      (MEMCLK_CAPACITANCE),
        .IBUF_LOW_PWR     (MEMCLK_IBUF_LOW_PWR),
        .IOSTANDARD       (MEMCLK_IOSTANDARD)
    ) ibuf_ibufg_i (
        .O    (memclk),    // output
        .I    (memclk_pad) // input
    );

    ibufds_ibufgds #(
        .CAPACITANCE      (FFCLK0_CAPACITANCE),
        .DIFF_TERM        (FFCLK0_DIFF_TERM),
        .IBUF_LOW_PWR     (FFCLK0_IBUF_LOW_PWR),
        .IOSTANDARD       (FFCLK0_IOSTANDARD)
    ) ibufds_ibufgds0_i (
        .O    (ffclk0),      // output
        .I    (ffclk0p_pad), // input
        .IB   (ffclk0n_pad)  // input
    );

    ibufds_ibufgds #(
        .CAPACITANCE      (FFCLK1_CAPACITANCE),
        .DIFF_TERM        (FFCLK1_DIFF_TERM),
        .IBUF_LOW_PWR     (FFCLK1_IBUF_LOW_PWR),
        .IOSTANDARD       (FFCLK1_IOSTANDARD)
    ) ibufds_ibufgds10_i (
        .O    (ffclk1),      // output
        .I    (ffclk1p_pad), // input
        .IB   (ffclk1n_pad)  // input
    );
    
   // RTC reference: integer number of microseconds, less than mclk/2. Not a global clock
   // temporary:
    reg [2:0] time_ref_r;
320
    always @ (posedge mclk) if (mrst) time_ref_r <= 0; else time_ref_r <= time_ref_r + 1;
321 322 323 324
    assign time_ref = time_ref_r[2];

endmodule