library IEEE;
use IEEE.STD_LOGIC_1164.all;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Simon is
generic(iNancho: integer :=8);
	port
	(
		onf: in STD_LOGIC;
		clk: inout bit;
		sec: inout bit;
		vel: inout bit;
		go: inout bit;
		done, do: inout bit;
		
		cont, ns: inout std_logic_vector(3 downto 0);
		puls: in std_logic_vector(3 downto 0);
		
        b0,b1,b2,b3,gano,loff,lini,linter,au: out STD_LOGIC
	);	
end Simon;
architecture dice of Simon is
TYPE Estados IS (off, inicio, inter, e0, e1, e2, e3);
SIGNAL EActual, EAnterior, ESiguiente: Estados;
begin 
LogicaEstados: process(EActual)
begin
case(EActual) is
	 when off=>
	      if(onf='0') then
	        ESiguiente<=off;
	      elsif(onf='1') then
				ESiguiente<=inicio;
		  end if;
     when inicio=>
          cont<="0000";
          if(onf<='0') then
             ESiguiente<=off;
          end if;
          if(go='0') then
             ESiguiente<=inicio;
          elsif(go='1') then
                if(sec='0') then
                   ESiguiente<=e0;
                else
                    ESiguiente<=e2;
                end if;
          end if;
     when inter=>
          if(onf<='0') then
             ESiguiente<=off;
          elsif(puls="0000") then
			 ESiguiente<=inter;
		  elsif(done='1') then
                ESiguiente<=e0;
                do<='1';
          elsif(done='0') then
                do<='0';
                ESiguiente<=e0;
                cont<="0000";
          end if;
     when e0=>
          cont<=cont+1;
          if(EAnterior=inicio) then
             ESiguiente<=inter;            
          elsif(sec='0' and do='1') then
                ESiguiente<=e1;
          elsif(EAnterior=e1 and sec='0') then
                ESiguiente<=e2;
          elsif(do='0') then
                ESiguiente<=inter;
          elsif(go='1') then
                ESiguiente<=inicio;          
          end if; 
     when e1=>
          cont<=cont+1;
          if(cont="0010") then
             ESiguiente<=inter;
          if(do='1' and sec='0') then
                ESiguiente<=e2;
          elsif(EAnterior=e3 and sec='0') then
                ESiguiente<=e0;
          elsif(go='1') then
                ESiguiente<=inicio;
          end if; 
     when e2=>
          cont<=cont+1;
          if(done='1' and sec='0') then
             ESiguiente<=e3;
          elsif(EAnterior=e0 and sec='0') then
                ESiguiente<=e3;
          elsif(go='1') then
                ESiguiente<=inicio;
          end if; 
     when e3=>
          cont<=cont+1;
          if(cont<"1000" and done='1' and sec='0') then
             ESiguiente<=e1;
          elsif(go='1') then
                ESiguiente<=inicio;
          end if;                                                                                                                                                               
end case;
end process LogicaEstados;
process(puls)
begin
if(EActual=inter) then
if(sec='0') then
   if(ns="0001") then
      if(puls="1000") then
         ns<=ns+1;
         if(cont="0001") then
            done<='1';
         end if;
      else
          ns<="0000";
          done<='0';
      end if;
   end if;
   if(ns="0001") then
      if(puls="0100") then
         ns<=ns+1;
         if(cont="0010") then
            done<='1';
         end if;
      else
          ns<="0000";
          done<='0';
      end if;
   end if;
   if(ns="0010") then
      if(puls="0010") then
         ns<=ns+1;
         if(cont="0011") then
            done<='1';
         end if;
      else
          ns<="0000";
          done<='0';
      end if;
   end if;
   if(ns="0011") then
      if(puls="0001") then
         ns<=ns+1;
         if(cont="0100") then
            done<='1';
         end if;
      else
          ns<="0000";
          done<='0';
      end if;
   end if;   
   if(ns="0100") then
      if(puls="0100") then
         ns<=ns+1;
         if(cont="0101") then
            done<='1';
         end if;
      else
          ns<="0000";
          done<='0';
      end if;
   end if;   
   if(ns="0101") then
      if(puls="1000") then
         ns<=ns+1;
         if(cont="0110") then
            done<='1';
         end if;
      else
          ns<="0000";
          done<='0';
      end if;
   end if;    
   if(ns="0110") then
      if(puls="0010") then
         ns<=ns+1;
         if(cont="0111") then
            done<='1';
         end if;
      else
          ns<="0000";
          done<='0';
      end if;
   end if;
   if(ns="0111") then
      if(puls="0001") then
         ns<=ns+1;
         if(cont="1000") then
            done<='1';
         end if;
      else
          ns<="0000";
          done<='0';
      end if;
   end if;
end if;
end if;      
end process;
MemoriaEstado: process(clk)
begin
if(clk'event and clk='1') then
   EAnterior<=EActual; 
   EActual<=ESiguiente;
end if;
end process MemoriaEstado;
b0<='1' when (EActual=e0 or puls="1000")
        else '0';
b1<='1' when (EActual=e1 or puls="0100")
        else '0';
b2<='1' when (EActual=e2 or puls="0010")
        else '0';
b3<='1' when (EActual=e3 or puls="0001")
        else '0';
gano<='1' when (done='1' and EActual=inicio)   
          else '0';     
        
loff<='1' when (EActual=off)
          else '0';
lini<='1' when (EActual=inicio)
          else '0';
linter<='1' when (EActual=inter)
            else '0';
end dice;