URL
https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk
Subversion Repositories open8_urisc
[/] [open8_urisc/] [trunk/] [VHDL/] [hd44780_4b.vhd] - Rev 322
Compare with Previous | Blame | View Log
-- Copyright (c)2021 Jeremy Seth Henry -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions are met: -- * Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- * Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution, -- where applicable (as part of a user interface, debugging port, etc.) -- -- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY -- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY -- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- -- VHDL Entity: o8_hd44780_4b -- Description: Provides low-level timing of the control signals in 4-bit mode -- (required by o8_hd44780_if) -- -- Revision History -- Author Date Change ------------------ -------- --------------------------------------------------- -- Seth Henry 04/12/21 Design Start library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; use ieee.std_logic_misc.all; entity hd44780_4b is generic( Tas : integer := 40; -- ns Tpwe : integer := 250; -- nS Tcyce : integer := 1000; -- nS Clock_Frequency : real := 100000000.0; -- Hz Reset_Level : std_logic := '1' ); port( Clock : in std_logic; Reset : in std_logic; -- Wr_Fnset : in std_logic; Wr_Data : in std_logic_vector(7 downto 0); Wr_Reg : in std_logic; Wr_En : in std_logic; -- IO_Done : out std_logic; -- LCD_RS : out std_logic; LCD_E : out std_logic; LCD_DQ : out std_logic_vector(7 downto 0) ); end entity; architecture behave of hd44780_4b is -- The ceil_log2 function returns the minimum register width required to -- hold the supplied integer. function ceil_log2 (x : in natural) return natural is variable retval : natural; begin retval := 1; while ((2**retval) - 1) < x loop retval := retval + 1; end loop; return retval; end function; constant CONV_NANOSECS : real := 0.000000001; constant Tas_r : real := CONV_NANOSECS * real(Tas); constant Tpwe_r : real := CONV_NANOSECS * real(Tpwe + Tas); constant Tcyc_r : real := CONV_NANOSECS * real(Tcyce + Tas); constant TCYC_i : integer := integer(Clock_Frequency * Tcyc_r); constant TCYC_BITS : integer := ceil_log2(TCYC_i); constant TCYC_DELAY : std_logic_vector(TCYC_BITS-1 downto 0) := conv_std_logic_vector(TCYC_i-1, TCYC_BITS); constant TAS_i : integer := integer(Clock_Frequency * Tas_r); constant TAS_DELAY : std_logic_vector(TCYC_BITS - 1 downto 0) := conv_std_logic_vector(TAS_i-1,TCYC_BITS); constant TPWE_i : integer := integer(Clock_Frequency * Tpwe_r); constant TPWE_DELAY : std_logic_vector(TCYC_BITS-1 downto 0) := conv_std_logic_vector(TPWE_i-1, TCYC_BITS); signal tcyc_timer : std_logic_vector(TCYC_BITS - 1 downto 0) := (others => '0'); type IO_STATES is (IDLE, TAS_UB, TPW_UB, TCYC_UB, INIT_LB, TPW_LB, TCYC_LB, DONE ); signal io_state : IO_STATES; signal fn_set : std_logic; signal Wr_Buffer : std_logic_vector(8 downto 0); alias Wr_Buffer_A is Wr_Buffer(8); alias Wr_Buffer_U is Wr_Buffer(7 downto 4); alias Wr_Buffer_L is Wr_Buffer(3 downto 0); alias LCD_DQ_U is LCD_DQ(7 downto 4); alias LCD_DQ_L is LCD_DQ(3 downto 0); begin LCD_IO_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then io_state <= IDLE; fn_set <= '0'; tcyc_timer <= (others => '0'); Wr_Buffer <= (others => '0'); IO_Done <= '0'; LCD_RS <= '0'; LCD_E <= '0'; LCD_DQ <= (others => '0'); elsif( rising_edge(Clock) )then IO_Done <= '0'; LCD_RS <= '0'; LCD_E <= '0'; LCD_DQ_U <= (others => '0'); LCD_DQ_L <= (others => '0'); tcyc_timer <= tcyc_timer + 1; case( io_state )is when IDLE => tcyc_timer <= (others => '0'); if( Wr_En = '1' )then Wr_Buffer <= Wr_Reg & Wr_Data; fn_set <= Wr_Fnset; io_state <= TAS_UB; end if; when TAS_UB => LCD_RS <= Wr_Buffer_A; if( tcyc_timer >= TAS_DELAY )then io_state <= TPW_UB; end if; when TPW_UB => LCD_RS <= Wr_Buffer_A; LCD_E <= '1'; LCD_DQ_U <= Wr_Buffer_U; if( tcyc_timer >= TPWE_DELAY )then io_state <= TCYC_UB; end if; when TCYC_UB => LCD_RS <= Wr_Buffer_A; LCD_DQ_U <= Wr_Buffer_U; if( tcyc_timer >= TCYC_DELAY )then io_state <= INIT_LB; end if; when INIT_LB => tcyc_timer <= TAS_DELAY; LCD_RS <= Wr_Buffer_A; LCD_DQ_U <= Wr_Buffer_U; io_state <= TPW_LB; if( fn_set = '1' )then fn_set <= '0'; io_state <= TPW_UB; end if; when TPW_LB => LCD_RS <= Wr_Buffer_A; LCD_E <= '1'; LCD_DQ_U <= Wr_Buffer_L; if( tcyc_timer >= TPWE_DELAY )then io_state <= TCYC_LB; end if; when TCYC_LB => LCD_RS <= Wr_Buffer_A; LCD_DQ_U <= Wr_Buffer_L; if( tcyc_timer >= TCYC_DELAY )then IO_Done <= '1'; io_state <= IDLE; end if; when others => null; end case; end if; end process; end architecture;