//************************************************************************************************/
//**     ####### #     #                                                                        **/
//**     #     # ##    #                                                                        **/
//**     #     # # #   #                                                                        **/
//**     #     # #  #  #                                                                        **/
//**     #     # #   # #                                                                        **/
//**     #     # #    ##                                                                        **/
//**     ####### #     #                                                                        **/
//**                                                                                            **/
//**      #####                                                                                 **/
//**     #     #  ######  #    #     #     ####    ####   #    #                                **/
//**     #        #       ##  ##     #    #    #  #    #  ##   #                                **/
//**      #####   #####   # ## #     #    #       #    #  # #  #                                **/
//**           #  #       #    #     #    #       #    #  #  # #                                **/
//**     #     #  #       #    #     #    #    #  #    #  #   ##                                **/
//**      #####   ######  #    #     #     ####    ####   #    #                                **/
//**                                                                                            **/
//**                                                                                            **/
//**                                       1-1, Sakata, Oizumi, Gunma, 370-0596 JAPAN           **/
//************************************************************************************************/
//**                                                                                            **/
//**   LE2464D  64K bit I2C EEPROM (VDD = 1.7V to 3.6V)                                    	**/
//**                                                                                            **/
//**   File Name        : LE2464D.v                                                         	**/
//**   Top Module       : LE2464D                                                           	**/
//**                                                                                            **/
//**    Feature         :                                                                       **/
//**                            Capacity                        64Kbit(8K x 8bit)               **/
//**                            Serial interface                I2C             		**/
//**                            Clock frequency                 1MHz                            **/
//**                            Automatic page write mode       32  Bytes                       **/
//************************************************************************************************/
//**    Notese:                                                                                 **/
//**    If you set up Initail data for EEPROM, you run Verilog_Simulation under condition.      **/
//**            " verilog xxxxx.v +define+INITIAL_DAT_MODE "                                	**/
//**                    Initial data(EEP ROM data) file is  "Init_data.hex"                     **/
//**                                                                                            **/
//************************************************************************************************/
//**   WLCSP6                                                                                   **/
//**                                                                                            **/
//**        Ball side View                                                                      **/
//**      _____________________                                                                 **/
//**     |                     |                                                                **/
//**     |  SDA   GND   TEST   | B                                                              **/
//**     |                     |                                                                **/
//**     |  SCL    WP    VCC   | A                                                              **/
//**     |_____________________|                                                                **/
//**         1      2     3                                                                     **/
//**                                                                                            **/
//**                                                                                            **/
//**   A1       input       SCL         :serial data clock                                      **/
//**   A2       input       WP          :write protect                                          **/
//**   A3                   VCC         :power supply                                           **/
//**   B1       inout       SDA         :serial data input/output                               **/
//**   B2                   GND         :ground                                                 **/
//**   B3       inout       TEST        :slave device address 2                                 **/
//**                                                                                            **/
//************************************************************************************************/
//**                                                                                            **/
//**   Revision         : 2.00                                                                  **/
//**   Release          : 19/Feb/2016                                                           **/
//**   Modified Date    : 19/Feb/2016                                                           **/
//**   Revision History :                                                                       **/
//**                                                                                            **/
//**   19/Feb/2016(Rev2.00)  :                                                                  **/
//**                            S0,S1,S2 --> (S0=0,S1=0 Fix, P2=Pin)                            **/
//**                                                                                            **/
//**                                                                                            **/
//**                                                                                            **/
//**                                                                                            **/
//**                                                                                            **/
//************************************************************************************************/
//**  LOGIC                                                                                     **/
//************************************************************************************************/
// **   L.01:  START Bit Detection								**/
// **   L.02:  STOP Bit Detection								**/
// **   L.03:  Input Shift Register								**/
// **   L.04:  Input Bit Counter								**/
// **   L.05:  Byte Cycle1 Register								**/
// **   L.06:  Address Setup									**/
// **   L.07:  Write Data Buffer								**/
// **   L.08:  Acknowledge Generator(Output)							**/
// **   L.09:  Acknowledge Detect								**/
// **   L.10:  Write Cycle Timer								**/
// **   L.11:  Write Cycle Processor								**/
// **   L.12:  Read Data									**/
// **   L.13:  Output Data									**/
// **   L.14:  SDA Data I/O Buffer (Open Drain)							**/
//**                                                                                            **/
//************************************************************************************************/
//**   TIMING CHECKS                                                                            **/
//************************************************************************************************/
//**   S.01: SCK width & Frequency              (tHIGH, tLOW)                                  	**/
//**   S.02: Start Condition			(tSU_STA, tHD_STA)                              **/
//**   S.03: Setup & hold time for SDA 		(tSU_DAT, tHD_DAT)                              **/
//**   S.04: Stop Condition			(tSU_STO, tHD_STO)                              **/
//**   S.05: Bus release time			(tBUF)                                          **/
//**   S.06: Noise suppression time		(tSP)                                   	**/
//**                                                                                            **/
//************************************************************************************************/


