library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

library unisim;
use unisim.vcomponents.all;

entity si5341_clk_configurator is
  port (   
    sys_clk100_in                         : in  std_logic;
    tick_1ms_in                           : in  std_logic;

    sda_in                                : in  std_logic;
    sda_out                               : out std_logic;
    sda_t_out                             : out std_logic;

    scl_in                                : in  std_logic;
    scl_out                               : out std_logic;
    scl_t_out                             : out std_logic;

    i2c_mux_access_ok_out                 : out std_logic; 
    si5341_access_ok_out                  : out std_logic; 
    si5341_config_done_out                : out std_logic; 
    si5341_config_error_out               : out std_logic; 

    man_clk_gen_en_in                     : in  std_logic;
    man_clk_gen_cfg_reset_in              : in  std_logic;
    reset_in                              : in  std_logic
  );
end entity si5341_clk_configurator;

architecture imp of si5341_clk_configurator is

  signal clk_gen_cfg_reset_d              : std_logic := '0';
  signal clk_gen_cfg_reset                : std_logic;
  
  signal i2c_mux_access_ok                : std_logic;
  signal si5341_access_ok                 : std_logic;
  signal si5341_config_done               : std_logic;
  signal si5341_config_error              : std_logic;

  type fsm_state_sm                       is (idle_st, si5341_reset_lo_st, si5341_reset_hi_st, si5341_config_st, si5341_config_wait_st, 
                                              si5341_config_check_st, done_st);
  signal state_d                          : fsm_state_sm := idle_st;
  signal tick_cnt_d                       : integer;
  
  signal state_test_r                     : std_logic_vector(2 downto 0) := (others => '0');
  
begin

  clk_gen_cfg_reset         <= man_clk_gen_cfg_reset_in when man_clk_gen_en_in = '1' else clk_gen_cfg_reset_d;
  
  i_clk_gen_cfg : entity work.clk_gen_cfg 
  generic map (
    simulation_mode                     => '0'
    )
  port map (
    sys_clk_in                          => sys_clk100_in,
    reset_in                            => clk_gen_cfg_reset,

    i2c_mux_access_ok_out               => i2c_mux_access_ok,    
    si5341_access_ok_out                => si5341_access_ok,     
    si5341_config_done_out              => si5341_config_done,   
    si5341_config_error_out             => si5341_config_error,  

    I_SDA_I                             => sda_in,
    O_SDA_O                             => sda_out,
    O_SDA_T                             => sda_t_out,

    I_SCL_I                             => scl_in,
    O_SCL_O                             => scl_out,
    O_SCL_T                             => scl_t_out
  );
  
  i2c_mux_access_ok_out     <= i2c_mux_access_ok; 
  si5341_access_ok_out      <= si5341_access_ok;   
  si5341_config_done_out    <= si5341_config_done; 
  si5341_config_error_out   <= si5341_config_error;
    
  process(state_d) 
  begin
    case state_d is
      when idle_st =>                 state_test_r    <= "000";
      when si5341_reset_lo_st =>      state_test_r    <= "001";
      when si5341_reset_hi_st =>      state_test_r    <= "010";
      when si5341_config_st =>        state_test_r    <= "011";
      when si5341_config_wait_st =>   state_test_r    <= "100";
      when si5341_config_check_st =>  state_test_r    <= "101";
      when done_st =>                 state_test_r    <= "110";
      when others =>                  state_test_r    <= "111";      
    end case;
  end process;
  
--  i_ila_0 : entity work.ila_0
--    port map (
--      clk                         => sys_clk100_in,
--      probe0                      => state_test_r,        --3
--      probe1(0)                   => i2c_mux_access_ok,   --1
--      probe2(0)                   => si5341_access_ok,    --1
--      probe3(0)                   => si5341_config_done,  --1
--      probe4(0)                   => si5341_config_error, --1
--      probe5(0)                   => clk_gen_cfg_reset,   --1
--      probe7(0)                   => clk_gen_cfg_reset_d, --1     
--      probe9(0)                   => tick_1ms_in          --1
--    );
   
  process(sys_clk100_in)
  begin
    if (rising_edge(sys_clk100_in)) then
      if (reset_in = '1') then
        clk_gen_cfg_reset_d         <= '0';
        tick_cnt_d                  <= 500;
        state_d                     <= idle_st;  
      else      
        if (tick_1ms_in  = '1') then
          tick_cnt_d                <= tick_cnt_d - 1;
        end if;
        
        case state_d is
          when idle_st =>  --0
            if (tick_cnt_d = 0) then
              tick_cnt_d            <= 250;
              state_d               <= si5341_reset_lo_st;  
            else
              state_d               <= idle_st;  
            end if;

          when si5341_reset_lo_st => --1
            if (tick_cnt_d = 0) then
              tick_cnt_d            <= 100;
              state_d               <= si5341_reset_hi_st;  
            else
              state_d               <= si5341_reset_lo_st;  
            end if;

          when si5341_reset_hi_st => --2
            if (tick_cnt_d = 0) then
              clk_gen_cfg_reset_d   <= '1';
              tick_cnt_d            <= 250;
              state_d               <= si5341_config_st;  
            else
              state_d               <= si5341_reset_hi_st;  
            end if;

          when si5341_config_st =>  --3
            if (tick_cnt_d = 0) then
              clk_gen_cfg_reset_d   <= '0';
              tick_cnt_d            <= 1000;
              state_d               <= si5341_config_wait_st;  
            else
              state_d               <= si5341_config_st;  
            end if;

          when si5341_config_wait_st =>  --4
            if (tick_cnt_d = 0) then
              tick_cnt_d            <= 1000;
              state_d               <= si5341_config_check_st;  
            else
              state_d               <= si5341_config_wait_st;  
            end if;

          when si5341_config_check_st => --5
            if (tick_cnt_d = 0) then
              tick_cnt_d            <= 250;
              state_d               <= idle_st;  
            elsif (i2c_mux_access_ok = '1' and si5341_access_ok = '1' and si5341_config_done = '1' and si5341_config_error = '0') then             
              state_d               <= done_st;                                                    
            else                                                                                
              state_d               <= si5341_config_check_st;                                     
            end if;

          when done_st => --6
            state_d               <= done_st;  

          when others =>  --7          
            state_d                 <= idle_st;
        end case;
      end if;
    end if;
  end process;
  
end architecture imp; 