----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 19.10.2017 08:01:54
-- Design Name: 
-- Module Name: VGA_top - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


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;

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

library ourTypes;
use ourTypes.types.all;

entity VGA_top is
    Port ( H125MHz : in STD_LOGIC;
           resetGeneral : in std_logic;
           led : out std_logic_vector (3 downto 0);
           vga_hs : out STD_LOGIC;
           vga_vs : out STD_LOGIC;
           vga_r : out STD_LOGIC_VECTOR (4 downto 0);
           vga_g : out STD_LOGIC_VECTOR (5 downto 0);
           vga_b : out STD_LOGIC_VECTOR (4 downto 0);
           
           button_up : in STD_LOGIC;
           button_down : in STD_LOGIC;
           button_left : in STD_LOGIC;
           button_right : in STD_LOGIC
           );
end VGA_top;

architecture Behavioral of VGA_top is

component clk_wiz_0
port
 (-- Clock in ports
  clk_in1           : in     std_logic;
  -- Clock out ports
  clk_out1          : out    std_logic
 );
end component;

ATTRIBUTE SYN_BLACK_BOX : BOOLEAN;
ATTRIBUTE SYN_BLACK_BOX OF clk_wiz_0 : COMPONENT IS TRUE;

ATTRIBUTE BLACK_BOX_PAD_PIN : STRING;
ATTRIBUTE BLACK_BOX_PAD_PIN OF clk_wiz_0 : COMPONENT IS "clk_in1,clk_out1";

component GeneSync is
    Port ( CLK   : in std_logic;
           HSYNC : out std_logic;
           VSYNC : out std_logic;
		   IMG   : out std_logic;
           X     : out std_logic_vector(9 downto 0);
           Y     : out std_logic_vector(8 downto 0));
end component;

component GeneRGB_V1  is
    Port ( 
	       X     : in unsigned(9 downto 0);
           Y     : in unsigned(8 downto 0);
           IMG   : in std_logic;
		   R     : out std_logic_vector(4 downto 0);
           G     : out std_logic_vector(5 downto 0);
           B     : out std_logic_vector(4 downto 0);
           snakeIn : in color;
           pommeIn : in color
           );
end component;

component Gene_Snake
generic ( addressSize : integer:=SNAKE_ADDRESS_SIZE);
Port ( X : in unsigned (9 downto 0);
       Y : in unsigned (8 downto 0);
       clk: in std_logic;
       reset: in std_logic;
       
       currentSnakes : in nSnakes;
       listRefs : in addresses;
       updateOrder : in std_logic;
       dataReady : in std_logic;
       tailIndex : in unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);

       cCaseX : out unsigned(5 downto 0);
       cCaseY : out unsigned(4 downto 0);
       dataRequest : out std_logic := '0';

       colorOut : out color;
        
       ROMAddress : out unsigned(SPRITES_ADDRESS_SIZE-1 downto 0) := (others => '0');
       ROMData : in std_logic_vector(SPRITES_DATA_SIZE-1 downto 0)
       );
end component Gene_Snake;

