-------------------------------------------------------------------------
-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
-- This file: system test using Xilinx ML-402

-- Copyright (C) 2007 J. Ahrensfeld

-- This library is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 2.1 of the License, or (at your option) any later version.

-- This library 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
-- Lesser General Public License for more details.

-- You should have received a copy of the GNU Lesser General Public
-- License along with this library; if not, write to the Free Software
-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

-- For questions and ideas, please contact the author at jens@jayfield.org

-----------------------------------------------------------------------

LIBRARY ieee;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL;
use std.textio.all; --  Imports the standard textio package.

Library UNISIM;
use UNISIM.vcomponents.all;

library work;
use work.cpu_pkg.all;
use work.vga_types.all;
use work.fifo_ctrl_pkg.all;
use work.sdram_config.all;
use work.sdram_types.all;

ENTITY systest IS
GENERIC
(
	sys_freq			: integer		    := 100E6;
	ddr_phaseshift		: integer			:= 0;
	ddr_frequency_hz	: integer			:= 100E6;
	tsvga				: vga_timespec_t	:= ts_vga_1280_1024_72
);
PORT
(
	sys_rst_n_in		: in std_logic;
	sys_clk_in			: in std_logic;

	-- Buttons and LEDs
	sys_btn				: in unsigned(4 downto 0);
	sys_dip				: in unsigned(7 downto 0);
	sys_led				: out unsigned(8 downto 0);

	-- UART
	sys_rx				: in std_logic;
	sys_tx				: out std_logic;

	-- LCD
	sys_lcd_d			: inout unsigned(3 downto 0);
	sys_lcd_e			: out std_logic;
	sys_lcd_rs			: out std_logic;
	sys_lcd_rw			: out std_logic;

	-- DDR SDRAM
	sys_sdr_clk_p		: out std_logic;    -- ddr_sdram_clock
	sys_sdr_clk_n		: out std_logic;    -- /ddr_sdram_clock
	sys_sdr_cke_q		: out std_logic;    -- clock enable
	sys_sdr_cs_qn		: out std_logic;    -- /chip select
	sys_sdr_ras_qn		: out std_logic;    -- /ras
	sys_sdr_cas_qn		: out std_logic;    -- /cas
	sys_sdr_we_qn		: out std_logic;    -- /write enable
	sys_sdr_dm_q		: out unsigned(DDR_DM_WIDTH-1 downto 0);     -- data mask bits, set to "00"
	sys_sdr_dqs_q		: inout unsigned(DDR_DQS_WIDTH-1 downto 0);    -- data strobe, only for write
	sys_sdr_ba_q		: out unsigned(DDR_BANK_WIDTH-1 downto 0);   -- bank select
	sys_sdr_a_q			: out unsigned(DDR_ADDR_WIDTH-1 downto 0);   -- address bus 
	sys_sdr_data		: inout unsigned(DDR_DATA_WIDTH-1 downto 0); -- bidir data bus
	sys_sdr_clk_fb		: in std_logic;
	
	-- VGA
	sys_vga_red			: out unsigned(7 downto 0);
	sys_vga_green		: out unsigned(7 downto 0);
	sys_vga_blue		: out unsigned(7 downto 0);
	sys_vga_blank_n		: out std_logic;
	sys_vga_sync_n		: out std_logic;
	sys_vga_hsync		: out std_logic;
	sys_vga_vsync		: out std_logic;
	sys_vga_clk			: out std_logic;

	sys_error			: out unsigned(1 downto 0) -- indicates Errors
	
);
--	attribute BUFFER_TYPE : string;
--	attribute BUFFER_TYPE of sys_clk_in			: signal is "BUFG";
--	attribute BUFFER_TYPE of sys_sdr_dcm_clk_fb	: signal is "BUFG";

END systest;

ARCHITECTURE behavior OF systest IS 

	COMPONENT cpu_embedded
	Port (
		rst			: in  STD_LOGIC;
		clk			: in  STD_LOGIC;
		ce			: in  STD_LOGIC;
		int_in		: in  STD_LOGIC;
		int_ack		: out  STD_LOGIC;
		xmem_we		: out STD_LOGIC;
		xmem_re		: out STD_LOGIC;
		xmem_din	: in  unsigned (DMEM_DATA_WIDTH-1 downto 0);
		xmem_dout	: out unsigned (DMEM_DATA_WIDTH-1 downto 0);
		xmem_addr	: out unsigned (DMEM_ADDR_WIDTH-1 downto 0);
		io_sel		: out STD_LOGIC
	);
	END COMPONENT;

	COMPONENT xrom
	Port (
		clk			: in  STD_LOGIC;
		ce			: in  STD_LOGIC;
		addr		: in  dmem_addr_t;
		dout		: out dmem_data_t
	);
	END COMPONENT;

	COMPONENT lcd_port
	PORT (
			rst			: in std_logic;
			clk			: in std_logic;
			we			: in std_logic;
			din			: in unsigned(7 downto 0);
			dout		: out unsigned(7 downto 0);
			lcd_d		: inout unsigned(3 downto 0);
			lcd_e		: out std_logic;
			lcd_rs		: out std_logic;
			lcd_rw		: out std_logic
		);
	END COMPONENT;

--
-- declaration of UART transmitter with integral 16 byte FIFO buffer
--
  component uart_tx
    Port (            data_in : in std_logic_vector(7 downto 0);
                 write_buffer : in std_logic;
                 reset_buffer : in std_logic;
                 en_16_x_baud : in std_logic;
                   serial_out : out std_logic;
                  buffer_full : out std_logic;
             buffer_half_full : out std_logic;
                          clk : in std_logic);
    end component;
