----------------------------------------------------------------------------------
-- Company: 
-- Engineer: GAMOM NGOUNOU
-- 
-- Create Date:    04:57:14 07/15/2012 
-- Design Name: 
-- Module Name:    load_instr - Behavioral 
-- Project Name: MPI CORE
-- Target Devices: 
-- Tool versions: 
-- Description: Ce mdule permet de charger une instruction dans le FIFO 1
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
library NocLib;
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;
use NocLib.CoreTypes.all;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity load_instr is
    Port ( Instruction : in  STD_LOGIC_VECTOR (Word-1 downto 0);
           Instruction_en : in  STD_LOGIC;
			  
           clk : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           dma_rd_grant : in  STD_LOGIC;
           dma_rd_request : out  STD_LOGIC:='0';
           instruction_ack : out  STD_LOGIC:='0';
           fifo_din : out  STD_LOGIC_VECTOR (Word-1 downto 0);
			  fifo_wr :out std_logic:='0';
			  copying :out std_logic:='0';
           fifo_full : in  STD_LOGIC;
           ram_address_rd : out  STD_LOGIC_VECTOR (ADRLEN-1 downto 0);
           ram_data : in  STD_LOGIC_VECTOR (WORD-1 downto 0);
			  Ram_rd_en : out std_logic);
end load_instr;

architecture Behavioral of load_instr is
--déclaration des types manipulés
type typ_loadinst is (init,setadr,readptr,getbus,readmem,freebus,st_timeout);
--déclaration des signaux
signal Ram_address_i:STD_LOGIC_VECTOR (ADRLEN-1 downto 0):=(others=>'0');
--signal ptr, ptr_i:STD_LOGIC_VECTOR (ADRLEN-1 downto 0):=(others=>'0'); --pointeur vers l'instruction en RAM
signal Base_Adr : STD_LOGIC_VECTOR (ADRLEN-1 downto 0):=(others=>'0');