signal dummyPos : pos; --juste pour avoir la taille du type
component updateSnake
generic ( dataSize : integer := to_stdlogicvector(dummyPos)'length);
Port (
        clk_lente : in std_logic;
        clk_rapide : in std_logic;
        reset : in std_logic;
        
        address : out unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
        dataIn : in std_logic_vector(dataSize-1 downto 0);
        dataOut : out std_logic_vector(dataSize-1 downto 0);
        writeEnable : out std_logic := '1';
        
        matAddress : out unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
        matDataIn : inout std_logic_vector(SNAKE_ADDRESS_SIZE-1 downto 0);
        matDataOut : out std_logic_vector(SNAKE_ADDRESS_SIZE-1 downto 0);
        matWriteEnable : out std_logic := '1';
        
        button_up : in STD_LOGIC;
        button_down : in STD_LOGIC;
        button_left : in STD_LOGIC;
        button_right : in STD_LOGIC;
        
        pommeCE : out std_logic;
        pommeX  : in unsigned(5 downto 0);
        pommeY : in unsigned(4 downto 0);
        resetPomme : out std_logic;
        
        tailIndex : out unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
        
        lost : out std_logic
        );
end component updateSnake;

component pomme
generic ( dataSize : integer := to_stdlogicvector(dummyPos)'length);
Port (
    clk : in std_logic;
    pxl_clk : in std_logic;
    reset : in std_logic;
    
    CE : in std_logic;
    
    X : in unsigned (9 downto 0);
    Y : in unsigned (8 downto 0);
    
    posX : out unsigned(5 downto 0);
    posY : out unsigned(4 downto 0);
    
    colorOut : out color;
    
    address : out unsigned(SNAKE_ADDRESS_SIZE-1 downto 0) := (others => '0');
    data : in std_logic_vector(dataSize-1 downto 0);
    
    matAddress : out unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
    matData : in std_logic_vector(SNAKE_ADDRESS_SIZE-1 downto 0) := (others => '0');
    
    ROMAddress : out unsigned(7 downto 0) := (others => '0');
    ROMData : in std_logic_vector(SPRITES_DATA_SIZE-1 downto 0)
);
end component pomme;

component RAMController
generic( snakeDataSize : integer := to_stdlogicvector(dummyPos)'length);
Port ( X : in unsigned(5 downto 0);
       Y : in unsigned(4 downto 0);

       request : in std_logic;
       
       clk : in std_logic;

       output : out nSnakes;
       listRefs : out addresses;

       dataReady : out std_logic;

       matWE : in std_logic;
       matWAddress : in unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
       matWData : in std_logic_vector(SNAKE_ADDRESS_SIZE-1 downto 0);
       matRData : out std_logic_vector(SNAKE_ADDRESS_SIZE-1 downto 0);

       listWE : in std_logic;
       listWAddress : in unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
       listWData : in std_logic_vector(snakeDataSize-1 downto 0);
       listRData : out std_logic_vector(snakeDataSize-1 downto 0)
);
end component RAMController;

component spritesRom
generic( addressSize : integer := SPRITES_ADDRESS_SIZE;
         length : integer := SPRITES_DATA_LENGTH;
         dataSize : integer := SPRITES_DATA_SIZE;
         fileName : string := "../projet-electronique/sprites/sprites.mem" --pour l'implementation
         --fileName : string := "../sprites/sprites.mem" --pour la simulation
);
Port ( address : in unsigned (addressSize-1 downto 0);
       data : out STD_LOGIC_VECTOR (dataSize-1 downto 0);
       clk : in STD_LOGIC);
end component spritesRom;

component Diviseur
  generic (nbBits : integer:=8);
  Port (  clk_in : in STD_LOGIC;
          reset : in STD_LOGIC;
          max : in unsigned (nbBits-1 downto 0);
          clk_out : out STD_LOGIC);
end component Diviseur;

signal Xi          : std_logic_vector(9 downto 0);
signal Yi          : std_logic_vector(8 downto 0);
signal Xpxl        : unsigned(9 downto 0);
signal Ypxl        : unsigned(8 downto 0);
signal IMGi        : std_logic;  
signal pxl_clk     : std_logic;

signal clk_lente: std_logic;
--signal valPosX: unsigned (9 downto 0);
--signal valPosY: unsigned (8 downto 0);
signal snakeColor: color;

signal cCaseX : unsigned(5 downto 0);
signal cCaseY : unsigned(4 downto 0);

signal dataReady,dataRequest : std_logic;

signal currentSnakes : nSnakes;
signal listRefs : addresses;

signal updateRAMAddress : unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
signal updateRAMDataIn : std_logic_vector(to_stdlogicvector(dummyPos)'length-1 downto 0);
signal updateRAMDataOut : std_logic_vector(to_stdlogicvector(dummyPos)'length-1 downto 0);
signal updateRAMWE : std_logic;
signal updateRAMRE : std_logic;

signal matupdRAMAddress : unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
signal matupdRAMDataIn : std_logic_vector(SNAKE_ADDRESS_SIZE-1 downto 0);
signal matupdRAMDataOut : std_logic_vector(SNAKE_ADDRESS_SIZE-1 downto 0);
signal matupdRAMWE : std_logic;
signal matupdRAMRE : std_logic;

signal RAMAddress : unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
signal RAMDataIn : std_logic_vector(to_stdlogicvector(dummyPos)'length-1 downto 0);
signal matRAMAddress : unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
signal matRAMDataIn : std_logic_vector(SNAKE_ADDRESS_SIZE-1 downto 0);

signal spritesROMAddress : unsigned(SPRITES_ADDRESS_SIZE-1 downto 0);
signal spritesROMData : std_logic_vector(SPRITES_DATA_SIZE-1 downto 0);

signal pommeROMAddress : unsigned(7 downto 0);
signal pommeROMData : std_logic_vector(SPRITES_DATA_SIZE-1 downto 0);

signal pommeCE : std_logic;
signal pommeX : unsigned(5 downto 0);
signal pommeY : unsigned(4 downto 0);
signal pommeColor : color;
signal pommeReset : std_logic;

signal pommeAddress : unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
signal pommeData : std_logic_vector(to_stdlogicvector(dummyPos)'length-1 downto 0);
signal pommeMatAddress : unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
signal pommeMatData : std_logic_vector(SNAKE_ADDRESS_SIZE-1 downto 0);

signal tailIndex : unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);

signal lost : std_logic;
signal clkCnt : unsigned(24 downto 0);
--signal clk_latch : std_logic;

begin

Xpxl <= unsigned(Xi);
Ypxl <= unsigned(Yi);

U0 : clk_wiz_0
   port map ( 
   -- Clock in ports
   clk_in1 => H125MHz,
   -- Clock out ports  
   clk_out1 => pxl_clk              
 );
--Pour la simulation on evite les IP
--PXL_CLK_DIV : Diviseur
--    -- in : 125MHz; out : 25MHz; ratio : 5; nbBits : 3
--    generic map (nbBits => 3)
--    port map (
--      clk_in => H125MHz,
--      reset => resetGeneral,
--      max => to_unsigned(6,3),
--      clk_out => pxl_clk
--    );
 
SYNC : GeneSync 
    port map(
    CLK    => pxl_clk,
    HSYNC  => vga_hs,
    VSYNC  => vga_vs,
    IMG    => IMGi,
	X      => Xi,
    Y      => Yi);
	 
RGB : GeneRGB_V1  
    port map(
	X     => Xpxl,
    Y     => Ypxl,
    IMG   => IMGi,
    R     => vga_r,
    G     => vga_g,
    B     => vga_b,
    snakeIn => snakeColor,
    pommeIn => pommeColor
    );
    
UPD_CLK_DIV : Diviseur
    -- pxl_clock 25MHz, clk_lente ~60Hz, 1 coup sur clk_lente = 25e6/60 = 4.2e5 coups sur pxl_clk. ln(4.2e5)/ln(2)=18.6, donc on prend 19bits. nv on part sur 25
    generic map (nbBits => 25)
    port map (
      clk_in => pxl_clk,
      reset => resetGeneral,
      max => clkCnt,
      --max => to_unsigned(420000,25),
      --max => to_unsigned(25000000,25),
      --max => to_unsigned(1000,25),
      --max => (others => '0'),
      clk_out => clk_lente
    );
    
SNAKE : Gene_Snake
    port map (
      X => Xpxl,
      Y => Ypxl,
      clk => H125Mhz,
      reset => resetGeneral,
      currentSnakes => currentSnakes,
      listRefs => listRefs,
      updateOrder => pxl_clk,
      dataReady => dataReady,
      tailIndex => tailIndex,
      cCaseX => cCaseX,
      cCaseY => cCaseY,
      dataRequest => dataRequest,
      colorOut => snakeColor,
      ROMAddress => spritesROMAddress,
      ROMData => spritesROMData
    );
    
RAMCTRL : RAMController
    port map (
        X => cCaseX,
        Y => cCaseY,
        
        request => dataRequest,
        
        clk => H125MHz,
        
        output => currentSnakes,
        listRefs => listRefs,
        
        dataReady => dataReady,
        
        matWE => matupdRAMWE,
        matWaddress => matRAMAddress,
        matWdata => matupdRAMDataOut,
        matRdata => matRAMDataIn,
        
        listWE => updateRAMWE,
        listWAddress => RAMAddress,
        listWData => updateRAMDataOut,
        listRData => RAMDataIn
   );

UPD : updateSnake
    port map (
        clk_lente => clk_lente,
        clk_rapide => H125MHz,
        reset => resetGeneral,
        
        address => updateRAMAddress,
        dataIn => updateRAMDataIn,
        dataOut => updateRAMDataOut,
        writeEnable => updateRAMWE,
        
        matAddress => matupdRAMAddress,
        matDataIn => matupdRAMDataIn,
        matDataOut => matupdRAMDataOut,
        matWriteEnable => matupdRAMWE,
        
        button_up => button_up,
        button_down => button_down,
        button_left => button_left,
        button_right => button_right,
        
        pommeCE => pommeCE,
        pommeX => pommeX,
        pommeY => pommeY,
        resetPomme => pommeReset,
        
        tailIndex => tailIndex,
        
        lost => lost
    );

APPLE : pomme
    port map (
        clk => H125MHz,
        pxl_clk => pxl_clk,
        reset => pommeReset,
        CE => pommeCE,
        X => Xpxl,
        Y => Ypxl,
        posX => pommeX,
        posY => pommeY,
        colorOut => pommeColor,
        address => pommeAddress,
        data => pommeData,
        matAddress => pommeMatAddress,
        matData => pommeMatData,
        ROMAddress => pommeROMAddress,
        ROMData => pommeROMData
    );
    
 ROM : spritesROM
    generic map(
        addressSize => SPRITES_ADDRESS_SIZE,
        length => SPRITES_DATA_LENGTH,
        dataSize => SPRITES_DATA_SIZE,
        fileName => "../projet-electronique/sprites/sprites.mem" --pour l'implementation
        --fileName => "../sprites/sprites.mem" --pour la simulation
    )
    port map(
        address => spritesROMAddress,
        data => spritesROMData,
        clk => H125MHz
    );
 POMMEROM : spritesROM
    generic map(
        addressSize => 8,
        length => 256,
        dataSize => SPRITES_DATA_SIZE,
        fileName => "../projet-electronique/sprites/pomme.mem" --pour l'implementation
        --fileName => "../sprites/pomme.mem" --pour la simulation
    )
    port map(
        address => pommeROMAddress,
        data => pommeROMData,
        clk => H125MHz
    );

process(pommeCE,updateRAMAddress,pommeAddress,pommeMatAddress,RAMDataIn,matUpdRAMAddress,matRAMDataIn)
begin
    if(pommeCE = '0') then
        RAMAddress <= updateRAMAddress;
        updateRAMDataIn <= RAMDataIn;
        matRAMAddress <= matUpdRAMAddress;
        matUpdRAMDataIn <= matRAMDataIn;
        
        pommeData <= (others => '0');
        pommeMatData <= (others => '0');
    else
        RAMAddress <= pommeAddress;
        pommeData <= RAMDataIn;
        matRAMAddress <= pommeMatAddress;
        pommeMatData <= matRAMDataIn;
        
        updateRAMDataIn <= (others => '0');
        matUpdRAMDataIn <= (others => '0');
    end if;
end process;

process(lost)
begin
    if(lost = '1') then
        clkCnt <= to_unsigned(0,25);
    else
        clkCnt <= to_unsigned(420000,25);
    end if;
end process;
--clkCnt <= to_unsigned(420000,25);

led(0) <= resetGeneral;
led(1) <= updateRAMWE;
led(2) <= clk_lente;
led(3) <= lost;
end Behavioral;
