--------------------------------------------------------------------------------
-- Company:        CERN, BE-CO-HT 
-- Engineer:       Carlos Gil Soriano
-- 
-- Create Date:    11:56:55 10/25/2011 
-- Design Name:    I2C slave register HDL
-- Module Name:    i2c_regs - Behavioral 
-- Project Name:   Level Conversion Circuits
-- Target Devices: Spartan 6
-- Tool versions:  
-- Description:    This is the HDL that holds all the register of the I2C slave
--                 core
--
-- The registers should be programmed in the following order:
--   1.- CTR0 Sets up the control register: enable, start, i2c address
--   2.- CTR1 Sets up the threshold for detection signals in RX and TX buffers
--
-- Revision: 
-- Revision 0.01 - File Created
--          1.0  - Stable version
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity i2c_regs is
   port (
      pf_wb_addr_i     : in  STD_LOGIC;
      rd_done_i        : in  STD_LOGIC;
      wr_done_i        : in  STD_LOGIC;

      wb_rst_i         : in   STD_LOGIC;
      wb_clk           : in   STD_LOGIC;

      wb_master_we_o   : out STD_LOGIC;
      wb_master_stb_o  : out STD_LOGIC;
      wb_master_cyc_o  : out STD_LOGIC;
      wb_master_sel_o  : out STD_LOGIC_VECTOR (3  downto 0);
      wb_master_data_i : in  STD_LOGIC_VECTOR (31 downto 0);
      wb_master_data_o : out STD_LOGIC_VECTOR (31 downto 0);
      wb_master_addr_o : out STD_LOGIC_VECTOR (15  downto 0);
      wb_master_ack_i  : in  STD_LOGIC;
      wb_master_rty_i  : in  STD_LOGIC;
      wb_master_err_i  : in  STD_LOGIC;

      -- These are the registers offers to others modules of the FPGA
      wb_slave_we_i   : in   STD_LOGIC;
      wb_slave_stb_i  : in   STD_LOGIC;
      wb_slave_cyc_i  : in   STD_LOGIC;
      wb_slave_sel_i  : in   STD_LOGIC_VECTOR (3  downto 0);
      wb_slave_data_i : in   STD_LOGIC_VECTOR (31 downto 0);
      wb_slave_data_o : out  STD_LOGIC_VECTOR (31 downto 0);
      wb_slave_addr_i : in   STD_LOGIC_VECTOR (3  downto 0);
      wb_slave_ack_o  : out  STD_LOGIC;
      wb_slave_rty_o  : out  STD_LOGIC;
      wb_slave_err_o  : out  STD_LOGIC;

      i2c_addr       : in   STD_LOGIC_VECTOR (6  downto 0);
      -- These are the registers that are offered to the i2c slave core
      I2C_MASK_o    : out  STD_LOGIC_VECTOR (6 downto 0);
      CTR0_o    : out  STD_LOGIC_VECTOR (15 downto 0);
      CTR1_o    : out  STD_LOGIC_VECTOR (15 downto 0);
      STA_i     : in   STD_LOGIC_VECTOR (15 downto 0);
      DRX0_i    : in   STD_LOGIC_VECTOR (7  downto 0);
      DRX1_i    : in   STD_LOGIC_VECTOR (7  downto 0);
      DRX2_i    : in   STD_LOGIC_VECTOR (7  downto 0);
      DRX3_i    : in   STD_LOGIC_VECTOR (7  downto 0);
      DRX4_i    : in   STD_LOGIC_VECTOR (7  downto 0);
      DRX5_i    : in   STD_LOGIC_VECTOR (7  downto 0);
      DTX0_o    : out  STD_LOGIC_VECTOR (7  downto 0);
      DTX1_o    : out  STD_LOGIC_VECTOR (7  downto 0);
      DTX2_o    : out  STD_LOGIC_VECTOR (7  downto 0);
      DTX3_o    : out  STD_LOGIC_VECTOR (7  downto 0);
      -- Controls for FIFO_dispatcher
      load_TX     : out  STD_LOGIC
   );
end i2c_regs;

