-- fsm.vhd: Finite State Machine
-- Author(s): Michal Schorm
--
library ieee;
use ieee.std_logic_1164.all;
-- ----------------------------------------------------------------------------
--                        Entity declaration
-- ----------------------------------------------------------------------------
entity fsm is
port(
   CLK         : in  std_logic;
   RESET       : in  std_logic;

   -- Input signals
   KEY         : in  std_logic_vector(15 downto 0);
   CNT_OF      : in  std_logic;

   -- Output signals
   FSM_CNT_CE  : out std_logic;
   FSM_MX_MEM  : out std_logic;
   FSM_MX_LCD  : out std_logic;
   FSM_LCD_WR  : out std_logic;
   FSM_LCD_CLR : out std_logic
);
end entity fsm;

-- ----------------------------------------------------------------------------
--                      Architecture declaration
-- ----------------------------------------------------------------------------
architecture behavioral of fsm is
   type t_state is (STATE1, STATE2, STATE3, STATE4, STATE5, STATE6, STATE7, STATE8, STATE9, STATE10, 
   STATE11, STATE12, STATE13, STATE14, STATE15, PREALLOWED, ALLOWED,DENIED, PREDENIED,FINISH);
   signal present_state, next_state : t_state;

begin
-- -------------------------------------------------------
sync_logic : process(RESET, CLK)
begin
   if (RESET = '1') then
      present_state <= TEST1;
   elsif (CLK'event AND CLK = '1') then
      present_state <= next_state;
   end if;
end process sync_logic;

-- -------------------------------------------------------
next_state_logic : process(present_state, KEY, CNT_OF)
begin
   case (present_state) is
   when STATE1 =>
            next_state <= STATE1;
         if (KEY(2) = '1') then
               next_state <= STATE2;
         elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;     
      
      when STATE2 =>
            next_state <= STATE2;
         if (KEY(3) = '1') then
               next_state <= STATE3;
         elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;
   
      when STATE3 =>
         next_state <= STATE3;
         if (KEY(0) = '1') then
         next_state <= STATE4;
      elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;
         
      when STATE4 =>
            next_state <= STATE4;
         if (KEY(2) = '1') then
               next_state <= STATE5;
         elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;
         
      when STATE5 =>
            next_state <= STATE5;
         if (KEY(8) = '1') then
               next_state <= STATE6;
            elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;
         
      when STATE6 =>
            next_state <= STATE6;
         if (KEY(1) = '1') then
               next_state <= STATE7;
         elsif (KEY(8) = '1') then
               next_state <= STATE11; 
            elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;
         
      when STATE7 =>
            next_state <= STATE7;
         if (KEY(1) = '1') then
               next_state <= STATE8;
            elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;
         
      when STATE8 =>
            next_state <= STATE8;
         if (KEY(9) = '1') then
               next_state <= STATE9;
         elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;
         
      when STATE9 =>
            next_state <= STATE9;
         if (KEY(0) = '1') then
               next_state <= STATE10;
         elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;
         
      when STATE10 =>
            next_state <= STATE10;
         if (KEY(1) = '1') then
               next_state <= PREALLOWED;
            elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;

      when STATE11 =>
            next_state <= STATE11;
         if (KEY(7) = '1') then
            next_state <= STATE12;
         elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;

      when STATE12 =>
            next_state <= STATE12;
         if (KEY(1) = '1') then
            next_state <= STATE13;
         elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;

      when STATE13 =>
            next_state <= STATE13;
         if (KEY(4) = '1') then
            next_state <= STATE14;
         elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;

      when STATE14 =>
            next_state <= STATE14;
         if (KEY(0) = '1') then
            next_state <= PREALLOWED;
         elsif (KEY(14 downto 0) /= "000000000000000") then
               next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
               next_state <= DENIED;
         end if;
-- -------------------------------------------------------
    when PREDENIED =>
            next_state <= PREDENIED;
         if (KEY(15) /= '1') then
            next_state <= PREDENIED;
         elsif (KEY(15) = '1') then
            next_state <= DENIED;
         end if;  
      
      when PREALLOWED =>
            next_state <= PREALLOWED;
         if (KEY(15) = '1') then
            next_state <= ALLOWED;
         elsif (KEY(14 downto 0) /= "000000000000000") then
            next_state <= PREDENIED;
         end if;  
      
      when ALLOWED =>
            next_state <= ALLOWED;
         if (CNT_OF = '1') then 
            next_state <= FINISH;
         end if;

      when DENIED =>
            next_state <= DENIED;
         if (CNT_OF = '1') then
            next_state <= FINISH;
         end if;
             
      when FINISH =>
            next_state <= FINISH;
         if (KEY(15) = '1') then
            next_state <= T1;
         end if;

-- -------------------------------------------------------
output_logic : process(present_state, KEY)
begin
   FSM_CNT_CE     <= '0';
   FSM_MX_MEM     <= '0';
   FSM_MX_LCD     <= '0';
   FSM_LCD_WR     <= '0';
   FSM_LCD_CLR    <= '0';

   case (present_state) is
   -- - - - - - - - - - - - - - - - - - - - - - -
    when STATE1 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
      
   when STATE2 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
      
   when STATE3 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
   
   when STATE4 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
      
   when STATE5 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
      
   when STATE6 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
     if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
      
   when STATE7 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
   
   when STATE8 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
      
   when STATE9 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
      
   when STATE10 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;

   when STATE11 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;

   when STATE12 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if; bn
          
   when STATE13 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;

   when STATE14 =>
      if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
   -- - - - - - - - - - - - - - - - - - - - - - -
   when PREDENIED =>
         if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;   
   
   when PREALLOWED =>
         if (KEY(14 downto 0) /= "000000000000000") then
         FSM_LCD_WR     <= '1';
      end if;
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
       
   when ALLOWED =>
      FSM_CNT_CE     <= '1';
      FSM_MX_LCD     <= '1';
      FSM_LCD_WR     <= '1';
      FSM_MX_MEM     <= '1';
      
   when DENIED =>
      FSM_CNT_CE     <= '1';
      FSM_MX_LCD     <= '1';
      FSM_LCD_WR     <= '1';
   -- - - - - - - - - - - - - - - - - - - - - - -
   when FINISH =>
      if (KEY(15) = '1') then
         FSM_LCD_CLR    <= '1';
      end if;
   -- - - - - - - - - - - - - - - - - - - - - - -
   when others =>
   end case;
end process output_logic;

end architecture behavioral;