--
-- Copyright (C) 2012 Jared Boone, ShareBrained Technology, Inc.
--
-- This file is part of PortaPack.
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2, or (at your option)
-- any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; see the file COPYING.  If not, write to
-- the Free Software Foundation, Inc., 51 Franklin Street,
-- Boston, MA 02110-1301, USA.

library ieee;
use ieee.std_logic_1164.all;

entity top is
	port (
		MCU_D				:	inout	std_logic_vector(7 downto 0);
		MCU_DIR			:	in		std_logic;
		MCU_IO_STBX		:	in		std_logic;
		MCU_LCD_WR		:	in		std_logic;
		MCU_ADDR			:	in		std_logic;
		MCU_LCD_TE		:	out	std_logic;
		MCU_P2_8			:	in		std_logic;
		MCU_LCD_RD		:	in		std_logic;
		
		TP_U				:	out	std_logic;
		TP_D				:	out	std_logic;
		TP_L				:	out	std_logic;
		TP_R				:	out	std_logic;
		
		SW_SEL			:	in		std_logic;
		SW_ROT_A			:	in		std_logic;
		SW_ROT_B			:	in		std_logic;
		SW_U				:	in		std_logic;
		SW_D				:	in		std_logic;
		SW_L				:	in		std_logic;
		SW_R				:	in		std_logic;
		
		LCD_RESETX		:	out	std_logic;
		LCD_RS			:	out	std_logic;
		LCD_WRX			:	out	std_logic;
		LCD_RDX			:	out	std_logic;
		LCD_DB			:	inout	std_logic_vector(15 downto 0);
		LCD_TE			:	in		std_logic;
		LCD_BACKLIGHT	:	out	std_logic
	);
end top;

architecture rtl of top is

	signal	switches : std_logic_vector(7 downto 0);
	
	type data_direction_t is (from_mcu, to_mcu);
	signal	data_dir	: data_direction_t;
	
	signal	mcu_data_out_lcd : std_logic_vector(7 downto 0);
	signal	mcu_data_out_io : std_logic_vector(7 downto 0);
	signal	mcu_data_out : std_logic_vector(7 downto 0);
	signal	mcu_data_in	: std_logic_vector(7 downto 0);
	
	signal	lcd_data_in : std_logic_vector(15 downto 0);
	signal  lcd_data_in_mux : std_logic_vector(7 downto 0);
	signal	lcd_data_out : std_logic_vector(15 downto 0);
	
	signal  lcd_data_in_q : std_logic_vector(7 downto 0) := (others => '0');
	signal  lcd_data_out_q : std_logic_vector(7 downto 0) := (others => '0');
	
	signal	tp_q : std_logic_vector(7 downto 0) := (others => '0');
	
	signal	lcd_reset_q : std_logic := '1';
	signal	lcd_backlight_q : std_logic := '0';
	
	signal	dir_read : boolean;
	signal	dir_write : boolean;
	
	signal	lcd_read_strobe : boolean;
	signal	lcd_write_strobe : boolean;
	signal	lcd_write : boolean;

	signal	io_strobe : boolean;
	signal	io_read_strobe : boolean;
	signal	io_write_strobe : boolean;
	
begin

	-- I/O data
	switches <= LCD_TE & not SW_ROT_B & not SW_ROT_A & not SW_SEL & not SW_U & not SW_D & not SW_L & not SW_R;

	TP_U <= tp_q(3) when tp_q(7) = '1' else 'Z';
	TP_D <= tp_q(2) when tp_q(6) = '1' else 'Z';
	TP_L <= tp_q(1) when tp_q(5) = '1' else 'Z';
	TP_R <= tp_q(0) when tp_q(4) = '1' else 'Z';
	
	LCD_BACKLIGHT <= lcd_backlight_q;
	
	MCU_LCD_TE <= LCD_TE;
	
	-- State management
	data_dir <= to_mcu when MCU_DIR = '1' else from_mcu;
	dir_read <= (data_dir = to_mcu);
	dir_write <= (data_dir = from_mcu);

	io_strobe <= (MCU_IO_STBX = '0');
	io_read_strobe <= io_strobe and dir_read;

	lcd_read_strobe <= (MCU_LCD_RD = '1');
	lcd_write <= not lcd_read_strobe;

	-- LCD interface
	LCD_RS <= MCU_ADDR;
	LCD_RDX <= not MCU_LCD_RD;
	LCD_WRX <= not MCU_LCD_WR;

	lcd_data_out <= lcd_data_out_q & mcu_data_in;
	lcd_data_in <= LCD_DB;
	LCD_DB <= lcd_data_out when lcd_write else (others => 'Z');
	
	LCD_RESETX <= not lcd_reset_q;
	
	-- MCU interface
	mcu_data_out_lcd <= lcd_data_in(15 downto 8) when lcd_read_strobe else lcd_data_in_q;
	mcu_data_out_io <= switches;
	mcu_data_out <= mcu_data_out_io when io_read_strobe else mcu_data_out_lcd;

	mcu_data_in <= MCU_D;
	MCU_D <= mcu_data_out when dir_read else (others => 'Z');
	
	-- Synchronous behaviors:
	-- LCD write: Capture LCD high byte on LCD_WRX falling edge.
	process(MCU_LCD_WR, mcu_data_in)
	begin
		if rising_edge(MCU_LCD_WR) then
			lcd_data_out_q <= mcu_data_in;
		end if;
	end process;
	
	-- LCD read: Capture LCD low byte on LCD_RD falling edge.
	process(MCU_LCD_RD, lcd_data_in)
	begin
		if falling_edge(MCU_LCD_RD) then
			lcd_data_in_q <= lcd_data_in(7 downto 0);
		end if;
	end process;
	
	-- I/O write (to resistive touch panel): Capture data from
	-- MCU and hold on TP pins until further notice.
	process(MCU_IO_STBX, dir_write, mcu_data_in, MCU_ADDR)
	begin
		if rising_edge(MCU_IO_STBX) and dir_write then
			if MCU_ADDR = '0' then
				tp_q <= mcu_data_in;
			else
				lcd_reset_q <= mcu_data_in(0);
				lcd_backlight_q <= mcu_data_in(7);
			end if;
		end if;
	end process;
end rtl;
