//////////////////////////////////////////////////////////////////////
////                                                              ////
////  Advantech Co., Ltd	FPGA Design                           ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////  Project	: TI Shannon EVM FPGA                             ////
////  File name	: clock_spi2x.v	                                  ////
////  Description                                                 ////
////      		: Shannon EVM FPGA Core MODULE                    ////
////  Created Date                                                ////
////			: 2010/12/09									  ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2010 Advantech Co., Ltd                        ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
module CDCE62005_2x     (FPGA_48MHz,        
                         FPGA_rst,          
                         Vccpg,             
                         PLL_Lock2,          
                         start,             
                         busy,              
                         ready,             
						 clk2_por_en,                   
						 clk2_resetfull_en,             
						 clk2_resetz_en,                
						 clk2_por,                      
						 clk2_resetfull,                
						 clk2_resetz,                   
                         iClock_div,        
                         Write_data,        
                         Read_data,         
                         CLOCK2_SSPCS_o,    
                         CLOCK2_SSPCK_o,    
                         CLOCK2_SSPSI_o,    
                         CLOCK2_SSPSO_i );  
  input         FPGA_48MHz;
  input         FPGA_rst;
  input         Vccpg;
  output        PLL_Lock2;
  reg           PLL_Lock2 = 1'b0;
  input         start;//0, trigger transaction
  output        busy;//1, busy
  output        ready;
  input         clk2_por_en;
  input         clk2_resetfull_en;
  input         clk2_resetz_en;
  output        clk2_por;
  reg           clk2_por = 1'b1;
  output        clk2_resetfull;
  reg           clk2_resetfull = 1'b1;
  output        clk2_resetz;
  reg           clk2_resetz = 1'b1;
  input  [7:0]  iClock_div;
  wire   [7:0]  Clock_div;
  reg    [7:0]  Clock_cnt   = 8'h00;
  input  [31:0] Write_data;
  output [31:0] Read_data;
  reg    [31:0] Read_data = 32'h0;
///////////////////////////
  output        CLOCK2_SSPCS_o;
  reg           CLOCK2_SSPCS_o = 1'b1;
  output        CLOCK2_SSPCK_o;
  reg           CLOCK2_SSPCK_o  = 1'b0;
  reg           dCLOCK_SSPCK_o  = 1'b0;
  output        CLOCK2_SSPSI_o;
  input         CLOCK2_SSPSO_i;
//////////////////////////
  reg           Vccpg_record = 1'b0;
  reg    [5:0]  Bit_cnt     = 6'h00;
  reg    [7:0]  M_rec_add   = 8'h00;
  reg    [7:0]  Pulse_width = 8'h00;
  reg           R_W_ind = 1'b1;//1, write
  reg    [1:0]  start_record = 2'h0;
  reg           ini_done = 1'b0;
  reg    [16:0] ini_T7 = 17'h0_0000;
  reg    [3:0]  ini_cnt = 4'h0;
  wire   [31:0] Write_data_buff;       
                             
                             
wire   [31:0] blk_mem_Write_data_buff_temp;
reg   [31:0] blk_mem_Write_data_buff;      
  
reg [3:0] blk_mem_ini_cnt=4'd0;       
reg [31:0] blk_mem_Write_data=32'd0;  

reg write_event_cng=1'b0;
reg write_event_cng_d=1'b0;  
  
