diff options
Diffstat (limited to 'netfpga10g/hdl/dma.vhd')
-rw-r--r-- | netfpga10g/hdl/dma.vhd | 640 |
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; + |