library ieee;
  use ieee.std_logic_1164.all;
  use ieee.numeric_std.all;
  
entity lcd_message is 
         
        port( 
        clk          : in std_logic;                      
        resetn       : in  std_logic;      -- KEY0   
        -- LCD signals
        LCD_DATA   : inout std_logic_vector(7 downto 0); 
        LCD_ON     : out std_logic;
        LCD_BLON   : out std_logic;
        LCD_RS     : out std_logic;               
        LCD_RW     : out std_logic;               
        LCD_EN     : out std_logic                 
        );
end entity;

architecture RTL of lcd_message is
   constant board_frequency : real := 50_000_000.0;
	constant mode          : std_logic_vector(1 downto 0) := "00";
	constant address       : std_logic_vector(6 downto 0):= "0000000";
	constant char          : std_logic_vector(7 downto 0):= X"00";
   constant write_char    : std_logic:='1';
   constant write_address : std_logic:='1';
   constant   go           : std_logic:='0';      
	type state is (boot, message1,message2, waiting,write1,write2, reset1, reset2);
	signal present    : state;
	signal future     : state;    

    signal lcd_write_char    : std_logic;
    signal lcd_write_address : std_logic;
    signal Din        : std_logic_vector (7 downto 0);
    signal lcd_char   : std_logic_vector (7 downto 0);
    signal lcd_ready  : std_logic;
    signal cpt        : std_logic_vector(4 downto 0);
    signal inc_cpt    : std_logic;
 
    
    signal lcd_mode   : std_logic_vector(1 downto 0);
    signal lcd_address : std_logic_vector(address'range);
    
begin


--------------------------------
-- LCD
--------------------------------

  dut :   entity work.LCD
    generic map (board_frequency => board_frequency)
    port map( 
        Clk         => clk,
        resetn      => resetn,
        
        D             => '1',
        C             => '0',
        B             => '0',
        
        char          => lcd_char,
        write_char    => lcd_write_char,
        mode          => lcd_mode,
        address       => lcd_address,
        write_address => lcd_write_address,
        ready         => lcd_ready,
        LCD_ON        => LCD_ON,
        LCD_BLON      => LCD_BLON,
        LCD_data      => LCD_DATA,
        Lcd_RS        => LCD_RS,
        Lcd_RW        => LCD_RW,
        Lcd_EN        => LCD_EN
        );
 
       
        
      
     
       
  rom : entity work.message
  port map (
   adr => cpt,
   do => din
  );
  
       process(resetn,clk) is          
       begin
            if resetn = '0' then               
              present <= boot;   
              cpt     <= (others => '0');         
            elsif rising_edge (clk) then                
              present <= future;
              if inc_cpt = '1' then cpt <= std_logic_vector(unsigned(cpt)+1);
              end if;
            end if;            
       end process;

  process(present, lcd_ready, cpt,Din ) is
  begin
    future     <= present;
    inc_cpt    <= '0'; 
    
    lcd_write_char    <= '0';
    lcd_write_address <= '0';
    lcd_char          <= char;
    lcd_mode          <= mode;
    lcd_address       <= address;
    
    case present is 
      when boot   => if lcd_ready = '1' then future <= reset1; 
                     end if;
                     lcd_mode <= "00";
                     
                     
      when waiting    => future <= waiting;                     
     
     when reset1  => lcd_write_char    <= '1';
                     lcd_write_address <= '0';
                     lcd_char          <= X"0C";  
                     lcd_address       <= "0000000";   
                     lcd_mode          <= "00";           
                     if lcd_ready = '0' then future <= reset2;     
                     end if;  
                     
     when reset2  => if lcd_ready = '1' then future <= message1;     
                     end if;       
                     
                     
     when message1 => if lcd_ready = '0' then future <= message2; 
                     end if;
                     lcd_write_char <= '1';
                     lcd_mode       <= "00";
                     lcd_char       <= Din;
                     
     when message2 => if lcd_ready = '1' then 
                        if unsigned (cpt) <31 then future <= message1; 
                        else future <= waiting;
                        end if;
                        inc_cpt <= '1';
                     end if;
                     lcd_mode <= "00";
                     lcd_char <= Din;
      
     when write1  =>  lcd_write_char    <= not write_char;
                      lcd_write_address <= not write_address;
                      lcd_char          <= char;                      
                     if lcd_ready = '0' then future <= write2;   
                     end if;  
                                 
     when write2  => if  write_char= '1' and write_address = '1' and lcd_ready= '1' then
                      future <= waiting ;
                     end if; 
                     
                                
    end case;
  end process; 
end architecture;