---------------------------------------------------------------------------------- -- Company: -- Engineer: KIEGAING EMMANUEL -- GAMOM ROLAND CHRISTIAN -- -- Create Date: 04:39:43 05/21/2011 -- Design Name: -- Module Name: DMA_ARBITER - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- gestionnaire DMA pour le port secodaire de la RAM true dual port des mémoire -- privée de chaque noeud -- Dependencies: -- -- Revision: 09/07/2012 -- Revision 1.01 - File Created -- Revision 1.2 - 19/03/2013 -- Correction de bugs et optimisation du nombre de cycles -- Création d'un testbench -- Additional Comments: Ce module pourra être optimisé pour générer les adresses automatiquement -- par le controleur DMA lorsqu'il est sollicité par la périphérie -- ---------------------------------------------------------------------------------- library IEEE; library NocLib; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; 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 DMA_ARBITER is Port ( dma_rd_request : in STD_LOGIC_VEctor (3 downto 0):=(others=>'0'); data_wr_in : in STD_LOGIC_VECTOR (Word-1 downto 0); data_rd_out : out STD_LOGIC_VECTOR (Word-1 downto 0); address_rd : in STD_LOGIC_VECTOR (ADRLEN-1 downto 0); --adresse pour lecture address_wr : in STD_LOGIC_VECTOR (ADRLEN-1 downto 0); -- adresse pour écriture address_out_wr : out STD_LOGIC_VECTOR (ADRLEN-1 downto 0); -- adresse de sortie du DMA Arbiter address_out_rd : out STD_LOGIC_VECTOR (ADRLEN-1 downto 0); ram_en : out STD_LOGIC; -- ram_we : out STD_LOGIC; data_wr_mem : out STD_LOGIC_VECTOR (Word-1 downto 0); -- donnée en sortie écriture data_rd_mem : in STD_LOGIC_VECTOR (Word-1 downto 0); -- données en sortie lecture dma_wr_grant : out STD_LOGIC_vector(3 downto 0):=(others=>'0'); -- autorisation d'écriture hold_req : out STD_Logic; --requete vers application hold_ack : in STD_Logic; --autorisation par l'application clk : in std_logic; reset : in std_logic; dma_rd_grant : out STD_LOGIC_vector(3 downto 0):=(others=>'0'); -- autorisation de lecture dma_wr_request : in STD_LOGIC_vector(3 downto 0):=(others=>'0')); -- demande de lecture end DMA_ARBITER; architecture Behavioral of DMA_ARBITER is type fsm_states is (idle,wait_ack,arbiter_ack, writing,ReadWrite,reading);-- definition du type etat pour le codage des etats des fsm signal dmac_state : fsm_states; signal prio_rd,prio_wr:std_logic_vector(3 downto 0);--vecteur de bits de priorité signal pri_rd,pri_wr : natural range 0 to 3; -- stocke le numéro du module qui a la priorité signal dma_rd_logic : std_logic_vector(3 downto 0):=(others=>'0'); signal dma_wr_logic : std_logic_vector(3 downto 0):=(others=>'0'); signal dma_rd_latch,dma_wr_latch: std_logic_vector(3 downto 0):=(others=>'0'); signal dma_req_wr, dma_req_rd : std_logic; signal last_grant_rd,last_grant_wr : STD_LOGIC_vector(3 downto 0):=(others=>'0'); signal tmp :std_logic_vector(3 downto 0):="0000"; begin --========================================================================== ---le MUX qui contrôle les adresses est géré à l'extérieur du contrôleur DMA dma_sync: process (clk,data_rd_mem,data_wr_in,address_rd,address_wr) begin data_rd_out<=data_rd_mem ; data_wr_mem <= data_wr_in; address_out_rd <= address_rd; address_out_wr <= address_wr; end process; --dma_rd_grant<= dma_rd_logic; --dma_wr_grant<= dma_wr_logic; dma_rd_grant<= dma_rd_latch; dma_wr_grant<= dma_wr_latch; --========================================================================== --Déterminer si une requête HOLD doit être émise vers l'application pour la libération du --bus mémoire tmp<=(others =>'0'); --for i in 0 to 3 loop --dma_req_wr<=dma_req_wr or dma_wr_request(i); --loop; --for i in 0 to 3 loop -- dma_req_rd<=dma_req_rd or dma_rd_request(i); -- construire le signal request vers l'extérieur --loop; hold_req<='1' when dma_req_rd='1' or dma_req_wr='1' else '0'; --envoyer un Hold vers l'application -- machine à etat du DMAC dmac_process : process(clk,reset) --variable tmp : natural range 0 to 15; variable tmp_rd,tmp_wr: std_logic_vector(3 downto 0); variable req_rd,req_wr : std_logic:='0' ; begin if rising_edge(clk) then if reset = '1' then dmac_state<= idle; prio_rd <="0001"; -- au debut priorité lecture au premier module prio_wr <="0010"; -- au debut priorité ecriture au deuxième module pri_rd<=0;--index de la priorité pri_wr<=1; req_rd:='0'; req_wr:='0'; else if req_wr='0' then --tant que le Ctrl DMA est libre alors faire bouger la priorité en écriture case dma_wr_request is when "0001" => pri_wr<=0; prio_wr<="0001"; req_wr:='1'; dma_req_wr<= '1'; dma_wr_logic <="0001"; when "0010" => pri_wr<=1; prio_wr<="0010"; req_wr:='1'; dma_req_wr<= '1'; dma_wr_logic <="0010"; when "0100" => pri_wr<=2; prio_wr<="0100"; req_wr:='1'; dma_req_wr<= '1'; dma_wr_logic <="0100"; when "1000" => pri_wr<=3; prio_wr<="1000"; req_wr:='1'; dma_req_wr<= '1'; dma_wr_logic <="1000"; when others => if req_rd='1' then --demande simultané de lecture et d'écriture if dma_rd_request(pri_rd)='1' then pri_wr<=pri_rd; req_wr:='1'; for i in 0 to 3 loop if i=pri_rd then prio_wr(i)<='1'; dma_wr_logic(i)<='1'; else prio_wr(i)<='0'; dma_wr_logic(i)<='0'; end if; end loop; end if; else --on affecte l'accè à la mémoire suivant le round robbin tmp_wr:= (dma_wr_request and prio_wr) ; dma_wr_logic <=tmp_wr; req_wr:= not(All_zeros(tmp_wr)); dma_req_wr<= not(All_zeros(tmp_wr)); end if; -- la priorité est circulaire et décale à chaque coup d'horloge if req_wr='0' then prio_wr<=rol_vec(prio_wr); if pri_wr=3 then pri_wr<=0; Prio_wr<="0001"; else pri_wr<=pri_wr+1; end if; end if; end case; else --req_wr='1' --demande simultané de lecture et d'écriture if dma_rd_request(pri_wr)='1' then pri_rd<=pri_wr; req_rd:='1'; prio_rd<=prio_wr; -- for i in 0 to 3 loop -- if i=pri_rd then -- prio_wr(i)<='1'; -- dma_wr_logic(i)<='1'; -- else -- prio_wr(i)<='0'; -- dma_wr_logic(i)<='0'; -- end if; -- end loop; end if; end if; if req_rd='0' then --tant que le Ctrl DMA est libre alors faire bouger la priorité case dma_rd_request is when "0001" => pri_rd<=0; prio_rd<="0001"; req_rd:='1'; dma_req_rd<= '1'; dma_rd_logic<="0001"; when "0010" => pri_rd<=1; prio_rd<="0010"; req_rd:='1'; dma_req_rd<= '1'; dma_rd_logic<="0010"; when "0100" => pri_rd<=2; prio_rd<="0100"; req_rd:='1'; dma_req_rd<= '1'; dma_rd_logic<="0100"; when "1000" => pri_rd<=3; prio_rd<="1000"; req_rd:='1'; dma_req_rd<= '1'; dma_rd_logic<="1000"; when others => --si une demande survient de la part d'un composant déjà acquitté alors celui-ci est prioritaire if req_wr='1' then if dma_rd_request(pri_wr)='1' then pri_rd<=pri_wr; req_rd:='1'; for i in 0 to 3 loop if i=pri_wr then prio_rd(i)<='1'; dma_rd_logic(i)<='1'; else prio_rd(i)<='0'; dma_rd_logic(i)<='0'; end if; end loop; end if; else tmp_rd:= (dma_rd_request and prio_rd) ; dma_rd_logic<=tmp_rd; dma_req_rd<= not (All_Zeros(tmp_rd)); req_rd:= not (All_Zeros(tmp_rd)); end if; -- la priorité est circulaire et décale à chaque coup d'horloge if req_rd='0' then prio_rd<=rol_vec(prio_rd); if pri_rd =3 then pri_rd<=0; prio_rd<="0001"; else pri_rd<=pri_rd+1; end if; end if; end case; end if; case dmac_state is when idle => if req_rd='1' or req_wr='1' then dmac_state<=wait_ack; else -- initialiser la priorité req_rd:='0'; dma_req_rd<= '0'; req_wr:='0'; dma_req_wr<= '0'; dma_wr_logic <="0000"; --aucun accès mémoire n'est accrédité dma_rd_logic <="0000"; end if; when wait_ack => -- l'application doit autoriser l'utilisation de la RAM par le Core if dma_wr_request(pri_wr) ='1' or dma_rd_request(pri_rd) ='1' then if hold_ack='1' then --dmac_state<=arbiter_ack; if dma_wr_request(pri_wr) ='1' and dma_rd_request(pri_rd) ='1' then -- dmac_state <= Readwrite; elsif dma_wr_request(pri_wr) ='0' and dma_rd_request(pri_rd) ='1' then dmac_state <= Reading; elsif dma_wr_request(pri_wr) ='1' and dma_rd_request(pri_rd) ='0' then dmac_state <= Writing; else dmac_state<=Idle; end if; end if; else if dma_wr_request(pri_wr) ='0' then req_wr:='0';-- forcer une nouvelle recherche de priorité end if; if dma_rd_request(pri_rd) ='0' then req_rd:='0'; end if; dmac_state<=Idle; end if; when arbiter_ack => -- if dma_wr_request(pri_wr) ='1' and dma_rd_request(pri_rd) ='1' then -- -- dmac_state <= Readwrite; -- elsif dma_wr_request(pri_wr) ='0' and dma_rd_request(pri_rd) ='1' then -- dmac_state <= Reading; -- elsif dma_wr_request(pri_wr) ='1' and dma_rd_request(pri_rd) ='0' then -- dmac_state <= Writing; -- else dmac_state<=Idle; -- end if; -- cet état a été combiné au précédent pour gagner un cycle when Writing => if dma_wr_request(pri_wr) ='1' then if hold_ack='1' then -- on reste dans cet état if dma_rd_request(pri_rd)='1' then dmac_state<=ReadWrite; else req_rd:='0'; end if; else dmac_state<=wait_ack; end if; elsif dma_rd_request(pri_rd) ='1' then dmac_state <= Reading; req_wr:='0'; else dmac_state <= idle; req_wr:='0'; end if; when ReadWrite => if hold_ack='1' then if dma_wr_request(pri_wr)='1' and dma_rd_request(pri_rd)='1' then dmac_state <= ReadWrite; elsif dma_wr_request(pri_wr)='1' and dma_rd_request(pri_rd)='0' then dmac_state <= Writing; req_rd:='0'; elsif dma_wr_request(pri_wr)='0' and dma_rd_request(pri_rd)='1' then dmac_state <= Reading; req_wr:='0'; else dmac_state <= Idle; req_rd:='0';req_wr:='0'; end if; else if (dma_wr_request(pri_wr)='1') or (dma_rd_request(pri_rd)='1') then dmac_state <= Wait_ack; else dmac_state <= Idle; end if; end if; when Reading => if dma_rd_request(pri_rd) ='1' then if hold_ack='1' then -- on reste dans cet état if dma_wr_request(pri_wr)='1' then dmac_state<=ReadWrite; else req_wr:='0'; end if; else dmac_state<=wait_ack; end if; elsif dma_wr_request(pri_wr) ='1' then dmac_state<=writing; req_rd:='0'; else dmac_state <= idle; req_rd:='0'; end if; when others => dmac_state <= idle; end case; end if; end if; end process; -- action_asociées ol: process(dmac_state, address_rd, address_wr,pri_wr,pri_rd,prio_wr,prio_rd,dma_wr_request,dma_rd_request) begin --tester les requêtes DMA en lecture ou en écriture case dmac_state is when idle => ram_en <='0'; ram_we <='0'; dma_wr_latch <=(others=>'0'); dma_rd_latch <=(others=>'0'); --address_out_rd <= address_rd; --hold_req<='0'; when wait_ack => ram_en <='0'; ram_we <='0'; dma_wr_latch<=(others=>'0'); dma_rd_latch<=(others=>'0'); --address_out_rd <= (others=>'Z'); --address_out_wr <= (others=>'Z'); --hold_req<='1'; when arbiter_ack => --à optimiser pour gagner un cycle ram_en <='0'; ram_we <='0'; dma_wr_latch<=(others=>'0'); dma_rd_latch<=(others=>'0'); --address_out_rd <= (others=>'Z'); --address_out_wr <= (others=>'Z'); when writing => -- ecriture dans la ram ram_en <='1'; ram_we <='1'; dma_wr_latch<=(others=>'0'); dma_wr_latch(pri_wr) <='1'; dma_rd_latch <=(others=>'0'); --address_out_rd <= (others=>'Z'); --address_out_wr <= address_wr; --hold_req<='1'; when ReadWrite => -- Lecture et écriture simultannée dans la Dual Port RAM ram_en <='1'; ram_we <='1'; dma_wr_latch<=(others=>'0'); dma_wr_latch(pri_wr) <='1'; dma_rd_latch<=(others=>'0'); dma_rd_latch(pri_rd)<='1'; --address_out_rd <= address_rd; --address_out_wr <= address_wr; --hold_req<='1'; when Reading => -- lecture dans la ram ram_en <='1'; ram_we <='0'; dma_wr_latch<=(others=>'0'); dma_rd_latch<=(others=>'0'); dma_rd_latch(pri_rd)<='1'; --address_out_rd <= address_rd; --address_out_wr <= (others=>'Z'); --hold_req<='1'; when others => ram_en <='0'; ram_we <='0'; dma_wr_latch <=(others=>'0'); dma_rd_latch <=(others=>'0'); --address_out_rd <= (others=>'Z'); --address_out_wr <= (others=>'Z'); --hold_req<='0'; end case; end process; end Behavioral;