------------------------------------------------------------------------------
-- mem_to_vga - entity/architecture pair
------------------------------------------------------------------------------
--
-- ***************************************************************************
-- ** Copyright (c) 1995-2012 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:          mem_to_vga
-- Version:           1.00.a
-- Description:       Example FSL core (VHDL).
-- Date:              Fri Oct 11 12:47:16 2013 (by Create and Import Peripheral Wizard)
-- VHDL Standard:     VHDL'93
------------------------------------------------------------------------------
-- Naming Conventions:
--   active low signals:                    "*_n"
--   clock signals:                         "clk", "clk_div#", "clk_#x"
--   reset signals:                         "rst", "rst_n"
--   generics:                              "C_*"
--   user defined types:                    "*_TYPE"
--   state machine next state:              "*_ns"
--   state machine current state:           "*_cs"
--   combinatorial signals:                 "*_com"
--   pipelined or register delay signals:   "*_d#"
--   counter signals:                       "*cnt*"
--   clock enable signals:                  "*_ce"
--   internal version of output port:       "*_i"
--   device pins:                           "*_pin"
--   ports:                                 "- Names begin with Uppercase"
--   processes:                             "*_PROCESS"
--   component instantiations:              "<ENTITY_>I_<#|FUNC>"
------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

-------------------------------------------------------------------------------------
--
--
-- Definition of Ports
-- FSL_Clk             : Synchronous clock
-- FSL_Rst           : System reset, should always come from FSL bus
-- FSL_S_Clk       : Slave asynchronous clock
-- FSL_S_Read      : Read signal, requiring next available input to be read
-- FSL_S_Data      : Input data
-- FSL_S_CONTROL   : Control Bit, indicating the input data are control word
-- FSL_S_Exists    : Data Exist Bit, indicating data exist in the input FSL bus
--
-------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Entity Section
------------------------------------------------------------------------------

entity mem_to_vga is
	port 
	(
		-- DO NOT EDIT BELOW THIS LINE ---------------------
		-- Bus protocol ports, do not add or delete. 
		FSL_Clk	: in	std_logic;
		FSL_Rst	: in	std_logic;
		FSL_S_Clk	: in	std_logic;
		FSL_S_Read	: out	std_logic;
		FSL_S_Data	: in	std_logic_vector(0 to 31);
		FSL_S_Control	: in	std_logic;
		FSL_S_Exists	: in	std_logic;
		-- DO NOT EDIT ABOVE THIS LINE ---------------------
		
		pixel_clk 	: in std_logic;
		HS          : out std_logic;
		VS          : out std_logic;
		rgb			: out std_logic_vector(7 downto 0)
	);

attribute SIGIS : string; 
attribute SIGIS of FSL_Clk : signal is "Clk"; 
attribute SIGIS of FSL_S_Clk : signal is "Clk"; 
end mem_to_vga;

------------------------------------------------------------------------------
-- Architecture Section
------------------------------------------------------------------------------

-- In this section, we povide an example implementation of ENTITY mem_to_vga
-- that Read all inputs and add each input to the contents of register 'sum' which
-- acts as an accumulator
--
-- You will need to modify this example or implement a new architecture for
-- ENTITY mem_to_vga to implement your coprocessor

architecture EXAMPLE of mem_to_vga is

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(9 downto 0);
			 vcount      : out std_logic_vector(10 downto 0);
--			 blank       : out std_logic;
			 new_frame 	 : out std_logic
		  );
end component;

COMPONENT bram
  PORT (
    clka : IN STD_LOGIC;
    wea : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
    addra : IN STD_LOGIC_VECTOR(13 DOWNTO 0);
    dina : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
    douta : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
  );
END COMPONENT;

	constant SCREEN_WIDTH : integer := 512;
	constant SCREEN_HEIGHT : integer := 256;

   type STATE_TYPE is (Idle, READ_FSL, RESP_PX);

   signal state,nstate       : STATE_TYPE;
	
	signal fsl_count, nfsl_count : integer range 0 to SCREEN_HEIGHT/2 -1;

	signal hcount_t			: std_logic_vector(9 downto 0);
	signal vcount_t 			: std_logic_vector(10 downto 0);
	signal hcount 				: unsigned(9 downto 0);
	signal vcount 				: unsigned(10 downto 0);
	signal blank, new_frame : std_logic;

	
	signal offset, noffset : integer range 0 to SCREEN_WIDTH-1;
	
--	signal addr1, naddr1 : integer range 0 to SCREEN_HEIGHT-1;
--	signal addr2, naddr2 : integer range 0 to SCREEN_WIDTH-1;
	signal ram_addr, nram_addr : unsigned(13 downto 0);
	signal ram_we, nram_we : std_logic;
	signal ram_din, nram_din : unsigned(7 downto 0);
	signal ram_dout : unsigned(7 downto 0);

	signal ram_offset, nram_offset : integer range 0 to 3:= 0;
	
	type color_conv_t is array(0 to 15) of std_logic_vector(7 downto 0);
	constant color_conv : color_conv_t := (
		"00000000",
		"00000010",
		"00000001",
		"00000011",
		
		"00010011",
		"00001011",
		"00011001",
		"00000101",
				
		"00010110",
		"10010110",
		"01010110",
		"11010100",
				
		"00100100",
		"10101000",
		"01100000",
		"11100000"
	);

