sens_parallel12.v 36.5 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 194
//    wire [17:0] status;
//    wire [18:0] status;
195 196
//    wire [22:0] status;
    wire [25:0] status; // added byte-wide xfpgatdo
197 198 199 200 201 202 203
    
    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
204
    reg      [7:0] xfpgatdo_byte; // tdo signal shifted left at each TCK _/~
205 206 207 208 209 210 211 212 213
    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
214 215 216 217 218 219 220 221 222 223 224 225
    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;    
226 227 228 229 230 231

    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
    
232
     
233 234
    assign set_pxd_delay =   set_idelay[2:0];
    assign set_other_delay = set_idelay[3];
235 236 237
//    assign status = {pxd_out_pre[1],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};
238 239 240 241 242
//    wire [25:0] status; // added byte-wide xfpgatdo

    assign status = {
///                  irst, async_prst_with_sens_mrst, imrst, rst_mmcm, pxd_out_pre[1],
                     xfpgatdo_byte[7:0],
243
                     vact_alive, hact_ext_alive, hact_alive, locked_pxd_mmcm, 
244 245
                     clkin_pxd_stopped_mmcm, clkfb_pxd_stopped_mmcm, xfpgadone,
                     ps_rdy, ps_out, xfpgatdo, senspgmin};
246
                        
247
    assign hact_out = hact_r;
248
    assign iaro = trigger_mode?  ~trig : iaro_soft;
249
    
Andrey Filippov's avatar
Andrey Filippov committed
250
    assign     irst=irst_r[2];
251
    
Andrey Filippov's avatar
Andrey Filippov committed
252
    always @ (posedge ipclk) begin
253 254
//        irst_r <= {irst_r[1:0], prst};
        irst_r <= {irst_r[1:0], prsts}; // extended reset that includes sensor reset and rst_mmcm
255
        set_width_ipclk_r <= irst_r[2] && !irst_r[1];
256 257 258 259 260 261
    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
262 263 264 265 266 267 268 269
    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)),
270 271 272
                                             (cmd_a==(SENSIO_DELAYS+2)),
                                             (cmd_a==(SENSIO_DELAYS+1)),
                                             (cmd_a==(SENSIO_DELAYS+0))};
Andrey Filippov's avatar
Andrey Filippov committed
273 274 275 276 277 278 279 280
        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);
281
        
Andrey Filippov's avatar
Andrey Filippov committed
282
        if      (mclk_rst)                                  xpgmen <= 0;
283 284
        else if (set_jtag_r && data_r[SENS_JTAG_PGMEN + 1]) xpgmen <= data_r[SENS_JTAG_PGMEN]; 

Andrey Filippov's avatar
Andrey Filippov committed
285
        if      (mclk_rst)                                  xfpgaprog <= 0;
286 287
        else if (set_jtag_r && data_r[SENS_JTAG_PROG + 1])  xfpgaprog <= data_r[SENS_JTAG_PROG]; 
                                     
Andrey Filippov's avatar
Andrey Filippov committed
288
        if      (mclk_rst)                                  xfpgatck <= 0;
289 290 291 292 293
        else if (set_jtag_r && data_r[SENS_JTAG_TCK + 1])   xfpgatck <= data_r[SENS_JTAG_TCK];
        
        // shift xfpgatdo to xfpgatdo_byte each time xfpgatck is 0->1
        if      (mclk_rst)                                                                       xfpgatdo_byte <= 0;
        else if (set_jtag_r && data_r[SENS_JTAG_TCK + 1] && !xfpgatck &&  data_r[SENS_JTAG_TCK]) xfpgatdo_byte <= {xfpgatdo_byte[6:0], xfpgatdo}; 
294

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

Andrey Filippov's avatar
Andrey Filippov committed
298
        if      (mclk_rst)                                  xfpgatdi <= 0;
299 300
        else if (set_jtag_r && data_r[SENS_JTAG_TDI + 1])   xfpgatdi <= data_r[SENS_JTAG_TDI];
        
Andrey Filippov's avatar
Andrey Filippov committed
301
        if      (mclk_rst)                                      imrst <= 0;
