-----------------------------------------------------------------------
-----------------------------------------------------------------------
-- PicoBlaze compatible I2C (TWI) controler
--
-- Data register is shared by Rx (read) and Tx (write).
-- Status register contains basic SPI status information.
-- SDIO speed depends on clock present on clk input and clk_div value
--
----------------------------------------------------------------------------------
-- Status register:
-- [0] - unused - (Page select in older versions)
-- [1] - Unused -
-- [2] - Unused -
-- [3] - Unused -
-- [4] - Unused -
-- [5] - Unused -
-- [6] Write request / busy flag        -- write 1 to initiate write; cleared automaticly when write is completed
-- [7] Read  request / busy flag        -- write 1 to initiate read;  cleared automaticly when read  is completed
----------------------------------------------------------------------
----------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
----------------------------------------------------------------------------------
ENTITY Two_Wire_Controler IS
    GENERIC(data_port_ID:   STD_LOGIC_VECTOR(7 DOWNTO 0):= "00000001";  -- data register port ID
            addr_port_ID:   STD_LOGIC_VECTOR(7 DOWNTO 0):= "00000010";  -- address register upper byte port ID
            stat_port_ID:   STD_LOGIC_VECTOR(7 DOWNTO 0):= "00000100";  -- status/control register port ID
            dadr_port_ID:   STD_LOGIC_VECTOR(7 DOWNTO 0):= "00000100";  -- device address register port ID
            clk_div:      INTEGER:= 2000);                              -- divider of system clock for SCLK (max 100 kHz for SFP)
                                                                        -- f(clk) = 100 MHz AND clk_div = 1000 => f(SCLK) = 50 kHz
    PORT(
            clk:            IN  STD_LOGIC;                              -- system clock

            -- PicoBlaze interface
            Data_in:        IN  STD_LOGIC_VECTOR(7 DOWNTO 0);           -- Data IN (PicoBlaze OUT)
            Data_out:       OUT STD_LOGIC_VECTOR(7 DOWNTO 0):= X"00";   -- Data reg OUT (to PicoBlaze input MUX)
            Address:        IN  STD_LOGIC_VECTOR(7 DOWNTO 0);           -- PicoBlaze Port ID
            write_strobe:   IN  STD_LOGIC;                              -- PicoBlaze write strobe

            -- MDIO physical interface
            SCL:            OUT STD_LOGIC;
            SDA:            INOUT STD_LOGIC := '1');
END Two_Wire_Controler;
----------------------------------------------------------------------------------
ARCHITECTURE Behavioral OF Two_Wire_Controler IS
----------------------------------------------------------------------------------
  SIGNAL data_reg:      STD_LOGIC_VECTOR(7 DOWNTO 0):= (OTHERS => '0');     -- data register
  SIGNAL data_reg_out:  STD_LOGIC_VECTOR(7 DOWNTO 0):= (OTHERS => '0');     -- data register for reading
  SIGNAL addr_reg:      STD_LOGIC_VECTOR(7 DOWNTO 0):= (OTHERS => '0');     -- address register
  SIGNAL stat_reg:      STD_LOGIC_VECTOR(7 DOWNTO 0):= (OTHERS => '0');     -- status register 
  SIGNAL DEV_addr_reg:  STD_LOGIC_VECTOR(4 DOWNTO 0):= (OTHERS => '0');     -- Accessed device address


--SIGNAL spi_state:     INTEGER RANGE 0 TO 117 := 0;
  SIGNAL spi_state:     STD_LOGIC_VECTOR(7 DOWNTO 0):= (OTHERS => '0');
  SIGNAL SPI_done:      STD_LOGIC := '0';               -- high in the last cycle of the SPI state machine
  SIGNAL SPI_wr_start:  STD_LOGIC := '0';               -- initiates SPI write cycle
  SIGNAL SPI_rd_start:  STD_LOGIC := '0';               -- initiates SPI read cycle
  SIGNAL SCL_i:         STD_LOGIC := '0';               -- internal SPI clock signal

  SIGNAL SPI_wr_start_latch:    STD_LOGIC := '0';       -- latched SPI_wr_start (because of clk_enable)
  SIGNAL SPI_rd_start_latch:    STD_LOGIC := '0';       -- latched SPI_rd_start (because of clk_enable)

  SIGNAL cnt_clk_EN:    INTEGER RANGE 1 TO clk_div := 1;                    -- SPI clock divider
  SIGNAL clk_enable:    STD_LOGIC := '0';                                   -- SPI clock divider

  SIGNAL spi_state_i:   INTEGER;                        -- state signal converted from STD_LOGIC_VECTOR to INTEGER

