module Analog_Testboard_FPGA
      (
        //Clocks
        input      clk320,             //Tx ref clock 
        input      clk40,
		  		  
        //MGT serial lanes
        output     downlinkSerial_o,   // Tx serial lane
        input      uplinkSerial_i,     // Rx serial lane

        output     lpgbt_rstb,
        output     lpgbt_pordis,
        output     lpgbt_mod0,
        output     lpgbt_mod1,
        output     lpgbt_mod2,
        output     lpgbt_mod3,
        output     lpgbt_stateovrd,
        output     lpgbt_lockmode,
        output     lpgbt_sc_i2c,  
 
        output     up_err,
		  
        //DAC control signals
        output     cal_rst_b,
        output     cal_sdi,
        output     cal_sclk,
        output     cal_ldac_b,
        input      cal_sdo,	
	
        //Calibration generator pulse
        output     cal_pulse_ctrl, 
		  
        //Preamplifier/Shaper serial control signals
        output     rstb_sr,
        output     select,
        output     clk_sr,
        output     srin_sr,
        input      srout_sr,
		 
        //I2C for Coluta #1 
        output     SCL_1,  
        inout      SDA_1,   
        output     RSTB1,   

        //I2C for Coluta #2
        output     SCL_2,  
        inout      SDA_2,   
        output     RSTB2,

        //I2C for LpGBT
        output     SLSCL_LPGBT,  
        inout      SLSDA_LPGBT,    
		  
		  
        //Bunch crossing reset signal
        output     BCRST,
		  
        // USB interface signals
        inout [7:0]DATA ,  //fifo DATA
        input      RXF ,   //low active: data available in FIFO
        input      TXE ,   //low active: data can be written into FIFO
        output     RD ,    //ReaD enable,  low to high transition
        output     WR ,    //WRite enable, high to low transition
		  
        //programmable delay trigger    
        output reg trigger,      //interface to external pulse
		  		  		  
        // test points
        output     TP1,
        output     TP2,
        output     TP_dummy    //just to remove warnings about signals which do not drive logic
      
      );

//wires
wire         pll_powerdown, clk5120, tx_ready,rx_ready,
             tx_cal_busy, rx_cal_busy, rx_is_lockedtodata,
             p0_locked;
	  
wire   [1:0] uplinkEcData_o, uplinkIcData_o;
wire         uplinkClk_o, uplinkClkEn_o;	
  
wire         clk_mgtTxClk_o,    clk_mgtRxClk_o;

wire         TP1_int, TP2_int;
wire         link_reset_pulse;
wire   [1:0] downlink_skipCycle;	  
	
wire   [7:0] misc_mux, PA_mux;
wire   [7:0] I2C_rdback_mux;
reg  [255:0] I2C_cntrl;
wire [255:0] I2C_shift_back; 
reg  [255:0] I2C_shift_back_shreg;
wire         clk5_int;
reg   [55:0] LpGBT_reg;
reg    [2:0] stw_cnt_rd, stw_cnt_wr;
reg          st_byte_read, st_byte_write;
reg          eoc_rd;
reg    [7:0] status1, status2, status3, status4, status5, status6;
reg   [15:0] BC_reg;
reg          fDATA_write, eoc_wr_DATA; 

reg   [63:0] ad_reg, oc_reg; 

reg   [16:0] fDATAw_cnt_rd;
reg    [6:0] fDATAw_cnt_wr;
reg          fDATA_read, eoc_rd_DATA;
reg          status_rd_pulse, status_read_op;
reg    [4:0] FIFO_DATA_start_del; 
reg          FIFO_DATA_op_start, FIFO_DATA_operation;
reg          rst, RST_N_flag;
reg    [1:0] rst_flg;
reg   [13:0] adc_counter_320;
reg          adc_write_op, adc_write_op_sync, eof_ADC_write;
				 
reg          start_op;
wire         clk320_trigger;
wire         last_i2c_ack, I2C_USB_done; 
wire         clk40_int, pll_40M_locked;

reg  [279:0] PA_cntrl_reg;
reg   [15:0] AUX_cntrl_reg;

wire   [7:0] dac_mux;
reg   [31:0] dac_reg;
wire  [23:0] dac_back;

wire   [7:0] LpGBT_mux;
wire [277:0] PA_cntrl_back;


//*******************************************************************************
//******************************Status register**********************************
//*******************************************************************************
//Status word description
//byte status1:
//   b[7:0] "11111110" (FE, read only)
//
//byte status2:
//   b[1:0] fifo A operation type flags:
//
//          2'b00 no-op
//          2'b01 FPGA control register write;
//          2'b10 FPGA control register read;
//          2'b11 Read memory data
//
//   b[4:2] control/data register address
//          3'b000 I2C    
//          3'b001 LpBGT control/dual port memory
//          3'b010 DAC    
//          3'b011 PA_SHAPER
//          3'b100 misc
//          3'b101 BC
//          3'b110 Auxiliary control register
//
//   
// 
//   b[5]    resetB for COLUTA chip
//   b[6]    reserved
//   b[7]    reserved
//
//byte status3:
//   b[7:0]  fifo DATA read/write byte counter (low  byte)
//           For control data write operation it (5 least signficant bits are used)
//           defines the number of bytes sent to internal buffer.
//           
//
//byte status4:
//   b[7:0]  fifo DATA read byte counter (high byte)
//           
//byte status5:                 
//   b[0]    start control data operation (execute data register commands)
//   b[1]    pulse command (increment pulse delay counter)  
//   b[2]    COLUTA analog measurement start
//   b[3]    reset trigger pulse delay
//
//   b[4]    reserved
//   b[5]    software reset (0-1 transition starts operation)
//   b[6]    start FIFO DATA operation, load FIFO DATA data into FPGA control register (0-1 transition starts operation)
//                                or read back FPGA control register to FIFO
//   b[7]    read the status word (0-1 transition starts operation)
//
//
//byte status6:
//   b[7:0]  all "11111111" (FF, read only)
//*******************************************************************************




//
// 	Code body starts here
//
reg [2:0]pll_rst;
always @ (negedge clk320)
 begin
  pll_rst[0] <= rst;
  pll_rst[1] <= pll_rst[0]; 
  pll_rst[2] <= !pll_rst[1] & pll_rst[0];
 end