`timescale 1ns/10ps

module LE2464D (SDA, SCL, WP, TEST);

   inout		SDA;				// serial data I/O
   input		SCL;				// serial data clock


   wire			slave0_enb, slave1_enb, slave2_enb;
//************************************************************************************************/
//**    Parameter for LE2464D (Slave-Pin, WP-Pin Infomation)                                    **/
//************************************************************************************************/

//--------- Case: PAD-Setting  ------------
/*
   input 		S0;				// slave address S0
   input 		S1;				// slave address S1
*/
   input 		TEST;				// slave address S2

   input		WP;				// write protect pin  "1"-->protect


//-------- Case: No PAD(Fix Setting) -------
//for 24xxxD
wire			S0;
wire			S1;
wire			S2;
assign			S0=0;
assign 			S1=0;
//assign 		S2=0;
assign 			S2=TEST;


//--------- Pull Up ------------
//pullup Ipull_up(SDA);


//************************************************************************************************/
//**    Parameter for LE2464D                                                                   **/
//************************************************************************************************/
`define Memory_SIZE     64*1024                       	// 64K-bit (A0-A12)
`define Memory_MSB      12                             	// A0-A12
`define PAGE_SIZE_e     32                              // 32-byte page size (A0-A4)
`define PAGE_MSB_e      4                               // A0-A4

`define Dev_ADD      	4'b1010                         // Device Address(1010)
//assign 		slave0_enb=0;			//2K=S0-S2,4K=S1-S2,8K=S2,16K=No,over_32K=S0-S2 
//assign 		slave1_enb=0;
//assign 		slave2_enb=0;

assign	 		slave0_enb=1;			//2K=S0-S2,4K=S1-S2,8K=S2,16K=No,over_32K=S0-S2 
assign	 		slave1_enb=1;
assign 			slave2_enb=1;


//************************************************************************************************/
//**    Specify for LE2464D   Timming Parameter (Output)	 				**/
//************************************************************************************************/
parameter               tWC=5000000-1;                  // Write Cycle 5ms
parameter               tAA=450-1;                      // Output valid from SCL

