----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 30.11.2021 10:35:30
-- Design Name: 
-- Module Name: Gene_Snake - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------
-- a faire:
--  - faire bouger le snake
--  - ajouter une clk

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

library ourTypes;
use ourTypes.types.all;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Gene_Snake is
generic( addressSize : integer:=10);
Port ( X : in unsigned (9 downto 0);
       Y : in unsigned (8 downto 0);
       clk: in std_logic;
       reset: in std_logic;
       
       currentSnake : in pos;
       updateOrder : in std_logic;
       listRef : in unsigned(addressSize-1 downto 0);
       
       colorOut : out color;
       
       currentAddress : out unsigned(addressSize-1 downto 0);
       matAddress : out unsigned(addressSize-1 downto 0);
       
       ROMAddress : out unsigned(SPRITES_ADDRESS_SIZE-1 downto 0);
       ROMData : in std_logic_vector(SPRITES_DATA_SIZE-1 downto 0)
       );
end Gene_Snake;

architecture Behavioral of Gene_Snake is

-- D???claration des signaux
signal snakeHere: std_logic; --1 si on doit afficher le pixel 0 sinon
signal dx : signed(2 downto 0);
signal dy : signed(2 downto 0);
signal running : std_logic;
signal startUpdate : std_logic;
signal snakeColor : color;

begin


-- Process de calcul d'affichage
process(X,Y,clk,reset,running,dx,dy,updateOrder,currentSnake,snakeHere)
begin
if(updateOrder'event and updateOrder = '1') then --si on as un signal sur pxl_clk (i.e. on vient de changer de pixel)
    if(snakeHere = '1') then
        snakeColor <= to_color(ROMData);
    else
        snakeColor.R <= (others => '0');
        snakeColor.G <= (others => '0');
        snakeColor.B <= (others => '0');
    end if;
    startUpdate <= '1';  --on marque qu'il faut refaire une update (on doit separer en deux signaux parce que sinon on aurait un edit sur deux clk differentes). C'est pas très élégant mais j'ai pas trouvé mieux
end if;

if(reset = '0') then
    running <= '0';
    snakeHere <= '0';
    snakecolor <= (others => (others => '0'));
elsif(clk'event and clk = '1') then
    if(startUpdate = '1') then
        running <= '1';
        snakeHere <= '0';
        dx <= to_signed(-1,3);
        dy <= to_signed(-1,3);
    end if;
    if(running = '1') then
        if(currentSnake.isDefined = '1') then
            if(X>=currentSnake.X-8 and X<currentSnake.X+8 and Y>=currentSnake.Y-8 and Y<currentSnake.Y+8) then
                snakeHere <= '1';
                ROMAddress <= resize(shift_left(to_integer(shift_right(currentSnake.dirY,2))*(Y-currentSnake.Y)+8,4)+(to_integer(shift_right(currentSnake.dirY,2))*(X-currentSnake.X)+8),8);
            end if;
        end if;
        
        dx <= dx + 1;
        if(dx = 2) then
            dx <= to_signed(-1,3);
            dy <= dy + 1;
        end if;
        
        if(dy = 2) then
            dy <= to_signed(-1,3);
            running <= '0';
        end if;
    end if;
end if;

if(running = '1') then
    startUpdate <= '0';
end if;

end process;

process(X,Y,dx,dy)
variable mX : integer;
variable mY : integer;
variable mInd : integer;
begin
    mX := to_integer(X)/16;
    mY := to_integer(Y)/16;
    mInd := mY*40 + mX;
    matAddress <= TO_UNSIGNED(mInd,SNAKE_ADDRESS_SIZE);--+to_integer(dy))*40+shift_right(X,4)+to_integer(dx);
    --matAddress <= '0' & X/16;--resize(shift_right(Y,4)*40+shift_right(X,4),SNAKE_ADDRESS_SIZE);
end process;

currentAddress <= listRef;

colorOut <= snakeColor;
end Behavioral;