//input clok PLL 
	pll_40MHz p0 
	(
		.rst      (pll_rst[2]),     // !!! may stop working
		.refclk   (clk40),          // refclk.clk
		.locked   (pll_40M_locked), // locked.export
		.outclk_0 (clk5_int),        
		.outclk_1 (clk40_int),       
		.outclk_2 (clk320_trigger)   
	);


//
//Main USB communication switch.
//
//There is only one bidirectional fifo in FT245 chip.
//The code has to distinguish situation that data are sent/received to/from
//status register or are sent/received to/from other parts
//of the code. 
//
reg       status_word_valid;
reg       USB_status_op;
always @ (posedge clk5_int)
   begin
    if      (status_word_valid==1'b0)                 USB_status_op <= 1'b1;
    else if (st_byte_write==1'b1 & stw_cnt_wr==3'b101)USB_status_op <= !status5[6];
    else if (eoc_rd_DATA | eoc_wr_DATA)               USB_status_op <= 1'b1;
   end

   
//
//status word write operation. 
//
reg [2:0] rst_del;
always @ (posedge clk5_int)
   begin

        //PC is the master of status comunication, it must deliver exactly 6 bytes of status !!!!!!!!!!!!!!
        if      (RXF==1'b1)            st_byte_write <= 1'b0;
        else if (st_byte_write==1'b1)  st_byte_write <= 1'b0;
        else if (RXF==1'b0)            st_byte_write <= USB_status_op;
        else                           st_byte_write <= 1'b0;
 
        //counter for number of status bytes to write
        if      ((st_byte_write==1'b1) & (DATA[7:0]==8'b11111111)) stw_cnt_wr <= 3'b000;
        else if ((st_byte_write==1'b1) & (DATA[7:0]==8'b11111110)) stw_cnt_wr <= 3'b001;
        else if ( st_byte_write==1'b1)                             stw_cnt_wr <= stw_cnt_wr + 3'b001;
		
        //reset
        rst_flg[0]   <= status5[5];       //status word reset
        rst_flg[1]   <= rst_flg[0];   
        rst_del[0]   <= (rst_flg[0] & !rst_flg[1]);
        rst_del[2:1] <= rst_del[1:0];
		
        if (rst_del[2]) rst <= 1'b1;
        else            rst <= 1'b0;
		
        //status registers
        if     (st_byte_write==1'b1 & stw_cnt_wr==3'b000) status1[7:0] <= DATA[7:0];
        else if(st_byte_write==1'b1 & stw_cnt_wr==3'b001) status2[7:0] <= DATA[7:0];
        else if(st_byte_write==1'b1 & stw_cnt_wr==3'b010) status3[7:0] <= DATA[7:0];
        else if(st_byte_write==1'b1 & stw_cnt_wr==3'b011) status4[7:0] <= DATA[7:0];
        else if(st_byte_write==1'b1 & stw_cnt_wr==3'b100) status5[7:0] <= DATA[7:0];
        else if(st_byte_write==1'b1 & stw_cnt_wr==3'b101) status6[7:0] <= DATA[7:0];     

        //PC has written to status word valid information
        if ((status1==8'b11111110)&(status6==8'b11111111)) status_word_valid <= 1'b1;
        else	                                            status_word_valid <= 1'b0;	
   end

//read data from FT245!!!!	
      assign RD =   (USB_status_op & !st_byte_write)  | (!USB_status_op & !fDATA_write);  

//
//status word read operation.
//
reg [5:0] stat_del;
always @ (posedge clk5_int)
   begin

        //leading edge of status5[7] starts read operation
        //restart is posible by writing into status5[7] sequence 0 1 
        stat_del[0]     <= status5[7];
        stat_del[5:1]   <= stat_del[4:0];
        status_rd_pulse <= !stat_del[5] & status5[7];
		
        if (rst==1'b1 | eoc_rd==1'b1)   status_read_op <= 1'b0;
        else if (status_rd_pulse==1'b1) status_read_op <= 1'b1;
		
        //counter for number of status bytes to be read
        if (rst==1'b1 | eoc_rd==1'b1) stw_cnt_rd <= 3'b000;
        else if (st_byte_read==1'b1)  stw_cnt_rd <= stw_cnt_rd + 3'b001;
	
        //status read operation is initiated by status word write operation
        //by setting    status5[7] (read the status word flag) to 1 
        if      (rst==1'b1 | TXE==1'b1)  st_byte_read <= 1'b0;
        else if (st_byte_write==1'b1)    st_byte_read <= 1'b0;
        else if (st_byte_read==1'b1)     st_byte_read <= 1'b0;
        //read status is possible only after write operation is finished
        else if (TXE==1'b0 & status_read_op & stw_cnt_wr==3'b000)  
                                         st_byte_read <= 1'b1;
	
        //end of read cycle
        if (st_byte_read & (stw_cnt_rd==3'b101)) eoc_rd <= 1'b1;
        else                                     eoc_rd <= 1'b0;
		
	end

	
//write data to FT245 !!!
	assign WR =  (USB_status_op & st_byte_read) | (!USB_status_op & fDATA_read);	

		
//		
//*******************************************************************************
//******************************FIFO DATA part**************************************
//*******************************************************************************

//
//send data from fifo into FPGA 
//
always @ (posedge clk5_int)
   begin

      //leading edge of status5[6] starts FIFO DATA operation
      FIFO_DATA_start_del[0]   <= status5[6];
      FIFO_DATA_start_del[3:1] <= FIFO_DATA_start_del[2:0];
		FIFO_DATA_start_del[4]   <= !FIFO_DATA_start_del[3] & FIFO_DATA_start_del[2];
		if      (rst )                  FIFO_DATA_op_start <= 1'b0;
		else if (FIFO_DATA_start_del[4])FIFO_DATA_op_start <= 1'b1;
		else                            FIFO_DATA_op_start <= 1'b0;
		
        if (rst==1'b1 | eoc_wr_DATA==1'b1 | eoc_rd_DATA==1'b1)  FIFO_DATA_operation <= 1'b0;
        else if (eoc_wr_DATA==1'b1)                             FIFO_DATA_operation <= 1'b0;
        else if (FIFO_DATA_op_start==1'b1)                      FIFO_DATA_operation <= 1'b1;
        else if (status_word_valid==1'b0)                       FIFO_DATA_operation <= 1'b0;
		
        //counter for number of data bytes to write
        if (rst==1'b1 | eoc_wr_DATA==1'b1) fDATAw_cnt_wr <= 7'b0000001;
        else if (fDATA_write==1'b1)        fDATAw_cnt_wr <= fDATAw_cnt_wr + 7'b0000001;
	
        //data byte write operation is initiated by PC software
        if (rst==1'b1 | RXF==1'b1 | status2[1:0]!=2'b01) fDATA_write <= 1'b0;
        else if (fDATA_write==1'b1)                      fDATA_write <= 1'b0;
        else if (RXF==1'b0 & FIFO_DATA_operation==1'b1)  fDATA_write <= 1'b1;
        else                                             fDATA_write <= 1'b0;
	
        //end of write cycle
        if (FIFO_DATA_operation==1'b0)                 eoc_wr_DATA <= 1'b0;
        else if ((fDATAw_cnt_wr[6:0]==status3[6:0])&
		          (status2[1:0]==2'b01)              &
				  fDATA_write)                             eoc_wr_DATA <= 1'b1;
        else                                           eoc_wr_DATA <= 1'b0;	

		
		  //56 bit LpBGT control register
		  if ((status2[4:0]==5'b00101)&(fDATA_write==1'b1)) LpGBT_reg     <= { DATA, LpGBT_reg[55:8] };		  

		  //16 bit BC control register
		  if ((status2[4:0]==5'b10101)&(fDATA_write==1'b1)) BC_reg        <= { DATA, BC_reg[15:8] };			  

		  //32 bit DAC control register
		  if ((status2[4:0]==5'b01001)&(fDATA_write==1'b1)) dac_reg       <= { DATA, dac_reg[31:8] };	
		  
		  //256 bit i2c control register
		  if ((status2[4:0]==5'b00001)&(fDATA_write==1'b1)) I2C_cntrl     <= { DATA, I2C_cntrl[255:8] };

        //2+138+138 bit PA control register (rounded to mod8)
        if ((status2[4:0]==5'b01101)&(fDATA_write==1'b1)) PA_cntrl_reg  <= { DATA, PA_cntrl_reg[279:8] };			  

		  //16 bit Auxiliary control register
		  if ((status2[4:0]==5'b11001)&(fDATA_write==1'b1)) AUX_cntrl_reg <= { DATA, AUX_cntrl_reg[15:8] };
		  
		 end

	
//
//send data from FPGA into fifo 
//
reg fDATA_read_del;
always @ (posedge clk5_int)
 begin	
    //counter for number of bytes to write
    //before you start read operation send 2'b00/01 to status2[1:0]
    if (rst==1'b1 | eoc_rd_DATA==1'b1 | (status2[1:0]==2'b00 | status2[1:0]==2'b01)) 
                                     fDATAw_cnt_rd <= 17'b00000000000000001;
    else if (fDATA_read==1'b1)       fDATAw_cnt_rd <= fDATAw_cnt_rd + 17'b00000000000000001;
	
    //FPGA data read operation is active
    //as soon as status register allows it
    if (rst==1'b1 | status2[1:0]==2'b00 | status2[1:0]==2'b01)           fDATA_read <= 1'b0;
    else if (fDATA_read==1'b1)                                           fDATA_read <= 1'b0;
    else if (fDATA_read_del==1'b1)                                       fDATA_read <= 1'b0;
    else if (TXE==1'b1)                                                  fDATA_read <= 1'b0;
    else if (TXE==1'b0 & FIFO_DATA_operation==1'b1 & eoc_rd_DATA== 1'b0) fDATA_read <= 1'b1;
	
    fDATA_read_del <= fDATA_read; // To provide delay to the counter so as to avoid extra clock cycle after EOC for reg  A is issued.
		
    //end of read cycle is set to "1" if
    //number of bytes transmitted agrees with status word counter
    if ((fDATAw_cnt_rd=={status4[4:0],status3,4'b0000})&      // 16bytes per sample
                                     (fDATA_read==1'b1)) eoc_rd_DATA <= 1'b1;
    else                                                 eoc_rd_DATA <= 1'b0;		
 end


 //USB read mux
	assign DATA   = 
     (st_byte_read==1'b1 &   stw_cnt_rd==3'b000  ) ? status1         :
     (st_byte_read==1'b1 &   stw_cnt_rd==3'b001  ) ? status2         :
     (st_byte_read==1'b1 &   stw_cnt_rd==3'b010  ) ? status3         :
     (st_byte_read==1'b1 &   stw_cnt_rd==3'b011  ) ? status4         :
     (st_byte_read==1'b1 &   stw_cnt_rd==3'b100  ) ? status5         :	
     (st_byte_read==1'b1 &   stw_cnt_rd==3'b101  ) ? status6         :
     (fDATA_read==1'b1   & status2[4:0]==5'b00010) ? I2C_rdback_mux  : 
     (fDATA_read==1'b1   & status2[4:0]==5'b00110) ? LpGBT_mux       : 
     (fDATA_read==1'b1   & status2[4:0]==5'b01010) ? dac_mux         :  
	  (fDATA_read==1'b1   & status2[4:0]==5'b01110) ? PA_mux          :  
     (fDATA_read==1'b1   & status2[4:0]==5'b10010) ? misc_mux        :  8'bZZZZZZZZ;	
 

// 
//state machine to mux data from LpGBT  
//
reg          l_ld;
wire [229:0] uplinkUserData_USB;
reg  [231:0] LpGBT_dp_data_reg;
wire  [11:0] dp_read_address;

always @ (posedge clk5_int)
 begin
  if      (FIFO_DATA_op_start | l_ld) LpGBT_dp_data_reg <= {2'b00,       uplinkUserData_USB};
  else if (fDATA_read)                LpGBT_dp_data_reg <= {8'b00000000, LpGBT_dp_data_reg[231:8] };
  
  if      (!fDATA_read)                  l_ld <= 1'b0;
  else if (fDATAw_cnt_rd[4:0]==5'b00000) l_ld <= 1'b1;
  else                                   l_ld <= 1'b0;
 end 

    assign       LpGBT_mux       = LpGBT_dp_data_reg[7:0]; 
    assign       dp_read_address = fDATAw_cnt_rd[16:5];
// 

//
//  DAC mux 
//
	assign dac_mux =     (fDATAw_cnt_rd[2:0]==3'b001) ? dac_back[ 7: 0] :
	                     (fDATAw_cnt_rd[2:0]==3'b010) ? dac_back[15: 8] :
	                     (fDATAw_cnt_rd[2:0]==3'b011) ? dac_back[23:16] :	8'b00000000;	
	
 //
 // mux for control register 
 //
 reg        tx_ready_reg;
 always @(posedge clk40_int)
  begin
	tx_ready_reg <= tx_ready;
  end

//fifo uplink signals
//goal is to separate clk40 and uplinkClk_o domains
wire [5:0] f_din, f_dout;
wire       rx_ready_f, wr_full_f1, rd_empty_f1;
wire [1:0] uplinkEcData_o_f, uplinkIcData_o_f;

assign f_din = {uplinkEcData_o, uplinkIcData_o, rx_ready, 1'b0};

	fifo_clk_bridge f1 (
		.data    (f_din),             //  fifo_input.datain
		.wrreq   (!wr_full_f1),       //            .wrreq
		.wrclk   (uplinkClk_o),       //            .wrclk
		.wrfull  (wr_full_f1),        //            .wrfull

		.rdclk   (clk40_int),         //            .rdclk		
		.rdreq   (!rd_empty_f1),      //            .rdreq
		.q       (f_dout),            // fifo_output.dataout
		.rdempty (rd_empty_f1)        //            .rdempty
	); 
	
   assign rx_ready_f       = f_dout  [1];
	assign uplinkEcData_o_f = f_dout[3:2];
 	assign uplinkIcData_o_f = f_dout[5:4];
 
	assign misc_mux =    (fDATAw_cnt_rd[2:0]==3'b001) ? {3'b000 , tx_ready_reg, rx_ready_f, pll_40M_locked, I2C_USB_done, last_i2c_ack} : 
	                     (fDATAw_cnt_rd[2:0]==3'b010) ? {4'b0000, uplinkEcData_o_f[1:0], uplinkIcData_o_f[1:0]                        } : 8'b00000000;							
													
 //
 // mux for I2C shift register 
 //
 always @ (posedge clk5_int)
 begin
  if      (FIFO_DATA_op_start & (status2[4:0]==5'b00010)) I2C_shift_back_shreg <= I2C_shift_back;
  else if (fDATA_read         & (status2[4:0]==5'b00010)) I2C_shift_back_shreg <= {8'b00000000, I2C_shift_back_shreg[255:8] };
 end
 

 assign I2C_rdback_mux =  I2C_shift_back_shreg [7:0];
 

 //
 // mux for PA read back register 
 //
 reg [279:0]PA_read_back;
 always @ (posedge clk5_int)
 begin
  if      (FIFO_DATA_op_start & (status2[4:0]==5'b01110)) PA_read_back <= {2'b00, PA_cntrl_back[277:0]};
  else if (fDATA_read         & (status2[4:0]==5'b01110)) PA_read_back <= {8'b00000000, PA_read_back[279:8] };
 end
 

 assign PA_mux =  PA_read_back [7:0];
 


//*******************************************************************************							 
//*******************************************************************************
//reset and  start flags (common synchronization)
//*******************************************************************************							 
//*******************************************************************************

reg  reset_1, BC_reset, usb_LpGBT_start, LpGBT_reset,
     i2c_reset, PA_reset,
     dac_reset,
     analog_start1, analog_start, pulser_start,
     control_start1, usb_i2c_start,
     usb_BC_start, usb_PA_start,
     usb_dac_start;

reg [4:0] control_start_del, analog_start_del;
	  
always @(posedge clk40_int) 
  begin	
   reset_1        <= rst;
   
//leading edge detected	 
   control_start_del  <= (control_start_del << 1) | status5[0];
   analog_start_del   <= (analog_start_del  << 1) | status5[2];   
   
   control_start1 <= ~control_start_del[4] & control_start_del[3];
   analog_start1  <= ~analog_start_del [4] & analog_start_del [3];
  end
   
always @(posedge clk40_int) 	
  begin		
	
   i2c_reset   <= reset_1;
   BC_reset    <= reset_1;
   LpGBT_reset <= reset_1;
   PA_reset    <= reset_1;
   dac_reset   <= reset_1;
	
   analog_start <= analog_start1;
   pulser_start <= analog_start1;	 
	 
   usb_i2c_start   <= (status2[4:0]==5'b00001) & control_start1;
   usb_BC_start    <= (status2[4:0]==5'b10101) & control_start1;
   usb_LpGBT_start <= (status2[4:0]==5'b00101) & control_start1;
   usb_PA_start    <= (status2[4:0]==5'b01101) & control_start1;
   usb_dac_start   <= (status2[4:0]==5'b01001) & control_start1;
	
  end
//*******************************************************************************							 
//*******************************************************************************



//****************************************************************
//**************************DAC operations************************
//****************************************************************

//start flag
reg[2:0] dac_start;
always @(posedge clk40_int)
begin
	dac_start[1:0] <= {dac_start[0],  (usb_dac_start)};
	dac_start[2]   <= ~dac_start[1] & dac_start[0];
	end


dac  dac1
 (  
  .clk           (clk40_int),
  .rst           (dac_reset),
  .op_start      (dac_start[2]),
  .DAC9881_cntrl (dac_reg[31:0]),
		  
  //
  .DAC_RESET_b   (cal_rst_b),
  .DAC_SCLK      (cal_sclk),
  .DAC_SYNC_b    (),
  .DAC_SDIN      (cal_sdi),
  .DAC_SDO       (cal_sdo),
  .DAC_LDAC_b    (cal_ldac_b),
  //
  .DAC9881_data_back  (dac_back[23:0])
 );
		
//****************************************************************
//****************************************************************
//****************************************************************
		
		
		
		

//****************************************************************
//                   ***** I2C state machine *****
//****************************************************************
// procedure:
//       a/PC software loads control data register through fifo A
//         (USB control data stream)
//       b/PC software starts the execution of the I2C instruction
//         in the control data stream
//       c/I2C state machine(below) automaticaly ecexutes 
//         all I2C commands in the queue
//
//
wire [7:0] wb_dat_o,wb_dat_i;
wire [2:0] wb_adr_i;
wire       wb_ack_o, wb_we_i, wb_stb_i, wb_cyc_i, 
           scl_pad_o, scl_padoen_oe;
wire       scl_pad_i, sda_pad_i;	


		  
//start flag
reg[2:0] I2C_start;
always @(posedge clk40_int)
begin
	I2C_start[1:0] <= {I2C_start[0],  (usb_i2c_start)};
	I2C_start[2]   <= ~I2C_start[1] & I2C_start[0];
end



//
//state machine converts USB control data stream into control sequence
//for Wishbone compatible I2C master core
// 

 USB_I2C_state_machine usb_i2c_sm
(
	// 
	.clk                (clk40_int),
	.rst                (i2c_reset),
	
	// I2C master core signals
	.i2c_reg_adr        (wb_adr_i),
	.data_to_i2c        (wb_dat_i),
	.data_from_i2c      (wb_dat_o),
	.i2c_we             (wb_we_i), 
	.i2c_stb            (wb_stb_i), 
	.i2c_cyc            (wb_cyc_i), 
	.wb_ack_o           (wb_ack_o),

	//USB command stream
	.i2c_operation_start(I2C_start[2]),
	.USB_cntr_in        (I2C_cntrl),
	.USB_data_out       (I2C_shift_back),
	.i2c_queue_done     (I2C_USB_done),
	.last_i2c_ack       (last_i2c_ack), 
	.usb_tst1           ()             //test only
	);

wire sda_padoen_oe /* synthesis keep */;
wire sda_pad_o /* synthesis keep */;
		 
//I2C interface to NevisADC chip
i2c_master_top    I2C
 (
  .wb_clk_i (clk40_int),  // master clock input
  .wb_rst_i (1'b0),       // synchronous active high reset
  .arst_i   (~i2c_reset), // asynchronous reset
  .wb_adr_i (wb_adr_i),   // lower address bits (3bits)
  .wb_dat_i (wb_dat_i),   // databus input      (8bits)
  .wb_dat_o (wb_dat_o),   // databus output     (8bits)
  .wb_we_i  (wb_we_i),    // write enable input
  .wb_stb_i (wb_stb_i),   // stobe/core select signal
  .wb_cyc_i (wb_cyc_i),   // valid bus cycle input
  .wb_ack_o (wb_ack_o),   // bus cycle acknowledge output
  .wb_inta_o (),          // interrupt request signal output
							 
  .scl_pad_i (scl_pad_i), //I2C bus signals
  .scl_pad_o (scl_pad_o), 
  .scl_padoen_o (scl_padoen_oe), 
  .sda_pad_i (sda_pad_i), 
  .sda_pad_o (sda_pad_o), 
  .sda_padoen_o (sda_padoen_oe) 
 ); 

//Auxiliary control register definition
//
//AUX_cntrl_reg[1:0]    00  LpGBT chip I2C selected
//                      01  COLUTA #1  I2C selected
//                      10  COLUTA #2  I2C selected
//             [6:2]        number of calib pulses generated per one trigger
							 
//I2C bus signals
//	assign SCL       = scl_padoen_oe ? 1'bZ : scl_pad_o;
//solution with no pull up resistor on SCL 
   assign SCL_1        = AUX_cntrl_reg[1:0]==2'b01 ? scl_padoen_oe : 1'b0;    //Coluta #1
   assign SCL_2        = AUX_cntrl_reg[1:0]==2'b10 ? scl_padoen_oe : 1'b0;    //Coluta #2
   assign SLSCL_LPGBT  = AUX_cntrl_reg[1:0]==2'b00 ? scl_padoen_oe : 1'b0;    //LpGBT chip

   assign SDA_1        = !(AUX_cntrl_reg[1:0]==2'b01) ? 1'bZ :
                                        sda_padoen_oe ? 1'bZ : sda_pad_o;
   assign SDA_2        = !(AUX_cntrl_reg[1:0]==2'b10) ? 1'bZ :
                                        sda_padoen_oe ? 1'bZ : sda_pad_o;
   assign SLSDA_LPGBT  = !(AUX_cntrl_reg[1:0]==2'b00) ? 1'bZ :
                                        sda_padoen_oe ? 1'bZ : sda_pad_o;
   
   assign scl_pad_i    = AUX_cntrl_reg[1:0]==2'b01 ? SCL_1       :
                         AUX_cntrl_reg[1:0]==2'b10 ? SCL_2       :
                         AUX_cntrl_reg[1:0]==2'b00 ? SLSCL_LPGBT : 1'b0;
		
   assign sda_pad_i    = AUX_cntrl_reg[1:0]==2'b01 ? SDA_1        :
                         AUX_cntrl_reg[1:0]==2'b10 ? SDA_2        :
                         AUX_cntrl_reg[1:0]==2'b00 ? SLSDA_LPGBT  : 1'b0;


   
   assign RSTB1      = !status2[5];       //resetB  for COLUTA I2C&chip #1
   assign RSTB2      = !status2[5];       //resetB  for COLUTA I2C&chip #2

//chip_id is set inside COLUTA  to "001"
//assign chip_id[2:0] = {3'b001};           //chip id for COLUTA I2C protocol	


//*********************************************************************		
//***********************PA/SHAPER signaling***************************
//*********************************************************************
//
//this is to control slow control logic of PA/SHAPER
//
reg[2:0] PA_start;
always @(posedge clk40_int)
begin
	PA_start[1:0] <= {PA_start[0],  (usb_PA_start)};
	PA_start[2]   <= ~PA_start[1] & PA_start[0];
	end 

//PA/SHAPER serial slow control logic
PA_SHAPER pa1
    (  
      //module state machine inputs
      .clk      (clk40_int),
      .rst      (PA_reset),
      .op_start (PA_start[2]),
      .PA_cntrl (PA_cntrl_reg[279:0]),
		  
      //serial slow control signals
      .rstb_sr  (rstb_sr),
      .select   (select),
      .srout_sr (srout_sr),			 
      .clk_sr   (clk_sr),
      .srin_sr  (srin_sr),
		
		.PA_cntrl_reg(PA_cntrl_back[277:0])
    );
		

//***********************************************************************		
//***********************Bunch crossing signal***************************
//***********************************************************************
//
//this is to start BC sequence
//
reg[2:0] BC_start;
always @(posedge clk40_int)
begin
	BC_start[1:0] <= {BC_start[0],  (usb_BC_start)};
	BC_start[2]   <= ~BC_start[1] & BC_start[0];
	end 
 
 
 //sequencer
BC_control BC_1
 (  
  //module state machine inputs
  .clk         (clk40_int),
  .rst         (BC_reset),
  .op_start    (BC_start[2]),
  .BC_cntrl    (BC_reg),
		  	  
  //BC signal
  .BCRST       (BCRST)

 );
 


//LpGBT control
//
//this is to start LpGBT sequence
//
wire  [31:0] downlinkUserData;
wire   [1:0] downlinkEcData,   downlinkIcData  ;
reg   [20:0] LpGBT_start;
wire [229:0] uplinkUserData_o;
wire         lpgbt_power_up;

always @(posedge clk40_int)
begin
	LpGBT_start[19:0] <= {LpGBT_start[18:0],  (usb_LpGBT_start)};
	LpGBT_start[20]   <= ~LpGBT_start[19] & LpGBT_start[18];
	end 

//LpGBT control execution	
LpGBT_control lc1
    (  
     //module state machine inputs
     .clk(clk40_int),
     .rst(LpGBT_reset),
     .op_start(LpGBT_start[2]),
     .LpGBT_cntrl(LpGBT_reg),
		  
     //link reset 
     .link_reset_pulse(link_reset_pulse),
			 
     //Ec & Ic data fields
     .downlinkEcData(downlinkEcData),
     .downlinkIcData(downlinkIcData), 
			 
     //downlink user data       
     .downlinkUserData(downlinkUserData),        
			 
     //Test signals
     .downlink_skipCycle(downlink_skipCycle),
	  
	  //slow control signals
     .lpgbt_rstb      (lpgbt_rstb),
     .lpgbt_pordis    (lpgbt_pordis),
     .lpgbt_mod0      (lpgbt_mod0),
     .lpgbt_mod1      (lpgbt_mod1),
     .lpgbt_mod2      (lpgbt_mod2),
     .lpgbt_mod3      (lpgbt_mod3),
     .lpgbt_stateovrd (lpgbt_stateovrd),
     .lpgbt_lockmode  (lpgbt_lockmode),
     .lpgbt_sc_i2c    (lpgbt_sc_i2c),
	  .lpgbt_power_up  (lpgbt_power_up) 
    );

	
//user data for downlink are synchronized below
reg        downlinkClkEn_i;
reg  [2:0] d_cnter=3'b000; 
reg [31:0] downlinkUserData_i=32'h00000000;
reg  [1:0] downlinkEcData_i=2'b11;
reg  [1:0] downlinkIcData_i=2'b11;


//downlink Ec and Ic flags
always@(posedge clk_mgtTxClk_o )
begin         
   if (d_cnter == 3'b111)d_cnter <= 3'b000;
   else                  d_cnter <= d_cnter + 3'b001;
     
   if (d_cnter == 3'b000) downlinkClkEn_i   <= 1'b1;
   else                   downlinkClkEn_i   <= 1'b0;  
				
   if (downlinkClkEn_i)   downlinkEcData_i   <= 2'b11;//downlinkEcData;  
				 
   if (downlinkClkEn_i)   downlinkIcData_i   <= 2'b11;//downlinkIcData;  
end	

//downlink user data
always@(posedge clk_mgtTxClk_o )// or posedge link_reset_pulse)
begin 
/* if      (link_reset_pulse)  downlinkUserData_i <= downlinkUserData;
 else */
 if (downlinkClkEn_i)   downlinkUserData_i <= downlinkUserData_i + 32'h00000001; 
end

// 
reg downlink_Rst, uplink_Rst;
wire clk_mgtSerial_s;

always @(posedge clk40_int)
begin
   downlink_Rst <= link_reset_pulse | rst;
   uplink_Rst   <= link_reset_pulse | rst;
end



lpgbtFpga_top   f0
   (
        // Clocks
		  .clk320 (clk320),                        // main pll clock      
		  
        .donwlinkClk_i  (clk_mgtTxClk_o),        // Downlink datapath clock (either 320 or 40MHz)
        .downlinkClkEn_i(downlinkClkEn_i),       // Clock enable (1 over 8 when encoding runs @ 320Mhz, '1' @ 40MHz)
        
        .uplinkClk_o  (uplinkClk_o),             // Clock provided by the Rx serdes: in phase with data
        .uplinkClkEn_o(uplinkClkEn_o),           // Clock enable pulsed when new data is ready
        
        .downlinkRst_i(downlink_Rst),            // Reset the downlink path
        .uplinkRst_i  (uplink_Rst),              // Reset the uplink path
        
        // Down link
        .downlinkUserData_i(downlinkUserData_i), // Downlink data (user) *******************
        .downlinkEcData_i  (downlinkEcData_i),   // Downlink EC field
        .downlinkIcData_i  (downlinkIcData_i),   // Downlink IC field
                
        .downLinkBypassInterleaver_i(1'b0),      // Bypass downlink interleaver (test purpose only)
        .downLinkBypassFECEncoder_i (1'b0),      // Bypass downlink FEC (test purpose only)
        .downLinkBypassScrambler_i  (1'b0),      // Bypass downlink scrambler (test purpose only)
        
        .downlinkReady_o        (tx_ready),      // Downlink ready status
        
        // Up link
        .uplinkUserData_o(uplinkUserData_o),     // Uplink data (user)
        .uplinkEcData_o  (uplinkEcData_o),       // Uplink EC field
        .uplinkIcData_o  (uplinkIcData_o),       // Uplink IC field
                
        .uplinkSelectDataRate_i   (1'b1),        // Uplink datarate selection (dynamic mode only - '0': 5.12Gbps / '1': 10.24Gbps)
        .uplinkSelectFEC_i        (1'b0),        // Uplink FEC selection (dynamic mode only - '0': FEC5 / '1': FEC12)
        .uplinkBypassInterleaver_i(1'b0),        // Bypass uplink interleaver (test purpose only)
        .uplinkBypassFECEncoder_i (1'b0),        // Bypass uplink FEC (test purpose only)
        .uplinkBypassScrambler_i  (1'b0),        // Bypass uplink scrambler (test purpose only)

        .uplinkReady_o(rx_ready),                // Uplink ready status
        
        // MGT
        .clk_mgtSerialClk_o(clk_mgtSerial_s),    // Transceiver serial clock
        .rxPMAInitVal_i    (8'b10000000),        // integer range 0 to 256; 
                                                 // Start-up time emulation (random value set by the TCL script)
 
        .clk_mgtTxClk_o(clk_mgtTxClk_o), 
        .clk_mgtRxClk_o(clk_mgtRxClk_o), 

        .downlinkSerial_o(downlinkSerial_o),     // Tx serial lane
        .uplinkSerial_i  (uplinkSerial_i),       // Rx serial lane
        

        // Test feature
        .downlink_skipCycle(downlink_skipCycle), // skipCycle in the downlink frame. makes the lpGBT lose lock and forces a new relock; this is clk'ed with txclk
											     // MSB is direction, LSB is enable
 
        .downlink_forceHeaderErr_i(1'b0),        // Force wrong header (downlink)
        .downlinkErrorMaskInject_i({64{1'b0}}),  // Force bit flip (downlink - serial)
        .uplink_forceHeaderErr_i  (1'b0),        // Force wrong header (uplink)
        .uplinkErrorMaskInject_i  ({256{1'b0}})  // Force bit flip (uplink - serial)

   );

//
//*****************LpGBT uplink data
//

//dual port operation start
reg  [12:0] dp_start_sr;
reg         dp_start0, dp_start1, dp_start2, dp_start;
reg         dp_write_op_sync, dp_write_op, dp_write_320, eof_dp_write;
reg  [11:0] dp_counter_320;
wire        wr_full, rd_empty, analog_start_fast;

//fifo for start signal
//goal is to separate clk40 and uplinkClk_o domains
	cntrl_fifo u0 (
		.data    (analog_start),      //  fifo_input.datain
		.wrreq   (!wr_full),          //            .wrreq
		.wrclk   (clk40_int),         //            .wrclk
		.wrfull  (wr_full),           //            .wrfull

		.rdclk   (uplinkClk_o),       //            .rdclk		
		.rdreq   (!rd_empty),         //            .rdreq
		.q       (analog_start_fast), // fifo_output.dataout
		.rdempty (rd_empty)           //            .rdempty
	);



always @(posedge uplinkClk_o)
begin	 
 dp_start_sr <= {dp_start_sr[11	:0], analog_start_fast}; 
 dp_start0   <= !dp_start_sr[12] & dp_start_sr[11];
	 
 dp_start1  <= dp_start0;
 dp_start2  <= dp_start1;
 dp_start   <= dp_start2;


 
//
//dp read state machine
//
//will fill with data whole dual port memory
//

 if      (dp_start)         dp_write_op_sync <= 1;
 else if (dp_write_op_sync) dp_write_op_sync <= 0;
		
 if      (dp_write_op_sync)   dp_counter_320 <= {12{1'b0}};
 else if (dp_write_320)       dp_counter_320 <= dp_counter_320 + 12'd1;
      
 if      (dp_write_op_sync)    dp_write_op <= 1;
 else if (eof_dp_write )       dp_write_op <= 0;

 if      (uplinkClkEn_o & dp_write_op & rx_ready)  dp_write_320 <= 1'b1;               
 else                                              dp_write_320 <= 1'b0;		
 
 if      (dp_write_op_sync)                           eof_dp_write <= 0;
 else if (dp_write_320 &(dp_counter_320=={12'hfff })) eof_dp_write <= 1;	

 end




//uplink data from LpGBT registered	
reg  [229:0] uplinkUserData_reg, uplinkUserData_reg_raw;

always @(posedge uplinkClk_o)
 begin
  if (uplinkClkEn_o) uplinkUserData_reg_raw <= uplinkUserData_o;
 
// data alignment due to shifts in LpGBT
  uplinkUserData_reg   [31:0] <= {uplinkUserData_reg_raw    [7:0], uplinkUserData_reg_raw   [15:8],
                                  uplinkUserData_reg_raw  [23:16], uplinkUserData_reg_raw  [31:24]};
  uplinkUserData_reg  [63:32] <= {uplinkUserData_reg_raw  [39:32], uplinkUserData_reg_raw  [47:40],
                                  uplinkUserData_reg_raw  [55:48], uplinkUserData_reg_raw  [63:56]};
  uplinkUserData_reg  [95:64] <= {uplinkUserData_reg_raw  [71:64], uplinkUserData_reg_raw  [79:72],
                                  uplinkUserData_reg_raw  [87:80], uplinkUserData_reg_raw  [95:88]};
  uplinkUserData_reg [127:96] <= {uplinkUserData_reg_raw [103:96], uplinkUserData_reg_raw[111:104],
                                  uplinkUserData_reg_raw[119:112], uplinkUserData_reg_raw[127:120]};
  uplinkUserData_reg[159:128] <= {uplinkUserData_reg_raw[135:128], uplinkUserData_reg_raw[143:136],
                                  uplinkUserData_reg_raw[151:144], uplinkUserData_reg_raw[159:152]};
  uplinkUserData_reg[191:160] <= {uplinkUserData_reg_raw[167:160], uplinkUserData_reg_raw[175:168],
                                  uplinkUserData_reg_raw[183:176], uplinkUserData_reg_raw[191:184]};											
  uplinkUserData_reg[223:192] <= {uplinkUserData_reg_raw[199:192], uplinkUserData_reg_raw[207:200],
                                  uplinkUserData_reg_raw[215:208], uplinkUserData_reg_raw[223:216]};
  uplinkUserData_reg[229:224] <=  uplinkUserData_reg_raw[229:224];
end 

//dual port memories for LpGBT data
	dp_32bit m0 (
		.data      (uplinkUserData_reg[31:0]),  
		.wraddress (dp_counter_320), 
		.rdaddress (dp_read_address), 
		.wren      (dp_write_320), 
		.wrclock   (uplinkClk_o), 
		.rdclock   (clk5_int), 
		.q         (uplinkUserData_USB[31:0]) 
	);

	dp_32bit m1 (
		.data      (uplinkUserData_reg[63:32]), 
		.wraddress (dp_counter_320), 
		.rdaddress (dp_read_address), 
		.wren      (dp_write_320),
		.wrclock   (uplinkClk_o),  
		.rdclock   (clk5_int), 
		.q         (uplinkUserData_USB[63:32]) 
	);	

	dp_32bit m2 (
		.data      (uplinkUserData_reg[95:64]), 
		.wraddress (dp_counter_320), 
		.rdaddress (dp_read_address), 
		.wren      (dp_write_320),
		.wrclock   (uplinkClk_o),  
		.rdclock   (clk5_int), 
		.q         (uplinkUserData_USB[95:64]) 
	);	 

	dp_32bit m3 (
		.data      (uplinkUserData_reg[127:96]), 
		.wraddress (dp_counter_320), 
		.rdaddress (dp_read_address), 
		.wren      (dp_write_320),
		.wrclock   (uplinkClk_o),  
		.rdclock   (clk5_int), 
		.q         (uplinkUserData_USB[127:96]) 
	);

	dp_32bit m4 (
		.data      (uplinkUserData_reg[159:128]), 
		.wraddress (dp_counter_320), 
		.rdaddress (dp_read_address), 
		.wren      (dp_write_320),
		.wrclock   (uplinkClk_o),  
		.rdclock   (clk5_int),  
		.q         (uplinkUserData_USB[159:128]) 
	);

	dp_32bit m5 (
		.data      (uplinkUserData_reg[191:160]), 
		.wraddress (dp_counter_320), 
		.rdaddress (dp_read_address), 
		.wren      (dp_write_320),
		.wrclock   (uplinkClk_o),  
		.rdclock   (clk5_int),  
		.q         (uplinkUserData_USB[191:160]) 
	);	

	dp_32bit m6 (
		.data      (uplinkUserData_reg[223:192]), 
		.wraddress (dp_counter_320), 
		.rdaddress (dp_read_address), 
		.wren      (dp_write_320),
		.wrclock   (uplinkClk_o),  
		.rdclock   (clk5_int),  
		.q         (uplinkUserData_USB[223:192]) 
	);	

	dp_6bit m7 (
		.data      (uplinkUserData_reg[229:224]), 
		.wraddress (dp_counter_320), 
		.rdaddress (dp_read_address), 
		.wren      (dp_write_320),
		.wrclock   (uplinkClk_o),  
		.rdclock   (clk5_int),  
		.q         (uplinkUserData_USB[229:224]) 
	);	


	
//simple test for routing 
	assign up_err = uplinkUserData_USB=={{200{1'b1}}, {30{1'b0}}};
	

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	 
//*******************************************************************************
//***********external pulser interface - programmable delay trigger**************
//*******************************************************************************
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

reg [3:0] delay_reg, delay_counter;
reg [9:0] delay_start;
reg [45:0]external_pulser_start;
reg       pulse_command, trigger_operation;

always @ (posedge clk40_int)
   begin      
        external_pulser_start[0]    <= pulser_start;
        external_pulser_start[45:1] <= external_pulser_start[44:0];                     //COLUTA analog measurement start
        
        if(status5[3])                 delay_reg <= 4'b1001;                            //reset the trigger delay counter
        else if (!external_pulser_start[35] && external_pulser_start[34] && status5[1])
                                       delay_reg <= delay_reg - 4'b0001;                //decrement delay counter
   end	  

always @ (posedge clk320_trigger)
 begin 
  delay_start[0]   <= external_pulser_start[2];
  delay_start[9:1] <= delay_start[8:0];
 
  if (delay_start[9])                   trigger_operation <= 1'b1;
  else if (delay_counter[3:0]==4'b0000) trigger_operation <= 1'b0;
                 
  if(delay_start[9])                    delay_counter <= delay_reg;        
  else if(trigger_operation)            delay_counter <= delay_counter - 4'b0001;
  else                                  delay_counter <= 4'b0000; 
      
        
  if (external_pulser_start[45])         pulse_command <= 0; 
  else if(delay_counter[3:0]==4'b0000)   pulse_command <= 1; 
		 
  trigger <= pulse_command;
 end

//
//Calibration pulse generation
//
//Calibration pulse should be ~1us long
//with period of ~8us
// 
reg [10:0] on_width_reg;
reg [11:0] off_width_reg;
reg  [4:0] n_pulse;
reg        calibration, pulse_off, pulse_on;

always @ (posedge clk320_trigger)
 begin
//start to generate the string of calibration pulses
  if      (~pulse_command)                              calibration <= 1'b1;
  else if ((n_pulse==5'b00001)&(off_width_reg==12'h000))calibration <= 1'b0;

//number of pulses to be generated
  if      (delay_start[9])                         n_pulse <= AUX_cntrl_reg[6:2]; 
  else if (pulse_off & (off_width_reg ==12'd0))    n_pulse <= n_pulse - 5'b00001; 

//pulse on timer  
  if      (delay_start[9] | (pulse_off & (off_width_reg==12'd0))) on_width_reg <= 11'd319;  
  else if (pulse_on)                                              on_width_reg <= on_width_reg - 11'd1;

//pulse off  timer
  if      (on_width_reg==12'd0) off_width_reg <= 12'd3198; 
  else if (pulse_off)           off_width_reg <= off_width_reg - 12'd1;

//state machine
 if (~calibration)
  begin
   pulse_on  <= 1'b0;
   pulse_off <= 1'b0;
  end
 else
  begin
//pulse on
   if     (~pulse_command)                               pulse_on  <= 1'b1;
   else if(pulse_on  & (on_width_reg ==11'h000))         pulse_on  <= 1'b0; 
   else if((n_pulse==5'b00001)&(off_width_reg==12'h000)) pulse_on  <= 1'b0; 
   else if(pulse_off & (off_width_reg==12'h000))         pulse_on  <= 1'b1;  

//pulse off
   if     (pulse_on  & (on_width_reg  ==11'h000))pulse_off <= 1'b1;
   else if(pulse_off & (off_width_reg ==12'h000))pulse_off <= 1'b0;   
  end
  
 end 

assign cal_pulse_ctrl = pulse_on;	  

		  assign TP1 = lpgbt_power_up;
		  assign TP2 = 1'b0;
		  
//Dummy test point
//just to remove warning about signals which do not drive logic
   assign TP_dummy  = 1'b0;		 

endmodule