//************************************************************************************************/
//**    Specify Cheack for LE2464D   Timming Parameter (Input)                              	**/
//************************************************************************************************/
`define tLOW    	500				// SCL pulse width - low
`define tHIGH   	300				// SCL pulse width - high
`define tSU_STA 	250				// Start Condition setup time
`define tHD_STA 	250				// Start Condition hold time
`define tSU_DAT 	 50				// Data-Input setup time
`define tHD_DAT 	0				// Data-Input hold time
`define tSU_STO 	250				// Stop Condition setup time
`define tBUF    	500				// Bus release time
`define tSP    		 50				// Noise suppression time

`define tSU_STA_act 	100				// Start Condition setup JITURYOKU
`define tHD_STA_act 	120				// Start Condition hold JITURYOKU
`define tSU_STO_act 	120				// Stop Condition setup JITURYOKU
`define tHD_STO_act 	100				// Stop Condition hold JITURYOKU


//************************************************************************************************/
//**                                                                                            **/
//**    I2C Commpn Logic:  32K,128K,256K,512K							**/ 
//**                                                                                            **/
//**                                                                                            **/
//**   Revision         : 2.00                                                                  **/
//**   Revision History :                                                                       **/
//************************************************************************************************/

   reg			SDA_DO;				// serial data - output
   reg			SDA_OE;				// serial data - output enable

   wire			SDA_DriveEnable;		// serial data output enable
   reg			SDA_DriveEnableDlyd;		// serial data output enable - delayed

   reg	[3:0]		BitCounter;			// bit counter (0,1-8,9)

   reg			START_FLAG;			// START Condition
   reg			STOP_FLAG;			// STOP bit received flag
   reg			BCYCLE_1;			// Bus Cycle 1 (1010+S2+S1+S0+RW)
   reg			BCYCLE_2;			// Bus Cycle 2 (A15+A14+A13+A12+A11+A10+A9+A8)
   reg			BCYCLE_3;			// Bus Cycle 3 (A7+A6+A5+A4+A3+A2+A1+A0)
   reg			ACK_Rcv;			// acknowledge received from CPU

   reg			Write_Com;			// Write command
   reg			Read;				// Read cycle
   reg			WRT;				// Write cycle

   reg	[7:0]		Store_Reg;			// input data store register
   reg  [7:0]		BCYCLE1_Reg;			// Bus Cycle 1 register
   reg  [7:0]		BCYCLE2_Reg;			// Bus Cycle 2 register
   reg  [7:0]		BCYCLE3_Reg;			// Bus Cycle 3 register
   wire			RW_bit;				// read/write bit

   wire			Slave_dec;			// Slave Address  Decorder
   wire			Slave0_dec;			// Slave Address0 Decorder
   wire			Slave1_dec;			// Slave Address1 Decorder
   wire			Slave2_dec;			// Slave Address2 Decorder

   reg	[`PAGE_MSB_e:0]	Page_Add;			// page address
   reg	[`PAGE_MSB_e:0]	Next_Page_Add;			// page address + 1
   reg	[`PAGE_MSB_e:0]	WrPointer;			// write buffer pointer

   reg	[7:0]		WriteBuffer [0:`PAGE_SIZE_e-1];	// page write buffer
   wire	[7:0]		OUT_Reg;			// Output Register(Output for SDA)


   reg	[`Memory_MSB:0]	Start_Add;			// start address(Address SetUP)
   reg	[`Memory_MSB:0]	Read_Add;			// read address pointer


   reg  [7:0]           Memory_data [0:`Memory_SIZE/8-1]; // EEPROM data memory array

   integer		Write_Count;			// write data input counter
   integer		LoopIndex;			// iterative loop index


   reg			ACK_Out_Flag;			// ACK Output timming
   reg			BitC_WRT_OK;			// WRT for Bitcount

   wire			SDA_DL,SCL_DL;
   assign #`tSU_STA_act		SDA_DL=SDA;
   assign #`tSU_STA_act		SCL_DL=SCL;
//************************************************************************************************/
//**    INITIALIZATION                                                                          **/
//************************************************************************************************/
   initial begin
      SDA_DO = 0;
      SDA_OE = 0;
   end

   initial begin
      START_FLAG = 0;
      STOP_FLAG  = 0;
      BCYCLE_1  = 0;
      BCYCLE_2  = 0;
      BCYCLE_3  = 0;
      ACK_Rcv  = 0;
      ACK_Out_Flag = 0;
      BitC_WRT_OK = 0;
   end

   initial begin
      BitCounter  = 0;
      BCYCLE1_Reg = 0;
      BCYCLE2_Reg = 0;
      BCYCLE3_Reg = 0;
   end

   initial begin
      Write_Com = 0;
      Read = 0;

      WRT = 0;
   end

  initial begin
        `ifdef INITIAL_DAT_MODE
                $readmemh( "Init_data_eep.hex", Memory_data);
        `endif
   end
//************************************************************************************************/
//**    LOGIC                                                                                   **/
//************************************************************************************************/
//------------------------------------------------------------------------------------------------
//      L.01:  START Condition
//------------------------------------------------------------------------------------------------

   always @(negedge SDA) begin
