-------------------------------------------------------------------------------
-- Title      : LCD Driver for the clock
-- Project    : 
-------------------------------------------------------------------------------
-- File       : lcddriver.vhd
-- Author     :   <Fador@HINATA>
-- Company    : 
-- Created    : 2008-10-07
-- Last update: 2008-10-08
-- Platform   : 
-- Standard   : VHDL'87
-------------------------------------------------------------------------------
-- Description: 
-------------------------------------------------------------------------------
-- Copyright (c) 2008 
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author  Description
-- 2008-10-07  1.0      Fador	Created
-------------------------------------------------------------------------------

library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;


entity lcddriver is
  
 generic (
   data_width_g : integer := 8;
   clk_rate_g   : integer := 50000000  
   );

  port (
    lcddata_r     : inout
                     std_logic_vector(data_width_g-1 downto 0);  -- lcddata
    lcdE_out_r    : out std_logic;                     -- Enable
    lcdRW_out_r   : out std_logic;                     -- read/write
    lcdRS_out_r   : out std_logic;                     -- RS
    lcdready_r    : out std_logic;                     -- is block ready

    clk           : in  std_logic;
    rst_n         : in  std_logic;
    data_in     : in  std_logic_vector(data_width_g-1 downto 0);
    -- e_in_r        : in  std_logic;
    rw_in       : in  std_logic;
    rs_in       : in  std_logic;
    data_ready_in : in  std_logic);

end lcddriver;




architecture rtl of lcddriver is

  signal lcdready : std_logic;
  signal slow_clk_r : integer;
  signal clk_limit_r : integer;
                           
  type statetype is (idle,init, datain, finish, initbusy, waitbusy, endbusy);

  signal state : statetype;
  
begin  -- rtl

  main: process (clk, rst_n)
  begin  -- process main
    if rst_n = '0' then                 -- asynchronous reset (active low)
      lcdready <= '1';                  -- alussa lcd on oletetusti valmiina
      lcdready_r <= '1';
      
      state <= idle;
      slow_clk_r <= 0;
      lcddata_r <= "00000000";
      clk_limit_r <= clk_rate_g/1000;   -- 1ms välein
      lcdRS_out_r <= '0';
      lcdRW_out_r <= '0';
    elsif clk'event and clk = '1' then  -- rising clock edge

      slow_clk_r <= slow_clk_r +1;

      if slow_clk_r = clk_limit_r then
        
        slow_clk_r <= 0;

        case state is
          when idle =>     if data_ready_in = '1' then
                             state <= init;
                             lcdready <= '0';
                           end if;
          when init =>     lcdE_out_r <= '1';
                           state <= datain;
                           
          when datain =>   lcddata_r <= data_in;
                           lcdRS_out_r <= rs_in;
                           lcdRW_out_r <= rw_in;
                           state <= finish;
                           
          when finish =>   lcdE_out_r <= '0';
                           lcddata_r <= "ZZZZZZZZ";
                           state <= initbusy;

          when initbusy => lcdE_out_r <= '1';
                           lcdRW_out_r <= '1';
                           lcdRS_out_r <= '0';
                           state <= waitbusy;

          -- Odotetaan kunnes näyttö on vapaana
          when waitbusy => if lcddata_r(7) = '0' then
                              state <= endbusy;                             
                              lcdRW_out_r <= '0';
                            else
                              lcdE_out_r <= '0';
                              state <= initbusy;                             
                            end if;
                           
          when endbusy =>  if data_ready_in = '0' then
                             lcdready <= '1';
                             state <= idle;                         
                           end if;
        end case;

      end if;   -- Slow clock
      
    end if;
    lcdready_r <= lcdready;
  end process main;

end rtl;