architecture Behavioral of i2c_regs is

   -------------------------------------
   -- STATUS register
   -------------------------------------
   -- 16 bits
   -- Wishbone access: Read-only
   ------------------------------------
   -- BIT       NAME           Description
   --  0         EN             General ENable
   --  1         RST            General ReSeT
   --  2         RD_WRN_INST    Reserved
   --  3         A_RX          
   --  4         A_TX          
   --  8-5       x              Reserved
   --  15-9      i2c_sla_fsm    i2c fsm
   -------------------------------------
  constant  STA_addr    : STD_LOGIC_VECTOR(3 downto 0) := X"0";

   -------------------------------------
   -- I2C MASK register
   -------------------------------------
   -- 16 bits
   -- Wishbone access: Read-only
   ------------------------------------
   -- BIT       NAME           Description
   --  6-0       MASK           I2C MASK
   --  15-7      x              Reserved
   -------------------------------------

   constant I2C_MASK_addr     : STD_LOGIC_VECTOR(3 downto 0) := X"1";
   -------------------------------------
   -- CTR0 register
   -------------------------------------
   -- 16 bits
   -- Wishbone access: Write-read
   ------------------------------------
   -- BIT       NAME           Description
   --  0         EN             general ENable
   --  1         RST            ReSeT
   --  2         PEN            Prescaler ENable
   --  5-3       x              Reserved
   --  7-6       BIA            Bytes Indirect Addressing
   --  14-8      A[6:0]         I2c address
   --  15        x              Reserved
   -------------------------------------
   constant  CTR0_addr   : STD_LOGIC_VECTOR(3 downto 0) := X"2";

   -------------------------------------
   -- CTR1 register
   -------------------------------------
   -- 16 bits
   -- Wishbone access: Read-only
   ------------------------------------
   -- BIT       NAME           Description
   --  6-0       BRD            Bytes to be ReaD from FPGA
   --  13-7      BWR            Bytes to be WRitten to FPGA
   --  15-14     WAL            Wishbone Addressing byte Lenght
   -------------------------------------
   constant  CTR1_addr   : STD_LOGIC_VECTOR(3 downto 0) := X"3";

   -------------------------------------
   -- DRXA register
   -------------------------------------
   -- 16 bits
   -- Wishbone access: Read-only
   ------------------------------------
   -- BIT       NAME           Description
   --  7-0       DRX0           Data RX register 0      
   --  15-8      DRX1           Data RX register 1
   --  23-16     DRX2           Data RX register 2
   --  31-24     DRX3           Data RX register 3
   -------------------------------------
   constant  DRXA_addr   : STD_LOGIC_VECTOR(3 downto 0) := X"4";
   
   -------------------------------------
   -- DRXB register
   -------------------------------------
   -- 16 bits
   -- Wishbone access: Read-only
   ------------------------------------
   -- BIT       NAME           Description
   --  7-0       DRX5           Data RX register 5 
   --  15-8      DRX6           Data RX register 6 
   --  31-16     x              Reserved
   -------------------------------------
   constant  DRXB_addr   : STD_LOGIC_VECTOR(3 downto 0) := X"5";

   -------------------------------------
   -- DTX register
   -------------------------------------
   -- 16 bits
   -- Wishbone access: Read-only
   ------------------------------------
   -- BIT       NAME           Description
   --  7-0       DTX0           Data TX register 0 
   --  15-8      DTX1           Data TX register 1 
   --  23-16     DTX2           Data TX register 2 
   --  31-24     DTX3           Data TX register 3 
   -------------------------------------
   constant  DTX_addr    : STD_LOGIC_VECTOR(3 downto 0) := X"6";

   type WB_BASIC_fsm is (S0_IDLE, S1A_WB_RD_RQT, S1B_WB_WR_RQT,
                         S2_WB_NOOP, S3_WB_ACK, Q0_OK, Q1_ERROR);

signal i2c_master_WB_BASIC_fsm     : WB_BASIC_fsm;
signal i2c_master_WB_BASIC_fsm_d1  : WB_BASIC_fsm;

signal s_wb_slave_ack : STD_LOGIC;
signal s_wb_slave_rty : STD_LOGIC;
signal s_wb_slave_err : STD_LOGIC;

signal s_STA          : STD_LOGIC_VECTOR  (15 downto 0);
signal s_I2C_MASK     : STD_LOGIC_VECTOR  (15  downto 0);
signal s_CTR0         : STD_LOGIC_VECTOR  (14  downto 0);
signal s_CTR1         : STD_LOGIC_VECTOR  (15 downto 0);

signal s_DTX0         : STD_LOGIC_VECTOR(7 downto 0);
signal s_DTX1         : STD_LOGIC_VECTOR(7 downto 0);
signal s_DTX2         : STD_LOGIC_VECTOR(7 downto 0);
signal s_DTX3         : STD_LOGIC_VECTOR(7 downto 0);