// always @(negedge SDA_DL) begin
//    if (SCL == 1) begin
      if ((SCL_DL == 1)&&(SCL == 1)) begin
	#`tHD_STA_act;
		if(SCL == 1)	begin
         		START_FLAG <= 1;
         		STOP_FLAG  <= 0;
         		BCYCLE_1  <= 0;
         		BCYCLE_2  <= 0;
         		BCYCLE_3  <= 0;
         		ACK_Rcv  <= 0;

         		Write_Com <= #1 0;
         		Read <= #1 0;

         		BitCounter <= 0;
		end
      end
   end

//------------------------------------------------------------------------------------------------
//      L.02:  STOP Condition
//------------------------------------------------------------------------------------------------

   always @(posedge SDA) begin
// always @(posedge SDA_DL) begin
//    if (SCL == 1) begin
      if ((SCL_DL == 1)&&(SCL == 1)) begin
	#`tHD_STO_act;
		if(SCL == 1)	begin
         		START_FLAG <= 0;
         		STOP_FLAG  <= 1;
         		BCYCLE_1  <= 0;
         		BCYCLE_2  <= 0;
         		BCYCLE_3  <= 0;
         		ACK_Rcv  <= 0;

         		Write_Com <= #1 0;
         		Read <= #1 0;

			if(BitCounter == 1)  BitC_WRT_OK=1;
			else		     BitC_WRT_OK=0;
         		BitCounter <= 10;
		end
      end
   end

//------------------------------------------------------------------------------------------------
//      L.03:  Input Shift Register
//------------------------------------------------------------------------------------------------

   always @(posedge SCL) begin
      Store_Reg[0] <= SDA;
      Store_Reg[1] <= Store_Reg[0];
      Store_Reg[2] <= Store_Reg[1];
      Store_Reg[3] <= Store_Reg[2];
      Store_Reg[4] <= Store_Reg[3];
      Store_Reg[5] <= Store_Reg[4];
      Store_Reg[6] <= Store_Reg[5];
      Store_Reg[7] <= Store_Reg[6];
   end

//------------------------------------------------------------------------------------------------
//      L.04:  Input Bit Counter
//------------------------------------------------------------------------------------------------

   always @(posedge SCL) begin
      if (BitCounter < 10) BitCounter <= BitCounter + 1;
   end

//------------------------------------------------------------------------------------------------
//      L.05:  Byte Cycle1 Register
//------------------------------------------------------------------------------------------------

   assign  Slave2_dec   = (~slave2_enb) | (Store_Reg[3] == S2);
   assign  Slave1_dec   = (~slave1_enb) | (Store_Reg[2] == S1);
   assign  Slave0_dec   = (~slave0_enb) | (Store_Reg[1] == S0);
   assign  Slave_dec    = Slave2_dec & Slave1_dec & Slave0_dec;


   always @(negedge SCL) begin
      if (START_FLAG & (BitCounter == 8)) begin
         if (!WRT & (Store_Reg[7:4] == `Dev_ADD) & Slave_dec) begin
            if (Store_Reg[0] == 0) Write_Com <= 1;
            if (Store_Reg[0] == 1) Read <= 1;

            BCYCLE1_Reg <= Store_Reg;

            BCYCLE_1 <= 1;
         end

         START_FLAG <= 0;
      end
   end

   assign RW_bit     = BCYCLE1_Reg[0];

//------------------------------------------------------------------------------------------------
//      L.06:  Address Setup
//------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (BCYCLE_1 & (BitCounter == 8)) begin
         if (RW_bit == 0) begin
            BCYCLE2_Reg <= Store_Reg;

            BCYCLE_2 <= 1;
         end

         BCYCLE_1 <= 0;
      end
   end


   always @(negedge SCL) begin
      if (BCYCLE_2 & (BitCounter == 8)) begin
         if (RW_bit == 0) begin
            BCYCLE3_Reg <= Store_Reg;
            Start_Add <= {BCYCLE2_Reg[`Memory_MSB-8:0],Store_Reg[7:0]};
            Read_Add <= {BCYCLE2_Reg[`Memory_MSB-8:0],Store_Reg[7:0]};

            BCYCLE_3 <= 1;
         end

         Write_Count <= 0;
         WrPointer <= 0;

         BCYCLE_2 <= 0;
      end
   end


//------------------------------------------------------------------------------------------------
//      L.07:  Write Data Buffer
//------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (BCYCLE_3 & (BitCounter == 8)) begin
//       if ((WP == 0) & (RW_bit == 0)) begin
         if (RW_bit == 0) begin
            WriteBuffer[WrPointer] <= Store_Reg[7:0];

            Write_Count <= Write_Count + 1;
            WrPointer <= WrPointer + 1;
         end
      end
   end

//------------------------------------------------------------------------------------------------
//      L.08:  Acknowledge Generator(Output)
//------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (!WRT) begin
         if (BitCounter == 8) begin
            if (Write_Com | (START_FLAG & (Store_Reg[7:4] == `Dev_ADD) & Slave_dec)) begin
	       ACK_Out_Flag <= 1;			//ACK Output (for moniter)
               SDA_DO <= 0;
               SDA_OE <= 1;
            end 
         end
         if (BitCounter == 9) begin
            BitCounter <= 0;

            if (!Read) begin
	       ACK_Out_Flag <= 0;			//ACK Output (for moniter)
               SDA_DO <= 0;
               SDA_OE <= 0;
            end
         end
      end

      if(Read)	ACK_Out_Flag <=0;		//ACK Output (for moniter)
   end 

