sens_parallel12.v 34.8 KB
Newer Older
1 2 3
/*******************************************************************************
 * Module: sens_parallel12
 * Date:2015-05-10  
4
 * Author: Andrey Filippov     
5 6
 * Description: Sensor interface with 12-bit for parallel bus
 *
7
 * Copyright (c) 2015 Elphel, Inc.
8 9 10 11 12 13 14 15 16 17 18 19
 * sens_parallel12.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.
 *
 *  sens_parallel12.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/> .
20 21 22 23 24 25
 *
 * 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"
26
 * files and/or simulating the code, the copyright holders of this Program give
27 28
 * 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
29
 * charge, and there is no dependence on any encrypted modules for simulating of
30 31 32
 * 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.
33 34 35
 *******************************************************************************/
`timescale 1ns/1ps

36 37
module  sens_parallel12 #(
    parameter SENSIO_ADDR =        'h330,
38
    parameter SENSIO_ADDR_MASK =   'h7f8,
39 40 41
    parameter SENSIO_CTRL =        'h0,
    parameter SENSIO_STATUS =      'h1,
    parameter SENSIO_JTAG =        'h2,
42 43
    parameter SENSIO_WIDTH =       'h3, // set line width (1.. 2^16) if 0 - use HACT
    parameter SENSIO_DELAYS =      'h4, // 'h4..'h7 - each address sets 4 delays through 4 bytes of 32-bit data
44
    parameter SENSIO_STATUS_REG =  'h21,
45 46 47 48 49 50 51 52 53 54 55 56 57

    parameter SENS_JTAG_PGMEN =    8,
    parameter SENS_JTAG_PROG =     6,
    parameter SENS_JTAG_TCK =      4,
    parameter SENS_JTAG_TMS =      2,
    parameter SENS_JTAG_TDI =      0,
    
    parameter SENS_CTRL_MRST=      0,  //  1: 0
    parameter SENS_CTRL_ARST=      2,  //  3: 2
    parameter SENS_CTRL_ARO=       4,  //  5: 4
    parameter SENS_CTRL_RST_MMCM=  6,  //  7: 6
    parameter SENS_CTRL_EXT_CLK=   8,  //  9: 8
    parameter SENS_CTRL_LD_DLY=   10,  // 10
58 59 60 61
    parameter SENS_CTRL_QUADRANTS =      12,  // 17:12, enable - 20
    parameter SENS_CTRL_QUADRANTS_WIDTH = 6,
    parameter SENS_CTRL_QUADRANTS_EN =   20,  // 17:12, enable - 20 (2 bits reserved)
     
62 63 64 65 66 67 68 69 70
    
    parameter LINE_WIDTH_BITS =   16,
    
    parameter IODELAY_GRP ="IODELAY_SENSOR", // may need different for different channels?
    parameter integer IDELAY_VALUE = 0,
    parameter integer PXD_DRIVE = 12,
    parameter PXD_IBUF_LOW_PWR = "TRUE",
    parameter PXD_IOSTANDARD = "DEFAULT",
    parameter PXD_SLEW = "SLOW",
71 72
    parameter real SENS_REFCLK_FREQUENCY =    300.0,
    parameter SENS_HIGH_PERFORMANCE_MODE =    "FALSE",
73
    
74
    parameter SENS_PHASE_WIDTH=               8,      // number of bits for te phase counter (depends on divisors)
Andrey Filippov's avatar
Andrey Filippov committed
75
//    parameter SENS_PCLK_PERIOD =              10.000,  // input period in ns, 0..100.000 - MANDATORY, resolution down to 1 ps
76
    parameter SENS_BANDWIDTH =                "OPTIMIZED",  //"OPTIMIZED", "HIGH","LOW"
77

Andrey Filippov's avatar
Andrey Filippov committed
78
    parameter CLKIN_PERIOD_SENSOR =   10.000, // input period in ns, 0..100.000 - MANDATORY, resolution down to 1 ps
79 80
    parameter CLKFBOUT_MULT_SENSOR =   8,  // 100 MHz --> 800 MHz
    parameter CLKFBOUT_PHASE_SENSOR =  0.000,  // CLOCK FEEDBACK phase in degrees (3 significant digits, -360.000...+360.000)
81 82
    parameter IPCLK_PHASE =            0.000,
    parameter IPCLK2X_PHASE =          0.000,
83 84
    parameter BUF_IPCLK =             "BUFR",
    parameter BUF_IPCLK2X =           "BUFR",  
85 86
    

87
    parameter SENS_DIVCLK_DIVIDE =     1,            // Integer 1..106. Divides all outputs with respect to CLKIN
Andrey Filippov's avatar
Andrey Filippov committed
88
    parameter SENS_REF_JITTER1   =     0.010,        // Expected jitter on CLKIN1 (0.000..0.999)
89 90 91
    parameter SENS_REF_JITTER2   =     0.010,
    parameter SENS_SS_EN         =     "FALSE",      // Enables Spread Spectrum mode
    parameter SENS_SS_MODE       =     "CENTER_HIGH",//"CENTER_HIGH","CENTER_LOW","DOWN_HIGH","DOWN_LOW"
92 93
    parameter SENS_SS_MOD_PERIOD =     10000,        // integer 4000-40000 - SS modulation period in ns
    parameter STATUS_ALIVE_WIDTH =     4
94
)(
Andrey Filippov's avatar
Andrey Filippov committed
95
//    input         rst,
96
    input         pclk,   // global clock input, pixel rate (96MHz for MT9P006)
Andrey Filippov's avatar
Andrey Filippov committed
97 98
    input         mclk_rst,
    input         prst,
99
    output        prsts,  // @pclk - includes sensor reset and sensor PLL reset
Andrey Filippov's avatar
Andrey Filippov committed
100 101
    output        irst,
    
102 103 104
    output        ipclk,  // re-generated sensor output clock (regional clock to drive external fifo) 
    output        ipclk2x,// twice frequency regenerated sensor clock (possibly to run external fifo)
//    input         pclk2x, // maybe not needed here
105 106
    input         trigger_mode, // running in triggered mode (0 - free running mode)
    input         trig,      // per-sensor trigger input
107
    // sensor pads excluding i2c
108 109
    inout         vact,
    inout         hact, //output in fillfactory mode
110 111 112
    inout         bpf,  // output in fillfactory mode
    inout  [11:0] pxd, //actually only 2 LSBs are inouts
    inout         mrst,
113
    inout         senspgm,    // SENSPGM I/O pin
114
    
115 116
    inout         arst,
    inout         aro,
117
    output        dclk, // externally connected to inout port
118
    // output
119 120
    output reg [11:0] pxd_out,
    output reg        vact_out, 
121 122 123
    output            hact_out,
    
    input [STATUS_ALIVE_WIDTH-1:0] status_alive_1cyc, //extra toggle @mclk bits to report with status 
124 125 126 127 128 129 130 131 132 133

    // JTAG to program 10359
//    input          xpgmen,     // enable programming mode for external FPGA
//    input          xfpgaprog,  // PROG_B to be sent to an external FPGA
//    output         xfpgadone,  // state of the MRST pin ("DONE" pin on external FPGA)
//    input          xfpgatck,   // TCK to be sent to external FPGA
//    input          xfpgatms,   // TMS to be sent to external FPGA
//    input          xfpgatdi,   // TDI to be sent to external FPGA
//    output         xfpgatdo,   // TDO read from external FPGA
//    output         senspgmin,    
134 135
    
    // programming interface
Andrey Filippov's avatar
Andrey Filippov committed
136
    input         mclk,     // global clock, half DDR3 clock, synchronizes all I/O through the command port
137 138 139 140 141 142 143
    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)
);

144 145 146 147
    // delaying vact and pxd by one clock cycle to match hact register
    wire [11:0] pxd_out_pre;
    wire        vact_out_pre; 

Andrey Filippov's avatar
Andrey Filippov committed
148
    reg  [2:0] irst_r;
149 150 151 152 153 154 155 156
    wire ibpf;
    wire ipclk_pre, ipclk2x_pre;
    
    reg  [31:0] data_r; 
    reg   [3:0] set_idelay;
    reg         set_ctrl_r;
    reg         set_status_r;
    reg   [1:0] set_width_r; // to make double-cycle subtract
157 158 159
    wire        set_width_ipclk_w; //re-clocked to ipclk
    reg         set_width_ipclk_r; // copy from mclk domain when reset is off
    wire        set_width_ipclk = set_width_ipclk_w || set_width_ipclk_r; //re-clocked to ipclk
160 161
    reg         set_jtag_r;
    
162 163 164
    reg [LINE_WIDTH_BITS-1:0] line_width_m1;       // regenerated HACT duration;
    reg [LINE_WIDTH_BITS-1:0] line_width_m1_ipclk;  // regenerated HACT duration;
    
165
    reg                       line_width_internal; // use regenetrated ( 0 - use HACT as is)
166
    reg                       line_width_internal_ipclk;
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
    reg [LINE_WIDTH_BITS-1:0] hact_cntr;
    
//    reg         set_quad; // [1:0] - px, [3:2] - HACT, [5:4] - VACT,
    wire        clk_fb;
    
    wire  [2:0] set_pxd_delay;
    wire        set_other_delay;
    
    wire        ps_rdy;
    wire  [7:0] ps_out;      
    wire        locked_pxd_mmcm;
    wire        clkin_pxd_stopped_mmcm;
    wire        clkfb_pxd_stopped_mmcm;
    
    // programmed resets to the sensor 
182 183
    reg         iaro_soft  = 0;
    wire        iaro;
184 185 186
    reg         iarst = 0;
    reg         imrst = 0;
    reg         rst_mmcm=1; // rst and command - en/dis 
187
    reg  [SENS_CTRL_QUADRANTS_WIDTH-1:0]  quadrants=0; //90-degree shifts for data {1:0], hact [3:2] and vact [5:4]
188
    reg         ld_idelay=0;
189
    reg         sel_ext_clk=0; // select clock source from the sensor (0 - use internal clock - to sensor)
190 191 192



193
    wire [17:0] status;
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
    
    wire        cmd_we;
    wire  [2:0] cmd_a;
    wire [31:0] cmd_data;
    
    wire           xfpgadone;  // state of the MRST pin ("DONE" pin on external FPGA)
    wire           xfpgatdo;   // TDO read from external FPGA
    wire           senspgmin;    

    reg            xpgmen=0;     // enable programming mode for external FPGA
    reg            xfpgaprog=0;  // PROG_B to be sent to an external FPGA
    reg            xfpgatck=0;   // TCK to be sent to external FPGA
    reg            xfpgatms=0;   // TMS to be sent to external FPGA
    reg            xfpgatdi=0;   // TDI to be sent to external FPGA
    wire           hact_ext;     // received hact signal
    reg            hact_ext_r;   // received hact signal, delayed by 1 clock
210 211 212 213 214 215 216 217 218 219 220 221
    reg            hact_r;       // received or regenerated hact 

// for debug/test alive    
    reg            vact_r;       
    reg            hact_r2;
    wire           vact_a_mclk;
    wire           hact_ext_a_mclk;
    wire           hact_a_mclk;
    reg            vact_alive;
    reg            hact_ext_alive;
    reg            hact_alive;
    reg  [STATUS_ALIVE_WIDTH-1:0] status_alive;    
222 223 224 225 226 227

    reg      [1:0] prst_with_sens_mrst = 2'h3; // prst extended to include sensor reset and rst_mmcm
    wire           async_prst_with_sens_mrst =  ~imrst | rst_mmcm; // mclk domain   

    assign  prsts = prst_with_sens_mrst[0];  // @pclk - includes sensor reset and sensor PLL reset
    
228
     
229 230
    assign set_pxd_delay =   set_idelay[2:0];
    assign set_other_delay = set_idelay[3];
231 232 233
    assign status = {vact_alive, hact_ext_alive, hact_alive, locked_pxd_mmcm, 
                     clkin_pxd_stopped_mmcm, clkfb_pxd_stopped_mmcm, xfpgadone,
                     ps_rdy, ps_out, xfpgatdo, senspgmin};
234
    assign hact_out = hact_r;
235
    assign iaro = trigger_mode?  ~trig : iaro_soft;
236
    
Andrey Filippov's avatar
Andrey Filippov committed
237
    assign     irst=irst_r[2];
238
    
Andrey Filippov's avatar
Andrey Filippov committed
239
    always @ (posedge ipclk) begin
240 241
//        irst_r <= {irst_r[1:0], prst};
        irst_r <= {irst_r[1:0], prsts}; // extended reset that includes sensor reset and rst_mmcm
242
        set_width_ipclk_r <= irst_r[2] && !irst_r[1];
243 244 245 246 247 248
    end

    always @(posedge pclk or posedge async_prst_with_sens_mrst) begin
        if (async_prst_with_sens_mrst) prst_with_sens_mrst <=  2'h3;
        else if (prst)                 prst_with_sens_mrst <=  2'h3;
        else                           prst_with_sens_mrst <= prst_with_sens_mrst >> 1;
Andrey Filippov's avatar
Andrey Filippov committed
249 250 251 252 253 254 255 256
    end
    
    always @(posedge mclk) begin
        if      (mclk_rst) data_r <= 0;
        else if (cmd_we)   data_r <= cmd_data;
        
        if      (mclk_rst) set_idelay <= 0;
        else               set_idelay <=  {4{cmd_we}} & {(cmd_a==(SENSIO_DELAYS+3)),
257 258 259
                                             (cmd_a==(SENSIO_DELAYS+2)),
                                             (cmd_a==(SENSIO_DELAYS+1)),
                                             (cmd_a==(SENSIO_DELAYS+0))};
Andrey Filippov's avatar
Andrey Filippov committed
260 261 262 263 264 265 266 267
        if (mclk_rst) set_status_r <=0;
        else          set_status_r <= cmd_we && (cmd_a== SENSIO_STATUS);                             
        
        if (mclk_rst) set_ctrl_r <=0;
        else          set_ctrl_r <= cmd_we && (cmd_a== SENSIO_CTRL);                             
        
        if (mclk_rst) set_jtag_r <=0;
        else          set_jtag_r <= cmd_we && (cmd_a== SENSIO_JTAG);
268
        
Andrey Filippov's avatar
Andrey Filippov committed
269
        if      (mclk_rst)                                  xpgmen <= 0;
270 271
        else if (set_jtag_r && data_r[SENS_JTAG_PGMEN + 1]) xpgmen <= data_r[SENS_JTAG_PGMEN]; 

Andrey Filippov's avatar
Andrey Filippov committed
272
        if      (mclk_rst)                                  xfpgaprog <= 0;
273 274
        else if (set_jtag_r && data_r[SENS_JTAG_PROG + 1])  xfpgaprog <= data_r[SENS_JTAG_PROG]; 
                                     
Andrey Filippov's avatar
Andrey Filippov committed
275
        if      (mclk_rst)                                  xfpgatck <= 0;
276 277
        else if (set_jtag_r && data_r[SENS_JTAG_TCK + 1])   xfpgatck <= data_r[SENS_JTAG_TCK]; 

Andrey Filippov's avatar
Andrey Filippov committed
278
        if      (mclk_rst)                                  xfpgatms <= 0;
279 280
        else if (set_jtag_r && data_r[SENS_JTAG_TMS + 1])   xfpgatms <= data_r[SENS_JTAG_TMS]; 

Andrey Filippov's avatar
Andrey Filippov committed
281
        if      (mclk_rst)                                  xfpgatdi <= 0;
282 283
        else if (set_jtag_r && data_r[SENS_JTAG_TDI + 1])   xfpgatdi <= data_r[SENS_JTAG_TDI];
        
Andrey Filippov's avatar
Andrey Filippov committed
284
        if      (mclk_rst)                                      imrst <= 0;
285 286
        else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1])      imrst <= data_r[SENS_CTRL_MRST]; 
         
Andrey Filippov's avatar
Andrey Filippov committed
287
        if      (mclk_rst)                                      iarst <= 0;
288 289
        else if (set_ctrl_r && data_r[SENS_CTRL_ARST + 1])      iarst <= data_r[SENS_CTRL_ARST]; 
         
Andrey Filippov's avatar
Andrey Filippov committed
290
        if      (mclk_rst)                                      iaro_soft <= 0;
291
        else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1])      iaro_soft <= data_r[SENS_CTRL_ARO]; 
292
         
Andrey Filippov's avatar
Andrey Filippov committed
293
        if      (mclk_rst)                                      rst_mmcm <= 0;
294 295
        else if (set_ctrl_r && data_r[SENS_CTRL_RST_MMCM + 1])  rst_mmcm <= data_r[SENS_CTRL_RST_MMCM]; 
         
Andrey Filippov's avatar
Andrey Filippov committed
296
        if      (mclk_rst)                                      sel_ext_clk <= 0;
297 298
        else if (set_ctrl_r && data_r[SENS_CTRL_EXT_CLK + 1])   sel_ext_clk <= data_r[SENS_CTRL_EXT_CLK]; 
         
Andrey Filippov's avatar
Andrey Filippov committed
299
        if      (mclk_rst)                                      quadrants <= 0;
300
        else if (set_ctrl_r && data_r[SENS_CTRL_QUADRANTS_EN])  quadrants <= data_r[SENS_CTRL_QUADRANTS +: SENS_CTRL_QUADRANTS_WIDTH]; 
301

Andrey Filippov's avatar
Andrey Filippov committed
302 303
        if  (mclk_rst) ld_idelay <= 0;
        else           ld_idelay <= set_ctrl_r && data_r[SENS_CTRL_LD_DLY]; 
304
        
Andrey Filippov's avatar
Andrey Filippov committed
305 306
        if  (mclk_rst) set_width_r <= 0;
        else           set_width_r <= {set_width_r[0],cmd_we && (cmd_a== SENSIO_WIDTH)}; 
307
        
Andrey Filippov's avatar
Andrey Filippov committed
308
        if      (mclk_rst)       line_width_m1 <= 0;
309 310
        else if (set_width_r[1]) line_width_m1 <= data_r[LINE_WIDTH_BITS-1:0] -1;
        
Andrey Filippov's avatar
Andrey Filippov committed
311
        if      (mclk_rst)       line_width_internal <= 0;
312
        else if (set_width_r[1]) line_width_internal <= ~ (|data_r[LINE_WIDTH_BITS:0]); // line width is 0
313 314 315 316 317 318 319 320
    end

    always @(posedge ipclk) begin
        if (irst)                 line_width_m1_ipclk <= 0;
        else if (set_width_ipclk) line_width_m1_ipclk <= line_width_m1;
    
        if (irst)                 line_width_internal_ipclk <= 0;
        else if (set_width_ipclk) line_width_internal_ipclk <= line_width_internal;
321
        // regenerate/propagate  HACT
322 323
        if (irst) hact_ext_r <= 1'b0;
        else      hact_ext_r <= hact_ext;
324
        
325 326
        if      (irst)                                                      hact_r <= 0;
        else if (hact_ext && !hact_ext_r)                                   hact_r <= 1;
327
        else if (line_width_internal_ipclk?(hact_ext ==0):(hact_cntr == 0)) hact_r <= 0; 
328
        
329 330 331
        if      (irst)                                 hact_cntr <= 0;
        else if (hact_ext && !hact_ext_r)              hact_cntr <= line_width_m1_ipclk; // from mclk
        else if (hact_r && !line_width_internal_ipclk) hact_cntr <= hact_cntr - 1;
332
        
333 334 335
        pxd_out <=  pxd_out_pre;
        vact_out <= vact_out_pre;
        
336 337 338 339
        // for debug/test alive  
        vact_r <= vact_out_pre;
        hact_r2 <= hact_r;
        
340 341
    end
    
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
    // for debug/test alive  
    always @(posedge mclk) begin
        if (mclk_rst || set_status_r) vact_alive     <= 0;
        else if (vact_a_mclk)         vact_alive     <= 1;
        
        if (mclk_rst || set_status_r) hact_ext_alive <= 0;
        else if (hact_ext_a_mclk)     hact_ext_alive <= 1;
        
        if (mclk_rst || set_status_r) hact_alive     <= 0;
        else if (hact_a_mclk)         hact_alive     <= 1;
        
        if (mclk_rst || set_status_r) status_alive     <= 0;
        else                          status_alive     <= status_alive | status_alive_1cyc;
        
    end
        
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
/*
 Control programming of external FPGA on the sensor/sensor multiplexor board
 Mulptiplex status signals into a single line
 bits:
  9: 8 - 3 - set xpgmen,
       - 2 - reset xpgmen,  
       - 0, 1 - no changes to xpgmen
  7: 6 - 3 - set xfpgaprog,
       - 2 - reset xfpgaprog,  
       - 0, 1 - no changes to xfpgaprog
  5: 4 - 3 - set xfpgatck,
       - 2 - reset xfpgatck,  
       - 0, 1 - no changes to xfpgatck
  3: 2 - 3 - set xfpgatms,
       - 2 - reset xfpgatms,
       - 0, 1 - no changes to xfpgatms
  1: 0 - 3 - set xfpgatdi,
       - 2 - reset xfpgatdi,
       - 0, 1 - no changes to xfpgatdi
    parameter SENS_CTRL_MRST=      0,  //  1: 0
    parameter SENS_CTRL_ARST=      2,  //  3: 2
    parameter SENS_CTRL_ARO=       4,  //  5: 4
    parameter SENS_CTRL_RST_MMCM=  6,  //  7: 6
    parameter SENS_CTRL_EXT_CLK=   8,  //  9: 8
    parameter SENS_CTRL_LD_DLY=   10,  // 10
    parameter SENS_CTRL_QUADRANTS=12,  // 17:12, enable - 20
       
*/
    
387
    pulse_cross_clock pulse_cross_clock_set_width_ipclk_i (
388 389 390 391 392
        .rst         (mclk_rst),          // input
        .src_clk     (mclk),              // input
        .dst_clk     (ipclk),             // input
        .in_pulse    (set_width_r[1]),    // input
        .out_pulse   (set_width_ipclk_w), // output
393 394
        .busy() // output
    );
395 396 397 398 399 400 401 402 403 404
    
    
    
    cmd_deser #(
        .ADDR        (SENSIO_ADDR),
        .ADDR_MASK   (SENSIO_ADDR_MASK),
        .NUM_CYCLES  (6),
        .ADDR_WIDTH  (3),
        .DATA_WIDTH  (32)
    ) cmd_deser_sens_io_i (
Andrey Filippov's avatar
Andrey Filippov committed
405 406 407 408 409 410
        .rst         (1'b0),     // rst), // input
        .clk         (mclk),     // input
        .srst        (mclk_rst), // input
        .ad          (cmd_ad),   // input[7:0] 
        .stb         (cmd_stb),  // input
        .addr        (cmd_a),    // output[15:0] 
411
        .data        (cmd_data), // output[31:0] 
Andrey Filippov's avatar
Andrey Filippov committed
412
        .we          (cmd_we)    // output
413 414 415 416
    );

    status_generate #(
        .STATUS_REG_ADDR(SENSIO_STATUS_REG),
417
        .PAYLOAD_BITS(15+3+STATUS_ALIVE_WIDTH) // STATUS_PAYLOAD_BITS)
418
    ) status_generate_sens_io_i (
Andrey Filippov's avatar
Andrey Filippov committed
419 420 421
        .rst        (1'b0),         // rst), // input
        .clk        (mclk),         // input
        .srst       (mclk_rst),     // input
422
        .we         (set_status_r), // input
Andrey Filippov's avatar
Andrey Filippov committed
423
        .wd         (data_r[7:0]),  // input[7:0] 
424
        .status     ({status_alive,status}),       // input[25:0] 
Andrey Filippov's avatar
Andrey Filippov committed
425 426 427
        .ad         (status_ad),    // output[7:0] 
        .rq         (status_rq),    // output
        .start      (status_start)  // input
428 429 430 431 432 433 434 435 436 437 438 439 440
    );
    
    
    
    
    // 2 lower PXD bits are multifunction (used for JTAG), instance them individually
    pxd_single #(
        .IODELAY_GRP           (IODELAY_GRP),
        .IDELAY_VALUE          (IDELAY_VALUE),
        .PXD_DRIVE             (PXD_DRIVE),
        .PXD_IBUF_LOW_PWR      (PXD_IBUF_LOW_PWR),
        .PXD_IOSTANDARD        (PXD_IOSTANDARD),
        .PXD_SLEW              (PXD_SLEW),
441 442
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
443 444
    ) pxd_pxd0_i (
        .pxd            (pxd[0]),          // inout
Andrey Filippov's avatar
Andrey Filippov committed
445 446 447
        .pxd_out        (xfpgatdi),        // input
        .pxd_en         (xpgmen),          // input
        .pxd_async      (),                // output
448
        .pxd_in         (pxd_out_pre[0]),  // output
449 450
        .ipclk          (ipclk),           // input
        .ipclk2x        (ipclk2x),         // input
Andrey Filippov's avatar
Andrey Filippov committed
451 452
        .mrst           (mclk_rst),        // input
        .irst           (irst),            // input
453 454 455 456 457 458
        .mclk           (mclk),            // input
        .dly_data       (data_r[7:0]),          // input[7:0] 
        .set_idelay     (set_pxd_delay[0]),// input
        .ld_idelay      (ld_idelay),       // input
        .quadrant       (quadrants[1:0])   // input[1:0] 
    );
459 460
// debugging implementation
//assign xfpgatdo = pxd_out[1];
461 462 463 464 465 466 467
    pxd_single #(
        .IODELAY_GRP           (IODELAY_GRP),
        .IDELAY_VALUE          (IDELAY_VALUE),
        .PXD_DRIVE             (PXD_DRIVE),
        .PXD_IBUF_LOW_PWR      (PXD_IBUF_LOW_PWR),
        .PXD_IOSTANDARD        (PXD_IOSTANDARD),
        .PXD_SLEW              (PXD_SLEW),
468 469
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
470 471 472 473 474
    ) pxd_pxd1_i (
        .pxd            (pxd[1]),          // inout
        .pxd_out        (1'b0),            // input
        .pxd_en         (1'b0),            // input
        .pxd_async      (xfpgatdo),        // output
475
        .pxd_in         (pxd_out_pre[1]),  // output
476 477
        .ipclk          (ipclk),           // input
        .ipclk2x        (ipclk2x),         // input
Andrey Filippov's avatar
Andrey Filippov committed
478 479
        .mrst           (mclk_rst),        // input
        .irst           (irst),            // input
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
        .mclk           (mclk),            // input
        .dly_data       (data_r[15:8]),          // input[7:0] 
        .set_idelay     (set_pxd_delay[0]),// input
        .ld_idelay      (ld_idelay),       // input
        .quadrant       (quadrants[1:0])   // input[1:0] 
    );
    // bits 2..11 are just PXD inputs, instance them all together
    generate
        genvar i;
        for (i=2; i < 12; i=i+1) begin: pxd_block
            pxd_single #(
                .IODELAY_GRP           (IODELAY_GRP),
                .IDELAY_VALUE          (IDELAY_VALUE),
                .PXD_DRIVE             (PXD_DRIVE),
                .PXD_IBUF_LOW_PWR      (PXD_IBUF_LOW_PWR),
                .PXD_IOSTANDARD        (PXD_IOSTANDARD),
                .PXD_SLEW              (PXD_SLEW),
497 498
                .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
                .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
499
            ) pxd_pxd2_12_i (
500 501 502 503
                .pxd            (pxd[i]),          // inout
                .pxd_out        (1'b0),            // input
                .pxd_en         (1'b0),            // input
                .pxd_async      (),                // output
504
                .pxd_in         (pxd_out_pre[i]),  // output
505 506
                .ipclk          (ipclk),           // input
                .ipclk2x        (ipclk2x),         // input
Andrey Filippov's avatar
Andrey Filippov committed
507 508
                .mrst           (mclk_rst),        // input
                .irst           (irst),            // input
509
                .mclk           (mclk),            // input
510 511 512 513
//                .dly_data       (data_r[8*((i+2)&3)+:8]), // input[7:0] alternating bytes of 32-bit word
//                .set_idelay     (set_pxd_delay[(i+2)>>2]),// input 0 for pxd[3:2], 1 for pxd[7:4], 2 for pxd [11:8]
                .dly_data       (data_r[8 * (i & 3) +: 8]), // input[7:0] alternating bytes of 32-bit word
                .set_idelay     (set_pxd_delay[i >> 2]),// input 0 for pxd[3:2], 1 for pxd[7:4], 2 for pxd [11:8]
514 515 516 517 518 519 520 521 522 523 524 525 526
                .ld_idelay      (ld_idelay),       // input
                .quadrant       (quadrants[1:0])   // input[1:0] 
            );
        end
    endgenerate
    
    pxd_single #(
        .IODELAY_GRP           (IODELAY_GRP),
        .IDELAY_VALUE          (IDELAY_VALUE),
        .PXD_DRIVE             (PXD_DRIVE),
        .PXD_IBUF_LOW_PWR      (PXD_IBUF_LOW_PWR),
        .PXD_IOSTANDARD        (PXD_IOSTANDARD),
        .PXD_SLEW              (PXD_SLEW),
527 528
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
529 530 531 532 533 534 535 536
    ) pxd_hact_i (
        .pxd            (hact),          // inout
        .pxd_out        (1'b0),          // input
        .pxd_en         (1'b0),          // input
        .pxd_async      (),              // output
        .pxd_in         (hact_ext),      // output
        .ipclk          (ipclk),         // input
        .ipclk2x        (ipclk2x),       // input
Andrey Filippov's avatar
Andrey Filippov committed
537 538
        .mrst           (mclk_rst),      // input
        .irst           (irst),          // input
539
        .mclk           (mclk),          // input
Andrey Filippov's avatar
Andrey Filippov committed
540
        .dly_data       (data_r[7:0]),    // input[7:0] 
541 542 543 544 545 546 547 548 549 550 551 552
        .set_idelay     (set_other_delay),// input
        .ld_idelay      (ld_idelay),     // input
        .quadrant       (quadrants[3:2]) // input[1:0] 
    );
    
    pxd_single #(
        .IODELAY_GRP           (IODELAY_GRP),
        .IDELAY_VALUE          (IDELAY_VALUE),
        .PXD_DRIVE             (PXD_DRIVE),
        .PXD_IBUF_LOW_PWR      (PXD_IBUF_LOW_PWR),
        .PXD_IOSTANDARD        (PXD_IOSTANDARD),
        .PXD_SLEW              (PXD_SLEW),
553 554
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
555 556 557 558 559
    ) pxd_vact_i (
        .pxd            (vact),          // inout
        .pxd_out        (1'b0),          // input
        .pxd_en         (1'b0),          // input
        .pxd_async      (),              // output
560
        .pxd_in         (vact_out_pre),  // output
561 562
        .ipclk          (ipclk),         // input
        .ipclk2x        (ipclk2x),       // input
Andrey Filippov's avatar
Andrey Filippov committed
563 564
        .mrst           (mclk_rst),      // input
        .irst           (irst),            // input
565 566 567 568 569 570 571 572 573 574 575 576 577 578
        .mclk           (mclk),          // input
        .dly_data       (data_r[15:8]),  // input[7:0] 
        .set_idelay     (set_other_delay),// input
        .ld_idelay      (ld_idelay),     // input
        .quadrant       (quadrants[5:4]) // input[1:0] 
    );
    // receive clock from sensor
    pxd_clock #(
        .IODELAY_GRP           (IODELAY_GRP),
        .IDELAY_VALUE          (IDELAY_VALUE),
        .PXD_DRIVE             (PXD_DRIVE),
        .PXD_IBUF_LOW_PWR      (PXD_IBUF_LOW_PWR),
        .PXD_IOSTANDARD        (PXD_IOSTANDARD),
        .PXD_SLEW              (PXD_SLEW),
579 580
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
581 582 583 584 585
    ) pxd_clock_i (
        .pxclk      (bpf),             // inout
        .pxclk_out  (1'b0),            // input
        .pxclk_en   (1'b0),            // input
        .pxclk_in   (ibpf),            // output
Andrey Filippov's avatar
Andrey Filippov committed
586
        .rst        (mclk_rst),        // input
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
        .mclk       (mclk),            // input
        .dly_data   (data_r[23:16]),   // input[7:0] 
        .set_idelay (set_other_delay), // input
        .ld_idelay  (ld_idelay)        // input
    );
    // generate dclk output
    oddr_ss #(
        .IOSTANDARD   (PXD_IOSTANDARD),
        .SLEW         (PXD_SLEW),
        .DDR_CLK_EDGE ("OPPOSITE_EDGE"),
        .INIT         (1'b0),
        .SRTYPE       ("SYNC")
    ) dclk_i (
        .clk   (pclk), // input
        .ce    (1'b1), // input
Andrey Filippov's avatar
Andrey Filippov committed
602
        .rst   (prst), // input
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
        .set   (1'b0), // input
        .din   (2'b01), // input[1:0] 
        .tin   (1'b0), // input
        .dq    (dclk) // output
    );

    // generate ARO/TCK
    iobuf #(
        .DRIVE        (PXD_DRIVE),
        .IBUF_LOW_PWR (PXD_IBUF_LOW_PWR),
        .IOSTANDARD   (PXD_IOSTANDARD),
        .SLEW         (PXD_SLEW)
    ) aro_tck_i (
        .O  (),                        // output - currently not used
        .IO (aro),                     // inout I/O pad
        .I  (xpgmen? xfpgatck : iaro), // input
        .T  (1'b0)                     // input - always on
    );

    // generate ARST/TMS
    iobuf #(
        .DRIVE        (PXD_DRIVE),
        .IBUF_LOW_PWR (PXD_IBUF_LOW_PWR),
        .IOSTANDARD   (PXD_IOSTANDARD),
        .SLEW         (PXD_SLEW)
    ) arst_tms_i (
        .O  (),                         // output - currently not used
        .IO (arst),                     // inout I/O pad
        .I  (xpgmen? xfpgatms : iarst), // input
        .T  (1'b0)                      // input - always on
    );
    
    // generate MRST/ receive DONE
    iobuf #(
        .DRIVE        (PXD_DRIVE),
        .IBUF_LOW_PWR (PXD_IBUF_LOW_PWR),
        .IOSTANDARD   (PXD_IOSTANDARD),
        .SLEW         (PXD_SLEW)
    ) mrst_done_i (
        .O  (xfpgadone),  // output - done from external FPGA
        .IO (mrst),       // inout I/O pad
        .I  (imrst),      // input
        .T  (xpgmen)      // input - disable when reading DONE
    );
    
    // Probe programmable/ control PROGRAM pin
    reg [1:0] xpgmen_d;
    reg force_senspgm=0;
    
    iobuf #(
        .DRIVE        (PXD_DRIVE),
        .IBUF_LOW_PWR (PXD_IBUF_LOW_PWR),
        .IOSTANDARD   (PXD_IOSTANDARD),
        .SLEW         (PXD_SLEW)
    ) senspgm_i (
        .O  (senspgmin),                         // output -senspgm pin state
        .IO (senspgm),                           // inout I/O pad
        .I  (xpgmen?(~xfpgaprog):force_senspgm), // input
        .T  (~(xpgmen || force_senspgm))         // input - disable when reading DONE
    );
663
    // pullup for mrst (used as input for "DONE") and senspgm (grounded on sensor boards)
664 665
    mpullup i_mrst_pullup(mrst);
    mpullup i_senspgm_pullup(senspgm);
Andrey Filippov's avatar
Andrey Filippov committed
666 667
    always @ (posedge mclk) begin
        if      (mclk_rst)              force_senspgm <= 0;
668
        else if (xpgmen_d[1:0]==2'b10) force_senspgm <= senspgmin;
Andrey Filippov's avatar
Andrey Filippov committed
669 670
        if      (mclk_rst) xpgmen_d <= 0;
        else               xpgmen_d <= {xpgmen_d[0], xpgmen};
671 672 673 674 675
    end

    // generate phase-shifterd pixel clock (and 2x version) from either the internal clock (that is output to the sensor) or from the clock
    // received from the sensor (may need to reset MMCM after resetting sensor)
    mmcm_phase_cntr #(
676
        .PHASE_WIDTH         (SENS_PHASE_WIDTH),
Andrey Filippov's avatar
Andrey Filippov committed
677
        .CLKIN_PERIOD        (CLKIN_PERIOD_SENSOR), // SENS_PCLK_PERIOD), assuming both sources have the same frequency!
678
        .BANDWIDTH           (SENS_BANDWIDTH),
679
        .CLKFBOUT_MULT_F     (CLKFBOUT_MULT_SENSOR), //8
680
        .DIVCLK_DIVIDE       (SENS_DIVCLK_DIVIDE),
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
        .CLKFBOUT_PHASE      (CLKFBOUT_PHASE_SENSOR),
        .CLKOUT0_PHASE       (IPCLK_PHASE),
        .CLKOUT1_PHASE       (IPCLK2X_PHASE),
//        .CLKOUT2_PHASE          (0.000),
//        .CLKOUT3_PHASE          (0.000),
//        .CLKOUT4_PHASE          (0.000),
//        .CLKOUT5_PHASE          (0.000),
//        .CLKOUT6_PHASE          (0.000),
        .CLKFBOUT_USE_FINE_PS("FALSE"),
        .CLKOUT0_USE_FINE_PS ("TRUE"),
        .CLKOUT1_USE_FINE_PS ("TRUE"),
//        .CLKOUT2_USE_FINE_PS ("FALSE"),
//        .CLKOUT3_USE_FINE_PS ("FALSE"),
//        .CLKOUT4_USE_FINE_PS("FALSE"),
//        .CLKOUT5_USE_FINE_PS("FALSE"),
//        .CLKOUT6_USE_FINE_PS("FALSE"),
Andrey Filippov's avatar
Andrey Filippov committed
697 698
        .CLKOUT0_DIVIDE_F    (8.000),
        .CLKOUT1_DIVIDE      (4),
699 700 701 702 703 704
//        .CLKOUT2_DIVIDE      (1),
//        .CLKOUT3_DIVIDE      (1),
//        .CLKOUT4_DIVIDE(1),
//        .CLKOUT5_DIVIDE(1),
//        .CLKOUT6_DIVIDE(1),
        .COMPENSATION        ("ZHOLD"),
705 706 707 708 709
        .REF_JITTER1         (SENS_REF_JITTER1),
        .REF_JITTER2         (SENS_REF_JITTER2),
        .SS_EN               (SENS_SS_EN),
        .SS_MODE             (SENS_SS_MODE),
        .SS_MOD_PERIOD       (SENS_SS_MOD_PERIOD),
710 711 712 713
        .STARTUP_WAIT        ("FALSE")
    ) mmcm_phase_cntr_i (
        .clkin1              (pclk),            // input
        .clkin2              (ibpf),            // input
714
        .sel_clk2            (sel_ext_clk),     // input
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
        .clkfbin             (clk_fb),          // input
        .rst                 (rst_mmcm),        // input
        .pwrdwn              (1'b0),            // input
        .psclk               (mclk),            // input
        .ps_we               (set_other_delay), // input
        .ps_din              (data_r[31:24]),   // input[7:0] 
        .ps_ready            (ps_rdy),          // output
        .ps_dout             (ps_out),          // output[7:0] reg 
        .clkout0             (ipclk_pre),       // output
        .clkout1             (ipclk2x_pre),     // output
        .clkout2(), // output
        .clkout3(), // output
        .clkout4(), // output
        .clkout5(), // output
        .clkout6(), // output
        .clkout0b(), // output
        .clkout1b(), // output
        .clkout2b(), // output
        .clkout3b(), // output
        .clkfbout            (clk_fb), // output
        .clkfboutb(), // output
        .locked              (locked_pxd_mmcm),
        .clkin_stopped       (clkin_pxd_stopped_mmcm), // output
        .clkfb_stopped       (clkfb_pxd_stopped_mmcm) // output
         // output
    );
741 742 743
    generate
        if      (BUF_IPCLK == "BUFG")  BUFG  clk1x_i (.O(ipclk),   .I(ipclk_pre));
        else if (BUF_IPCLK == "BUFH")  BUFH  clk1x_i (.O(ipclk),   .I(ipclk_pre));
Andrey Filippov's avatar
Andrey Filippov committed
744
        else if (BUF_IPCLK == "BUFR")  BUFR  clk1x_i (.O(ipclk),   .I(ipclk_pre), .CE(1'b1), .CLR(prst));
745 746 747 748 749 750 751 752
        else if (BUF_IPCLK == "BUFMR") BUFMR clk1x_i (.O(ipclk),   .I(ipclk_pre));
        else if (BUF_IPCLK == "BUFIO") BUFIO clk1x_i (.O(ipclk),   .I(ipclk_pre));
        else assign ipclk = ipclk_pre;
    endgenerate

    generate
        if      (BUF_IPCLK2X == "BUFG")  BUFG  clk2x_i (.O(ipclk2x), .I(ipclk2x_pre));
        else if (BUF_IPCLK2X == "BUFH")  BUFH  clk2x_i (.O(ipclk2x), .I(ipclk2x_pre));
Andrey Filippov's avatar
Andrey Filippov committed
753
        else if (BUF_IPCLK2X == "BUFR")  BUFR  clk2x_i (.O(ipclk2x), .I(ipclk2x_pre), .CE(1'b1), .CLR(prst));
754 755 756 757
        else if (BUF_IPCLK2X == "BUFMR") BUFMR clk2x_i (.O(ipclk2x), .I(ipclk2x_pre));
        else if (BUF_IPCLK2X == "BUFIO") BUFIO clk2x_i (.O(ipclk2x), .I(ipclk2x_pre));
        else assign ipclk2x = ipclk2x_pre;
    endgenerate
758

759 760
// BUFR ipclk_bufr_i   (.O(ipclk),   .CE(), .CLR(), .I(ipclk_pre));
// BUFR ipclk2x_bufr_i (.O(ipclk2x), .CE(), .CLR(), .I(ipclk2x_pre));
761

762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
// for debug/test alive   
    pulse_cross_clock pulse_cross_clock_vact_a_mclk_i (
        .rst         (irst),                     // input
        .src_clk     (ipclk),                    // input
        .dst_clk     (mclk),                     // input
        .in_pulse    (vact_out_pre && !vact_r),  // input
        .out_pulse   (vact_a_mclk),              // output
        .busy() // output
    );

    pulse_cross_clock pulse_cross_clock_hact_ext_a_mclk_i (
        .rst         (irst),                     // input
        .src_clk     (ipclk),                    // input
        .dst_clk     (mclk),                     // input
        .in_pulse    (hact_ext && !hact_ext_r),  // input
        .out_pulse   (hact_ext_a_mclk),          // output
        .busy() // output
    );

    pulse_cross_clock pulse_cross_clock_hact_a_mclk_i (
        .rst         (irst),                     // input
        .src_clk     (ipclk),                    // input
        .dst_clk     (mclk),                     // input
        .in_pulse    (hact_r && !hact_r2),       // input
        .out_pulse   (hact_a_mclk),              // output
        .busy() // output
    );

790 791 792

endmodule