signal s_load_TX        : STD_LOGIC;
signal s_wb_master_we_o : STD_LOGIC;

begin

I2C_MASK_o          <= s_I2C_MASK(6 downto 0);
CTR0_o(15)          <= '0';
CTR0_o(14 downto 0) <= s_CTR0(14 downto 0);
CTR1_o              <= s_CTR1;
DTX0_o              <= s_DTX0;
DTX1_o              <= s_DTX1;
DTX2_o              <= s_DTX2;
DTX3_o              <= s_DTX3;
wb_slave_ack_o      <= s_wb_slave_ack;
wb_slave_rty_o      <= s_wb_slave_rty;
wb_slave_err_o      <= s_wb_slave_err;
load_TX             <= s_load_TX;
wb_master_we_o      <= s_wb_master_we_o;

wbmaster_reg_proc: process(wb_clk)
begin
   if rising_edge(wb_clk) then
      if wb_rst_i = '1' then
         i2c_master_WB_BASIC_fsm  <=  S0_IDLE;
      else
         i2c_master_WB_BASIC_fsm_d1  <= i2c_master_WB_BASIC_fsm;
         case i2c_master_WB_BASIC_fsm is
            when S0_IDLE   =>
               if pf_wb_addr_i = '1' then
                  i2c_master_WB_BASIC_fsm <= S1A_WB_RD_RQT;
               elsif rd_done_i = '1' then 
                  i2c_master_WB_BASIC_fsm <= S1B_WB_WR_RQT;
               else
                  i2c_master_WB_BASIC_fsm <= S0_IDLE;
               end if;
            when S1A_WB_RD_RQT  =>
               i2c_master_WB_BASIC_fsm <= S2_WB_NOOP;
            when S1B_WB_WR_RQT  =>
               i2c_master_WB_BASIC_fsm <= S2_WB_NOOP;
            when S2_WB_NOOP =>
               i2c_master_WB_BASIC_fsm <= S3_WB_ACK;
            when S3_WB_ACK  =>
               i2c_master_WB_BASIC_fsm <= Q0_OK;
            when Q0_OK      =>
               i2c_master_WB_BASIC_fsm <= S0_IDLE;
            when others     =>
               i2c_master_WB_BASIC_fsm <= S0_IDLE;
         end case;

      end if;
   else
   end if;
end process wbmaster_reg_proc;

wbmaster_comb_proc: process(i2c_master_WB_BASIC_fsm)
begin
   wb_master_cyc_o   <= '0'; 
   wb_master_stb_o   <= '0'; 
   s_wb_master_we_o  <= '0'; 
   wb_master_sel_o   <= (others => '0');
   wb_master_data_o  <= (others => '0'); 
   wb_master_addr_o  <= (others => '0'); 
   case i2c_master_WB_BASIC_fsm is
      when S0_IDLE        =>
      -- This case is accessed when prefetching a wishbone
      -- address, in that case, the first two bytes of the
      -- DRXi registers hold the wishbone address.
      when S1A_WB_RD_RQT  =>
         wb_master_cyc_o       <= '1';
         wb_master_stb_o       <= '1';
         wb_master_sel_o       <= X"F";
         wb_master_addr_o      <= DRX1_i & DRX2_i;
      when S1B_WB_WR_RQT  =>
         wb_master_cyc_o       <= '1';
         wb_master_stb_o       <= '1';
         s_wb_master_we_o      <= '1';
         wb_master_sel_o       <= X"F";
         wb_master_data_o      <= DRX3_i & DRX2_i & DRX1_i & DRX0_i;
         wb_master_addr_o      <= DRX5_i & DRX4_i;
      when S2_WB_NOOP     =>
         wb_master_cyc_o       <= '1';
         wb_master_stb_o       <= '1';
         s_wb_master_we_o      <= '0';
         if i2c_master_WB_BASIC_fsm_d1 = S1B_WB_WR_RQT then
            s_wb_master_we_o   <= '1';
         else
         end if;
      when S3_WB_ACK      =>
      -- No matter if we have errors or not, but we plase the init configuration
      when Q0_OK          =>
      when others         =>
   end case;
end process;

