library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;

library ourTypes;
use ourTypes.types.all;

entity RAMController is
generic(
           snakeDataSize : integer
       );
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 := '0';

       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 RAMController;

architecture Behavioral of RAMController is
    component snakeRam
    generic(length : integer;
            addressSize : integer;
            dataSize : integer
        );
    Port ( addresses : in addresses;
           clk1 : in std_logic;
           output : out std_logic_vector_array(0 to 8)(dataSize-1 downto 0);
           
           address2 : in unsigned(addressSize-1 downto 0);
           dataIn2 : in std_logic_vector(dataSize-1 downto 0);
           dataOut2 : out std_logic_vector(dataSize-1 downto 0);
           writeEnable2 : in STD_LOGIC;
           clk2 : in STD_LOGIC
           );
    end component snakeRam;

    signal RAMClk : std_logic; --Pour l'instant c'est la même que H125MHz mais on pourrait avoir besoin de plus
    signal matAddresses : addresses;
    signal refAddresses : std_logic_vector_array(0 to 8)(SNAKE_ADDRESS_SIZE-1 downto 0);
    signal snakeOut : std_logic_vector_array(0 to 8)(snakeDataSize-1 downto 0);
begin

SNAKE_RAM : snakeRAM --La RAM pour le snake
    generic map (
        length => MAX_SNAKE,
        addressSize => SNAKE_ADDRESS_SIZE,
        dataSize => snakeDataSize
    )
    port map (
        addresses => to_addresses(refAddresses),
        output => snakeOut,
        clk1 => RAMClk,
        
        address2 => listWAddress,
        dataIn2 => listWData,
        dataOut2 => listRData,
        writeEnable2 => listWE,
        clk2 => clk
    );

MAT_RAM : snakeRAM --La RAM pour la matrice de correspondance
    generic map (
        length => MAX_SNAKE,
        addressSize => SNAKE_ADDRESS_SIZE,
        dataSize => SNAKE_ADDRESS_SIZE
    )
    port map (
        addresses => matAddresses,
        output => refAddresses,
        clk1 => RAMClk,
        
        address2 => matWAddress,
        dataIn2 => matWData,
        dataOut2 => matRData,
        writeEnable2 => matWE,
        clk2 => clk
    );

process(clk)
variable clkCount : integer := 0;
variable running : boolean := true;
begin
    if(clk'event and clk = '1') then
        if(request = '1' and not running) then
            running := true;
            dataReady <= '0';
        end if;
        if(running) then
            clkCount := clkCount + 1;
        end if;
        if(clkCount = 3) then
            running := false;
            clkCount := 0;
            dataReady <= '1';
        end if;
    end if;
end process;

RAMClk <= clk;
output <= to_pos(snakeOut);
listRefs <= to_addresses(refAddresses);

GENERATEDX : for dx in -1 to 1 generate
    GENERATEDY : for dy in -1 to 1 generate
        matAddresses((dy+1)*3+dx+1) <= to_unsigned(40 * constrain(to_integer(Y) + dy,0,29) + constrain(to_integer(X) + dx,0,39),SNAKE_ADDRESS_SIZE);
    end generate GENERATEDY;
end generate GENERATEDX;
end Behavioral;