begin

	hcount <= unsigned(hcount_t);
	vcount <= unsigned(vcount_t);

  vga: vga_controller_640_60
    port map (
			rst => FSL_Rst,
			pixel_clk => pixel_clk,
			HS          => HS,
			VS          => VS,
			hcount     => hcount_t,
			vcount     => vcount_t,
--			blank      => blank,
			new_frame 	=> new_frame
	);
	
--ram: block_ram
--	port map (
--			Clk => FSL_Clk,
--			addr1 => addr1,
--			addr2 => addr2,
--			we => ram_we,
--			data_i => ram_din,
--			data_o => ram_dout
--		  );
		  
ram : bram
  PORT MAP (
    clka => FSL_Clk,
    wea(0) => ram_we,
    addra => std_logic_vector(ram_addr),
    dina => std_logic_vector(ram_din),
    unsigned(douta) => ram_dout
  );
	
	process (FSL_Clk, FSL_Rst)
	begin
		if (FSL_Rst = '1') then
			state <= IDLE;
			fsl_count <= 0;
			offset <= 0;
			
			ram_addr <= (others => '0');
			ram_we <= '0';
			ram_din <= X"00";
			ram_offset <= 0;
		
		elsif (rising_edge(FSL_Clk)) then
			state <= nstate;
			fsl_count <= nfsl_count;
			offset <= noffset;
			
			ram_addr <= nram_addr;
			ram_we <= nram_we;
			ram_din <= nram_din;
			ram_offset <= nram_offset;
		end if;
	end process;
	
	process (state, vcount, hcount, FSL_S_Data, FSL_S_Exists, offset, fsl_count, ram_dout, ram_addr, ram_we, ram_din, ram_offset)
	
	variable offset_temp : integer range 0 to SCREEN_WIDTH+1;
	variable vcount_mod : unsigned(5 downto 0);
	variable hcount_mod : unsigned(7 downto 0);
	variable row : unsigned(5 downto 0);
	variable col : unsigned(7 downto 0);
	variable temp : integer;
	
	begin
		nstate <= state;
		FSL_S_Read <= '0';
		rgb <= "10010010";
		noffset <= offset;
		nfsl_count <= fsl_count;
		nram_we <= '0';
		nram_addr <= ram_addr;
		row := ram_addr(13 downto 8);
		col := ram_addr(7 downto 0);
		nram_din <= ram_din;
		nram_offset <= ram_offset;
		
		case state is
		when IDLE =>
			if (hcount = 0 and vcount = 0) then
				nstate <= RESP_PX;
			end if;
			
		when READ_FSL =>			
			if offset = 0 then
				offset_temp := SCREEN_WIDTH-1;
			else
				offset_temp := offset-1;
			end if;
			
			if (fsl_count >= SCREEN_HEIGHT/4) then -- 2 pixels per byte/write instruction, 2 pixels high resolution
				nstate <= IDLE;
				noffset <= offset_temp;
				nfsl_count <= 0;
				
			elsif (ram_offset > 0) then
				nram_we <= '1';
				row := to_unsigned(fsl_count+ram_offset, 6);
				col := to_unsigned(offset_temp, 8);
				nram_din <= unsigned(FSL_S_Data(24-ram_offset*8 to 31-ram_offset*8));

				if (ram_offset = 3) then
					nfsl_count <= fsl_count+4;
					nram_offset <= 0;
				else
					nram_offset <= ram_offset+1;
				end if;

			elsif (FSL_S_Exists = '1') then
				
				nram_we <= '1';
				row := to_unsigned(fsl_count, 6);
				col := to_unsigned(offset_temp, 8);
				nram_din <= unsigned(FSL_S_Data(24 to 31));
				
				nram_offset <= ram_offset+1;
				
				FSL_S_Read <= '1';
			end if;
		
		when RESP_PX =>
			
			vcount_mod := vcount(7 downto 2); --"0" & vcount(10 downto 1);
			hcount_mod := hcount(8 downto 1); --"00" & hcount(10 downto 2);
		
			if (hcount < SCREEN_WIDTH and vcount < SCREEN_HEIGHT) then
				
				row := vcount_mod;
				if (hcount_mod+offset < SCREEN_WIDTH) then
					temp := to_integer(hcount_mod+offset);
					col := to_unsigned(temp, 8);
				else
					temp := to_integer(hcount_mod+offset-SCREEN_WIDTH);
					col := to_unsigned(temp, 8);
				end if;
				
				if (vcount(1) = '0') then
					rgb <= color_conv(to_integer(ram_dout(3 downto 0)));
				else
					rgb <= color_conv(to_integer(ram_dout(7 downto 4)));
				end if;

			else
				rgb <= X"00";
				
			end if;
			
				
			if (vcount >= SCREEN_HEIGHT) then
				nstate <= READ_FSL;
			end if;
		end case;
		
		nram_addr <= row & col;
		
	end process;

end architecture EXAMPLE;