wbslave_proc: process (wb_clk)
begin
   if rising_edge(wb_clk) then
      if wb_rst_i = '1' then
         wb_slave_data_o          <= (others => '0');
         s_wb_slave_ack           <= '0';
         s_wb_slave_rty           <= '0';
         s_wb_slave_err           <= '0';
            -- This is the default maybe it is good to place the
            -- autoconfiguration here.
         s_I2C_MASK (6  downto 0) <= "0011111";
         s_I2C_MASK (15 downto 7) <= (others => '0');
         s_CTR0 (0)               <= '1';
         s_CTR0 (5  downto 1)     <= (others => '0');
         s_CTR0 (7  downto 6)     <= "10";
         s_CTR0 (14 downto 8)     <= i2c_addr AND "0011111";
         s_CTR1 (6  downto 0)     <= "000" & X"4";
         s_CTR1 (13 downto 7)     <= "000" & X"4";
         s_CTR1 (15 downto 14)    <= "10";
         s_DTX0                   <= (others => '0');
         s_DTX1                   <= (others => '0');
         s_DTX2                   <= (others => '0');
         s_DTX3                   <= (others => '0');
         s_load_TX                <= '0';
      elsif (wb_slave_stb_i = '1' and wb_slave_cyc_i = '1') then
         s_wb_slave_ack   <= '0';
         s_wb_slave_rty   <= '0';
         s_wb_slave_err   <= '0';
         s_load_TX        <= '0';
         case wb_slave_we_i is 
            when '1' =>
               case wb_slave_addr_i is        
                  when I2C_MASK_addr             => 
                     s_I2C_MASK(6  downto 0)  <= wb_slave_data_i(6  downto 0); 
                     s_I2C_MASK(15 downto 7)  <= (others => '0'); 
                     s_wb_slave_ack           <= '1';
                  when CTR0_addr         => 
                     s_CTR0           <= wb_slave_data_i(14  downto 0); 
                     s_wb_slave_ack   <= '1';
                  when CTR1_addr        => 
                     s_CTR1           <= wb_slave_data_i(15  downto 0); 
                     s_wb_slave_ack   <= '1';
                  when DTX_addr         =>
                     s_DTX0           <= wb_slave_data_i(7  downto 0); 
                     s_DTX1           <= wb_slave_data_i(15 downto 8); 
                     s_DTX2           <= wb_slave_data_i(23 downto 16); 
                     s_DTX3           <= wb_slave_data_i(31 downto 24); 
                     s_load_TX        <= '1';
                     s_wb_slave_ack   <= '1';
                  when others           =>
                     s_wb_slave_err   <= '1';
               end case;
            when others =>
               case wb_slave_addr_i is
                  when STA_addr                      => 
                     wb_slave_data_o(15 downto 0)  <= STA_i; 
                     wb_slave_data_o(31 downto 16) <= (others => '0');
                     s_wb_slave_ack                <= '1';
                  when I2C_MASK_addr                 => 
                     wb_slave_data_o(6 downto 0)   <= s_I2C_MASK(6 downto 0); 
                     wb_slave_data_o(31 downto 7)  <= (others => '0');
                     s_wb_slave_ack                  <= '1';
                  when CTR0_addr                     => 
                     wb_slave_data_o(14  downto 0) <= s_CTR0;
                     wb_slave_data_o(31 downto 15) <= (others => '0');
                     s_wb_slave_ack                <= '1';
                  when CTR1_addr                     => 
                     wb_slave_data_o(15 downto 0)  <= s_CTR1; 
                     wb_slave_data_o(31 downto 16) <= (others => '0');
                     s_wb_slave_ack                  <= '1';
                  when DRXA_addr                     => 
                     wb_slave_data_o(7  downto 0)  <= DRX0_i; 
                     wb_slave_data_o(15 downto 8)  <= DRX1_i; 
                     wb_slave_data_o(23 downto 16) <= DRX2_i; 
                     wb_slave_data_o(31 downto 24) <= DRX3_i; 
                     s_wb_slave_ack                <= '1';
                  when DRXB_addr => 
                     wb_slave_data_o(7  downto 0)  <= DRX4_i; 
                     wb_slave_data_o(15 downto 8)  <= DRX5_i; 
                     wb_slave_data_o(31 downto 16) <= (others => '0');
                     s_wb_slave_ack                <= '1';
                  when DTX_addr                      => 
                     wb_slave_data_o(7  downto 0)  <= s_DTX0; 
                     wb_slave_data_o(15 downto 8)  <= s_DTX1; 
                     wb_slave_data_o(23 downto 16) <= s_DTX2; 
                     wb_slave_data_o(31 downto 24) <= s_DTX3;
                     s_wb_slave_ack                <= '1';
                  when others           =>
                     s_wb_slave_err   <= '1';
               end case;
         end case;
      else
      end if;
   else
   end if;
end process;

end Behavioral;