--
-- declaration of UART Receiver with integral 16 byte FIFO buffer
--
  component uart_rx
    Port (            serial_in : in std_logic;
                       data_out : out std_logic_vector(7 downto 0);
                    read_buffer : in std_logic;
                   reset_buffer : in std_logic;
                   en_16_x_baud : in std_logic;
            buffer_data_present : out std_logic;
                    buffer_full : out std_logic;
               buffer_half_full : out std_logic;
                            clk : in std_logic);
  end component;

	signal rst : std_logic;
	signal rst_in : std_logic;
	signal started_up : std_logic := '1';
	signal clk : std_logic;
	signal int_in, int_ack, int_en, io_sel, int_force : std_logic;

	signal cpu_baudrate : dmem_data_t;
	signal cpu_din : dmem_data_t;
	signal cpu_dout : dmem_data_t;
	signal cpu_addr : dmem_addr_t;
	signal cpu_we : std_logic;
	signal cpu_re : std_logic;
	signal ctrl_reg : dmem_data_t;
	signal led_reg : dmem_data_t;
	signal cpu_lcd_out_reg, cpu_lcd_in_reg, reg_uart_tx: dmem_data_t;
	signal cpu_lcd_we : std_logic;
	signal cpu_sdr_buf_we, cpu_sdr_valid : std_logic;
	signal cpu_color				: color_t;
	signal cpu_vga_enable : std_logic;
	signal cpu_error_leds		: unsigned(1 downto 0);
	--
	-- Signals for connection of peripherals
	--
	signal uart_status_port : dmem_data_t;
	--
	-- Signals to form an timer generating an interrupt every microsecond
	--
	constant timer_reload : integer := 99999;
	signal timer_count   : integer range 0 to 99999 :=0;
	signal timer_pulse, timer_en   : std_logic;
	--
	-- Signals for UART connections
	--
	signal          baud_count : integer range 0 to 255 :=0;
	signal        en_16_x_baud : std_logic;
	signal       write_to_uart : std_logic;
	signal             tx_full : std_logic;
	signal        tx_half_full : std_logic;
	signal      read_from_uart : std_logic;
	signal             rx_data : std_logic_vector(7 downto 0);
	signal     rx_data_present : std_logic;
	signal             rx_full : std_logic;
	signal        rx_half_full : std_logic;
	
	-- X-ROM
	signal xrom_data : dmem_data_t;
	signal sdr_data  : dmem_data_t;
	
	-- DDR SDRAM
	constant BURST_LEN		: natural := 8;
	subtype sdr_buf_t is unsigned(SDR_DATA_WIDTH-1 downto 0);
	signal sdr_buf_in, sdr_vga_data : sdr_buf_t := (others => '0');
	signal cpu_sd_ack : std_logic;

	signal cpu_sd_request_strobe	: std_logic;
	signal sdr_tag_in			: user_tag_t;
	signal sdr_tag_wr		: user_tag_t;
	signal sdr_tag_rd		: user_tag_t;
	signal sdr_ucmd           : user_cmd_t;
	signal cpu_sd_cmd           : user_cmd_t;
	signal cpu_sd_cmd_we           : std_logic;
	signal sdr_ucmd_vld       : std_logic;
	signal cpu_sdr_addr      : user_addr_t;
	signal cpu_vga_read_offset  : user_addr_t;
	signal sdr_addr           : user_addr_t;
	signal sdr_busy_q         : std_logic;
	signal sdr_udata_in        : unsigned(SDR_DATA_WIDTH-1 downto 0);
	signal sdr_udata_req_wr     : std_logic;
	signal sdr_udata_out_q     : unsigned(SDR_DATA_WIDTH-1 downto 0);
	signal sdr_udata_vld_q     : std_logic;
	
	signal cmd_fifo_din				: unsigned(29 downto 0);
	signal cmd_fifo_dout			: unsigned(29 downto 0);
	signal cmd_fifo_re				: std_logic;
	signal cmd_fifo_we				: std_logic;
	signal cmd_fifo_full			: std_logic;
	signal cmd_fifo_empty			: std_logic;

	signal cpu_write_fifo_din			: unsigned(SDR_DATA_WIDTH-1 downto 0);
	signal cpu_write_fifo_dout			: unsigned(SDR_DATA_WIDTH-1 downto 0);
	signal cpu_write_fifo_re			: std_logic;
	signal cpu_write_fifo_we			: std_logic;
	signal cpu_write_fifo_full			: std_logic;
	signal cpu_write_fifo_empty			: std_logic;

	signal cpu_read_fifo_din			: unsigned(SDR_DATA_WIDTH-1 downto 0);
	signal cpu_read_fifo_dout			: unsigned(SDR_DATA_WIDTH-1 downto 0);
	signal cpu_read_fifo_re				: std_logic;
	signal cpu_read_fifo_we				: std_logic;
	signal cpu_read_fifo_full			: std_logic;
	signal cpu_read_fifo_empty			: std_logic;
	
	alias tag_fifo_in is cmd_fifo_din(29 downto 26);
	alias cmd_fifo_in is cmd_fifo_din(25 downto 24);
	alias addr_fifo_in is cmd_fifo_din(23 downto 0);
	alias tag_fifo_out is cmd_fifo_dout(29 downto 26);
	alias cmd_fifo_out is cmd_fifo_dout(25 downto 24);
	alias addr_fifo_out is cmd_fifo_dout(23 downto 0);
	