//------------------------------------------------------------------------------------------------
//      L.09:  Acknowledge Detect
//------------------------------------------------------------------------------------------------

   always @(posedge SCL) begin
      if (Read & (BitCounter == 8)) begin
         if ((SDA == 0) & (SDA_OE == 0)) ACK_Rcv <= 1;		//ACK
	 else if ((SDA == 1) & (SDA_OE == 0)) begin		//No ACK
		ACK_Rcv <=0;
		Read <=0;
	end
      end
   end

   always @(negedge SCL) ACK_Rcv <= 0;

//------------------------------------------------------------------------------------------------
//      L.10:  Write Cycle Timer
//------------------------------------------------------------------------------------------------

   always @(posedge STOP_FLAG) begin
//    if (Write_Com & (WP == 0) & (Write_Count > 0)) begin
      if (Write_Com & (WP == 0) & (Write_Count > 0) & (BitC_WRT_OK == 1)) begin
         WRT = 1;
         #(tWC);
         WRT = 0;
      end
      else if(!WRT) begin
	 Write_Count <=0;
      end
   end

   always @(posedge STOP_FLAG) begin
      #(1.0);
      STOP_FLAG = 0;
      BitC_WRT_OK = 0;
   end

//------------------------------------------------------------------------------------------------
//      L.11:  Write Cycle Processor
//------------------------------------------------------------------------------------------------

   always @(negedge WRT) begin
      for (LoopIndex = 0; LoopIndex < Write_Count; LoopIndex = LoopIndex + 1) begin