//////////////////////////
  reg    [31:0] write_recd = 32'h0000_0000;
  
  reg           en_reset   = 1'b0;//1, enable counting
  reg    [3:0]  start_reset_cnt = 4'h0;
  reg           fake_FPGA_rst = 1'b0;
  always@(posedge FPGA_48MHz or negedge FPGA_rst) begin//control CS
    if(~FPGA_rst) begin
		write_recd      <= 32'h0000_0000;
		en_reset        <= 1'b0;
		start_reset_cnt <= 4'h0;
		fake_FPGA_rst   <= 1'b0;
        clk2_por        <= 1'b1;
        clk2_resetfull  <= 1'b1;
        clk2_resetz     <= 1'b1;
	end
	
	else begin//rPLL_Lock1
	  write_recd    <= Write_data;

	  if(Write_data[3:0]!=4'he) fake_FPGA_rst <= start_record[1] | (!start_record[0]);
	  
    if(start_record==2'b01) begin
	     en_reset        <= 1'b1;
		   start_reset_cnt <= 4'h0;
       clk2_por        <= 1'b1;
       clk2_resetfull  <= 1'b1;
       clk2_resetz     <= 1'b1;
    end  
	  else if(en_reset && PLL_Lock2) begin
	    start_reset_cnt <= start_reset_cnt + 1'b1;
      clk2_por        <= ~clk2_por_en;
      clk2_resetfull  <= ~clk2_resetfull_en;
      clk2_resetz     <= ~clk2_resetz_en;
      
		  if(start_reset_cnt==4'hf) begin
		    en_reset       <= 1'b0;
        clk2_por       <= 1'b1;
        clk2_resetfull <= 1'b1;
        clk2_resetz    <= 1'b1;
      end
      
	  end
	end
  end
/////////////////////////////  
  assign Write_data_buff = ini_done ? blk_mem_Write_data_buff : Write_data;
 
                                  
  assign CLOCK2_SSPSI_o = (!CLOCK2_SSPCS_o && R_W_ind) ? (Bit_cnt==6'h20 ? Write_data_buff[6'h1f] : Write_data_buff[Bit_cnt]) : 1'b0;
  assign busy = (~FPGA_rst || ~CLOCK2_SSPCS_o || ~PLL_Lock2 || M_rec_add[3:0]==4'he) ? 1'b1 : 1'b0;
  assign ready = 0;
  assign Clock_div[7:0] = (iClock_div[7:0]==8'h0)? 8'h1 : iClock_div[7:0];
////////////////delay function////////////////////
  parameter delay2ms   = 17'h17700;
  parameter delay100us = 17'h12c0;
  wire          delay_en;//1 ,enable delay; 0, disable
  wire    [16:0] fake_Clock_div;
  assign delay_en = 1'b1;
  assign fake_Clock_div = delay_en ? (ini_cnt==4'd8 ? delay2ms : (ini_cnt==4'd10 ? delay100us : Clock_div )   ) : Clock_div ;
//////////////////////////////////////////////////
  always@(posedge FPGA_48MHz or negedge FPGA_rst) begin//control CS
    if(~FPGA_rst) begin
        Vccpg_record   <= 1'b0;
        CLOCK2_SSPCS_o <= 1'b1;
        ini_done       <= 1'b0;
        ini_T7         <= 17'h0_0000;
        ini_cnt        <= 4'h0;
        start_record   <= 2'h0;
        R_W_ind        <= 1'b1;
        M_rec_add      <= 8'h00;
        Pulse_width    <= 8'h00;
//        ini_done       <= 1'b0;
    end
    
    else begin//a
      Vccpg_record <=  Vccpg;
      start_record <= {start_record[0],start};
      if((!Vccpg_record && Vccpg) || start_record==2'b01) begin
          CLOCK2_SSPCS_o <= 1'b0;//trigger from power-on
          //ini_done       <= 1'b1;
          ini_T7         <= 17'h0_0000;
          ini_cnt        <= 4'h0;
          if(Write_data[3:0]!=4'he) ini_done <= 1'b1;//modified by james
		  else M_rec_add <= Write_data_buff[7:0];//trigger by read
      end
  
      else if(CLOCK2_SSPCS_o && ini_done) begin
        ini_T7 <= ini_T7 + 1'b1;
        if(ini_T7==17'h0_0000 && ini_cnt==4'd12 && PLL_Lock2) ini_done <= 1'b0;
      
        else if(ini_T7==17'h0_0000 && ini_cnt!=4'd12) ini_cnt <= ini_cnt + 1'b1;
       
        else if(ini_T7==fake_Clock_div) begin
          ini_T7         <= 17'h0_0000;
          M_rec_add      <= Write_data_buff[7:0];
          CLOCK2_SSPCS_o <= 1'b0;//load default 
        end
      end
    
      if(Bit_cnt==6'h20  && Clock_cnt==Clock_div && CLOCK2_SSPCK_o) begin
        CLOCK2_SSPCS_o <= 1'b1;//T6 setup time
        R_W_ind        <= 1'b1;
      end
    
      if(M_rec_add[3:0]==4'he && CLOCK2_SSPCS_o && Pulse_width!= Clock_div) begin
         R_W_ind     <= 1'b0;//Read
         Pulse_width <= Pulse_width + 1'b1;   
      end
    
      else if(Pulse_width==Clock_div && !R_W_ind && CLOCK2_SSPCS_o) begin//trigger by read command
         CLOCK2_SSPCS_o <= 1'b0;
         Pulse_width    <= 8'h00;
         M_rec_add[3:0] <= 4'h0;
      end
    end//a
  end

  always@(posedge FPGA_48MHz or negedge FPGA_rst) begin//control CLOCK1_SSPCK_o
    if(~FPGA_rst) begin
        Clock_cnt     <= 8'h00;
        CLOCK2_SSPCK_o <= 1'b0;
    end

    else begin//original not modify
      Clock_cnt <= Clock_cnt + 1'b1;
      if(Clock_cnt == Clock_div) begin
         CLOCK2_SSPCK_o <= (~CLOCK2_SSPCS_o) & (~CLOCK2_SSPCK_o);
         Clock_cnt     <= 8'h0;
      end

      if(!start_record[1] && start_record[0]) begin
        CLOCK2_SSPCK_o <= 1'b0;
        Clock_cnt     <= Clock_div - 1'b1;//T1 setup time
      end
    end
  end
  
  always@(posedge FPGA_48MHz or negedge FPGA_rst) begin//control CLOCK1_SSPCK_o
    if(~FPGA_rst) begin
		dCLOCK_SSPCK_o <= 1'b0;
    end
    else begin
		dCLOCK_SSPCK_o <= CLOCK2_SSPCK_o;
    end
  end

   always@(posedge FPGA_48MHz or posedge CLOCK2_SSPCS_o) begin
      if(CLOCK2_SSPCS_o) Bit_cnt <= 6'h00;
      else if(~dCLOCK_SSPCK_o && CLOCK2_SSPCK_o) Bit_cnt <= Bit_cnt + 1;
  end

  always@(posedge CLOCK2_SSPCK_o or negedge fake_FPGA_rst) begin//read command
    if(~fake_FPGA_rst) begin
        Read_data <= 32'h0;
        PLL_Lock2  <= 1'b0;
    end

    else if(!R_W_ind) begin
      Read_data[Bit_cnt] <= CLOCK2_SSPSO_i;
      if(M_rec_add[7:4]==4'h8 && Bit_cnt==6'h0c) PLL_Lock2 <= CLOCK2_SSPSO_i;
    end
  end  
  



always@(posedge FPGA_48MHz or negedge FPGA_rst)
if (~FPGA_rst) begin
blk_mem_Write_data<=32'd0;
end
else if (PLL_Lock2 & (write_recd!=Write_data) ) begin
  case (Write_data[3:0])
  4'd0:blk_mem_Write_data<=Write_data;                   //E984_0320
  4'd1:blk_mem_Write_data<=Write_data;                   //6984_0301
  4'd2:blk_mem_Write_data<=Write_data;                   //E902_0302
  4'd3:blk_mem_Write_data<=Write_data;                   //E984_0303
  4'd4:blk_mem_Write_data<=Write_data;                   //6986_0314
  4'd5:blk_mem_Write_data<=Write_data;                   //101C_0BE5
  4'd6:blk_mem_Write_data<=Write_data;                   //04BE_0F06
  4'd7:blk_mem_Write_data<=Write_data;                   //FD00_37F7 
  default:begin end                                      //0000008e
  endcase                                  
end  


always@(posedge FPGA_48MHz or negedge FPGA_rst)
if (~FPGA_rst) 
write_event_cng<=1'b0;
else if (PLL_Lock2 & (write_recd!=Write_data) )
write_event_cng<=~write_event_cng;  


always@(posedge FPGA_48MHz or negedge FPGA_rst)
if (~FPGA_rst) 
write_event_cng_d<=1'b0;
else
write_event_cng_d<=write_event_cng;                                 

assign write_pulse = write_event_cng_d^write_event_cng; 


  
blk_mem_32x11_clk_gen2 clk_gen_ram (
	.clka(FPGA_48MHz),
	.wea(write_pulse), // Bus [0 : 0] 	
	.addra(blk_mem_Write_data[3:0]), // Bus [3 : 0] 
	.dina(blk_mem_Write_data[31:0]), // Bus [31 : 0] 
	.clkb(FPGA_48MHz),
	.addrb(blk_mem_ini_cnt), // Bus [3 : 0] 
	.doutb(blk_mem_Write_data_buff_temp)); // Bus [31 : 0]   
  
  
       
  
always@(posedge FPGA_48MHz or negedge FPGA_rst)
if (~FPGA_rst) begin
blk_mem_ini_cnt<=4'd0;
end
else begin   
  case (ini_cnt[3:0])
    4'd0:blk_mem_ini_cnt<=ini_cnt;                   //E984_0320
    4'd1:blk_mem_ini_cnt<=ini_cnt;                   //6984_0301
    4'd2:blk_mem_ini_cnt<=ini_cnt;                   //E902_0302
    4'd3:blk_mem_ini_cnt<=ini_cnt;                   //E984_0303
    4'd4:blk_mem_ini_cnt<=ini_cnt;                   //6986_0314
    4'd5:blk_mem_ini_cnt<=ini_cnt;                   //101C_0BE5
    4'd6:blk_mem_ini_cnt<=ini_cnt;                   //04BE_0F06
    4'd7:blk_mem_ini_cnt<=ini_cnt;                   //FD00_37F7//and then wait 2msec 
    4'd8:blk_mem_ini_cnt<=4'd6;                      //80be_0f06//write encal bit to 0   
    4'd9:blk_mem_ini_cnt<=4'd6;                      //84be_0f06
                //write encal bit to 1 to generate rising edge and then wait 100usec  
    4'd10:blk_mem_ini_cnt<=4'd10;                    //80008cd8//write sync bit12 to 0       
    4'd11:blk_mem_ini_cnt<=4'd10;                    //80009cd8//write sync bit12 to 1   
    4'd12:blk_mem_ini_cnt<=4'd10;                    //0000008e   
    default:begin end
  endcase                                  
end   

  
  
always@(*)
  case (ini_cnt) 
    4'd8:    blk_mem_Write_data_buff = {1'b1, blk_mem_Write_data_buff_temp[30:27], 1'b0, blk_mem_Write_data_buff_temp[25:0]};
    4'd9:    blk_mem_Write_data_buff = {1'b1, blk_mem_Write_data_buff_temp[30:27], 1'b1, blk_mem_Write_data_buff_temp[25:0]};
    4'd10:   blk_mem_Write_data_buff = {32'h8000_8cd8}; 
    4'd11:   blk_mem_Write_data_buff = {32'h8000_9cd8};     
    default: blk_mem_Write_data_buff = blk_mem_Write_data_buff_temp; 
  endcase                                    

   
  
  
endmodule