302 303
        else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1])      imrst <= data_r[SENS_CTRL_MRST]; 
         
Andrey Filippov's avatar
Andrey Filippov committed
304
        if      (mclk_rst)                                      iarst <= 0;
305 306
        else if (set_ctrl_r && data_r[SENS_CTRL_ARST + 1])      iarst <= data_r[SENS_CTRL_ARST]; 
         
Andrey Filippov's avatar
Andrey Filippov committed
307
        if      (mclk_rst)                                      iaro_soft <= 0;
308
        else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1])      iaro_soft <= data_r[SENS_CTRL_ARO]; 
309
         
Andrey Filippov's avatar
Andrey Filippov committed
310
        if      (mclk_rst)                                      rst_mmcm <= 0;
311 312
        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
313
        if      (mclk_rst)                                      sel_ext_clk <= 0;
314 315
        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
316
        if      (mclk_rst)                                      quadrants <= 0;
317
        else if (set_ctrl_r && data_r[SENS_CTRL_QUADRANTS_EN])  quadrants <= data_r[SENS_CTRL_QUADRANTS +: SENS_CTRL_QUADRANTS_WIDTH]; 
318

Andrey Filippov's avatar
Andrey Filippov committed
319 320
        if  (mclk_rst) ld_idelay <= 0;
        else           ld_idelay <= set_ctrl_r && data_r[SENS_CTRL_LD_DLY]; 
321
        
Andrey Filippov's avatar
Andrey Filippov committed
322 323
        if  (mclk_rst) set_width_r <= 0;
        else           set_width_r <= {set_width_r[0],cmd_we && (cmd_a== SENSIO_WIDTH)}; 
324
        
Andrey Filippov's avatar
Andrey Filippov committed
325
        if      (mclk_rst)       line_width_m1 <= 0;
326 327
        else if (set_width_r[1]) line_width_m1 <= data_r[LINE_WIDTH_BITS-1:0] -1;
        
Andrey Filippov's avatar
Andrey Filippov committed
328
        if      (mclk_rst)       line_width_internal <= 0;
329
        else if (set_width_r[1]) line_width_internal <= ~ (|data_r[LINE_WIDTH_BITS:0]); // line width is 0
330 331 332 333 334 335 336 337
    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;
338
        // regenerate/propagate  HACT
339 340
        if (irst) hact_ext_r <= 1'b0;
        else      hact_ext_r <= hact_ext;
341
        
342 343
        if      (irst)                                                      hact_r <= 0;
        else if (hact_ext && !hact_ext_r)                                   hact_r <= 1;
344
        else if (line_width_internal_ipclk?(hact_ext ==0):(hact_cntr == 0)) hact_r <= 0; 
345
        
346 347 348
        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;
349
        
350 351 352
        pxd_out <=  pxd_out_pre;
        vact_out <= vact_out_pre;
        
353 354 355 356
        // for debug/test alive  
        vact_r <= vact_out_pre;
        hact_r2 <= hact_r;
        
357 358
    end
    
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
    // 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
        
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
/*
 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
       
*/
    
404
    pulse_cross_clock pulse_cross_clock_set_width_ipclk_i (
405 406 407 408 409
        .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
410 411
        .busy() // output
    );
412 413 414 415 416 417 418 419 420 421
    
    
    
    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
422 423 424 425 426 427
        .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] 
428
        .data        (cmd_data), // output[31:0] 
Andrey Filippov's avatar
Andrey Filippov committed
429
        .we          (cmd_we)    // output
430 431 432 433
    );

    status_generate #(
        .STATUS_REG_ADDR(SENSIO_STATUS_REG),
434
//        .PAYLOAD_BITS(15+3+STATUS_ALIVE_WIDTH) // STATUS_PAYLOAD_BITS)
435 436
//        .PAYLOAD_BITS(15+3+STATUS_ALIVE_WIDTH+1) // STATUS_PAYLOAD_BITS)
        .PAYLOAD_BITS(26) // STATUS_PAYLOAD_BITS)
