------------------------------------------------------------------------------
-- user_logic.vhd - entity/architecture pair
------------------------------------------------------------------------------
--
-- ***************************************************************************
-- ** Copyright (c) 1995-2010 Xilinx, Inc.  All rights reserved.            **
-- **                                                                       **
-- ** Xilinx, Inc.                                                          **
-- ** XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"         **
-- ** AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND       **
-- ** SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,        **
-- ** OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,        **
-- ** APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION           **
-- ** THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,     **
-- ** AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE      **
-- ** FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY              **
-- ** WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE               **
-- ** IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR        **
-- ** REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF       **
-- ** INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS       **
-- ** FOR A PARTICULAR PURPOSE.                                             **
-- **                                                                       **
-- ***************************************************************************
--
------------------------------------------------------------------------------
-- Filename:          user_logic.vhd
-- Version:           1.00.a
-- Description:       User logic.
-- Date:              Mon Sep 12 15:41:52 2011 (by Create and Import Peripheral Wizard)
-- VHDL Standard:     VHDL'93
------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

library proc_common_v3_00_a;
use proc_common_v3_00_a.proc_common_pkg.all;

library graph_acc_v1_00_a;
use graph_acc_v1_00_a.vga_controller_640_60;
use graph_acc_v1_00_a.BRAM_imgs;

------------------------------------------------------------------------------
-- Entity section
------------------------------------------------------------------------------

entity user_logic is
  generic (
    C_SLV_DWIDTH                   	: integer := 32;
    C_NUM_REG                      	: integer := 4);
  port (
    Bus2IP_Clk                     	: in  std_logic;
    Bus2IP_Reset                   	: in  std_logic;
    Bus2IP_Data                    	: in  std_logic_vector(0 to C_SLV_DWIDTH-1);
    Bus2IP_BE                      	: in  std_logic_vector(0 to C_SLV_DWIDTH/8-1);
    Bus2IP_RdCE                    	: in  std_logic_vector(0 to C_NUM_REG-1);
    Bus2IP_WrCE                    	: in  std_logic_vector(0 to C_NUM_REG-1);
    IP2Bus_Data                    	: out std_logic_vector(0 to C_SLV_DWIDTH-1);
    IP2Bus_RdAck                   	: out std_logic;
    IP2Bus_WrAck                   	: out std_logic;
    IP2Bus_Error                   	: out std_logic;
    
    HS								: out std_logic;
	VS								: out std_logic;
	VGA_rgb							: out std_logic_vector(0 to 7));

  attribute SIGIS 					: string;
  attribute SIGIS of Bus2IP_Clk    	: signal is "CLK";
  attribute SIGIS of Bus2IP_Reset  	: signal is "RST";

end entity user_logic;

------------------------------------------------------------------------------
-- Architecture section
------------------------------------------------------------------------------