--	attribute rom_style: string;
--	attribute rom_style of cmd_fifo_dout: signal is "DISTRIBUTED";
--	attribute rom_style of cpu_cpu_write_fifo_dout: signal is "DISTRIBUTED";
--	attribute rom_style of cpu_read_fifo_dout: signal is "DISTRIBUTED";

	-- VGA
	signal vga_clk					: std_logic;
	signal vga_ready				: std_logic;
	signal vga_color_w				: color_t;
	signal vga_color				: color_t;
	signal vga_color_we				: std_logic;
	signal vga_fifo_full			: std_logic;
	signal vga_fifo_almost_full		: std_logic;
	signal vga_hsync				: std_logic;
	signal vga_vsync				: std_logic;
	signal vga_pos_x		       	: natural range 0 to tsvga.ts_h.ncyc_scan-1;
	signal vga_pos_y		      	: natural range 0 to tsvga.ts_v.ncyc_scan-1;
	signal vga_scan_x				: std_logic;
	signal vga_scan_y				: std_logic;
	signal vga_scan_rdy				: std_logic;
	signal vga_scan_rdy_h			: std_logic;
	signal vga_scan_rdy_v			: std_logic;
	signal vga_active				: std_logic;
	
	type vga_cmd_state_t is (vga_cmd_s_init, vga_cmd_s_idle, vga_cmd_s_request, vga_cmd_s_access);
	signal vga_cmd_s, vga_cmd_sn : vga_cmd_state_t;

	type vga_data_state_t is (vga_data_s_init, vga_data_s_idle, vga_data_s_read1, vga_data_s_read2);
	signal vga_data_s, vga_data_sn : vga_data_state_t;

	type sd_ctrl_state_t is (s_sd_idle, s_sd_vga_access_grant, s_sd_vga_access, s_sd_cpu_access_grant, s_sd_cpu_access);
	signal st, stn : sd_ctrl_state_t;

	signal sd_vga_access			: std_logic;
	signal sd_cpu_access			: std_logic;
	signal sd_vga_request			: std_logic;
	signal sd_cpu_request			: std_logic;

	-- Character generator
	signal cg_rst					: std_logic;
	signal cg_en					: std_logic;
	signal cg_ready					: std_logic;
	signal cg_clr_screen			: std_logic;
	signal cg_clr_line				: std_logic;
	signal cg_ascii_data			: dmem_data_t;
	signal cg_ascii_data_we			: std_logic;
	signal cg_ascii_posy_we			: std_logic;
	signal cg_ascii_posx_we			: std_logic;
	signal cg_draw_en				: std_logic;
	signal cg_color					: color_t;

	-- DDR to VGA
	signal vga_cmd_cnt		       	: natural range 0 to 255;
	signal vga_pixel_cnt			: natural range 0 to tsvga.ts_h.ncyc_scan*tsvga.ts_v.ncyc_scan-1;
	signal vga_sd_addr				: user_addr_t;
	signal vga_sd_valid				: std_logic;
	signal vga_pixel_cnt_en			: std_logic;
	signal vga_sd_cmd          		: user_cmd_t;
	signal vga_sd_cmd_we            : std_logic;
	
	signal vga_read_fifo_din			: unsigned(SDR_DATA_WIDTH-1 downto 0);
	signal vga_read_fifo_dout			: unsigned(SDR_DATA_WIDTH-1 downto 0);
	signal vga_read_fifo_re				: std_logic;
	signal vga_read_fifo_we				: std_logic;
	signal vga_read_fifo_full			: std_logic;
	signal vga_read_fifo_empty			: std_logic;
	signal vga_read_fifo_almost_full	: std_logic;
	signal vga_read_fifo_almost_empty	: std_logic;

BEGIN

	int_in <= sys_btn(4) or sys_dip(7) or timer_pulse or int_force or rx_data_present;
	rst_in <= not (started_up and sys_rst_n_in);
	uart_status_port <= "000" & rx_data_present & rx_full & rx_half_full & tx_full & tx_half_full ;

	-- VGA mapping
	sys_vga_clk		<= vga_clk;
	sys_vga_red		<= vga_color(r);
	sys_vga_green	<= vga_color(g);
	sys_vga_blue	<= vga_color(b);
	vga_scan_rdy	<= vga_scan_rdy_h and vga_scan_rdy_v;
	sys_error		<= cpu_error_leds;

	cg_en 			<= vga_scan_x and vga_scan_y;
	cg_rst			<= rst;
	
------------------------------------------------------------------
cpu_sdr_buffer:
	process(clk)
	variable index, lo, hi : integer;
	begin
		if rising_edge(clk) then
			index := to_integer(cpu_addr(2 downto 0));
			hi := dmem_data_t'length*(index+1)-1;
			lo := dmem_data_t'length*(index);
			if cpu_sdr_buf_we = '1' then
				sdr_buf_in(hi downto lo) <= cpu_dout;
			end if;
			sdr_data <= cpu_read_fifo_dout(hi downto lo);
		end if;
	end process;	

------------------------------------------------------------------
led_out:
	process(rst, clk)
	begin
		if rst = '1' then
			sys_led <= (others => '0');
		elsif rising_edge(clk) then
			sys_led <= int_in & led_reg;
		end if;
	end process;	
		