437
    ) status_generate_sens_io_i (
Andrey Filippov's avatar
Andrey Filippov committed
438 439 440
        .rst        (1'b0),         // rst), // input
        .clk        (mclk),         // input
        .srst       (mclk_rst),     // input
441
        .we         (set_status_r), // input
Andrey Filippov's avatar
Andrey Filippov committed
442
        .wd         (data_r[7:0]),  // input[7:0] 
443 444
//        .status     ({status_alive,status}),       // input[25:0] 
        .status     ({status}),       // input[25:0] 
Andrey Filippov's avatar
Andrey Filippov committed
445 446 447
        .ad         (status_ad),    // output[7:0] 
        .rq         (status_rq),    // output
        .start      (status_start)  // input
448 449 450 451 452 453 454 455 456 457 458 459 460
    );
    
    
    
    
    // 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),
461 462
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
463 464
    ) pxd_pxd0_i (
        .pxd            (pxd[0]),          // inout
Andrey Filippov's avatar
Andrey Filippov committed
465 466 467
        .pxd_out        (xfpgatdi),        // input
        .pxd_en         (xpgmen),          // input
        .pxd_async      (),                // output
468
        .pxd_in         (pxd_out_pre[0]),  // output
469 470
        .ipclk          (ipclk),           // input
        .ipclk2x        (ipclk2x),         // input
Andrey Filippov's avatar
Andrey Filippov committed
471 472
        .mrst           (mclk_rst),        // input
        .irst           (irst),            // input
473 474 475 476 477 478
        .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] 
    );
479
    
480 481
// debugging implementation
//assign xfpgatdo = pxd_out[1];
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
    /* Instance template for module iobuf */
//`define DEBUF_JTAG 1
`ifdef DEBUF_JTAG    
    iobuf #(
        .DRIVE        (PXD_DRIVE),
        .IBUF_LOW_PWR (PXD_IBUF_LOW_PWR),
        .IOSTANDARD   (PXD_IOSTANDARD),
        .SLEW         (PXD_SLEW)
    ) pxd_pxd1_i (
        .O            (pxd_out_pre[1]), // output
        .IO           (pxd[1]), // inout
        .I            (1'b0), // input
        .T            (1'b1) // input
    );
    assign xfpgatdo = pxd_out_pre[1];
`else
    wire n_xfpgatdo;
    assign xfpgatdo = !n_xfpgatdo;
500 501 502 503 504 505 506
    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),