signal Base_AdrSet : std_logic:='0' ; --indique l'adresse de base des instructions positionée
signal fifo_din_i:std_logic_vector(WORD-1 downto 0):=(others=>'Z');
signal fifo_wr_i :std_logic:='0';
signal base_adrset_i : std_logic:='0';
signal instruction_ack_i :std_logic:='0';
signal Dma_rd_request_i :std_logic:='0';
signal count,count_i : natural range 0 to 31:=0; --permet de faie évoluer la sous-MAE
signal etloadinst,next_loadinst : typ_loadinst;
begin
SYNC_PROC: process (clk)
   begin
      if rising_edge(clk) then
         if (reset = '1') or instruction_en='0' then
            etloadinst <= init;
            Base_adrSet<= '0';
				dma_rd_request<='0';
				instruction_ack<='0';
         else
            etloadinst <= next_loadinst;
            fifo_din <= fifo_din_i;
				Base_AdrSet<=Base_adrSet_i;
				ram_address_rd<=ram_address_i;
				dma_rd_request<=dma_rd_request_i;
				instruction_ack<=instruction_ack_i;
				count<=count_i;
				
				
         -- assign other outputs to internal signals
         end if;        
      end if;
   end process;
 
   --
   OUTPUT_DECODE: process (etloadinst,Count_i,Ram_data,Dma_rd_grant,fifo_wr_i,Ram_address_i)
	variable Adr_inst1,adr_inst2 : natural;
   begin
      --insert statements to decode internal output signals
      --below is simple example
      case etloadinst is
		 when init =>
		 Dma_rd_request_i<='0';
		 fifo_wr<='0';
		 copying<='0';
		 Ram_rd_en<='0';
		 Instruction_ack_i<='0';
		 fifo_din_i<=(others=>'Z');
		 Base_AdrSet_i<='0';
		 
		 when SetAdr =>
		 Dma_rd_request_i<='0';
		 Instruction_ack_i<='0';
		 fifo_wr<='0';
		 copying<='0';
		 Ram_rd_en<='0';
		 
		 fifo_din_i<=(others=>'Z');
		 Base_AdrSet_i<='1';
		 
		 when getbus =>
		 fifo_wr<='0';
		 copying<='1';
		 Ram_rd_en<=Dma_rd_grant;
		 Dma_rd_request_i<='1';
		 Instruction_ack_i<='0';
		 fifo_din_i<=(others=>'Z');
		 Base_AdrSet_i<='1';
		 when readptr => 
		 fifo_wr<='0';
			 
		 copying<='1';
		 Ram_rd_en<='1';
		 Dma_rd_request_i<='1';
		 Instruction_ack_i<='0';
		 fifo_din_i<=(others=>'Z');
		 Base_AdrSet_i<='1';
		 when readmem =>
		 Dma_rd_request_i<='1';
		 copying<='1';
		 Ram_rd_en<='1';
		 fifo_wr<=fifo_wr_i;
		 fifo_din_i<=Ram_data;
		 Base_AdrSet_i<='1';
		 Instruction_ack_i<='0';
		 
		 when freebus =>
		 Dma_rd_request_i<='0';
		 fifo_wr<='0';
		 copying<='0';
		 Ram_rd_en<='0';
		 Instruction_ack_i<='1';
		 fifo_din_i<=(others=>'Z');
		 Base_AdrSet_i<='1';
		 when st_timeout =>
		 Dma_rd_request_i<='0';
		 fifo_wr<='0';
		copying<='0';
		 Ram_rd_en<='0';
		 Instruction_ack_i<='0';
		 fifo_din_i<=(others=>'Z');
		 Base_AdrSet_i<='1';
		end case;
   end process;
 
   NEXT_STATE_DECODE: process (etloadinst, Base_AdrSet,Ram_data,Instruction,instruction_en, fifo_full,dma_rd_grant,count)
   variable ptr : std_logic_vector(ADRLEN-1 downto 0);
	variable timeout: natural range 0 to 255;
	variable Base_AD,ADRtmp,iptr : natural range 0 to 65535;
	begin
      --declare default state for next_state to avoid latches
      next_loadinst <= etloadinst;  --default is to stay in current state
      --insert statements to decode next_state
      --below is a simple example
      case (etloadinst) is
         when init => if base_adrset='1'  and Instruction_en='1' then
							
								next_loadinst<=getbus;
							elsif Instruction_en='1' then
								next_loadinst<=Setadr;
								Base_Adr<=X"0000";
							else
								next_loadinst<=init;
								Base_Adr<=X"0000";
							end if;
							fifo_wr_i<='0';
							count_i<=0;
							--
			When Setadr => if Base_adrSet='0' then
									Base_Adr<=instruction & X"00";  --récupération des bits de poids forts de l'instruction
										  --
								end if;
								next_loadinst<=init;
					Ram_address_i<=(others=>'Z');
					count_i<=0;
         when getbus =>
            BASE_AD:=to_integer(unsigned(base_adr));
				if dma_rd_grant = '1' then
               next_loadinst <= readptr;
					
					-- prépare la prochaine lecture
					
					
				else
					
				end if;
				Ram_address_i<=(others=>'Z');
				count_i<=0;
         When readptr =>
				if dma_rd_grant = '1' then --s'assurer que le bus est disponible
					
						
						
					if count=0 then 
						Ram_address_i<=std_logic_vector(to_unsigned(BASE_AD+2,16));
						count_i <=count+1;
					elsif count=1 then-- attend que la donnée soit positionnée	
						count_i <=count+1;
					
					elsif count=2 then
						count_i <=count+1;
					
					elsif count=3 then
						ptr(Word-1 downto 0):=Ram_data;
						Ram_address_i<=incr_vec(ram_address_i,'1');
						count_i <=count+1;
					elsif count=4 then
						
						count_i <=count+1;
					elsif count=5 then
						ptr(15 downto 8):=Ram_data;
						--count_i <=count+1;
					--elsif count=6 then
						--ptr(15 downto 8):=Ram_data;
						count_i<=0;
						timeout:=0;
						next_loadinst <= readmem;
					else
					
					end if;
					
				else
				  timeout:=timeout+1;
				end if;
			when readmem =>
            if dma_rd_grant = '1' then --s'assurer que le bus est disponible
					if fifo_full='0' then
						
						if count=0 then 
							iptr:=to_integer(unsigned(ptr));
							AdrTmp:=iptr;
							count_i <=count+1;
							fifo_wr_i<='0';
						elsif	 count=1 then 
							count_i <=count+1;
							fifo_wr_i<='0';
						elsif	 count=2 then 
							count_i <=count+1;
							AdrTmp:=iptr+1; --incrémentation de l'adresse
							fifo_wr_i<='0';
						elsif	 count=3 then 
							count_i <=count+1;		
							fifo_wr_i<='1'; --écriture de la donnée dans le fifo
						elsif count=4 then
							fifo_wr_i<='0';
							
							count_i <=count+1;
						elsif count=5 then
							fifo_wr_i<='1'; --lecture de la donnée 2
							count_i <=count+1;	
							AdrTmp:=iptr+2;
						elsif	 count=6 then 
							count_i <=count+1;
							fifo_wr_i<='0'; 
						elsif	 count=7 then 
							count_i <=count+1;
							fifo_wr_i<='0';  
						elsif count=8 then
							fifo_wr_i<='1';--lecture de la donnée 3
							count_i <=count+1;
							AdrTmp:=iptr+3;
						elsif count =9 then
							count_i <=count+1;
							
							fifo_wr_i<='0'; 
						elsif	 count=10 then 
							count_i <=count+1;
							fifo_wr_i<='0';
							
						elsif count=11 then
							fifo_wr_i<='1'; --lecture de la donnée 4
							count_i <=count+1;
							ADRTmp:=iptr+4;--incrémente l'adresse
						elsif count =12 then
							count_i <=count+1;
							
							fifo_wr_i<='0'; 
						elsif	 count=13 then 
							count_i <=count+1;
							fifo_wr_i<='0';
						elsif count=14 then
							fifo_wr_i<='1';--lecture de la donnée 5
							count_i <=count+1;
							ADRtmp:=iptr+5;
						elsif count =15 then
							count_i <=count+1;
							fifo_wr_i<='0'; 
						elsif	 count=16 then 
							count_i <=count+1;
							fifo_wr_i<='0';
						elsif count=17 then
							fifo_wr_i<='1';--lecture de la donnée 6
							count_i <=count+1;
							next_loadinst <= freebus;	
						end if;
						
						Ram_address_i<=STD_LOGIC_VECTOR(to_unsigned(AdrTmp,16));
					end if;
					
				else
				  timeout:=timeout+1;
					if timeout=50 then
						next_loadinst<=st_timeout;
					end if;
					Ram_address_i<=(others=>'Z'); -- le bus n'est pas libre
					
				end if;
				
         when freebus =>
				fifo_wr_i<='0';
				count_i<=0;
				 Ram_address_i<=(others=>'Z');
            if instruction_en='0' then 
					next_loadinst <= init;
				end if;
			when st_timeout =>
				fifo_wr_i<='0';
			 Ram_address_i<=(others=>'Z');
				next_loadinst<=init;
				count_i<=0;
      end case;      
   end process;

end Behavioral;

