summaryrefslogtreecommitdiff
path: root/netfpga10g/hdl/dma.vhd
diff options
context:
space:
mode:
Diffstat (limited to 'netfpga10g/hdl/dma.vhd')
-rw-r--r--netfpga10g/hdl/dma.vhd640
1 files changed, 640 insertions, 0 deletions
diff --git a/netfpga10g/hdl/dma.vhd b/netfpga10g/hdl/dma.vhd
new file mode 100644
index 0000000..4c7e4f8
--- /dev/null
+++ b/netfpga10g/hdl/dma.vhd
@@ -0,0 +1,640 @@
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity dma is
+generic (
+ BITS : integer := 14
+);
+port (
+ clk : in std_logic;
+ reset : in std_logic;
+
+ rx_read : in std_logic;
+ rx_write : in std_logic;
+ rx_complete : in std_logic;
+ rx_data : in std_logic_vector(63 downto 0);
+ rx_address : in std_logic_vector(28 downto 0);
+
+ tx_read : out std_logic;
+ tx_write : out std_logic;
+ tx_complete : out std_logic;
+ tx_data : out std_logic_vector(63 downto 0);
+ tx_address : out std_logic_vector(28 downto 0);
+ tx_length : out std_logic_vector(8 downto 0);
+ tx_accept : in std_logic;
+ tx_done : in std_logic;
+
+ port0_read : out std_logic;
+ port0_rd_data : in std_logic_vector(63 downto 0);
+ port0_rd_empty : in std_logic;
+ port0_rd_count : in std_logic_vector(BITS downto 0);
+
+ port0_write : out std_logic;
+ port0_wr_data : out std_logic_vector(63 downto 0);
+ port0_wr_full : in std_logic;
+ port0_wr_count : in std_logic_vector(BITS downto 0);
+
+ port1_read : out std_logic;
+ port1_rd_data : in std_logic_vector(63 downto 0);
+ port1_rd_empty : in std_logic;
+ port1_rd_count : in std_logic_vector(BITS downto 0);
+
+ port1_write : out std_logic;
+ port1_wr_data : out std_logic_vector(63 downto 0);
+ port1_wr_full : in std_logic;
+ port1_wr_count : in std_logic_vector(BITS downto 0);
+
+ port2_read : out std_logic;
+ port2_rd_data : in std_logic_vector(63 downto 0);
+ port2_rd_empty : in std_logic;
+ port2_rd_count : in std_logic_vector(BITS downto 0);
+
+ port2_write : out std_logic;
+ port2_wr_data : out std_logic_vector(63 downto 0);
+ port2_wr_full : in std_logic;
+ port2_wr_count : in std_logic_vector(BITS downto 0);
+
+ port3_read : out std_logic;
+ port3_rd_data : in std_logic_vector(63 downto 0);
+ port3_rd_empty : in std_logic;
+ port3_rd_count : in std_logic_vector(BITS downto 0);
+
+ port3_write : out std_logic;
+ port3_wr_data : out std_logic_vector(63 downto 0);
+ port3_wr_full : in std_logic;
+ port3_wr_count : in std_logic_vector(BITS downto 0);
+
+ max_read : in std_logic_vector(2 downto 0);
+ max_write : in std_logic_vector(2 downto 0);
+
+ interrupt : out std_logic;
+ interrupt_rdy : in std_logic;
+
+ mdio_command : out std_logic_vector(0 to 27);
+ mdio_data : in std_logic_vector(0 to 15);
+ mdio_enable : out std_logic;
+ mdio_done : in std_logic;
+
+ leds : out std_logic_vector(2 downto 0)
+);
+end dma;
+
+architecture arch of dma is
+ type state_t is (state_idle, state_tx_read, state_tx_write, state_tx_complete, state_rx_complete,
+ state_dma_read, state_dma_write, state_interrupt, state_command,
+ state_test_write_head, state_test_write,
+ state_test_read_head, state_test_read, state_test_complete,
+ state_mdio);
+ signal state : state_t;
+
+ signal fifo_read : std_logic;
+ signal fifo_write : std_logic;
+ signal fifo_din : std_logic_vector(63 downto 0);
+ signal fifo_dout : std_logic_vector(63 downto 0);
+ signal fifo_full : std_logic;
+ signal fifo_empty : std_logic;
+ signal fifo_count : std_logic_vector(BITS downto 0);
+
+ component simple_fifo port (
+ clk : in std_logic;
+ rst : in std_logic;
+ rd_en : in std_logic;
+ wr_en : in std_logic;
+ din : in std_logic_vector(63 downto 0);
+ dout : out std_logic_vector(63 downto 0);
+ full : out std_logic;
+ empty : out std_logic;
+ data_count : out std_logic_vector(BITS downto 0)
+ );
+ end component;
+
+ signal cmd_read : std_logic;
+ signal cmd_write : std_logic;
+ signal cmd_din : std_logic_vector(63 downto 0);
+ signal cmd_dout : std_logic_vector(63 downto 0);
+ signal cmd_full : std_logic;
+ signal cmd_empty : std_logic;
+
+ component cmd_fifo port (
+ clk : in std_logic;
+ rst : in std_logic;
+ rd_en : in std_logic;
+ wr_en : in std_logic;
+ din : in std_logic_vector(63 downto 0);
+ dout : out std_logic_vector(63 downto 0);
+ full : out std_logic;
+ empty : out std_logic
+ );
+ end component;
+
+ signal test_completion : std_logic_vector(63 downto 0);
+begin
+ process (clk, reset)
+ variable bar_addr : unsigned(BITS downto 0);
+ variable dma_addr : unsigned(28 downto 0);
+ variable length : unsigned(BITS downto 0);
+ variable remain : unsigned(BITS downto 0);
+ variable cycles : unsigned(BITS downto 0);
+ variable backup_addr : unsigned(28 downto 0);
+ variable backup_length : unsigned(BITS downto 0);
+ begin
+ if reset = '1' then
+ state <= state_idle;
+ tx_read <= '0';
+ tx_write <= '0';
+ tx_complete <= '0';
+ tx_data <= (others => '0');
+ tx_address <= (others => '0');
+ tx_length <= (others => '0');
+ fifo_read <= '0';
+ fifo_write <= '0';
+ fifo_din <= (others => '0');
+ interrupt <= '0';
+ cmd_read <= '0';
+ cmd_write <= '0';
+ cmd_din <= (others => '0');
+ test_completion <= (others => '0');
+ port0_read <= '0';
+ port0_write <= '0';
+ port0_wr_data <= (others => '0');
+ port1_read <= '0';
+ port1_write <= '0';
+ port1_wr_data <= (others => '0');
+ port2_read <= '0';
+ port2_write <= '0';
+ port2_wr_data <= (others => '0');
+ port3_read <= '0';
+ port3_write <= '0';
+ port3_wr_data <= (others => '0');
+ mdio_enable <= '0';
+ mdio_command <= (others => '0');
+
+ elsif rising_edge(clk) then
+ fifo_read <= '0';
+ fifo_write <= '0';
+ fifo_din <= (others => '0');
+ cmd_read <= '0';
+ cmd_write <= '0';
+ cmd_din <= (others => '0');
+ port0_read <= '0';
+ port0_write <= '0';
+ port1_read <= '0';
+ port1_write <= '0';
+ port2_read <= '0';
+ port2_write <= '0';
+ port3_read <= '0';
+ port3_write <= '0';
+
+ -- bar read
+ if state = state_idle and rx_read = '1' then
+ state <= state_tx_complete;
+ tx_complete <= '1';
+ tx_data <= (others => '0');
+ tx_address <= rx_address;
+ bar_addr := unsigned(rx_address(BITS downto 0));
+
+ -- read fifo
+ if bar_addr = 0 then
+ if fifo_empty = '1' then
+ tx_data <= (others => '1');
+ else
+ tx_data <= fifo_dout;
+ fifo_read <= '1';
+ end if;
+
+ -- read command
+ elsif bar_addr = 1 then
+ if cmd_empty = '1' then
+ tx_data <= (others => '1');
+ else
+ tx_data <= cmd_dout;
+ cmd_read <= '1';
+ end if;
+
+ -- other
+ elsif bar_addr = 3 then
+ tx_data(BITS downto 0) <= fifo_count;
+
+ elsif bar_addr = 4 then
+ tx_data(2 downto 0) <= max_read;
+
+ elsif bar_addr = 5 then
+ tx_data(2 downto 0) <= max_write;
+
+ elsif bar_addr = 6 then
+ tx_data <= test_completion;
+
+ -- read ports
+ elsif bar_addr = 10 then
+ if port0_rd_empty = '1' then
+ tx_data <= (others => '1');
+ else
+ tx_data <= port0_rd_data;
+ port0_read <= '1';
+ end if;
+
+ elsif bar_addr = 11 then
+ if port1_rd_empty = '1' then
+ tx_data <= (others => '1');
+ else
+ tx_data <= port1_rd_data;
+ port1_read <= '1';
+ end if;
+
+ elsif bar_addr = 12 then
+ if port2_rd_empty = '1' then
+ tx_data <= (others => '1');
+ else
+ tx_data <= port2_rd_data;
+ port2_read <= '1';
+ end if;
+
+ elsif bar_addr = 13 then
+ if port3_rd_empty = '1' then
+ tx_data <= (others => '1');
+ else
+ tx_data <= port3_rd_data;
+ port3_read <= '1';
+ end if;
+
+ -- read counts
+ elsif bar_addr = 20 then
+ tx_data(BITS downto 0) <= port0_rd_count;
+
+ elsif bar_addr = 21 then
+ tx_data(BITS downto 0) <= port0_wr_count;
+
+ elsif bar_addr = 22 then
+ tx_data(BITS downto 0) <= port1_rd_count;
+
+ elsif bar_addr = 23 then
+ tx_data(BITS downto 0) <= port1_wr_count;
+
+ elsif bar_addr = 24 then
+ tx_data(BITS downto 0) <= port2_rd_count;
+
+ elsif bar_addr = 25 then
+ tx_data(BITS downto 0) <= port2_wr_count;
+
+ elsif bar_addr = 26 then
+ tx_data(BITS downto 0) <= port3_rd_count;
+
+ elsif bar_addr = 27 then
+ tx_data(BITS downto 0) <= port3_wr_count;
+
+ -- read mdio
+ elsif bar_addr = 30 then
+ tx_data(15 downto 0) <= mdio_data;
+ end if;
+
+ elsif state = state_tx_complete then
+ if tx_done = '1' then
+ state <= state_idle;
+ end if;
+
+ -- bar write
+ elsif state = state_idle and rx_write = '1' then
+ bar_addr := unsigned(rx_address(BITS downto 0));
+
+ -- write fifo
+ if bar_addr = 0 then
+ if fifo_full = '0' then
+ fifo_din <= rx_data;
+ fifo_write <= '1';
+ end if;
+
+ -- write command
+ elsif bar_addr = 1 then
+ if cmd_full = '0' then
+ cmd_din <= rx_data;
+ cmd_write <= '1';
+ end if;
+
+ if rx_data(0) = '1' then
+ state <= state_command;
+ end if;
+
+ -- write test
+ elsif bar_addr = 2 then
+ dma_addr := unsigned(rx_data(31 downto 3));
+ length := unsigned(rx_data(BITS+32 downto 32));
+ cycles := unsigned(rx_data(BITS+48 downto 48));
+ backup_addr := dma_addr;
+ backup_length := length;
+
+ if rx_data(1) = '0' then
+ state <= state_test_read_head;
+ else
+ state <= state_test_write_head;
+ end if;
+
+ -- write ports
+ elsif bar_addr = 10 then
+ if port0_wr_full = '0' then
+ port0_wr_data <= rx_data;
+ port0_write <= '1';
+ end if;
+
+ elsif bar_addr = 11 then
+ if port1_wr_full = '0' then
+ port1_wr_data <= rx_data;
+ port1_write <= '1';
+ end if;
+
+ elsif bar_addr = 12 then
+ if port2_wr_full = '0' then
+ port2_wr_data <= rx_data;
+ port2_write <= '1';
+ end if;
+
+ elsif bar_addr = 13 then
+ if port3_wr_full = '0' then
+ port3_wr_data <= rx_data;
+ port3_write <= '1';
+ end if;
+
+ -- write mdio
+ elsif bar_addr = 30 then
+ state <= state_mdio;
+ mdio_enable <= '1';
+ mdio_command <= rx_data(27 downto 0);
+ end if;
+
+ -- mdio
+ elsif state = state_mdio then
+ if mdio_done = '1' then
+ mdio_enable <= '0';
+ state <= state_interrupt;
+ interrupt <= '1';
+ end if;
+
+ -- test read
+ elsif state = state_test_read_head then
+ remain := 16 - resize(dma_addr(3 downto 0), remain'length);
+
+ if max_read = "001" then
+ remain := 32 - resize(dma_addr(4 downto 0), remain'length);
+ elsif max_read = "010" then
+ remain := 64 - resize(dma_addr(5 downto 0), remain'length);
+ elsif max_read = "011" then
+ remain := 128 - resize(dma_addr(6 downto 0), remain'length);
+ elsif max_read = "100" then
+ remain := 256 - resize(dma_addr(7 downto 0), remain'length);
+ elsif max_read = "101" then
+ remain := 512 - resize(dma_addr(8 downto 0), remain'length);
+ end if;
+
+ if remain > length then
+ remain := length;
+ end if;
+
+ state <= state_test_read;
+ tx_read <= '1';
+ tx_address <= std_logic_vector(dma_addr);
+ tx_length <= std_logic_vector(remain(8 downto 0));
+ length := length - remain;
+ dma_addr := dma_addr + remain;
+
+ elsif state = state_test_read then
+ if tx_done = '1' then
+ state <= state_test_complete;
+ end if;
+
+ elsif state = state_test_complete then
+ if rx_complete = '1' then
+ test_completion <= rx_data;
+ remain := remain - 1;
+
+ if remain = 0 then
+ if length > 0 then
+ state <= state_test_read_head;
+
+ elsif cycles > 1 then
+ state <= state_test_read_head;
+ dma_addr := backup_addr;
+ length := backup_length;
+ cycles := cycles - 1;
+ else
+ state <= state_interrupt;
+ interrupt <= '1';
+ end if;
+ end if;
+ end if;
+
+ -- test write
+ elsif state = state_test_write_head then
+ remain := 16 - resize(dma_addr(3 downto 0), remain'length);
+
+ if max_write = "001" then
+ remain := 32 - resize(dma_addr(4 downto 0), remain'length);
+ elsif max_write = "010" then
+ remain := 64 - resize(dma_addr(5 downto 0), remain'length);
+ elsif max_write = "011" then
+ remain := 128 - resize(dma_addr(6 downto 0), remain'length);
+ elsif max_write = "100" then
+ remain := 256 - resize(dma_addr(7 downto 0), remain'length);
+ elsif max_write = "101" then
+ remain := 512 - resize(dma_addr(8 downto 0), remain'length);
+ end if;
+
+ if remain > length then
+ remain := length;
+ end if;
+
+ state <= state_test_write;
+ tx_write <= '1';
+ tx_data <= x"FFEEDDCC00000000";
+ tx_address <= std_logic_vector(dma_addr);
+ tx_length <= std_logic_vector(remain(8 downto 0));
+ length := length - remain;
+ dma_addr := dma_addr + remain;
+
+ elsif state = state_test_write then
+ if tx_done = '1' then
+ if length > 0 then
+ state <= state_test_write_head;
+
+ elsif cycles > 1 then
+ state <= state_test_write_head;
+ dma_addr := backup_addr;
+ length := backup_length;
+ cycles := cycles - 1;
+ else
+ state <= state_interrupt;
+ interrupt <= '1';
+ end if;
+ end if;
+
+ -- command
+ elsif state = state_command then
+ if cmd_empty = '1' then
+ state <= state_interrupt;
+ interrupt <= '1';
+ else
+ cmd_read <= '1';
+
+ if cmd_dout(1) = '0' then
+ state <= state_dma_read;
+ dma_addr := unsigned(cmd_dout(31 downto 3));
+ length := unsigned(cmd_dout(BITS+32 downto 32));
+ fifo_din <= std_logic_vector(resize(length, fifo_din'length));
+ fifo_write <= '1';
+ else
+ state <= state_dma_write;
+ dma_addr := unsigned(cmd_dout(31 downto 3));
+ length := unsigned(fifo_dout(BITS downto 0)) + 1;
+ end if;
+ end if;
+
+ elsif state = state_interrupt then
+ if interrupt_rdy = '1' then
+ state <= state_idle;
+ interrupt <= '0';
+ end if;
+
+ -- dma read
+ elsif state = state_dma_read then
+ remain := 16 - resize(dma_addr(3 downto 0), remain'length);
+
+ if max_read = "001" then
+ remain := 32 - resize(dma_addr(4 downto 0), remain'length);
+ elsif max_read = "010" then
+ remain := 64 - resize(dma_addr(5 downto 0), remain'length);
+ elsif max_read = "011" then
+ remain := 128 - resize(dma_addr(6 downto 0), remain'length);
+ elsif max_read = "100" then
+ remain := 256 - resize(dma_addr(7 downto 0), remain'length);
+ elsif max_read = "101" then
+ remain := 512 - resize(dma_addr(8 downto 0), remain'length);
+ end if;
+
+ if remain > length then
+ remain := length;
+ end if;
+
+ state <= state_tx_read;
+ tx_read <= '1';
+ tx_address <= std_logic_vector(dma_addr);
+ tx_length <= std_logic_vector(remain(8 downto 0));
+ length := length - remain;
+ dma_addr := dma_addr + remain;
+
+ elsif state = state_tx_read then
+ if tx_done = '1' then
+ state <= state_rx_complete;
+ end if;
+
+ elsif state = state_rx_complete then
+ if rx_complete = '1' then
+ fifo_din <= rx_data;
+ fifo_write <= '1';
+ remain := remain - 1;
+
+ if remain = 0 then
+ if length > 0 then
+ state <= state_dma_read;
+ else
+ state <= state_command;
+ end if;
+ end if;
+ end if;
+
+ -- dma write
+ elsif state = state_dma_write then
+ remain := 16 - resize(dma_addr(3 downto 0), remain'length);
+
+ if max_write = "001" then
+ remain := 32 - resize(dma_addr(4 downto 0), remain'length);
+ elsif max_write = "010" then
+ remain := 64 - resize(dma_addr(5 downto 0), remain'length);
+ elsif max_write = "011" then
+ remain := 128 - resize(dma_addr(6 downto 0), remain'length);
+ elsif max_write = "100" then
+ remain := 256 - resize(dma_addr(7 downto 0), remain'length);
+ elsif max_write = "101" then
+ remain := 512 - resize(dma_addr(8 downto 0), remain'length);
+ end if;
+
+ if remain > length then
+ remain := length;
+ end if;
+
+ state <= state_tx_write;
+ tx_write <= '1';
+ tx_data <= fifo_dout;
+ tx_address <= std_logic_vector(dma_addr);
+ tx_length <= std_logic_vector(remain(8 downto 0));
+ fifo_read <= '1';
+ length := length - remain;
+ dma_addr := dma_addr + remain;
+ remain := remain - 1;
+
+ elsif state = state_tx_write then
+ if tx_done = '1' then
+ if length > 0 then
+ state <= state_dma_write;
+ else
+ state <= state_command;
+ end if;
+
+ elsif tx_accept = '1' and remain > 0 then
+ tx_data <= fifo_dout;
+ fifo_read <= '1';
+ remain := remain - 1;
+ end if;
+ end if;
+
+ if tx_done = '1' then
+ tx_read <= '0';
+ tx_write <= '0';
+ tx_complete <= '0';
+ tx_data <= (others => '0');
+ tx_address <= (others => '0');
+ tx_length <= (others => '0');
+ end if;
+ end if;
+ end process;
+
+ fifo : entity work.port_fifo port map (
+ reset => reset,
+
+ rd_clk => clk,
+ rd_read => fifo_read,
+ rd_data => fifo_dout,
+ rd_empty => fifo_empty,
+ rd_count => fifo_count,
+
+ wr_write => fifo_write,
+ wr_data => fifo_din,
+ wr_full => fifo_full
+ --wr_count => wr_count
+ );
+
+ commands : cmd_fifo port map (
+ clk => clk,
+ rst => reset,
+ rd_en => cmd_read,
+ wr_en => cmd_write,
+ din => cmd_din,
+ dout => cmd_dout,
+ full => cmd_full,
+ empty => cmd_empty
+ );
+
+ leds <= "000" when state = state_idle else
+ -- bar read
+ "001" when state = state_tx_complete else
+ -- dma read
+ "010" when state = state_dma_read or state = state_tx_read or state = state_rx_complete else
+ -- dma write
+ "011" when state = state_dma_write or state = state_tx_write else
+ -- mdio
+ "100" when state = state_mdio else
+ -- interrupt
+ "101" when state = state_interrupt else
+ -- other
+ "111";
+end arch;
+