sens_parallel12.v 30.2 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 20 21 22
 * 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/> .
 *******************************************************************************/
`timescale 1ns/1ps

23 24
module  sens_parallel12 #(
    parameter SENSIO_ADDR =        'h330,
25
    parameter SENSIO_ADDR_MASK =   'h7f8,
26 27 28
    parameter SENSIO_CTRL =        'h0,
    parameter SENSIO_STATUS =      'h1,
    parameter SENSIO_JTAG =        'h2,
29 30
    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
31
    parameter SENSIO_STATUS_REG =  'h21,
32 33 34 35 36 37 38 39 40 41 42 43 44

    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
45 46 47 48
    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)
     
49 50 51 52 53 54 55 56 57
    
    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",
58 59
    parameter real SENS_REFCLK_FREQUENCY =    300.0,
    parameter SENS_HIGH_PERFORMANCE_MODE =    "FALSE",
60
    
61 62 63
    parameter SENS_PHASE_WIDTH=               8,      // number of bits for te phase counter (depends on divisors)
    parameter SENS_PCLK_PERIOD =              10.000,  // input period in ns, 0..100.000 - MANDATORY, resolution down to 1 ps
    parameter SENS_BANDWIDTH =                "OPTIMIZED",  //"OPTIMIZED", "HIGH","LOW"
64 65 66

    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)
67 68
    parameter IPCLK_PHASE =            0.000,
    parameter IPCLK2X_PHASE =          0.000,
69 70
    parameter BUF_IPCLK =             "BUFR",
    parameter BUF_IPCLK2X =           "BUFR",  
71 72
    

73 74 75 76 77 78
    parameter SENS_DIVCLK_DIVIDE =     1,            // Integer 1..106. Divides all outputs with respect to CLKIN
    parameter SENS_REF_JITTER1   =     0.010,        // Expectet jitter on CLKIN1 (0.000..0.999)
    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"
    parameter SENS_SS_MOD_PERIOD =     10000        // integer 4000-40000 - SS modulation period in ns
79 80
    
)(
Andrey Filippov's avatar
Andrey Filippov committed
81
//    input         rst,
82
    input         pclk,   // global clock input, pixel rate (96MHz for MT9P006)
Andrey Filippov's avatar
Andrey Filippov committed
83 84 85 86
    input         mclk_rst,
    input         prst,
    output        irst,
    
87 88 89
    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
90 91
    input         trigger_mode, // running in triggered mode (0 - free running mode)
    input         trig,      // per-sensor trigger input
92
    // sensor pads excluding i2c
93 94
    inout         vact,
    inout         hact, //output in fillfactory mode
95 96 97
    inout         bpf,  // output in fillfactory mode
    inout  [11:0] pxd, //actually only 2 LSBs are inouts
    inout         mrst,
98
    inout         senspgm,    // SENSPGM I/O pin
99
    
100 101
    inout         arst,
    inout         aro,
102
    output        dclk, // externally connected to inout port
103
    // output
104 105 106
    output reg [11:0] pxd_out,
    output reg        vact_out, 
    output            hact_out, 
107 108 109 110 111 112 113 114 115 116

    // 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,    
117 118
    
    // programming interface
Andrey Filippov's avatar
Andrey Filippov committed
119
    input         mclk,     // global clock, half DDR3 clock, synchronizes all I/O through the command port
120 121 122 123 124 125 126
    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)
);

127 128 129 130
    // 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
131
    reg  [2:0] irst_r;
132 133 134 135 136 137 138 139
    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
140
    wire        set_width_ipclk; //re-clocked to pclk
141 142
    reg         set_jtag_r;
    
143 144 145
    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;
    
146
    reg                       line_width_internal; // use regenetrated ( 0 - use HACT as is)
147
    reg                       line_width_internal_ipclk;
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
    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 
163 164
    reg         iaro_soft  = 0;
    wire        iaro;
165 166 167
    reg         iarst = 0;
    reg         imrst = 0;
    reg         rst_mmcm=1; // rst and command - en/dis 
168
    reg  [SENS_CTRL_QUADRANTS_WIDTH-1:0]  quadrants=0; //90-degree shifts for data {1:0], hact [3:2] and vact [5:4]
169
    reg         ld_idelay=0;
170
    reg         sel_ext_clk=0; // select clock source from the sensor (0 - use internal clock - to sensor)
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195



    wire [14:0] status;
    
    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
    reg            hact_r;       // received or regenerated hact  
    assign set_pxd_delay =   set_idelay[2:0];
    assign set_other_delay = set_idelay[3];
    assign status = {locked_pxd_mmcm,clkin_pxd_stopped_mmcm,clkfb_pxd_stopped_mmcm,xfpgadone,ps_rdy, ps_out,xfpgatdo,senspgmin};
    assign hact_out = hact_r;
196
    assign iaro = trigger_mode?  ~trig : iaro_soft;
197
    
Andrey Filippov's avatar
Andrey Filippov committed
198 199 200 201 202 203 204 205 206 207 208
    assign     irst=irst_r[2];
    always @ (posedge ipclk) begin
        irst_r <= {irst_r[1:0], prst};
    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)),
209 210 211
                                             (cmd_a==(SENSIO_DELAYS+2)),
                                             (cmd_a==(SENSIO_DELAYS+1)),
                                             (cmd_a==(SENSIO_DELAYS+0))};
Andrey Filippov's avatar
Andrey Filippov committed
212 213 214 215 216 217 218 219
        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);
220
        
Andrey Filippov's avatar
Andrey Filippov committed
221
        if      (mclk_rst)                                  xpgmen <= 0;
222 223
        else if (set_jtag_r && data_r[SENS_JTAG_PGMEN + 1]) xpgmen <= data_r[SENS_JTAG_PGMEN]; 

Andrey Filippov's avatar
Andrey Filippov committed
224
        if      (mclk_rst)                                  xfpgaprog <= 0;
225 226
        else if (set_jtag_r && data_r[SENS_JTAG_PROG + 1])  xfpgaprog <= data_r[SENS_JTAG_PROG]; 
                                     
Andrey Filippov's avatar
Andrey Filippov committed
227
        if      (mclk_rst)                                  xfpgatck <= 0;
228 229
        else if (set_jtag_r && data_r[SENS_JTAG_TCK + 1])   xfpgatck <= data_r[SENS_JTAG_TCK]; 

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

Andrey Filippov's avatar
Andrey Filippov committed
233
        if      (mclk_rst)                                  xfpgatdi <= 0;
234 235
        else if (set_jtag_r && data_r[SENS_JTAG_TDI + 1])   xfpgatdi <= data_r[SENS_JTAG_TDI];
        
Andrey Filippov's avatar
Andrey Filippov committed
236
        if      (mclk_rst)                                      imrst <= 0;
237 238
        else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1])      imrst <= data_r[SENS_CTRL_MRST]; 
         
Andrey Filippov's avatar
Andrey Filippov committed
239
        if      (mclk_rst)                                      iarst <= 0;
240 241
        else if (set_ctrl_r && data_r[SENS_CTRL_ARST + 1])      iarst <= data_r[SENS_CTRL_ARST]; 
         
Andrey Filippov's avatar
Andrey Filippov committed
242
        if      (mclk_rst)                                      iaro_soft <= 0;
243
        else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1])      iaro_soft <= data_r[SENS_CTRL_ARO]; 
244
         
Andrey Filippov's avatar
Andrey Filippov committed
245
        if      (mclk_rst)                                      rst_mmcm <= 0;
246 247
        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
248
        if      (mclk_rst)                                      sel_ext_clk <= 0;
249 250
        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
251
        if      (mclk_rst)                                      quadrants <= 0;
252
        else if (set_ctrl_r && data_r[SENS_CTRL_QUADRANTS_EN])  quadrants <= data_r[SENS_CTRL_QUADRANTS +: SENS_CTRL_QUADRANTS_WIDTH]; 
253

Andrey Filippov's avatar
Andrey Filippov committed
254 255
        if  (mclk_rst) ld_idelay <= 0;
        else           ld_idelay <= set_ctrl_r && data_r[SENS_CTRL_LD_DLY]; 
256
        
Andrey Filippov's avatar
Andrey Filippov committed
257 258
        if  (mclk_rst) set_width_r <= 0;
        else           set_width_r <= {set_width_r[0],cmd_we && (cmd_a== SENSIO_WIDTH)}; 
259
        
Andrey Filippov's avatar
Andrey Filippov committed
260
        if      (mclk_rst)       line_width_m1 <= 0;
261 262
        else if (set_width_r[1]) line_width_m1 <= data_r[LINE_WIDTH_BITS-1:0] -1;
        
Andrey Filippov's avatar
Andrey Filippov committed
263
        if      (mclk_rst)       line_width_internal <= 0;
264
        else if (set_width_r[1]) line_width_internal <= ~ (|data_r[LINE_WIDTH_BITS:0]);
265 266 267 268 269 270 271 272
    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;
273
        // regenerate/propagate  HACT
274 275
        if (irst) hact_ext_r <= 1'b0;
        else      hact_ext_r <= hact_ext;
276
        
277 278 279
        if      (irst)                                                      hact_r <= 0;
        else if (hact_ext && !hact_ext_r)                                   hact_r <= 1;
        else if (line_width_internal_ipclk?(hact_cntr == 0):(hact_ext ==0)) hact_r <= 0; 
280
        
281 282
        if      (irst)                    hact_cntr <= 0;
        else if (hact_ext && !hact_ext_r) hact_cntr <= line_width_m1_ipclk; // from mclk
283 284
        else if (hact_r)                  hact_cntr <= hact_cntr - 1;
        
285 286 287
        pxd_out <=  pxd_out_pre;
        vact_out <= vact_out_pre;
        
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
    end
    
/*
 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
       
*/
    
319 320 321 322 323 324 325 326
    pulse_cross_clock pulse_cross_clock_set_width_ipclk_i (
        .rst         (mclk_rst),           // input
        .src_clk     (mclk),          // input
        .dst_clk     (ipclk),          // input
        .in_pulse    (set_width_r[1]),      // input
        .out_pulse   (set_width_ipclk),      // output
        .busy() // output
    );
327 328 329 330 331 332 333 334 335 336
    
    
    
    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
337 338 339 340 341 342
        .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] 
343
        .data        (cmd_data), // output[31:0] 
Andrey Filippov's avatar
Andrey Filippov committed
344
        .we          (cmd_we)    // output
345 346 347 348 349 350
    );

    status_generate #(
        .STATUS_REG_ADDR(SENSIO_STATUS_REG),
        .PAYLOAD_BITS(15) // STATUS_PAYLOAD_BITS)
    ) status_generate_sens_io_i (
Andrey Filippov's avatar
Andrey Filippov committed
351 352 353
        .rst        (1'b0),         // rst), // input
        .clk        (mclk),         // input
        .srst       (mclk_rst),     // input
354
        .we         (set_status_r), // input
Andrey Filippov's avatar
Andrey Filippov committed
355 356 357 358 359
        .wd         (data_r[7:0]),  // input[7:0] 
        .status     (status),       // input[25:0] 
        .ad         (status_ad),    // output[7:0] 
        .rq         (status_rq),    // output
        .start      (status_start)  // input
360 361 362 363 364 365 366 367 368 369 370 371 372
    );
    
    
    
    
    // 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),
373 374
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
375 376
    ) pxd_pxd0_i (
        .pxd            (pxd[0]),          // inout
Andrey Filippov's avatar
Andrey Filippov committed
377 378 379
        .pxd_out        (xfpgatdi),        // input
        .pxd_en         (xpgmen),          // input
        .pxd_async      (),                // output
380
        .pxd_in         (pxd_out_pre[0]),  // output
381 382
        .ipclk          (ipclk),           // input
        .ipclk2x        (ipclk2x),         // input
Andrey Filippov's avatar
Andrey Filippov committed
383 384
        .mrst           (mclk_rst),        // input
        .irst           (irst),            // input
385 386 387 388 389 390
        .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] 
    );
391 392
// debugging implementation
//assign xfpgatdo = pxd_out[1];
393 394 395 396 397 398 399
    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),
400 401
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
402 403 404 405 406
    ) pxd_pxd1_i (
        .pxd            (pxd[1]),          // inout
        .pxd_out        (1'b0),            // input
        .pxd_en         (1'b0),            // input
        .pxd_async      (xfpgatdo),        // output
407
        .pxd_in         (pxd_out_pre[1]),  // output
408 409
        .ipclk          (ipclk),           // input
        .ipclk2x        (ipclk2x),         // input
Andrey Filippov's avatar
Andrey Filippov committed
410 411
        .mrst           (mclk_rst),        // input
        .irst           (irst),            // input
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
        .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),
429 430
                .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
                .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
431
            ) pxd_pxd2_12_i (
432 433 434 435
                .pxd            (pxd[i]),          // inout
                .pxd_out        (1'b0),            // input
                .pxd_en         (1'b0),            // input
                .pxd_async      (),                // output
436
                .pxd_in         (pxd_out_pre[i]),  // output
437 438
                .ipclk          (ipclk),           // input
                .ipclk2x        (ipclk2x),         // input
Andrey Filippov's avatar
Andrey Filippov committed
439 440
                .mrst           (mclk_rst),        // input
                .irst           (irst),            // input
441
                .mclk           (mclk),            // input
442 443 444 445
//                .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]
446 447 448 449 450 451 452 453 454 455 456 457 458
                .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),
459 460
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
461 462 463 464 465 466 467 468
    ) 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
469 470
        .mrst           (mclk_rst),      // input
        .irst           (irst),          // input
471
        .mclk           (mclk),          // input
Andrey Filippov's avatar
Andrey Filippov committed
472
        .dly_data       (data_r[7:0]),    // input[7:0] 
473 474 475 476 477 478 479 480 481 482 483 484
        .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),
485 486
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
487 488 489 490 491
    ) pxd_vact_i (
        .pxd            (vact),          // inout
        .pxd_out        (1'b0),          // input
        .pxd_en         (1'b0),          // input
        .pxd_async      (),              // output
492
        .pxd_in         (vact_out_pre),  // output
493 494
        .ipclk          (ipclk),         // input
        .ipclk2x        (ipclk2x),       // input
Andrey Filippov's avatar
Andrey Filippov committed
495 496
        .mrst           (mclk_rst),      // input
        .irst           (irst),            // input
497 498 499 500 501 502 503 504 505 506 507 508 509 510
        .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),
511 512
        .REFCLK_FREQUENCY      (SENS_REFCLK_FREQUENCY),
        .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE)
513 514 515 516 517
    ) 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
518
        .rst        (mclk_rst),        // input
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
        .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
534
        .rst   (prst), // input
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
        .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
    );
595
    // pullup for mrst (used as input for "DONE") and senspgm (grounded on sensor boards)
596 597
    mpullup i_mrst_pullup(mrst);
    mpullup i_senspgm_pullup(senspgm);
Andrey Filippov's avatar
Andrey Filippov committed
598 599
    always @ (posedge mclk) begin
        if      (mclk_rst)              force_senspgm <= 0;
600
        else if (xpgmen_d[1:0]==2'b10) force_senspgm <= senspgmin;
Andrey Filippov's avatar
Andrey Filippov committed
601 602
        if      (mclk_rst) xpgmen_d <= 0;
        else               xpgmen_d <= {xpgmen_d[0], xpgmen};
603 604 605 606 607
    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 #(
608 609 610
        .PHASE_WIDTH         (SENS_PHASE_WIDTH),
        .CLKIN_PERIOD        (SENS_PCLK_PERIOD),
        .BANDWIDTH           (SENS_BANDWIDTH),
611
        .CLKFBOUT_MULT_F     (CLKFBOUT_MULT_SENSOR), //8
612
        .DIVCLK_DIVIDE       (SENS_DIVCLK_DIVIDE),
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
        .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
629 630
        .CLKOUT0_DIVIDE_F    (8.000),
        .CLKOUT1_DIVIDE      (4),
631 632 633 634 635 636
//        .CLKOUT2_DIVIDE      (1),
//        .CLKOUT3_DIVIDE      (1),
//        .CLKOUT4_DIVIDE(1),
//        .CLKOUT5_DIVIDE(1),
//        .CLKOUT6_DIVIDE(1),
        .COMPENSATION        ("ZHOLD"),
637 638 639 640 641
        .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),
642 643 644 645
        .STARTUP_WAIT        ("FALSE")
    ) mmcm_phase_cntr_i (
        .clkin1              (pclk),            // input
        .clkin2              (ibpf),            // input
646
        .sel_clk2            (sel_ext_clk),     // input
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
        .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
    );
673 674 675
    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
676
        else if (BUF_IPCLK == "BUFR")  BUFR  clk1x_i (.O(ipclk),   .I(ipclk_pre), .CE(1'b1), .CLR(prst));
677 678 679 680 681 682 683 684
        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
685
        else if (BUF_IPCLK2X == "BUFR")  BUFR  clk2x_i (.O(ipclk2x), .I(ipclk2x_pre), .CE(1'b1), .CLR(prst));
686 687 688 689
        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
690

691 692
// BUFR ipclk_bufr_i   (.O(ipclk),   .CE(), .CLR(), .I(ipclk_pre));
// BUFR ipclk2x_bufr_i (.O(ipclk2x), .CE(), .CLR(), .I(ipclk2x_pre));
693

694 695 696

endmodule