/******************************************************************************* * Module: sens_parallel12 * Date:2015-05-10 * Author: Andrey Filippov * Description: Sensor interface with 12-bit for parallel bus * * Copyright (c) 2015 Elphel, Inc. * 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 . * * 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" * files and/or simulating the code, the copyright holders of this Program give * 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 * charge, and there is no dependence on any encrypted modules for simulating of * 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. *******************************************************************************/ `timescale 1ns/1ps module sens_parallel12 #( parameter SENSIO_ADDR = 'h330, parameter SENSIO_ADDR_MASK = 'h7f8, parameter SENSIO_CTRL = 'h0, parameter SENSIO_STATUS = 'h1, parameter SENSIO_JTAG = 'h2, 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 parameter SENSIO_STATUS_REG = 'h21, 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 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) 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", parameter real SENS_REFCLK_FREQUENCY = 300.0, parameter SENS_HIGH_PERFORMANCE_MODE = "FALSE", 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" parameter CLKIN_PERIOD_SENSOR = 10.000, // input period in ns, 0..100.000 - MANDATORY, resolution down to 1 ps 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) parameter IPCLK_PHASE = 0.000, parameter IPCLK2X_PHASE = 0.000, parameter BUF_IPCLK = "BUFR", parameter BUF_IPCLK2X = "BUFR", parameter SENS_DIVCLK_DIVIDE = 1, // Integer 1..106. Divides all outputs with respect to CLKIN parameter SENS_REF_JITTER1 = 0.010, // Expected 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 parameter STATUS_ALIVE_WIDTH = 4 )( // input rst, input pclk, // global clock input, pixel rate (96MHz for MT9P006) input mclk_rst, input prst, output prsts, // @pclk - includes sensor reset and sensor PLL reset output irst, 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 input trigger_mode, // running in triggered mode (0 - free running mode) input trig, // per-sensor trigger input // sensor pads excluding i2c inout vact, inout hact, //output in fillfactory mode inout bpf, // output in fillfactory mode inout [11:0] pxd, //actually only 2 LSBs are inouts inout mrst, inout senspgm, // SENSPGM I/O pin inout arst, inout aro, output dclk, // externally connected to inout port // output output reg [11:0] pxd_out, output reg vact_out, output hact_out, input [STATUS_ALIVE_WIDTH-1:0] status_alive_1cyc, //extra toggle @mclk bits to report with status // 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, // programming interface input mclk, // global clock, half DDR3 clock, synchronizes all I/O through the command port 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) ); // delaying vact and pxd by one clock cycle to match hact register wire [11:0] pxd_out_pre; wire vact_out_pre; reg [2:0] irst_r; 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 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 reg set_jtag_r; 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; reg line_width_internal; // use regenetrated ( 0 - use HACT as is) reg line_width_internal_ipclk; 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 reg iaro_soft = 0; wire iaro; reg iarst = 0; reg imrst = 0; reg rst_mmcm=1; // rst and command - en/dis reg [SENS_CTRL_QUADRANTS_WIDTH-1:0] quadrants=0; //90-degree shifts for data {1:0], hact [3:2] and vact [5:4] reg ld_idelay=0; reg sel_ext_clk=0; // select clock source from the sensor (0 - use internal clock - to sensor) // wire [17:0] status; // wire [18:0] status; // wire [22:0] status; wire [25:0] status; // added byte-wide xfpgatdo 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 reg [7:0] xfpgatdo_byte; // tdo signal shifted left at each TCK _/~ 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 // 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; 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 assign set_pxd_delay = set_idelay[2:0]; assign set_other_delay = set_idelay[3]; // 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}; // 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], 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}; assign hact_out = hact_r; assign iaro = trigger_mode? ~trig : iaro_soft; assign irst=irst_r[2]; always @ (posedge ipclk) begin // irst_r <= {irst_r[1:0], prst}; irst_r <= {irst_r[1:0], prsts}; // extended reset that includes sensor reset and rst_mmcm set_width_ipclk_r <= irst_r[2] && !irst_r[1]; 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; 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)), (cmd_a==(SENSIO_DELAYS+2)), (cmd_a==(SENSIO_DELAYS+1)), (cmd_a==(SENSIO_DELAYS+0))}; 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); if (mclk_rst) xpgmen <= 0; else if (set_jtag_r && data_r[SENS_JTAG_PGMEN + 1]) xpgmen <= data_r[SENS_JTAG_PGMEN]; if (mclk_rst) xfpgaprog <= 0; else if (set_jtag_r && data_r[SENS_JTAG_PROG + 1]) xfpgaprog <= data_r[SENS_JTAG_PROG]; if (mclk_rst) xfpgatck <= 0; 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}; if (mclk_rst) xfpgatms <= 0; else if (set_jtag_r && data_r[SENS_JTAG_TMS + 1]) xfpgatms <= data_r[SENS_JTAG_TMS]; if (mclk_rst) xfpgatdi <= 0; else if (set_jtag_r && data_r[SENS_JTAG_TDI + 1]) xfpgatdi <= data_r[SENS_JTAG_TDI]; if (mclk_rst) imrst <= 0; else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1]) imrst <= data_r[SENS_CTRL_MRST]; if (mclk_rst) iarst <= 0; else if (set_ctrl_r && data_r[SENS_CTRL_ARST + 1]) iarst <= data_r[SENS_CTRL_ARST]; if (mclk_rst) iaro_soft <= 0; else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1]) iaro_soft <= data_r[SENS_CTRL_ARO]; if (mclk_rst) rst_mmcm <= 0; else if (set_ctrl_r && data_r[SENS_CTRL_RST_MMCM + 1]) rst_mmcm <= data_r[SENS_CTRL_RST_MMCM]; if (mclk_rst) sel_ext_clk <= 0; else if (set_ctrl_r && data_r[SENS_CTRL_EXT_CLK + 1]) sel_ext_clk <= data_r[SENS_CTRL_EXT_CLK]; if (mclk_rst) quadrants <= 0; else if (set_ctrl_r && data_r[SENS_CTRL_QUADRANTS_EN]) quadrants <= data_r[SENS_CTRL_QUADRANTS +: SENS_CTRL_QUADRANTS_WIDTH]; if (mclk_rst) ld_idelay <= 0; else ld_idelay <= set_ctrl_r && data_r[SENS_CTRL_LD_DLY]; if (mclk_rst) set_width_r <= 0; else set_width_r <= {set_width_r[0],cmd_we && (cmd_a== SENSIO_WIDTH)}; if (mclk_rst) line_width_m1 <= 0; else if (set_width_r[1]) line_width_m1 <= data_r[LINE_WIDTH_BITS-1:0] -1; if (mclk_rst) line_width_internal <= 0; else if (set_width_r[1]) line_width_internal <= ~ (|data_r[LINE_WIDTH_BITS:0]); // line width is 0 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; // regenerate/propagate HACT if (irst) hact_ext_r <= 1'b0; else hact_ext_r <= hact_ext; if (irst) hact_r <= 0; else if (hact_ext && !hact_ext_r) hact_r <= 1; else if (line_width_internal_ipclk?(hact_ext ==0):(hact_cntr == 0)) hact_r <= 0; 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; pxd_out <= pxd_out_pre; vact_out <= vact_out_pre; // for debug/test alive vact_r <= vact_out_pre; hact_r2 <= hact_r; end // 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 /* 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 */ 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_w), // output .busy() // output ); cmd_deser #( .ADDR (SENSIO_ADDR), .ADDR_MASK (SENSIO_ADDR_MASK), .NUM_CYCLES (6), .ADDR_WIDTH (3), .DATA_WIDTH (32) ) cmd_deser_sens_io_i ( .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] .data (cmd_data), // output[31:0] .we (cmd_we) // output ); status_generate #( .STATUS_REG_ADDR(SENSIO_STATUS_REG), // .PAYLOAD_BITS(15+3+STATUS_ALIVE_WIDTH) // STATUS_PAYLOAD_BITS) // .PAYLOAD_BITS(15+3+STATUS_ALIVE_WIDTH+1) // STATUS_PAYLOAD_BITS) .PAYLOAD_BITS(26) // STATUS_PAYLOAD_BITS) ) status_generate_sens_io_i ( .rst (1'b0), // rst), // input .clk (mclk), // input .srst (mclk_rst), // input .we (set_status_r), // input .wd (data_r[7:0]), // input[7:0] // .status ({status_alive,status}), // input[25:0] .status ({status}), // input[25:0] .ad (status_ad), // output[7:0] .rq (status_rq), // output .start (status_start) // input ); // 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), .REFCLK_FREQUENCY (SENS_REFCLK_FREQUENCY), .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE) ) pxd_pxd0_i ( .pxd (pxd[0]), // inout .pxd_out (xfpgatdi), // input .pxd_en (xpgmen), // input .pxd_async (), // output .pxd_in (pxd_out_pre[0]), // output .ipclk (ipclk), // input .ipclk2x (ipclk2x), // input .mrst (mclk_rst), // input .irst (irst), // input .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] ); // debugging implementation //assign xfpgatdo = pxd_out[1]; /* 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; 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), .REFCLK_FREQUENCY (SENS_REFCLK_FREQUENCY), .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE) ) pxd_pxd1_i ( .pxd (pxd[1]), // inout .pxd_out (1'b0), // input .pxd_en (1'b0), // input .pxd_async (n_xfpgatdo), // output .pxd_in (pxd_out_pre[1]), // output .ipclk (ipclk), // input .ipclk2x (ipclk2x), // input .mrst (mclk_rst), // input .irst (irst), // input .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] ); `endif // 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), .REFCLK_FREQUENCY (SENS_REFCLK_FREQUENCY), .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE) ) pxd_pxd2_12_i ( .pxd (pxd[i]), // inout .pxd_out (1'b0), // input .pxd_en (1'b0), // input .pxd_async (), // output .pxd_in (pxd_out_pre[i]), // output .ipclk (ipclk), // input .ipclk2x (ipclk2x), // input .mrst (mclk_rst), // input .irst (irst), // input .mclk (mclk), // input // .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] .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), .REFCLK_FREQUENCY (SENS_REFCLK_FREQUENCY), .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE) ) 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 .mrst (mclk_rst), // input .irst (irst), // input .mclk (mclk), // input .dly_data (data_r[7:0]), // input[7:0] .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), .REFCLK_FREQUENCY (SENS_REFCLK_FREQUENCY), .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE) ) pxd_vact_i ( .pxd (vact), // inout .pxd_out (1'b0), // input .pxd_en (1'b0), // input .pxd_async (), // output .pxd_in (vact_out_pre), // output .ipclk (ipclk), // input .ipclk2x (ipclk2x), // input .mrst (mclk_rst), // input .irst (irst), // input .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), .REFCLK_FREQUENCY (SENS_REFCLK_FREQUENCY), .HIGH_PERFORMANCE_MODE (SENS_HIGH_PERFORMANCE_MODE) ) pxd_clock_i ( .pxclk (bpf), // inout .pxclk_out (1'b0), // input .pxclk_en (1'b0), // input .pxclk_in (ibpf), // output .rst (mclk_rst), // input .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 .rst (prst), // input .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 ); // pullup for mrst (used as input for "DONE") and senspgm (grounded on sensor boards) mpullup i_mrst_pullup(mrst); mpullup i_senspgm_pullup(senspgm); always @ (posedge mclk) begin if (mclk_rst) force_senspgm <= 0; else if (xpgmen_d[1:0]==2'b10) force_senspgm <= senspgmin; if (mclk_rst) xpgmen_d <= 0; else xpgmen_d <= {xpgmen_d[0], xpgmen}; 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 #( .PHASE_WIDTH (SENS_PHASE_WIDTH), .CLKIN_PERIOD (CLKIN_PERIOD_SENSOR), // SENS_PCLK_PERIOD), assuming both sources have the same frequency! .BANDWIDTH (SENS_BANDWIDTH), .CLKFBOUT_MULT_F (CLKFBOUT_MULT_SENSOR), //8 .DIVCLK_DIVIDE (SENS_DIVCLK_DIVIDE), .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"), .CLKOUT0_DIVIDE_F (8.000), .CLKOUT1_DIVIDE (4), // .CLKOUT2_DIVIDE (1), // .CLKOUT3_DIVIDE (1), // .CLKOUT4_DIVIDE(1), // .CLKOUT5_DIVIDE(1), // .CLKOUT6_DIVIDE(1), .COMPENSATION ("ZHOLD"), .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), .STARTUP_WAIT ("FALSE") ) mmcm_phase_cntr_i ( .clkin1 (pclk), // input .clkin2 (ibpf), // input .sel_clk2 (sel_ext_clk), // input .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 ); 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)); else if (BUF_IPCLK == "BUFR") BUFR clk1x_i (.O(ipclk), .I(ipclk_pre), .CE(1'b1), .CLR(prst)); 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)); else if (BUF_IPCLK2X == "BUFR") BUFR clk2x_i (.O(ipclk2x), .I(ipclk2x_pre), .CE(1'b1), .CLR(prst)); 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 // BUFR ipclk_bufr_i (.O(ipclk), .CE(), .CLR(), .I(ipclk_pre)); // BUFR ipclk2x_bufr_i (.O(ipclk2x), .CE(), .CLR(), .I(ipclk2x_pre)); // 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 ); endmodule