----------------------------------------------------------------------------------
BEGIN
----------------------------------------------------------------------------------

  SCL <= SCL_i;
  stat_reg(5 DOWNTO 1) <= "00000";

  spi_state_i <= CONV_INTEGER(spi_state);

----------------------------------------------------------------------------------
-- PicoBlaze interface
----------------------------------------------------------------------------------

  -- Processor write to controller internal registers
  PROCESS(clk) BEGIN
    IF RISING_EDGE(clk) THEN
      IF write_strobe = '1' THEN
        CASE Address IS
          WHEN data_port_ID => data_reg     <= Data_in;
          WHEN stat_port_ID => stat_reg(0)  <= Data_in(0);
          WHEN addr_port_ID => addr_reg     <= Data_in;
          WHEN dadr_port_ID => DEV_addr_reg <= Data_in(4 DOWNTO 0);
          WHEN OTHERS         => NULL;
        END CASE;
      END IF;
    END IF;
  END PROCESS;
  --------------------------------------------------------------------------------
  -- Write or Read cycle start
  PROCESS(clk) BEGIN
    IF RISING_EDGE(clk) THEN

      -- clear busy flags when transmission is completed
      IF SPI_done = '1' THEN
        stat_reg(7 DOWNTO 6) <= "00";
        SPI_rd_start <= '0';
        SPI_wr_start <= '0';

      -- if processor writes to the controll register
      ELSIF write_strobe = '1' AND Address = stat_port_ID THEN

        -- if SPI is idle
        IF stat_reg(7 DOWNTO 6) = "00" THEN

          -- write command
          IF Data_in(6) = '1' THEN
            stat_reg(6) <= '1';
            SPI_wr_start <= '1';
            SPI_rd_start <= '0';

          -- read command
          ELSIF Data_in(7) = '1' THEN
            stat_reg(7) <= '1';
            SPI_rd_start <= '1';
            SPI_wr_start <= '0';

          END IF;
        ELSE
          SPI_rd_start <= '0';            
          SPI_wr_start <= '0';
        END IF;
      ELSE
        SPI_rd_start <= '0';            
        SPI_wr_start <= '0';
      END IF;
    END IF;
  END PROCESS;

  --------------------------------------------------------------------------------
  -- Processor read of controller internal registers

  PROCESS(Address, data_reg_out, stat_reg, addr_reg, DEV_addr_reg) BEGIN
    CASE Address IS
      WHEN data_port_ID => data_out <= data_reg_out;
      WHEN addr_port_ID => data_out <= addr_reg;
      WHEN stat_port_ID => data_out <= stat_reg;
      WHEN dadr_port_ID => data_out <= "000" & DEV_addr_reg;
      WHEN OTHERS       => data_out <= X"00";
    END CASE;
  END PROCESS;

----------------------------------------------------------------------------------
-- clock divider ( f(SCLK) =< 100 kHz )
----------------------------------------------------------------------------------
  PROCESS(clk) BEGIN
    IF RISING_EDGE(clk) THEN
      IF cnt_clk_EN = clk_div THEN
        cnt_clk_EN <= 1;
        clk_enable <= '1';
      ELSE
        cnt_clk_EN <= cnt_clk_EN + 1;
        clk_enable <= '0';
      END IF;
    END IF;
  END PROCESS;