507 508
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
509 510 511 512
    ) pxd_pxd1_i (
        .pxd            (pxd[1]),          // inout
        .pxd_out        (1'b0),            // input
        .pxd_en         (1'b0),            // input
513
        .pxd_async      (n_xfpgatdo),      // output
514
        .pxd_in         (pxd_out_pre[1]),  // output
515 516
        .ipclk          (ipclk),           // input
        .ipclk2x        (ipclk2x),         // input
Andrey Filippov's avatar
Andrey Filippov committed
517 518
        .mrst           (mclk_rst),        // input
        .irst           (irst),            // input
519
        .mclk           (mclk),            // input
520
        .dly_data       (data_r[15:8]),    // input[7:0] 
521 522 523 524
        .set_idelay     (set_pxd_delay[0]),// input
        .ld_idelay      (ld_idelay),       // input
        .quadrant       (quadrants[1:0])   // input[1:0] 
    );
525 526 527 528
`endif    
    
    
    
529 530 531 532 533 534 535 536 537 538 539
    // 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),
540 541
                .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
                .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
542
            ) pxd_pxd2_12_i (
543 544 545 546
                .pxd            (pxd[i]),          // inout
                .pxd_out        (1'b0),            // input
                .pxd_en         (1'b0),            // input
                .pxd_async      (),                // output
547
                .pxd_in         (pxd_out_pre[i]),  // output
548 549
                .ipclk          (ipclk),           // input
                .ipclk2x        (ipclk2x),         // input
Andrey Filippov's avatar
Andrey Filippov committed
550 551
                .mrst           (mclk_rst),        // input
                .irst           (irst),            // input
552
                .mclk           (mclk),            // input
553 554 555 556
//                .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]
557 558 559 560 561 562 563 564 565 566 567 568 569
                .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),
570 571
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
572 573 574 575 576 577 578 579
    ) 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
580 581
        .mrst           (mclk_rst),      // input
        .irst           (irst),          // input
582
        .mclk           (mclk),          // input
Andrey Filippov's avatar
Andrey Filippov committed
583
        .dly_data       (data_r[7:0]),    // input[7:0] 
584 585 586 587 588 589 590 591 592 593 594 595
        .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),
596 597
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
598 599 600 601 602
    ) pxd_vact_i (
        .pxd            (vact),          // inout
        .pxd_out        (1'b0),          // input
        .pxd_en         (1'b0),          // input
        .pxd_async      (),              // output
603
        .pxd_in         (vact_out_pre),  // output
604 605
        .ipclk          (ipclk),         // input
        .ipclk2x        (ipclk2x),       // input
Andrey Filippov's avatar
Andrey Filippov committed
606 607
        .mrst           (mclk_rst),      // input
        .irst           (irst),            // input
608 609 610 611 612 613 614 615 616 617 618 619 620 621
        .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),
622 623
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
624 625 626 627 628
    ) 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
629
        .rst        (mclk_rst),        // input
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
        .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
645
        .rst   (prst), // input
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
        .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
    );
706
    // pullup for mrst (used as input for "DONE") and senspgm (grounded on sensor boards)
707 708
    mpullup i_mrst_pullup(mrst);
    mpullup i_senspgm_pullup(senspgm);
Andrey Filippov's avatar
Andrey Filippov committed
709 710
    always @ (posedge mclk) begin
        if      (mclk_rst)              force_senspgm <= 0;
711
        else if (xpgmen_d[1:0]==2'b10) force_senspgm <= senspgmin;
Andrey Filippov's avatar
Andrey Filippov committed
712 713
        if      (mclk_rst) xpgmen_d <= 0;
        else               xpgmen_d <= {xpgmen_d[0], xpgmen};
714 715 716 717 718
    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 #(
719
        .PHASE_WIDTH         (SENS_PHASE_WIDTH),
Andrey Filippov's avatar
Andrey Filippov committed
720
        .CLKIN_PERIOD        (CLKIN_PERIOD_SENSOR), // SENS_PCLK_PERIOD), assuming both sources have the same frequency!
721
        .BANDWIDTH           (SENS_BANDWIDTH),
722
        .CLKFBOUT_MULT_F     (CLKFBOUT_MULT_SENSOR), //8
723
        .DIVCLK_DIVIDE       (SENS_DIVCLK_DIVIDE),
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
        .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
740 741
        .CLKOUT0_DIVIDE_F    (8.000),
        .CLKOUT1_DIVIDE      (4),
742 743 744 745 746 747
//        .CLKOUT2_DIVIDE      (1),
//        .CLKOUT3_DIVIDE      (1),
//        .CLKOUT4_DIVIDE(1),
//        .CLKOUT5_DIVIDE(1),
//        .CLKOUT6_DIVIDE(1),
        .COMPENSATION        ("ZHOLD"),
748 749 750 751 752
        .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),
753 754 755 756
        .STARTUP_WAIT        ("FALSE")
    ) mmcm_phase_cntr_i (
        .clkin1              (pclk),            // input
        .clkin2              (ibpf),            // input
757
        .sel_clk2            (sel_ext_clk),     // input
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
        .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
    );
784 785 786
    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
787
        else if (BUF_IPCLK == "BUFR")  BUFR  clk1x_i (.O(ipclk),   .I(ipclk_pre), .CE(1'b1), .CLR(prst));
788 789 790 791 792 793 794 795
        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
796
        else if (BUF_IPCLK2X == "BUFR")  BUFR  clk2x_i (.O(ipclk2x), .I(ipclk2x_pre), .CE(1'b1), .CLR(prst));
797 798 799 800
        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
801

802 803
// BUFR ipclk_bufr_i   (.O(ipclk),   .CE(), .CLR(), .I(ipclk_pre));
// BUFR ipclk2x_bufr_i (.O(ipclk2x), .CE(), .CLR(), .I(ipclk2x_pre));
804

805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
// 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
    );

833 834 835

endmodule