library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; entity DMA is port ( clk,reset : in std_logic; addr_in : in unsigned(5 downto 0); data_in : in unsigned(15 downto 0); addr_out : out unsigned(5 downto 0); data_out : out unsigned(7 downto 0); busy : out std_logic ); end DMA; architecture b of DMA is type stato is (idle,read1,write1,write2); signal cs,ns : stato; signal count,ncount : unsigned(3 downto 0); signal tr_word : unsigned(15 downto 0); signal base_address : unsigned(5 downto 0); signal sample : std_logic; begin -- Parte sequenziale: Aggiornamento dello stato e decremento -- del contatore di accesso process(clk,reset) begin if reset='1' then cs <= idle; count <= conv_unsigned(0,4); else if clk'event and clk='1' then cs <= ns; count <= ncount; end if; end if; end process; -- Registro che campiona l'indirizzo base di accesso -- (l'offset viene determinato da count, specificato a fine file) process(clk,reset) begin if reset='1' then base_address <= (others=>'0'); else if clk'event and clk='1' then if cs=idle and sample='1' then base_address <= data_in(5 downto 0); end if; end if; end if; end process; -- Registro che campiona il dato da trasferire (16 bit) process(clk,reset) begin if reset='1' then tr_word <= (others=>'0'); else if clk'event and clk='1' then if cs=read1 then tr_word <= data_in; end if; end if; end if; end process; -- Address Decoding: Riconosce la scrittura della parola di controllo -- dando il via alla transazione -- Nota: tale lettura e' possibile solo se non si hanno transazioni -- in corso, e quindi nello stato "IDLE" process(addr_in,cs) begin if (cs=idle and conv_integer(addr_in)=16#30#) then sample <= '0'; else sample <= '1'; end if; end process; -- Parte combinatoria della FSM process(cs,sample,count,base_address,tr_word ) begin case cs is when idle => addr_out <= (others=> 'Z'); data_out <= (others=> 'Z'); busy <= '0'; if sample='1' then ns <= read1; else ns <= idle; end if; when read1 => addr_out <= base_address + count; data_out <= (others => 'Z'); busy <= '1'; ns <= write1; when write1 => addr_out <= conv_unsigned(16#20#,6); data_out <= tr_word(15 downto 8); busy <= '1'; ns <= write2; when write2 => addr_out <= conv_unsigned(16#20#,6); data_out <= tr_word(7 downto 0); busy <= '1'; if conv_integer(count) = 0 then ns <= idle; else ns <= read1; end if; when others => addr_out <= (others=>'Z'); data_out <= (others=>'Z'); busy <= '1'; ns <= idle; end case; end process; -- Processo COMBINATORIO che gestisce il conteggio -- Poiche' count e' un valore che deve essere mantenuto -- in memoria nella evoluzione della macchina a stati, -- (In pratica e' variabile di stato) esistono due possibili -- implementazioni: a) Descriverlo come variabile interna al processo -- FSM (Non ideale, perche' il risultato dipende dalla interpretazione -- dello strumento di sintesi) o b) Descriverlo con una coppia di segnali -- count e ncount separati da un Registro. -- Il valore futuro di count dipende dallo stato ed e' determinato dal -- presente processo combinatorio process(cs,sample) begin if cs=idle and sample='1' then ncount <= data_in(9 downto 6); elsif cs=write2 then ncount <= count-2; else ncount <= count; end if; end process; end b;