----------------------------------------------------------------------------------
-- SPI controller core
----------------------------------------------------------------------------------

  PROCESS(clk) BEGIN
    IF RISING_EDGE(clk) THEN

      IF SPI_wr_start = '1' THEN SPI_wr_start_latch <= '1'; END IF;
      IF SPI_rd_start = '1' THEN SPI_rd_start_latch <= '1'; END IF;

      IF clk_enable = '1' THEN


        --------------------------------------------------------------------------
        -- State machine control
        CASE spi_state_i IS
          WHEN      0 => IF SPI_wr_start_latch = '1' OR SPI_rd_start_latch = '1' THEN
                           spi_state <= spi_state + 1;
                         END IF;
                         SPI_done <= '0';
          WHEN    117 => spi_state <= (OTHERS => '0');
                         SPI_done <= '1';
          WHEN OTHERS => spi_state <= spi_state + 1;
                         SPI_done <= '0';
        END CASE;

      --------------------------------------------------------------------------
        IF stat_reg(6) = '1' THEN -- data write
    
          CASE spi_state_i IS

            WHEN  0 => SCL_i <= '1'; SDA <= '1';          -- Idle

            WHEN  1 => SCL_i <= '1'; SDA <= '0';          -- Start Condition
                       SPI_wr_start_latch <= '0';
                       SPI_rd_start_latch <= '0';
            WHEN  2 => SCL_i <= '0'; SDA <= '0';

            WHEN  3 => SCL_i <= '0'; SDA <= '1';          -- 101000
            WHEN  4 => SCL_i <= '1'; SDA <= '1';
            WHEN  5 => SCL_i <= '0'; SDA <= '1';
            WHEN  6 => SCL_i <= '0'; SDA <= '0';          --
            WHEN  7 => SCL_i <= '1'; SDA <= '0';
            WHEN  8 => SCL_i <= '0'; SDA <= '0';
            WHEN  9 => SCL_i <= '0'; SDA <= DEV_addr_reg(4);  -- device address
            WHEN 10 => SCL_i <= '1'; SDA <= DEV_addr_reg(4);
            WHEN 11 => SCL_i <= '0'; SDA <= DEV_addr_reg(4);
            WHEN 12 => SCL_i <= '0'; SDA <= DEV_addr_reg(3);  --
            WHEN 13 => SCL_i <= '1'; SDA <= DEV_addr_reg(3);
            WHEN 14 => SCL_i <= '0'; SDA <= DEV_addr_reg(3);
            WHEN 15 => SCL_i <= '0'; SDA <= DEV_addr_reg(2);  --
            WHEN 16 => SCL_i <= '1'; SDA <= DEV_addr_reg(2);
            WHEN 17 => SCL_i <= '0'; SDA <= DEV_addr_reg(2);
            WHEN 18 => SCL_i <= '0'; SDA <= DEV_addr_reg(1);  --
            WHEN 19 => SCL_i <= '1'; SDA <= DEV_addr_reg(1);
            WHEN 20 => SCL_i <= '0'; SDA <= DEV_addr_reg(1);
            WHEN 21 => SCL_i <= '0'; SDA <= DEV_addr_reg(0);  --      XXXXXXX komentar neplati XXXXXXXXX upper/lower address space
            WHEN 22 => SCL_i <= '1'; SDA <= DEV_addr_reg(0);
            WHEN 23 => SCL_i <= '0'; SDA <= DEV_addr_reg(0);

            WHEN 24 => SCL_i <= '0'; SDA <= '0';          -- read (1) / write (0)
            WHEN 25 => SCL_i <= '1'; SDA <= '0';
            WHEN 26 => SCL_i <= '0'; SDA <= '0';

            WHEN 27 => SCL_i <= '0'; SDA <= 'Z';          -- ACK
            WHEN 28 => SCL_i <= '1'; SDA <= 'Z';
            WHEN 29 => SCL_i <= '0'; SDA <= 'Z';

            WHEN 30 => SCL_i <= '0'; SDA <= addr_reg(7);  -- register address
            WHEN 31 => SCL_i <= '1'; SDA <= addr_reg(7);
            WHEN 32 => SCL_i <= '0'; SDA <= addr_reg(7);
            WHEN 33 => SCL_i <= '0'; SDA <= addr_reg(6);  --
            WHEN 34 => SCL_i <= '1'; SDA <= addr_reg(6);
            WHEN 35 => SCL_i <= '0'; SDA <= addr_reg(6);
            WHEN 36 => SCL_i <= '0'; SDA <= addr_reg(5);  --
            WHEN 37 => SCL_i <= '1'; SDA <= addr_reg(5);
            WHEN 38 => SCL_i <= '0'; SDA <= addr_reg(5);
            WHEN 39 => SCL_i <= '0'; SDA <= addr_reg(4);  --
            WHEN 40 => SCL_i <= '1'; SDA <= addr_reg(4);
            WHEN 41 => SCL_i <= '0'; SDA <= addr_reg(4);
            WHEN 42 => SCL_i <= '0'; SDA <= addr_reg(3);  --
            WHEN 43 => SCL_i <= '1'; SDA <= addr_reg(3);
            WHEN 44 => SCL_i <= '0'; SDA <= addr_reg(3);
            WHEN 45 => SCL_i <= '0'; SDA <= addr_reg(2);  --
            WHEN 46 => SCL_i <= '1'; SDA <= addr_reg(2);
            WHEN 47 => SCL_i <= '0'; SDA <= addr_reg(2);
            WHEN 48 => SCL_i <= '0'; SDA <= addr_reg(1);  --
            WHEN 49 => SCL_i <= '1'; SDA <= addr_reg(1);
            WHEN 50 => SCL_i <= '0'; SDA <= addr_reg(1);
            WHEN 51 => SCL_i <= '0'; SDA <= addr_reg(0);  --
            WHEN 52 => SCL_i <= '1'; SDA <= addr_reg(0);
            WHEN 53 => SCL_i <= '0'; SDA <= addr_reg(0);
                                                
            WHEN 54 => SCL_i <= '0'; SDA <= 'Z';          -- ACK
            WHEN 55 => SCL_i <= '1'; SDA <= 'Z';
            WHEN 56 => SCL_i <= '0'; SDA <= 'Z';

            WHEN 57 => SCL_i <= '0'; SDA <= data_reg(7);  -- data
            WHEN 58 => SCL_i <= '1'; SDA <= data_reg(7);
            WHEN 59 => SCL_i <= '0'; SDA <= data_reg(7);
            WHEN 60 => SCL_i <= '0'; SDA <= data_reg(6);  --
            WHEN 61 => SCL_i <= '1'; SDA <= data_reg(6);
            WHEN 62 => SCL_i <= '0'; SDA <= data_reg(6);
            WHEN 63 => SCL_i <= '0'; SDA <= data_reg(5);  --
            WHEN 64 => SCL_i <= '1'; SDA <= data_reg(5);
            WHEN 65 => SCL_i <= '0'; SDA <= data_reg(5);
            WHEN 66 => SCL_i <= '0'; SDA <= data_reg(4);  --
            WHEN 67 => SCL_i <= '1'; SDA <= data_reg(4);
            WHEN 68 => SCL_i <= '0'; SDA <= data_reg(4);
            WHEN 69 => SCL_i <= '0'; SDA <= data_reg(3);  --
            WHEN 70 => SCL_i <= '1'; SDA <= data_reg(3);
            WHEN 71 => SCL_i <= '0'; SDA <= data_reg(3);
            WHEN 72 => SCL_i <= '0'; SDA <= data_reg(2);  --
            WHEN 73 => SCL_i <= '1'; SDA <= data_reg(2);
            WHEN 74 => SCL_i <= '0'; SDA <= data_reg(2);
            WHEN 75 => SCL_i <= '0'; SDA <= data_reg(1);  --
            WHEN 76 => SCL_i <= '1'; SDA <= data_reg(1);
            WHEN 77 => SCL_i <= '0'; SDA <= data_reg(1);
            WHEN 78 => SCL_i <= '0'; SDA <= data_reg(0);  --
            WHEN 79 => SCL_i <= '1'; SDA <= data_reg(0);
            WHEN 80 => SCL_i <= '0'; SDA <= data_reg(0);
