git-svn-id: http://moon:8086/svn/vhdl/trunk@1036 cc03376c-175c-47c8-b038-4cd826a8556b
231 lines
5.3 KiB
VHDL
231 lines
5.3 KiB
VHDL
-----------------------------------------------------------------------
|
|
-- $Header: D:\usr\cvsroot/VHDL/lib/JBUS/src/dmac.vhd,v 1.2 2013/05/28 11:23:15 jens Exp $
|
|
-----------------------------------------------------------------------
|
|
library IEEE;
|
|
use IEEE.STD_LOGIC_1164.ALL;
|
|
use IEEE.NUMERIC_STD.ALL;
|
|
|
|
use work.utils_pkg.all;
|
|
use work.busmaster_types.all;
|
|
|
|
------------------------------------------------------------------
|
|
entity dmac is
|
|
Generic
|
|
(
|
|
DATA_WIDTH : natural := 32;
|
|
XFER_CHUNK_SIZE : natural := 512
|
|
);
|
|
Port
|
|
(
|
|
clk : in std_logic;
|
|
rst : in std_logic;
|
|
|
|
master_req : out std_logic;
|
|
master_gnt : in std_logic;
|
|
|
|
dma_start : out std_logic;
|
|
dma_active : out std_logic;
|
|
dma_end : out std_logic;
|
|
|
|
req_rdy : out std_logic;
|
|
req_en : in std_logic;
|
|
req_rw : in std_logic;
|
|
req_addr_start : in unsigned(31 downto 0);
|
|
req_num_xfers : in unsigned(31 downto 0);
|
|
req_addr_auto_inc : in std_logic;
|
|
|
|
req_complete : out std_logic;
|
|
req_complete_ack : in std_logic;
|
|
|
|
-- busmaster control
|
|
bus_cyc_complete : in std_logic;
|
|
bus_cmd_rdy : in std_logic;
|
|
bus_cmd_we : out std_logic;
|
|
bus_cmd_cycle_en : out std_logic;
|
|
|
|
-- busmaster command
|
|
bus_cmd_out : out bm_cmd_t
|
|
);
|
|
end dmac;
|
|
|
|
architecture Behavioral of dmac is
|
|
|
|
signal start_en : std_logic;
|
|
signal finish_en : std_logic;
|
|
signal complete : std_logic;
|
|
signal addr_inc_en : std_logic;
|
|
signal addr : unsigned(31 downto 0);
|
|
signal rw : std_logic;
|
|
|
|
signal req_count_en : std_logic;
|
|
signal req_count : unsigned(31 downto 0);
|
|
signal req_count_next : unsigned(32 downto 0);
|
|
signal req_count_rdy : std_logic;
|
|
|
|
signal chunk_count_rst : std_logic;
|
|
signal chunk_count_en : std_logic;
|
|
signal chunk_count : unsigned(31 downto 0);
|
|
signal chunk_count_next : unsigned(32 downto 0);
|
|
signal chunk_count_rdy : std_logic;
|
|
|
|
type state_t is (INIT, READY, START, SETUP, XFER, FINISH, DONE);
|
|
signal s, sn : state_t;
|
|
|
|
begin
|
|
|
|
bus_cmd_out.addr <= addr;
|
|
bus_cmd_out.sel <= (others => '1');
|
|
bus_cmd_out.rw <= rw;
|
|
req_complete <= complete;
|
|
|
|
state_next:
|
|
process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
if rst = '1' then
|
|
s <= INIT;
|
|
else
|
|
s <= sn;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
state:
|
|
process(s, req_en, master_gnt, req_count_rdy, chunk_count_rdy, bus_cyc_complete, bus_cmd_rdy)
|
|
begin
|
|
|
|
bus_cmd_cycle_en <= '0';
|
|
bus_cmd_we <= '0';
|
|
start_en <= '0';
|
|
finish_en <= '0';
|
|
req_count_en <= '0';
|
|
req_rdy <= '0';
|
|
chunk_count_rst <= '0';
|
|
chunk_count_en <= '0';
|
|
master_req <= '0';
|
|
dma_start <= '0';
|
|
dma_active <= '0';
|
|
dma_end <= '0';
|
|
|
|
sn <= s;
|
|
case s is
|
|
when INIT =>
|
|
sn <= READY;
|
|
|
|
when READY =>
|
|
req_rdy <= '1';
|
|
if req_en = '1' then
|
|
start_en <= '1';
|
|
sn <= SETUP;
|
|
end if;
|
|
|
|
when SETUP =>
|
|
dma_start <= '1';
|
|
sn <= START;
|
|
|
|
when START =>
|
|
master_req <= '1';
|
|
chunk_count_rst <= '1';
|
|
if req_count_rdy = '1' then
|
|
sn <= READY;
|
|
elsif master_gnt = '1' and bus_cyc_complete = '1' then
|
|
sn <= XFER;
|
|
end if;
|
|
|
|
when XFER =>
|
|
dma_active <= '1';
|
|
master_req <= '1';
|
|
bus_cmd_we <= '1';
|
|
bus_cmd_cycle_en <= '1';
|
|
req_count_en <= bus_cmd_rdy;
|
|
chunk_count_en <= bus_cmd_rdy;
|
|
if req_count_rdy = '1' then
|
|
sn <= FINISH;
|
|
elsif chunk_count_rdy = '1' then
|
|
sn <= START;
|
|
end if;
|
|
|
|
when FINISH =>
|
|
master_req <= '1';
|
|
dma_end <= '1';
|
|
sn <= DONE;
|
|
|
|
when DONE =>
|
|
master_req <= '1';
|
|
if bus_cyc_complete = '1' then
|
|
sn <= READY;
|
|
finish_en <= '1';
|
|
end if;
|
|
|
|
when others =>
|
|
sn <= READY;
|
|
|
|
end case;
|
|
end process;
|
|
|
|
addr_gen:
|
|
process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
if start_en = '1' then
|
|
rw <= req_rw;
|
|
addr <= req_addr_start;
|
|
addr_inc_en <= req_addr_auto_inc;
|
|
elsif req_count_en = '1' and addr_inc_en = '1' then
|
|
addr <= addr + DATA_WIDTH/8;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
req_count_next <= ('0' & req_num_xfers) - 1 when start_en = '1' else ('0' & req_count) - 1;
|
|
req_count_rdy <= req_count_next(32);
|
|
|
|
req_counter:
|
|
process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
if start_en = '1' then
|
|
req_count <= req_count_next(31 downto 0);
|
|
elsif req_count_en = '1' then
|
|
if req_count_rdy = '0' then
|
|
req_count <= req_count_next(31 downto 0);
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
chunk_count_next <= to_unsigned(XFER_CHUNK_SIZE, 33) - 1 when chunk_count_rst = '1' else ('0' & chunk_count) - 1;
|
|
chunk_count_rdy <= chunk_count_next(32);
|
|
|
|
chunk_counter:
|
|
process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
if chunk_count_rst = '1' then
|
|
chunk_count <= chunk_count_next(31 downto 0);
|
|
elsif chunk_count_en = '1' then
|
|
if chunk_count_rdy = '0' then
|
|
chunk_count <= chunk_count_next(31 downto 0);
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
complete_register:
|
|
process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
if start_en = '1' or rst = '1' then
|
|
complete <= '0';
|
|
elsif complete = '0' then
|
|
if finish_en = '1' then
|
|
complete <= '1';
|
|
elsif req_complete_ack = '1' then
|
|
complete <= '0';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end Behavioral;
|