architecture IMP of user_logic is
----------------------------------------
-- Components
----------------------------------------
	component vga_controller_640_60 is
		port(
	   		rst         	: in std_logic;
	   		pixel_clk   	: in std_logic;
	   		HS          	: out std_logic;
	   		VS          	: out std_logic;
	   		hcount      	: out std_logic_vector(10 downto 0);
	   		vcount      	: out std_logic_vector(10 downto 0);
	   		blank       	: out std_logic);
	end component;
	
	component BRAM_imgs is
		port (
			clka			: IN std_logic;
			addra			: IN std_logic_VECTOR(12 downto 0);
			douta			: OUT std_logic_VECTOR(7 downto 0));
	end component;

	----------------------------------------
	-- Signals
	----------------------------------------
	signal bram_sprite_addr 			: std_logic_vector(12 downto 0);
	signal bram_sprite_dout 			: std_logic_vector(7 downto 0);

	signal pixel_clk 					: std_logic;
	signal hcount,vcount 				: std_logic_vector(10 downto 0);
	signal blank 						: std_logic;
	signal VGA_out,VGA_keep 			: std_logic_vector(0 to 7);

	subtype element is std_logic_vector(3 downto 0);
	type board is array(integer range 0 to 15,integer range 0 to 15) of element;

	signal gameboard,gb_keep 			: board;
	signal p1h,p2h,p1h_keep,p2h_keep 	: std_logic_vector(9 downto 0);
	signal p1v,p2v,p1v_keep,p2v_keep 	: std_logic_vector(8 downto 0);

	signal slv_reg0                     : std_logic_vector(0 to C_SLV_DWIDTH-1);
	signal slv_reg_write_sel            : std_logic_vector(0 to 3);

	begin

	Sprite : BRAM_imgs
		port map (
			clka			=> Bus2IP_Clk,
			addra 			=> bram_sprite_addr,
			douta 			=> bram_sprite_dout);
	  

	VGA_ctrl : vga_controller_640_60
		port map(
			rst     		=> Bus2IP_Reset,
	   		pixel_clk	   	=> Bus2IP_Clk,   -- "to fast"
			HS      	    => HS,
			VS      	    => VS,
			hcount	      	=> hcount,
	   		vcount      	=> vcount,
	   		blank			=> blank);

	memory_access : process(vcount,hcount,p1v,p1h,p2h,p2v)
	begin
		if ((p1h >= hcount(10 downto 1)) 
			AND (p1h < (hcount(10 downto 1) + 32)) 
			AND (p1v >= vcount(9 downto 0)) 
			AND (p1v < (vcount(9 downto 0) + 32))) then
			
			bram_sprite_addr <= "101" & (vcount(4 downto 0) - p1v(4 downto 0)) & (hcount(5 downto 1) - p1h(4 downto 0));
		else
			if ((p2h >= hcount(10 downto 1)) 
				AND (p2h < (hcount(10 downto 1) + 32)) 
				AND (p2v >= vcount(9 downto 0)) 
				AND (p2v < (vcount(9 downto 0) + 32))) then
				
				bram_sprite_addr <= "101" & (vcount(4 downto 0) - p2v(4 downto 0)) & (hcount(5 downto 1) - p2h(4 downto 0));
			else
				case (gameboard(conv_integer(vcount(8 downto 5)),conv_integer(hcount(9 downto 6)))) is
				when "0001" => bram_sprite_addr <= "0000000000000";									-- Ground
				when "0010" => bram_sprite_addr <= "011" & vcount(4 downto 0) & hcount(5 downto 1); -- Stone
				when "0011" => bram_sprite_addr <= "100" & vcount(4 downto 0) & hcount(5 downto 1); -- Brick
				when "0100" => bram_sprite_addr <= "000" & vcount(4 downto 0) & hcount(5 downto 1); -- Bomb
				when "0101" => bram_sprite_addr <= "010" & vcount(4 downto 0) & hcount(5 downto 1); -- Fire C
				when "0110" => bram_sprite_addr <= "001" & vcount(4 downto 0) & hcount(5 downto 1); -- Fire H
				when "0111" => bram_sprite_addr <= "001" & hcount(5 downto 1) & vcount(4 downto 0); -- Fire V
				when others => bram_sprite_addr <= "0000000101101";
				end case;
			end if;
		end if;
	end process;


	rendering_comb : process(vcount,hcount,VGA_keep,blank)
	begin
		VGA_out <= VGA_keep;
		
		if (blank = '1') then
			VGA_out = "00000000";
		else {
			if ((p1h >= hcount(10 downto 1)) 	-- Player 1 should be displayed
				AND (p1h < (hcount(10 downto 1) + 32)) 
				AND (p1v >= vcount(9 downto 0)) 
				AND (p1v < (vcount(9 downto 0) + 32))) then
			
				VGA_out <= bram_sprite_dout;
			else
				if ((p2h >= hcount(10 downto 1)) -- Player 2 should be displayed
					AND (p2h < (hcount(10 downto 1) + 32)) 
					AND (p2v >= vcount(9 downto 0)) 
					AND (p2v < (vcount(9 downto 0) + 32))) then
				
					if bram_sprite_dout = "11100000" then -- Player 2 should be blue
						VGA_out <= "00000001";
					else
						VGA_out <= bram_sprite_dout;
					end if;
				
				else -- Neither player1 or player 2 should be displayed 
					VGA_out <= bram_sprite_dout; -- Display gameboard image
				end if;
			
			end if;
		end if;
	end process rendering_comb;

	-- protocoll [player/board][player1/player2][playerHpos/([boardRow][boardCol][boardValue])][playerVpos/([boardRow][boardCol][boardValue])]
	-- protocoll bits [0][1][[10-19]/([8-11][12-15][16-19])][[23-31]/([20-23][24-27][28-31])]
	cpu_input : process(slv_reg0)
	begin
		gameboard <= gb_keep;
		p1h <= p1h_keep;
		p2h <= p2h_keep;
		p1v <= p1v_keep;
		p2v <= p2v_keep;
		
		if slv_reg0(0) = '1' then			-- Player info
		
			if slv_reg0(1) = '1' then		-- Player 1 position
				p1h <= slv_reg0(10 to 19);
				p1v <= slv_reg0(23 to 31);
			else							-- Player 2 position
				p2h <= slv_reg0(10 to 19);
				p2v <= slv_reg0(23 to 31);
			end if;
			
		else								-- Board info
			gameboard(conv_integer(slv_reg0(20 to 23)),conv_integer(slv_reg0(24 to 27))) <= slv_reg0(28 to 31);			
			if (slv_reg0(1) = '1') then 	-- Board info 2
				gameboard(conv_integer(slv_reg0(8 to 11)),conv_integer(slv_reg0(12 to 15))) <= slv_reg0(16 to 19);
			end if;
			
		end if;
	end process cpu_input;

	slv_reg_write_sel <= Bus2IP_WrCE(0 to 3);
	-- synchronous process 
	slv_reg_write : process (Bus2IP_Clk) is
	begin
		if Bus2IP_Clk'event and Bus2IP_Clk = '1' then
			VGA_keep <= VGA_out;
			gb_keep  <= gameboard;
			p1h_keep <= p1h;
			p2h_keep <= p2h;
			p1v_keep <= p1v;
			p2v_keep <= p2v;
		  	VGA_rgb <= VGA_out; 
		  	
			if Bus2IP_Reset = '1' then
				slv_reg0 <= (others => '0');
			else
				if slv_reg_write_sel = "1000" AND Bus2IP_BE = "1111" then
					slv_reg0 <= Bus2IP_Data;
				end if;
			end if;
			
		end if;
	end process slv_reg_write;

end IMP;