--          WHEN 80 => SCL_i <= '0'; SDA <= 'Z';
                                                      
            WHEN 81 => SCL_i <= '0'; SDA <= 'Z';          -- ACK
            WHEN 82 => SCL_i <= '1'; SDA <= 'Z';
            WHEN 83 => SCL_i <= '0'; SDA <= 'Z';

            WHEN 84 => SCL_i <= '0'; SDA <= '0';          -- Stop Condition
            WHEN 85 => SCL_i <= '1'; SDA <= '0';
            WHEN 86 => SCL_i <= '1'; SDA <= '1';

            WHEN OTHERS => SCL_i <= '1'; SDA <= '1';      -- Idle
          END CASE;




        ELSE        -- read cycle

          CASE spi_state_i IS

            WHEN  0 => SCL_i <= '1'; SDA <= '1';          -- Idle

            WHEN  1 => SCL_i <= '1'; SDA <= '0';          -- Start Condition
                       SPI_wr_start_latch <= '0';
                       SPI_rd_start_latch <= '0';
            WHEN  2 => SCL_i <= '0'; SDA <= '0';

            WHEN  3 => SCL_i <= '0'; SDA <= '1';           -- 10AAAAA
            WHEN  4 => SCL_i <= '1'; SDA <= '1';
            WHEN  5 => SCL_i <= '0'; SDA <= '1';
            WHEN  6 => SCL_i <= '0'; SDA <= '0';           --
            WHEN  7 => SCL_i <= '1'; SDA <= '0';
            WHEN  8 => SCL_i <= '0'; SDA <= '0';
            WHEN  9 => SCL_i <= '0'; SDA <= DEV_addr_reg(4);      -- device address
            WHEN 10 => SCL_i <= '1'; SDA <= DEV_addr_reg(4);
            WHEN 11 => SCL_i <= '0'; SDA <= DEV_addr_reg(4);
            WHEN 12 => SCL_i <= '0'; SDA <= DEV_addr_reg(3);      --
            WHEN 13 => SCL_i <= '1'; SDA <= DEV_addr_reg(3);
            WHEN 14 => SCL_i <= '0'; SDA <= DEV_addr_reg(3);
            WHEN 15 => SCL_i <= '0'; SDA <= DEV_addr_reg(2);      --
            WHEN 16 => SCL_i <= '1'; SDA <= DEV_addr_reg(2);
            WHEN 17 => SCL_i <= '0'; SDA <= DEV_addr_reg(2);
            WHEN 18 => SCL_i <= '0'; SDA <= DEV_addr_reg(1);      --
            WHEN 19 => SCL_i <= '1'; SDA <= DEV_addr_reg(1);
            WHEN 20 => SCL_i <= '0'; SDA <= DEV_addr_reg(1);
            WHEN 21 => SCL_i <= '0'; SDA <= DEV_addr_reg(0);      -- upper/lower address space
            WHEN 22 => SCL_i <= '1'; SDA <= DEV_addr_reg(0);
            WHEN 23 => SCL_i <= '0'; SDA <= DEV_addr_reg(0);

            WHEN 24 => SCL_i <= '0'; SDA <= '0';          -- read (1) / write (0)
            WHEN 25 => SCL_i <= '1'; SDA <= '0';
            WHEN 26 => SCL_i <= '0'; SDA <= '0';

            WHEN 27 => SCL_i <= '0'; SDA <= 'Z';          -- ACK
            WHEN 28 => SCL_i <= '1'; SDA <= 'Z';
            WHEN 29 => SCL_i <= '0'; SDA <= 'Z';

            WHEN 30 => SCL_i <= '0'; SDA <= addr_reg(7);  -- register address
            WHEN 31 => SCL_i <= '1'; SDA <= addr_reg(7);
            WHEN 32 => SCL_i <= '0'; SDA <= addr_reg(7);
            WHEN 33 => SCL_i <= '0'; SDA <= addr_reg(6);  --
            WHEN 34 => SCL_i <= '1'; SDA <= addr_reg(6);
            WHEN 35 => SCL_i <= '0'; SDA <= addr_reg(6);
            WHEN 36 => SCL_i <= '0'; SDA <= addr_reg(5);  --
            WHEN 37 => SCL_i <= '1'; SDA <= addr_reg(5);
            WHEN 38 => SCL_i <= '0'; SDA <= addr_reg(5);
            WHEN 39 => SCL_i <= '0'; SDA <= addr_reg(4);  --
            WHEN 40 => SCL_i <= '1'; SDA <= addr_reg(4);
            WHEN 41 => SCL_i <= '0'; SDA <= addr_reg(4);
            WHEN 42 => SCL_i <= '0'; SDA <= addr_reg(3);  --
            WHEN 43 => SCL_i <= '1'; SDA <= addr_reg(3);
            WHEN 44 => SCL_i <= '0'; SDA <= addr_reg(3);
            WHEN 45 => SCL_i <= '0'; SDA <= addr_reg(2);  --
            WHEN 46 => SCL_i <= '1'; SDA <= addr_reg(2);
            WHEN 47 => SCL_i <= '0'; SDA <= addr_reg(2);
            WHEN 48 => SCL_i <= '0'; SDA <= addr_reg(1);  --
            WHEN 49 => SCL_i <= '1'; SDA <= addr_reg(1);
            WHEN 50 => SCL_i <= '0'; SDA <= addr_reg(1);
            WHEN 51 => SCL_i <= '0'; SDA <= addr_reg(0);  --
            WHEN 52 => SCL_i <= '1'; SDA <= addr_reg(0);
            WHEN 53 => SCL_i <= '0'; SDA <= addr_reg(0);

            WHEN 54 => SCL_i <= '0'; SDA <= 'Z';          -- ACK
            WHEN 55 => SCL_i <= '1'; SDA <= 'Z';
            WHEN 56 => SCL_i <= '0'; SDA <= 'Z';

