-- The Electronic Gardener -- -- Mark Kudryk, Kim Ellis -- -- Message Decoder -- -- Author: Mark Kudryk -- name: message.vhd -- date: November 4, 1998 -- -- Size: 140 Logic Cells -- Period: 21.0 ns -- Clock: 47.61 MHz -- -- Description: This module is responsible for receiving a request from the menu -- state machine to display a certain menu message. It will retrieve -- the message from an EEPROM, and then feed the LCD driver the -- message byte-by-byte. Each message is 16 bytes long. -- -- Some messages will require the inclusion of variable values, which -- the state machine will provide. -- -- If a message includes variable values, it will be stored in memory as -- follows: -- -- TIME ?&#:?&# > -- -- When the '?' is retrieved, it will prompt this module to ask the menu -- state machine to provide a variable. This variable will be in binary -- format. Upon arrival it will automatically be converted into two -- ASCII bytes. Sometimes both bytes will need to be displayed, sometimes -- only one. The '&' character will prompt for the display of the higher -- byte, the '#' the lower byte. -- library ieee; use ieee.std_logic_1164.all; entity message is port (-- the following is the interface with the menu state machine base_address: in std_logic_vector (12 downto 0); binary_data: in std_logic_vector (7 downto 0); ready_for_message: out std_logic; display_message: in std_logic; request_variable: out std_logic; variable_valid: in std_logic; -- the following is the interface with the EEPROM data_address: out std_logic_vector (12 downto 0); EEPROM_data: in std_logic_vector (7 downto 0); chip_enable_not: out std_logic; output_enable_not: out std_logic; -- the following is the interace with the LCD driver data_to_display: out std_logic_vector (7 downto 0); lcd_ready_for_line: in std_logic; new_line_ready: out std_logic; byte_requested: in std_logic; byte_valid: out std_logic; -- other inputs clock, reset: in std_logic); end entity message; architecture behaviour of message is -- -- COMPONENT DECLARATION -- component datareg is generic (WIDTH :positive := 8); port (data_in: in std_logic_vector(WIDTH-1 downto 0); reset, latch: in std_logic; data_out: out std_logic_vector(WIDTH-1 downto 0)); end component datareg; component increment is generic (width: positive:= 8); port (data_in: in std_logic_vector(width-1 downto 0); data_out: out std_logic_vector(width-1 downto 0)); end component increment; component comp is generic(width: positive :=8; threshold: natural:= 48); port(data_in: in std_logic_vector(width-1 downto 0); equal: out std_logic); end component comp; component mux_test is generic (width: positive := 8); port(data0, data1: in std_logic_vector (width-1 downto 0); choose: in std_logic; output: out std_logic_vector(width-1 downto 0)); end component mux_test; component bcd_ascii is port (bcd: in std_logic_vector (7 downto 0); reset: in std_logic; ascii_0, ascii_1: out std_logic_vector (7 downto 0)); end component bcd_ascii; -- -- INTERNAL SIGNALS -- signal int_data_address0, int_data_address1, int_data_address2: std_logic_vector (12 downto 0); signal memory_data, bcd_latched, high_ascii, low_ascii, ascii_data: std_logic_vector (7 downto 0); signal latch1_sel, latch2_sel, latch4_sel: std_logic; signal mux1_sel, mux2_sel, mux3_sel: std_logic; signal special_char1, special_char2, special_char3, special_char3_not: std_logic; -- -- STATES -- type state_type is (one, two, three, four, five); signal state: state_type; begin -- -- The following three components declare the address data path. -- MUX1: component mux_test generic map (width => 13) port map (data0 => base_address, data1 => int_data_address2, choose => mux1_sel, output => int_data_address0); LATCH1: component datareg generic map (width => 13) port map (data_in => int_data_address0, reset => reset, latch => latch1_sel, data_out => int_data_address1); data_address <= int_data_address1; INC1: component increment generic map (width => 13) port map (data_in => int_data_address1, data_out => int_data_address2); -- -- The following five components declare the message content data path -- COMP1: component comp generic map (threshold => 63) -- checking for '?' port map(data_in => EEPROM_data, equal => special_char1); COMP2: component comp generic map (threshold => 38) -- checking for '&' port map(data_in => EEPROM_data, equal => special_char2); COMP3: component comp generic map (threshold => 33) -- checking for '!' port map(data_in => EEPROM_data, equal => special_char3); mux2_sel <= special_char2 or special_char3; MUX2: component mux_test port map (data0 => EEPROM_data, data1 => ascii_data, choose => mux2_sel, output => memory_data); LATCH2: component datareg port map (data_in => memory_data, reset => reset, latch => latch2_sel, data_out => data_to_display); -- -- The following two components declare the BCD to ASCII decoder. -- LATCH4: component datareg port map (data_in => binary_data, reset => reset, latch => latch4_sel, data_out => bcd_latched); CONVERT: component bcd_ascii port map (bcd => bcd_latched, reset => reset, ascii_0 => low_ascii, ascii_1 => high_ascii); MUX3: component mux_test port map (data0 => low_ascii, data1 => high_ascii, choose => mux3_sel, output => ascii_data); special_char3_not <= not special_char3; mux3_sel <= special_char2 and special_char3_not; state_machine: process(clock, reset) variable flag: bit; begin if reset = '1' then latch1_sel <= '0'; latch2_sel <= '0'; latch4_sel <= '0'; chip_enable_not <= '1'; output_enable_not <= '1'; state <= one; ready_for_message <= '0'; request_variable <= '0'; new_line_ready <= '0'; byte_valid <= '0'; elsif clock'event and clock = '1' then case state is when one => if lcd_ready_for_line = '1' then -- LCD Driver has requested a line, now let's ask the menu -- state machine for a line code. ready_for_message <= '1'; latch1_sel <= '0'; latch2_sel <= '0'; state <= two; flag := '0'; end if; when two => if display_message = '1' then -- Menu State machine has placed valid address on the address bus, along -- with the proper line. -- Go ahead and retrieve message bytes from the EEPROM and send it -- to the LCD driver mux1_sel <= '0'; -- select the incoming address -- latch the line select ready_for_message <= '0'; new_line_ready <= '1'; -- tell the LCD a new line is on its way. state <= three; end if; when three => if byte_requested = '1' then -- LCD driver has requested a byte. Go to the EEPROM and get it. latch1_sel <= '1'; -- latch the address latch2_sel <= '0'; new_line_ready <= '0'; chip_enable_not <= '0'; output_enable_not <= '0'; state <= four; elsif lcd_ready_for_line = '1' and flag = '1' then -- Line has been completed displayed. Get ready for the next one. state <= one; end if; byte_valid <= '0'; latch4_sel <= '0'; when four => -- At this point, a valid byte of data from the EEPROM should be available. if special_char1 = '0' then latch2_sel <= '1'; -- latch the data to be sent to the LCD byte_valid <= '1'; state <= three; -- go get next byte else -- This message has variables. Request the variable from the menu state machine. request_variable <= '1'; -- Ask for variable data. state <= five; end if; flag := '1'; mux1_sel <= '1'; -- set mux to the incremented address latch1_sel <= '0'; chip_enable_not <= '1'; output_enable_not <= '1'; when five => if variable_valid = '1' then -- A valid binary byte has arrived from the menu state machine. It should -- be converted by now. Go return to the incoming data stream. Characters -- from that stream will properly select which byte to display. request_variable <= '0'; latch4_sel <= '1'; state <= three; end if; end case; end if; end process state_machine; end architecture behaviour;