------------------------------------------------------------------
timer:
	process(rst, clk, timer_count, timer_en)
	begin
		if rst = '1' then
			timer_count <= timer_reload;
			timer_pulse <= '0';
		elsif rising_edge(clk) then
			timer_pulse <= '0';
			if timer_count /= 0 then
				if timer_en = '1' then
					timer_count <= timer_count - 1;
				end if;	
			else
				timer_pulse <= '1';
				timer_count <= timer_reload;
			end if;	
		end if;
	end process;	

------------------------------------------------------------------
reg_mux:
	process(clk)
	variable data : dmem_data_t;
	variable addr : dmem_addr_t;
	variable is_io : boolean;
	variable cpu_read : std_logic;
	begin
		
		read_from_uart <= '0';
		if rising_edge(clk) then
			addr := cpu_addr;
			is_io := (io_sel = '1');
			cpu_read := cpu_re;
		end if;	
		
		if is_io then
			case addr is
			when X"00" =>	-- 00
				data := "0000" & unsigned(sys_btn(3 downto 0));
			when X"01" =>	-- 01 
				data := led_reg;
			when X"02" =>	-- 02
				data := unsigned(rx_data);
				read_from_uart <= cpu_read;
			when X"03" =>	-- 03
				data := cpu_lcd_in_reg;
			when X"04" =>	-- 04
				data := int_force & '0' & cpu_error_leds & '0' & cpu_vga_enable & timer_en & int_en; 
			when X"05" =>	-- 05 
				data := unsigned(sys_dip);
			when X"06" =>	-- 06 
				data := uart_status_port;
			when X"07" =>	-- 07 
				data := sd_cpu_access & sd_vga_access & cpu_read_fifo_empty & cpu_read_fifo_full & cpu_write_fifo_empty & cpu_write_fifo_full & cmd_fifo_empty & cmd_fifo_full;
			when X"08" =>	-- 08 
				data := cpu_sdr_addr(7 downto 0);
			when X"09" =>	-- 09 
				data := cpu_sdr_addr(15 downto 8);
			when X"0A" =>	-- 10 
				data := cpu_sdr_addr(23 downto 16);
			when X"0E" =>
				data := (not rst) & "00000" & cg_ready & vga_ready;
			when X"13" =>	-- 10 
				data := cpu_baudrate;
			when others => 
				data := X"00";
			end case;
		else
			if cpu_addr(7) = '1' then
				data := sdr_data;
			else				
				data := xrom_data;
			end if;	
		end if;	
		cpu_din <= data;

	end process;
	
