//************************************************************************
//
// module controls AD9650 - 16 bit ADC used on COLUTA tester board
// v2.0 jb/june/2018
//
//************************************************************************
//
//  Internal AD9650 registers are by SPI interface working
//  in MSB-First mode
//  Module also generates SYNC signal.
//
//  ******ad9650_cntrl data format******
//  ad9650_cntrl[23:0]  SPI instruction register
//
//  ad9650_cntrl  [23]  R/-W; 
//  ad9650_cntrl  [22]  W1;      default = 0
//  ad9650_cntrl  [21]  W0;      default = 0     only one data byte is transfered
//  ad9650_cntrl[20:8]  A[12:0]; register address
//  ad9650_cntrl[ 7:0]  D[ 7:0]; data
//
//
//  ad9650_cntrl[25:24] phase counter to generate SYNC signal    
//
//  ad9650_cntrl[26]  operation type (0 - SPI    1 - SYNCH generation)   
//
//************************************************************************

module AD9650
     (
      //module control inputs         
      input fast_clk,
      input clk40,
      input rst,
      input op_start,
      input wire[26:0] ad9650_cntrl,
		  
      //DRE ADC interface 
      output reg SYNC,
      output reg CSB,
      output reg SCLK,
      inout wire SDIO,
		  
      //data from AD9650
      output reg[7:0]ad9650_data_back,

      //operation done
      output reg op_done
     );

reg        op_starts, op_start_reg, cycle_start, next_cycle;
reg [11:0] cph;
reg [23:0] SPI_instr_reg;
reg  [4:0] bit_num;
reg        SDIO_reg;



//this is for clock domain adjustment
reg [15:0]rst_del;
wire      reset;
always @(posedge clk40) 
begin
   rst_del <= {rst_del[14:0],rst};
end

   assign reset = rst_del[15]; 

	

//******************************SPI operation*****************************************
always @(posedge clk40 or posedge reset)	
begin	
 if (reset) 
  begin
   CSB       <= 1'b1; 
   SCLK      <= 1'b0;  
   SDIO_reg  <= 1'b0;
	op_done   <= 1'b1;
  end
  
else 
         begin
           //basic bit cycle
               op_start_reg <= op_start & ~ad9650_cntrl[26];  //SPI operation detected
               op_starts    <= ~op_start_reg & op_start & ~ad9650_cntrl[26];
               cycle_start  <=  op_starts | next_cycle; 
               cph[11:0]    <= {cph[10:0], cycle_start};
	
	        //SPI CSB signal
               if (op_starts)    CSB <= 1'b0;
               else if (op_done) CSB <= 1'b1;

           //SPI clock signal
               if     (cph[5]) SCLK  <=  1'b1;
               else if(cph[11])SCLK  <=  1'b0; 

           //SPI SDIO signal     strange thing ?????
               if (ad9650_cntrl[23]==1'b0)  SDIO_reg <= SPI_instr_reg[23]; //write operation
               else if (bit_num < 5'b11000)        //read  operation
                                            SDIO_reg <= SPI_instr_reg[23];
                               

           //SPI instruction register
               if (op_starts)        SPI_instr_reg[23:0] <= ad9650_cntrl[23:0];
               else if (next_cycle)  SPI_instr_reg[23:0] <= {SPI_instr_reg[22:0] , 1'b0};
				
           // bit number register
               if (op_starts)       bit_num[4:0] <= 5'b10111;//23 decimal
               else if (next_cycle) bit_num[4:0] <= bit_num[4:0] - 5'b00001;
				
           //next cycle flag
               if (cph[11] & ~(bit_num==5'b00000)) next_cycle <= 1'b1;
               else                                next_cycle <= 1'b0;

           // operation done flag
               if (op_starts)                         op_done <= 1'b0;	
               else if ((bit_num==5'b00000)& cph[11]) op_done <= 1'b1;
         end	
end

//SDIO signal
assign SDIO = op_done                  ? 1'bZ     :
              (ad9650_cntrl[23]==1'b0) ? SDIO_reg :        //write operation
              (bit_num < 5'b11000)     ? SDIO_reg : 1'bZ;  //read operation, first part, second part 

//read back register
always @(posedge SCLK)
  begin
   if (CSB==1'b0) ad9650_data_back[7:0] <= {ad9650_data_back[6:0], SDIO};
  end


//******************************SYNC operation*****************************************
reg  op_in_p, LE_clk40, clk40_reg;
reg  clk40_n160;
reg  SYNC_start_reg, SYNC_op_starts, LE_detected_flag;
reg  [2:0]sync_cnt;

always @(posedge fast_clk)
begin
	clk40_n160 <= clk40;
end



always @(posedge fast_clk or posedge reset )	
begin	
 if (reset) 
          begin    
               SYNC          <= 1'b0; 
               op_in_p       <= 1'b0; 
               sync_cnt[2:0] <= 3'b111;
          end
else  
         begin
              //operation start flags
               SYNC_start_reg <= op_start & ad9650_cntrl[26];  //SPI operation detected
               SYNC_op_starts <= ~SYNC_start_reg & op_start & ad9650_cntrl[26];

              //operation in progress
              if (SYNC_op_starts)        op_in_p <= 1'b1; 
              else if (sync_cnt==3'b111) op_in_p <= 1'b0; 

              //find the next leading edge of 40MHz clock
                 clk40_reg <= clk40_n160 & op_in_p;
              LE_clk40     <= ~clk40_reg & clk40_n160 & op_in_p;
				  
				  if (LE_clk40)          LE_detected_flag <= 1'b1;
				  else if (op_in_p==1'b0)LE_detected_flag <= 1'b0;
				  

              //synchronization counter 
              if (SYNC_op_starts)        sync_cnt[2:0] <= {1'b0, ad9650_cntrl[25:24]};
              else if (LE_detected_flag) sync_cnt[2:0] <= sync_cnt[2:0] - 3'b001;

              //SYNC signal generated if sync_cnt at 3'b111
              if ((sync_cnt==3'b111) & op_in_p) SYNC <= 1'b1;
              else                              SYNC <= 1'b0;
				  

         end
end              

endmodule