--          WHEN 53 => SCL_i <= '0'; SDA <= 'Z';
--          WHEN 54 => SCL_i <= '1'; SDA <= 'Z';          -- ACK
--          WHEN 55 => SCL_i <= '0'; SDA <= 'Z';
--          WHEN 56 => SCL_i <= '0'; SDA <= '1';

            WHEN 57 => SCL_i <= '0'; SDA <= '1';          -- Start Condition (after dummy write)
            WHEN 58 => SCL_i <= '1'; SDA <= '1';
            WHEN 59 => SCL_i <= '1'; SDA <= '0';
            WHEN 60 => SCL_i <= '0'; SDA <= '0';
                
            WHEN 61 => SCL_i <= '0'; SDA <= '1';          -- 10AAAAA
            WHEN 62 => SCL_i <= '1'; SDA <= '1';
            WHEN 63 => SCL_i <= '0'; SDA <= '1';
            WHEN 64 => SCL_i <= '0'; SDA <= '0';          --
            WHEN 65 => SCL_i <= '1'; SDA <= '0';
            WHEN 66 => SCL_i <= '0'; SDA <= '0';
            WHEN 67 => SCL_i <= '0'; SDA <= DEV_addr_reg(4);          -- device address
            WHEN 68 => SCL_i <= '1'; SDA <= DEV_addr_reg(4);
            WHEN 69 => SCL_i <= '0'; SDA <= DEV_addr_reg(4);
            WHEN 70 => SCL_i <= '0'; SDA <= DEV_addr_reg(3);          --
            WHEN 71 => SCL_i <= '1'; SDA <= DEV_addr_reg(3);
            WHEN 72 => SCL_i <= '0'; SDA <= DEV_addr_reg(3);
            WHEN 73 => SCL_i <= '0'; SDA <= DEV_addr_reg(2);          --
            WHEN 74 => SCL_i <= '1'; SDA <= DEV_addr_reg(2);
            WHEN 75 => SCL_i <= '0'; SDA <= DEV_addr_reg(2);
            WHEN 76 => SCL_i <= '0'; SDA <= DEV_addr_reg(1);          --
            WHEN 77 => SCL_i <= '1'; SDA <= DEV_addr_reg(1);
            WHEN 78 => SCL_i <= '0'; SDA <= DEV_addr_reg(1);
            WHEN 79 => SCL_i <= '0'; SDA <= DEV_addr_reg(0);          -- 
            WHEN 80 => SCL_i <= '1'; SDA <= DEV_addr_reg(0);
            WHEN 81 => SCL_i <= '0'; SDA <= DEV_addr_reg(0);