#1;
         Page_Add = Start_Add[`PAGE_MSB_e:0] + LoopIndex;
//       Memory_data[{Start_Add[`Memory_MSB:`PAGE_MSB_1P],Page_Add[`PAGE_MSB_e:0]}] = WriteBuffer[LoopIndex[`PAGE_MSB_e:0]];
         Memory_data[{Start_Add[`Memory_MSB:(`PAGE_MSB_e + 1)],Page_Add[`PAGE_MSB_e:0]}] = WriteBuffer[LoopIndex[`PAGE_MSB_e:0]];
      end

      Next_Page_Add[`PAGE_MSB_e:0] = Page_Add[`PAGE_MSB_e:0] + 1;
//    Read_Add <= {Start_Add[`Memory_MSB:`PAGE_MSB_1P],Next_Page_Add[`PAGE_MSB_e:0]};
      Read_Add <= {Start_Add[`Memory_MSB:(`PAGE_MSB_e + 1)],Next_Page_Add[`PAGE_MSB_e:0]};

      $writememh ("eep_data_model.hex",  Memory_data);
   end

//------------------------------------------------------------------------------------------------
//      L.12:  Read Data
//------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (BitCounter == 8) begin
         if (Read) begin
            Read_Add <= Read_Add + 1;
         end
         if (Write_Com & BCYCLE_3) begin
            Page_Add  = Start_Add[`PAGE_MSB_e:0] + Write_Count[`PAGE_MSB_e:0];
            Next_Page_Add[`PAGE_MSB_e:0] = Page_Add[`PAGE_MSB_e:0] + 1;
//          Read_Add <= {Start_Add[`Memory_MSB:`PAGE_MSB_1P],Next_Page_Add[`PAGE_MSB_e:0]};
            Read_Add <= {Start_Add[`Memory_MSB:(`PAGE_MSB_e + 1)],Next_Page_Add[`PAGE_MSB_e:0]};
         end
      end
   end

   assign OUT_Reg = Memory_data[Read_Add];

//------------------------------------------------------------------------------------------------
//      L.13:  Output Data
//------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (Read) begin
         if (BitCounter == 8) begin
            SDA_DO <= 0;
            SDA_OE <= 0;
         end
         else if (BitCounter == 9) begin
            SDA_DO <= OUT_Reg[7];

            if (ACK_Rcv) SDA_OE <= 1;		//ACK Recive
         end
         else begin
            SDA_DO <= OUT_Reg[7-BitCounter];
         end
      end
   end

//------------------------------------------------------------------------------------------------
//      L.14:  SDA Data I/O Buffer(Open Drain)
//------------------------------------------------------------------------------------------------

   bufif1 (SDA, 1'b0, SDA_DriveEnableDlyd);

   assign SDA_DriveEnable = !SDA_DO & SDA_OE;
   always @(SDA_DriveEnable) SDA_DriveEnableDlyd <= #(tAA) SDA_DriveEnable;


//************************************************************************************************/
//**                                                                                            **/
//**    TIMING CHECKS   :                                                                       **/
//**                                                                                            **/
//**                                                                                            **/
//**   TMC Revision     : 2.00                                                                  **/
//**   Revision History :                                                                       **/
//************************************************************************************************/

`ifdef NO_EEPSPECIFY
`else
   specify

//------------------------------------------------------------------------------------------------
//      S.01:  SCK width & Frequency
//------------------------------------------------------------------------------------------------
      $width (negedge SCL, `tLOW);
      $width (posedge SCL, `tHIGH);

//------------------------------------------------------------------------------------------------
//      S.02:  Start Condition
//------------------------------------------------------------------------------------------------
      $setup (posedge SCL, negedge SDA, `tSU_STA);
      $hold  (negedge SDA, negedge SCL, `tHD_STA);

//------------------------------------------------------------------------------------------------
//      S.03:  Setup & hold time for SDA (Data Input)
//------------------------------------------------------------------------------------------------
      $setup (SDA, posedge SCL &&& ~SDA_OE, `tSU_DAT);
      $hold  (negedge SCL &&& ~SDA_OE, SDA, `tHD_DAT);

      $setup (WP, posedge SCL, `tSU_DAT);
      $hold  (negedge SCL, WP, `tHD_DAT);

//------------------------------------------------------------------------------------------------
//      S.04:  Stop Condition
//------------------------------------------------------------------------------------------------
      $setup (posedge SCL, posedge SDA, `tSU_STO);

//------------------------------------------------------------------------------------------------
//      S.05:  Bus release time
//------------------------------------------------------------------------------------------------
      $width (posedge SDA &&& SCL, `tBUF);

//------------------------------------------------------------------------------------------------
//      S.06:  Noise suppression time
//------------------------------------------------------------------------------------------------
      $width (posedge SDA &&& ~SDA_OE, `tSP);
      $width (posedge SCL, `tSP);
      $width (posedge WP, `tSP);
      $width (negedge SDA &&& ~SDA_OE, `tSP);
      $width (negedge SCL, `tSP);
      $width (negedge WP, `tSP);


   endspecify
`endif

//************************************************************************************************/

endmodule