------------------------------------------------------------------
ctrl_reg_write:
	process(rst, clk)
	variable addr : unsigned(dmem_addr_t'length-1 downto 0);
	begin
		if (rst = '1') then
			cpu_color				<= (X"80", X"80", X"80");
			cpu_error_leds			<= (others => '0');
			int_force				<= '0';
			int_en					<= '0';
			timer_en				<= '0';
			led_reg					<= (others => '0');
			cpu_lcd_out_reg			<= (others => '0');
			reg_uart_tx				<= (others => '0');
			cpu_sdr_addr			<= (others => '0');
			cg_ascii_data			<= (others => '0');
			cg_ascii_posy_we		<= '0';
			cg_ascii_posx_we		<= '0';
			cg_ascii_data_we		<= '0';
			cg_clr_line				<= '0';
			cg_clr_screen			<= '0';
			cpu_read_fifo_re 		<= '0';
			cpu_write_fifo_we 		<= '0';
			cpu_sd_cmd_we 			<= '0';
			cpu_sd_cmd				<= UCMD_NOP;
			cpu_sd_request_strobe	<= '0';
			cpu_vga_enable			<= '0';
			cpu_baudrate			<= to_unsigned(53, dmem_data_t'length);
			cpu_vga_read_offset		<= (others => '0');
		elsif rising_edge(clk) then
			int_force				<= '0';
			write_to_uart			<= '0';
			cpu_lcd_we				<= '0';
			cpu_sdr_buf_we			<= '0';
			cg_ascii_posy_we		<= '0';
			cg_ascii_posx_we		<= '0';
			cg_ascii_data_we		<= '0';
			cg_clr_line				<= '0';
			cg_clr_screen			<= '0';
			cpu_read_fifo_re 		<= '0';
			cpu_write_fifo_we 		<= '0';
			cpu_sd_cmd_we 			<= '0';
			cpu_sd_request_strobe	<= '0';
			addr := cpu_addr;
			if cpu_we = '1' then	
				if io_sel = '1' then
					case addr is
						when X"01" =>	-- 01
							led_reg <= cpu_dout;
						when X"02" =>	-- 02
							reg_uart_tx <= cpu_dout;
							write_to_uart <= '1';
						when X"03" =>	-- 03
							cpu_lcd_we <= '1';
							cpu_lcd_out_reg <= cpu_dout;
						when X"04" =>	-- 04
							int_force			<= cpu_dout(7);
							cpu_error_leds		<= cpu_dout(5 downto 4);
							cpu_vga_enable		<= cpu_dout(2);
							timer_en			<= cpu_dout(1);
							int_en				<= cpu_dout(0);
						when X"07" =>	-- 07
							cpu_sd_request_strobe <= cpu_dout(7);
							cpu_read_fifo_re 	<= cpu_dout(5);
							cpu_write_fifo_we 	<= cpu_dout(4);
							cpu_sd_cmd_we 	<= cpu_dout(2);
							cpu_sd_cmd		<= cpu_dout(1 downto 0);
						when X"08" =>	-- 08
							cpu_sdr_addr(7 downto 0) <= cpu_dout;
						when X"09" =>	-- 09
							cpu_sdr_addr(15 downto 8) <= cpu_dout;
						when X"0A" =>	-- 10
							cpu_sdr_addr(23 downto 16) <= cpu_dout;
						when X"0B" =>	-- 08
							cg_ascii_data 		<= cpu_dout;
						    cg_ascii_posx_we	<= '1';
						when X"0C" =>	-- 09
							cg_ascii_data 		<= cpu_dout;
						    cg_ascii_posy_we	<= '1';
						when X"0D" =>	-- 0A
							cg_ascii_data 		<= cpu_dout;
							cg_ascii_data_we	<= '1';
						when X"0E" =>	-- 0B
							cg_clr_screen		<= cpu_dout(0);
							cg_clr_line			<= cpu_dout(1);
						when X"10" =>	-- 04
							cpu_color(r)		<= cpu_dout;
						when X"11" =>	-- 04
							cpu_color(g)		<= cpu_dout;
						when X"12" =>	-- 04
							cpu_color(b)		<= cpu_dout;
						when X"13" =>	-- 04
							cpu_baudrate		<= cpu_dout;
						when X"14" =>
							cpu_vga_read_offset(7 downto 0) <= cpu_dout;
						when X"15" =>
							cpu_vga_read_offset(15 downto 8) <= cpu_dout;
						when X"16" =>
							cpu_vga_read_offset(23 downto 16) <= cpu_dout;
						when others => null;
					end case;
				else
					case addr is
						when X"80"|X"81"|X"82"|X"83"|X"84"|X"85"|X"86"|X"87" =>
							cpu_sdr_buf_we <= '1';
						when others => null;
					end case;
				end if;	
			end if;	
		end if;	
	end process;

------------------------------------------------------------------
	cpu_sd_request_flag: process (rst, clk)
	begin
		if (rst = '1') then
			sd_cpu_request <= '0';
		elsif rising_edge(clk) then
			if cpu_sd_request_strobe = '1' then
				sd_cpu_request <= '1';
			elsif cpu_sd_ack = '1' then
				sd_cpu_request <= '0';
			end if;
		end if;	
	end process;

------------------------------------------------------------------
sdram_write_control:
	process(st, sd_cpu_request, sd_vga_request, cpu_sd_cmd_we, vga_sd_cmd_we)
	begin
		cpu_sd_ack 		<= '0';
		sd_vga_access	<= '0';
		sd_cpu_access	<= '0';
		stn				<= st;
		
		case st is
		when s_sd_idle =>
			if sd_vga_request = '1' then
				stn <= s_sd_vga_access_grant;
			elsif sd_cpu_request = '1' then
				stn <= s_sd_cpu_access_grant;
			end if;	
		when s_sd_vga_access_grant =>
			sd_vga_access	<= '1';
			if vga_sd_cmd_we = '1' then
				stn <= s_sd_vga_access;
			end if;	
		when s_sd_vga_access =>
			sd_vga_access	<= '1';
			if vga_sd_cmd_we = '0' then
				stn <= s_sd_idle;
			end if;	
		when s_sd_cpu_access_grant =>
			cpu_sd_ack <= '1';
			sd_cpu_access	<= '1';
			if cpu_sd_cmd_we = '1' then
				stn <= s_sd_cpu_access;
			end if;	
		when s_sd_cpu_access =>
			sd_cpu_access	<= '1';
			if cpu_sd_cmd_we = '0' then
				stn <= s_sd_idle;
			end if;	
		when others => 
			stn <= s_sd_idle;
		end case;	
	end process;	

	process(rst, clk)
	begin
		if rst = '1' then
			st	<= s_sd_idle;
		elsif rising_edge(clk) then
			st	<= stn;
		end if;
	end process;	

------------------------------------------------------------------
	vga_to_sd_cmd: process (vga_cmd_s, vga_cmd_cnt, cpu_vga_enable, vga_scan_rdy, vga_ready, sd_vga_access, cmd_fifo_full, vga_read_fifo_empty, vga_read_fifo_almost_empty)
	begin
		sd_vga_request		<= '0';
		vga_sd_cmd			<= UCMD_NOP;
		vga_sd_cmd_we 		<= '0';			
		vga_pixel_cnt_en	<= '0';
		
		vga_cmd_sn 	<= vga_cmd_s;
		case vga_cmd_s is
		when vga_cmd_s_init =>
			if vga_ready = '1' and vga_scan_rdy = '1' then
				vga_cmd_sn <= vga_cmd_s_idle;
			end if;	
		when vga_cmd_s_idle =>
			if cpu_vga_enable = '1' and vga_read_fifo_almost_empty = '1' then
				vga_cmd_sn <= vga_cmd_s_request;
			end if;	

		when vga_cmd_s_request =>
			sd_vga_request		<= '1';
			if sd_vga_access = '1' then
				vga_cmd_sn <= vga_cmd_s_access;
			end if;	
		
		when vga_cmd_s_access =>
			if cmd_fifo_full = '0' and vga_cmd_cnt /= 64 then
				vga_pixel_cnt_en	<= '1';
				vga_sd_cmd		<= UCMD_READ;
				vga_sd_cmd_we 	<= '1';
			else
				vga_cmd_sn <= vga_cmd_s_idle;
			end if;	

		when others =>
			vga_cmd_sn <= vga_cmd_s_idle;
		
		end case;
			
	end process;

	vga_cmd_nxt: process (rst, clk)
	begin
		if (rst = '1') then
			vga_cmd_s <= vga_cmd_s_init;
		elsif rising_edge(clk) then
			vga_cmd_s <= vga_cmd_sn;
		end if;	
	end process;

------------------------------------------------------------------
	pixel_counter: process (rst, clk)
	begin
		if rst = '1' then
			vga_cmd_cnt	<= 0;
			vga_pixel_cnt	<= 0;
			vga_sd_addr <= (others => '0');
		elsif rising_edge(clk) then
			if vga_pixel_cnt_en = '1' then
				if vga_pixel_cnt < tsvga.ts_h.ncyc_scan*tsvga.ts_v.ncyc_scan-BURST_LEN then
					vga_pixel_cnt	<= vga_pixel_cnt + BURST_LEN;
					vga_cmd_cnt	<= vga_cmd_cnt + 1;
					vga_sd_addr	<= vga_sd_addr + BURST_LEN;
				else	
					vga_pixel_cnt	<= 0;
					vga_sd_addr	<= cpu_vga_read_offset;
				end if;	
			else
				vga_cmd_cnt	<= 0;
			end if;
		end if;
	end process;

------------------------------------------------------------------
	vga_to_sd_data: process (vga_data_s, vga_fifo_full, vga_read_fifo_empty, vga_read_fifo_dout, vga_scan_rdy, vga_fifo_almost_full)
	begin
		vga_read_fifo_re <= '0';
		vga_color_w		<= (vga_read_fifo_dout(23 downto 16), vga_read_fifo_dout(15 downto 8), vga_read_fifo_dout(7 downto 0));
		vga_color_we 	<= '0';			
		
		vga_data_sn 	<= vga_data_s;
		case vga_data_s is
		when vga_data_s_init =>
			if vga_read_fifo_empty = '0' and vga_scan_rdy = '1' then
				vga_data_sn <= vga_data_s_idle;
			end if;	
		when vga_data_s_idle =>
			if vga_fifo_almost_full = '0' then
				vga_data_sn <= vga_data_s_read1;
			end if;	
		when vga_data_s_read1 =>
			vga_color_w		<= (vga_read_fifo_dout(23 downto 16), vga_read_fifo_dout(15 downto 8), vga_read_fifo_dout(7 downto 0));
			if vga_read_fifo_empty = '0' then
				if vga_fifo_full = '0' then
					vga_color_we 	<= '1';			
					vga_data_sn 	<= vga_data_s_read2;
				else
					vga_data_sn <= vga_data_s_idle;
				end if;
			end if;	
		when vga_data_s_read2 =>
			vga_color_w		<= (vga_read_fifo_dout(47 downto 40), vga_read_fifo_dout(39 downto 32), vga_read_fifo_dout(31 downto 24));
			if vga_fifo_full = '0' then
				vga_color_we 	<= '1';			
				vga_read_fifo_re <= '1';
				vga_data_sn <= vga_data_s_read1;
			end if;

		when others =>
			vga_data_sn <= vga_data_s_idle;
		
		end case;
			
	end process;

	vga_data_nxt: process (rst, clk)
	begin
		if (rst = '1') then
			vga_data_s <= vga_data_s_init;
		elsif rising_edge(clk) then
			vga_data_s <= vga_data_sn;
		end if;	
	end process;

------------------------------------------------------------------
inst_cpu_embedded: cpu_embedded
	PORT MAP(
		rst => rst,
		clk => clk,
		ce => '1',
		int_in => int_in,
		int_ack => int_ack,
		xmem_we => cpu_we,
		xmem_re => cpu_re,
		xmem_din => cpu_din,
		xmem_dout => cpu_dout,
		xmem_addr => cpu_addr,
		io_sel => io_sel
	);

	inst_xrom: xrom
	PORT MAP(
		clk			=> clk,
		ce			=> '1',
		addr		=> cpu_addr,
		dout 		=> xrom_data
	);

	inst_lcd_port: lcd_port
	PORT MAP(
		rst => rst,
		clk => clk,
		we => cpu_lcd_we,
		din => cpu_lcd_out_reg,
		dout => cpu_lcd_in_reg,
		lcd_d => sys_lcd_d,
		lcd_e => sys_lcd_e,
		lcd_rs => sys_lcd_rs,
		lcd_rw => sys_lcd_rw
	);
	
  transmit: uart_tx 
  port map (            data_in => std_logic_vector(reg_uart_tx), 
                   write_buffer => write_to_uart,
                   reset_buffer => rst,
                   en_16_x_baud => en_16_x_baud,
                     serial_out => sys_tx,
                    buffer_full => tx_full,
               buffer_half_full => tx_half_full,
                            clk => clk );
	
  receive: uart_rx
  port map (            serial_in => sys_rx,
                         data_out => rx_data,
                      read_buffer => read_from_uart,
                     reset_buffer => rst,
                     en_16_x_baud => en_16_x_baud,
              buffer_data_present => rx_data_present,
                      buffer_full => rx_full,
                 buffer_half_full => rx_half_full,
                              clk => clk );  


	-- Instantiate synchronous FIFO
	inst_command_fifo: entity work.fifo_sync
	GENERIC MAP
	(
		addr_width			=> 8,
		data_width			=> 4+2+24,
		almost_full_thresh	=> 240,
		almost_empty_thresh	=> 16
	)
	PORT MAP
	(
		rst			=>	rst,
		clk			=>	clk,
		we			=>	cmd_fifo_we,
		re			=>	cmd_fifo_re,
		fifo_full	=>	cmd_fifo_full,
		fifo_empty	=>	cmd_fifo_empty,
		fifo_afull	=>	open,
		fifo_aempty	=>	open,
		data_w		=>  cmd_fifo_din,
		data_r		=>  cmd_fifo_dout
	);

	-- Instantiate synchronous FIFO
	inst_cpu_write_fifo: entity work.fifo_sync
	GENERIC MAP
	(
		addr_width			=> 8,
		data_width			=> 2*DDR_DATA_WIDTH,
		almost_full_thresh	=> 252,
		almost_empty_thresh	=> 4
	)
	PORT MAP
	(
		rst			=>	rst,
		clk			=>	clk,
		we			=>	cpu_write_fifo_we,
		re			=>	cpu_write_fifo_re,
		fifo_full	=>	cpu_write_fifo_full,
		fifo_empty	=>	cpu_write_fifo_empty,
		fifo_afull	=>	open,
		fifo_aempty	=>	open,
		data_w		=>  cpu_write_fifo_din,
		data_r		=>  cpu_write_fifo_dout
	);

	-- Instantiate synchronous FIFO
	inst_cpu_read_fifo: entity work.fifo_sync
	GENERIC MAP
	(
		addr_width			=> 8,
		data_width			=> 2*DDR_DATA_WIDTH,
		almost_full_thresh	=> 252,
		almost_empty_thresh	=> 4
	)
	PORT MAP
	(
		rst			=>	rst,
		clk			=>	clk,
		we			=>	cpu_read_fifo_we,
		re			=>	cpu_read_fifo_re,
		fifo_full	=>	cpu_read_fifo_full,
		fifo_empty	=>	cpu_read_fifo_empty,
		fifo_afull	=>	open,
		fifo_aempty	=>	open,
		data_w		=>  cpu_read_fifo_din,
		data_r		=>  cpu_read_fifo_dout
	);

	-- Instantiate synchronous FIFO
	inst_vga_read_fifo: entity work.fifo_sync
	GENERIC MAP
	(
		addr_width			=> 10,
		data_width			=> 2*DDR_DATA_WIDTH,
		almost_full_thresh	=> 960,
		almost_empty_thresh	=> 128
	)
	PORT MAP
	(
		rst			=>	rst,
		clk			=>	clk,
		we			=>	vga_read_fifo_we,
		re			=>	vga_read_fifo_re,
		fifo_full	=>	vga_read_fifo_full,
		fifo_empty	=>	vga_read_fifo_empty,
		fifo_afull	=>	vga_read_fifo_almost_full,
		fifo_aempty	=>	vga_read_fifo_almost_empty,
		data_w		=>  vga_read_fifo_din,
		data_r		=>  vga_read_fifo_dout
	);

	tag_fifo_in			<= "0001" when sd_cpu_access = '1' else "0010" when sd_vga_access = '1' else "0000";
	addr_fifo_in		<= cpu_sdr_addr(23 downto 0) when sd_cpu_access = '1' else vga_sd_addr;
	cmd_fifo_in			<= cpu_sd_cmd when sd_cpu_access = '1' else vga_sd_cmd;
	cmd_fifo_we			<= cpu_sd_cmd_we when sd_cpu_access = '1' else vga_sd_cmd_we;
	sdr_ucmd_vld		<= (not cmd_fifo_empty) and (not sdr_busy_q);
	sdr_ucmd			<= cmd_fifo_out;
	sdr_addr			<= addr_fifo_out;
	sdr_tag_in			<= tag_fifo_out;

	cmd_fifo_re			<= sdr_ucmd_vld;
	sdr_udata_in		<= cpu_write_fifo_dout;
	cpu_read_fifo_we	<= sdr_udata_vld_q when sdr_tag_rd = "0001" else '0';
	vga_read_fifo_we	<= sdr_udata_vld_q when sdr_tag_rd = "0010" else '0';
	cpu_read_fifo_din	<= sdr_udata_out_q;	
	vga_read_fifo_din	<= sdr_udata_out_q;	

	cpu_write_fifo_din	<= sdr_buf_in;
	cpu_write_fifo_re	<= sdr_udata_req_wr and (not cpu_write_fifo_empty);

	-- DDR SDRAM Controller Core
	inst_sdram_ctrl : entity work.sdram_ctrl_top
	Generic map
	(
		BL 				=> BURST_LEN,
		read_phaseshift => ddr_phaseshift,
		f_sysclk 		=> ddr_frequency_hz
	)
	Port map
	(
	
		sys_rst_in			=> rst_in,
		sys_clk_in			=> sys_clk_in,

		sys_rst_out			=> rst,
		sys_clk_out			=> clk,
		sys_clk_fb			=> sys_sdr_clk_fb,
		
		-- User interface
		u_data_vld			=> sdr_udata_vld_q,
		u_data_req_w		=> sdr_udata_req_wr,
		u_data_req_r		=> open,
		u_tag_in			=> sdr_tag_in,
		u_tag_rd			=> sdr_tag_rd,
		u_tag_wr			=> sdr_tag_wr,
		u_busy				=> sdr_busy_q,
		u_addr				=> sdr_addr,
		u_cmd				=> sdr_ucmd,
		u_cmd_we			=> sdr_ucmd_vld,
		u_data_wr			=> sdr_udata_in,
		u_data_rd			=> sdr_udata_out_q,
		
		-- SDRAM signals
		sd_clk_p			=> sys_sdr_clk_p,
		sd_clk_n			=> sys_sdr_clk_n,
		sd_cke				=> sys_sdr_cke_q,
		sd_cs_n				=> sys_sdr_cs_qn,
		sd_cas_n			=> sys_sdr_cas_qn,
		sd_ras_n			=> sys_sdr_ras_qn,
		sd_we_n				=> sys_sdr_we_qn,
		sd_addr				=> sys_sdr_a_q,
		sd_ba				=> sys_sdr_ba_q,
		sd_dm				=> sys_sdr_dm_q,
		sd_dqs				=> sys_sdr_dqs_q,
		sd_data				=> sys_sdr_data
		
	);

	inst_vga_backend: entity work.vga_backend
	GENERIC MAP
	(
		sys_freq					=> sys_freq,
		fifo_depth					=> 2048,
		fifo_almost_full_thresh		=> 1920,
		fifo_almost_empty_thresh	=> 128,
		tsvga						=> tsvga
	)		
	PORT MAP
	(
		sys_rst				=> rst,
		sys_clk				=> clk,
		vga_ready			=> vga_ready,
		color_in			=> vga_color_w,
		color_fifo_we		=> vga_color_we,
		color_fifo_full		=> vga_fifo_full,
		color_fifo_afull	=> vga_fifo_almost_full,
		direct_color_in		=> cg_color,
		direct_draw_en		=> cg_draw_en,
		stat_hsync			=> vga_hsync,	
		stat_vsync			=> vga_vsync,
		stat_hready			=> vga_scan_rdy_h,
		stat_vready			=> vga_scan_rdy_v,
		stat_hscan			=> vga_scan_x,
		stat_vscan			=> vga_scan_y,
		stat_hpos			=> vga_pos_x,
		stat_vpos			=> vga_pos_y,
		vga_clk_out			=> vga_clk,
		vga_color_out		=> vga_color,
		vga_blank_n			=> sys_vga_blank_n,
		vga_sync_n			=> sys_vga_sync_n,
		vga_hsync			=> sys_vga_hsync,
		vga_vsync			=> sys_vga_vsync
		
	);

	inst_char_gen : entity work.char_gen
	GENERIC MAP
	(
		tsvga				=> tsvga,
		CHARACTER_SCALE		=> 1,
		CHAR_ROM_SIZE_X		=> 8,	-- Pixels
		CHAR_ROM_SIZE_Y		=> 16,	-- Pixels
		CHAR_ROM_DEPTH		=> 256,	-- Chars
		MAX_CHAR_PER_LINE	=> 80,	-- Chars
		MAX_LINE_PER_FRAME	=> 32,	-- Chars
		CHAR_SPACING_X		=> 0, 	-- Pixels
		CHAR_SPACING_Y		=> 0,	-- Pixels
		SCREEN_OFFSET_X		=> 16,	-- Pixels
		SCREEN_OFFSET_Y		=> 16	-- Pixels
	)		
	PORT MAP
	(
	    rst				=> rst,
	    sys_clk			=> clk,
	    vga_clk			=> vga_clk,
	    ce				=> cg_en,
	    frame_pulse		=> vga_scan_rdy,
	    clr_screen		=> cg_clr_screen,
	    clr_line		=> cg_clr_line,
	    ascii_data		=> cg_ascii_data,
	    ascii_data_we	=> cg_ascii_data_we,
	    ascii_posy_we	=> cg_ascii_posy_we,
	    ascii_posx_we	=> cg_ascii_posx_we,
	    ready			=> cg_ready,
	    pos_x			=> vga_pos_x,
	    pos_y			=> vga_pos_y,
	    char_draw_en	=> cg_draw_en
    );

	------------------------------------------------------------------
	STARTUP_VIRTEX4_inst : STARTUP_VIRTEX4
	port map (
		EOS => started_up,      -- End of Startup 1-bit output
		CLK => open,      -- Clock input for start-up sequence
		GSR => '0', -- Global Set/Reset input (GSR cannot be used for the port name)
		GTS => '0', -- Global 3-state input (GTS cannot be used for the port name)
		USRCCLKO => '0',   -- USRCCLKO 1-bit input
		USRCCLKTS => '0', -- USRCCLKTS 1-bit input
		USRDONEO => '0',   -- USRDONEO 1-bit input
		USRDONETS => '0'  -- USRDONETS 1-bit input
	);
   
------------------------------------------------------------------
  --
  -- Set baud rate to 38400 for the UART communications
  -- Requires en_16_x_baud to be 614400Hz which is a single cycle pulse every 163 cycles at 100MHz 
  --
  -- NOTE : If the highest value for baud_count exceeds 127 you will need to adjust 
  --        the range of integers in the signal declaration for baud_count.
  --

------------------------------------------------------------------
	proc_cg_color_sample:
	process (vga_clk)
	variable p0, p1 : color_t;
	begin
		if rising_edge(vga_clk) then
			cg_color <= p1;
			p1 := p0;
			p0 := cpu_color;
		end if;
	end process;

  baud_timer: process(clk)
  begin
    if clk'event and clk='1' then
      if baud_count=cpu_baudrate then
           baud_count <= 0;
         en_16_x_baud <= '1';
       else
           baud_count <= baud_count + 1;
         en_16_x_baud <= '0';
      end if;
    end if;
  end process baud_timer;

END;