--          WHEN 79 => SCL_i <= '0'; SDA <= stat_reg(0);  -- upper/lower address space
--          WHEN 80 => SCL_i <= '1'; SDA <= stat_reg(0);
--          WHEN 81 => SCL_i <= '0'; SDA <= stat_reg(0);

            WHEN 82 => SCL_i <= '0'; SDA <= '1';          -- read (1) / write (0)
            WHEN 83 => SCL_i <= '1'; SDA <= '1';
            WHEN 84 => SCL_i <= '0'; SDA <= '1';

            WHEN 85 => SCL_i <= '0'; SDA <= 'Z';          -- ACK
            WHEN 86 => SCL_i <= '1'; SDA <= 'Z';
            WHEN 87 => SCL_i <= '0'; SDA <= 'Z';

            WHEN  88 => SCL_i <= '0'; SDA <= 'Z';  -- data
            WHEN  89 => SCL_i <= '1'; SDA <= 'Z';
            WHEN  90 => SCL_i <= '0'; SDA <= 'Z'; data_reg_out(7) <= SDA;
            WHEN  91 => SCL_i <= '0'; SDA <= 'Z';
            WHEN  92 => SCL_i <= '1'; SDA <= 'Z';
            WHEN  93 => SCL_i <= '0'; SDA <= 'Z'; data_reg_out(6) <= SDA;
            WHEN  94 => SCL_i <= '0'; SDA <= 'Z';
            WHEN  95 => SCL_i <= '1'; SDA <= 'Z';
            WHEN  96 => SCL_i <= '0'; SDA <= 'Z'; data_reg_out(5) <= SDA;
            WHEN  97 => SCL_i <= '0'; SDA <= 'Z';
            WHEN  98 => SCL_i <= '1'; SDA <= 'Z';
            WHEN  99 => SCL_i <= '0'; SDA <= 'Z'; data_reg_out(4) <= SDA;
            WHEN 100 => SCL_i <= '0'; SDA <= 'Z';
            WHEN 101 => SCL_i <= '1'; SDA <= 'Z';
            WHEN 102 => SCL_i <= '0'; SDA <= 'Z'; data_reg_out(3) <= SDA;
            WHEN 103 => SCL_i <= '0'; SDA <= 'Z';
            WHEN 104 => SCL_i <= '1'; SDA <= 'Z';
            WHEN 105 => SCL_i <= '0'; SDA <= 'Z'; data_reg_out(2) <= SDA;
            WHEN 106 => SCL_i <= '0'; SDA <= 'Z';
            WHEN 107 => SCL_i <= '1'; SDA <= 'Z';
            WHEN 108 => SCL_i <= '0'; SDA <= 'Z'; data_reg_out(1) <= SDA;
            WHEN 109 => SCL_i <= '0'; SDA <= 'Z';
            WHEN 110 => SCL_i <= '1'; SDA <= 'Z';
            WHEN 111 => SCL_i <= '0'; SDA <= 'Z'; data_reg_out(0) <= SDA;
                                                                   
            WHEN 112 => SCL_i <= '0'; SDA <= '1';          -- NO ACK
            WHEN 113 => SCL_i <= '1'; SDA <= '1';
            WHEN 114 => SCL_i <= '1'; SDA <= '1';

--          WHEN 112 => SCL_i <= '0'; SDA <= '0';          -- ACK
--          WHEN 113 => SCL_i <= '1'; SDA <= '0';
--          WHEN 114 => SCL_i <= '1'; SDA <= '0';

            WHEN 115 => SCL_i <= '0'; SDA <= '0';          -- Stop Condition
            WHEN 116 => SCL_i <= '1'; SDA <= '0';
            WHEN 117 => SCL_i <= '1'; SDA <= '1';

            WHEN OTHERS => SCL_i <= '1'; SDA <= '1';      -- Idle
          END CASE;

        END IF;
      END IF;
    END IF;
  END PROCESS;

----------------------------------------------------------------------------------
END Behavioral;
---------------------------------------------------------------------------------- 