diff options
Diffstat (limited to 'netfpga10g/hdl/engine.vhd')
-rw-r--r-- | netfpga10g/hdl/engine.vhd | 570 |
1 files changed, 570 insertions, 0 deletions
diff --git a/netfpga10g/hdl/engine.vhd b/netfpga10g/hdl/engine.vhd new file mode 100644 index 0000000..16f0a8b --- /dev/null +++ b/netfpga10g/hdl/engine.vhd @@ -0,0 +1,570 @@ + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; +library UNISIM; +use UNISIM.VComponents.all; + +entity engine is +generic ( + BUFF_COUNT : integer := 16; + BUFF_BITS : integer := 4; -- 2^4 = 16 + BAR_BITS : integer := 17; + TIME_BITS : integer := 20 +); +port ( + clk : in STD_LOGIC; + + rd_buff : out STD_LOGIC_VECTOR (BUFF_BITS - 1 downto 0) := (others => '0'); + rd_en : out STD_LOGIC := '0'; + rd_data : in STD_LOGIC_VECTOR (63 downto 0); + rd_length : in STD_LOGIC_VECTOR (8 downto 0); + rd_valid : in STD_LOGIC_VECTOR (BUFF_COUNT - 1 downto 0); + + wr_buff : out STD_LOGIC_VECTOR (BUFF_BITS - 1 downto 0) := (others => '0'); + wr_en : out STD_LOGIC := '0'; + wr_data : out STD_LOGIC_VECTOR (63 downto 0) := (others => '0'); + wr_done : out STD_LOGIC := '0'; + wr_cancel : out STD_LOGIC_VECTOR (BUFF_COUNT - 1 downto 0); + wr_accept : in STD_LOGIC_VECTOR (BUFF_COUNT - 1 downto 0); + + 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 (63 downto 3); + rx_tag : in std_logic_vector(4 downto 0); + + tx_read : out STD_LOGIC := '0'; + tx_write : out STD_LOGIC := '0'; + tx_complete : out STD_LOGIC := '0'; + tx_data : out STD_LOGIC_VECTOR (63 downto 0) := (others => '0'); + tx_address : out STD_LOGIC_VECTOR (63 downto 3) := (others => '0'); + tx_length : out STD_LOGIC_VECTOR (8 downto 0) := (others => '0'); + tx_tag : out std_logic_vector(4 downto 0) := (others => '0'); + tx_accept : in STD_LOGIC; + tx_done : in STD_LOGIC; + + interrupt : out std_logic := '0'; + interrupt_rdy : in std_logic; + + max_read : in std_logic_vector(2 downto 0); + max_write : in std_logic_vector(2 downto 0); + + mdio_command : out std_logic_vector(0 to 27) := (others => '0'); + mdio_data : in std_logic_vector(0 to 15); + mdio_enable : out std_logic := '0'; + mdio_done : in std_logic +); +end engine; + +architecture arch of engine is + + constant BUFF_EMPTY : std_logic_vector(1 downto 0) := "00"; + constant BUFF_ADDR : std_logic_vector(1 downto 0) := "01"; + constant BUFF_DATA : std_logic_vector(1 downto 0) := "10"; + constant BUFF_FULL : std_logic_vector(1 downto 0) := "11"; + + type buff_t is array (0 to BUFF_COUNT - 1) of std_logic_vector(1 downto 0); + type length_t is array (0 to BUFF_COUNT - 1) of unsigned(8 downto 0); + type address_t is array (0 to BUFF_COUNT - 1) of unsigned(63 downto 3); + type time_t is array (0 to BUFF_COUNT - 1) of unsigned(TIME_BITS - 1 downto 0); + + type rx_state_t is (rx_state_idle, rx_state_write_done, rx_state_mdio); + type tx_state_t is (tx_state_idle, tx_state_read, tx_state_write, + tx_state_complete, tx_state_interrupt); + + signal rx_state : rx_state_t := rx_state_idle; + signal tx_state : tx_state_t := tx_state_idle; + + signal tx_data_i : std_logic_vector(63 downto 0) := (others => '0'); + + constant CMD_STATUS : std_logic_vector(1 downto 0) := "00"; + constant CMD_SEND : std_logic_vector(1 downto 0) := "01"; + constant CMD_RECV : std_logic_vector(1 downto 0) := "10"; + constant CMD_MDIO : std_logic_vector(1 downto 0) := "11"; + + signal send_buff : buff_t := (others => BUFF_FULL); + signal send_length : length_t := (others => (others => '0')); + signal send_remain : length_t := (others => (others => '0')); + signal send_address : address_t := (others => (others => '0')); + signal send_read_time : time_t := (others => (others => '0')); + + signal recv_buff : buff_t := (others => BUFF_EMPTY); + signal recv_address0 : unsigned(63 downto 3); + signal recv_address1 : unsigned(63 downto 3); + signal recv_address2 : unsigned(63 downto 3); + signal recv_address3 : unsigned(63 downto 3); + signal recv_address4 : unsigned(63 downto 3); + signal recv_address5 : unsigned(63 downto 3); + signal recv_address6 : unsigned(63 downto 3); + signal recv_address7 : unsigned(63 downto 3); + signal recv_address8 : unsigned(63 downto 3); + signal recv_address9 : unsigned(63 downto 3); + signal recv_address10 : unsigned(63 downto 3); + signal recv_address11 : unsigned(63 downto 3); + signal recv_address12 : unsigned(63 downto 3); + signal recv_address13 : unsigned(63 downto 3); + signal recv_address14 : unsigned(63 downto 3); + signal recv_address15 : unsigned(63 downto 3); + + signal send_int : std_logic := '0'; + signal send_int_needed : std_logic := '0'; + signal send_read : std_logic := '0'; + signal send_read_done : std_logic := '0'; + signal send_read_buff : integer range 0 to BUFF_COUNT - 1 := 0; + signal send_read_length : unsigned(8 downto 0); + signal send_read_remain : unsigned(8 downto 0); + signal send_read_address : unsigned(63 downto 3); + signal send_write : std_logic := '0'; + signal send_write_new : std_logic := '0'; + signal send_write_buff : integer range 0 to BUFF_COUNT - 1 := 0; + signal send_write_length : unsigned(8 downto 0); + signal send_write_address : unsigned(63 downto 3); + + signal debug_address : std_logic_vector(63 downto 3) := (others => '0'); + signal debug_data : std_logic_vector(63 downto 0) := (others => '0'); + signal debug_cmd : std_logic_vector(1 downto 0) := (others => '0'); + signal debug_buff : std_logic_vector(BUFF_BITS - 1 downto 0) := (others => '0'); + signal debug_length : std_logic_vector(8 downto 0) := std_logic_vector(to_unsigned(42, 9)); + + signal debug_cmpl_count : unsigned(7 downto 0) := (others => '0'); + signal debug_cmpl_data : std_logic_vector(63 downto 0) := (others => '0'); + signal debug_cmpl_tag : std_logic_vector(4 downto 0) := (others => '0'); + signal debug_cmpl_state : std_logic_vector(7 downto 0) := x"FF"; + + signal debug_write_count : unsigned(7 downto 0) := (others => '0'); + signal debug_write_length : std_logic_vector(8 downto 0) := (others => '0'); + signal debug_write_addr : std_logic_vector(63 downto 3) := (others => '0'); + signal debug_write_data : std_logic_vector(63 downto 0) := (others => '0'); + + signal debug_accept_count : unsigned(7 downto 0) := (others => '0'); + signal debug_done_count : unsigned(7 downto 0) := (others => '0'); + + signal timer : unsigned(TIME_BITS - 1 downto 0) := (others => '0'); +begin + rd_en <= tx_accept when tx_state = tx_state_write else '0'; + + tx_data <= rd_data when tx_state = tx_state_write else tx_data_i; + + process (clk) + variable bar_read : std_logic := '0'; + variable bar_read_address : std_logic_vector(63 downto 3) := (others => '0'); + + variable tmp_cmd : std_logic_vector(1 downto 0); + variable tmp_buff : integer range 0 to BUFF_COUNT - 1; + variable tmp_length : unsigned(8 downto 0); + variable tmp_remain : unsigned(8 downto 0); + variable tmp_address : unsigned(63 downto 3); + variable tmp_bar : unsigned(BAR_BITS - 1 downto 0); + + -- see 'metered reads' in pcie core manual (xilinx) + -- a maximum of 8 openstanding reads is allowed + constant READ_MAX : unsigned(3 downto 0) := x"8"; + variable read_count : unsigned(3 downto 0) := (others => '0'); + variable read_decr : std_logic; + variable read_incr : std_logic; + begin + if rising_edge(clk) then + wr_en <= '0'; + wr_data <= (others => '0'); + wr_done <= '0'; + wr_cancel <= (others => '0'); + read_decr := '0'; + read_incr := '0'; + + timer <= timer + 1; + + -- ENGINE: RX + if rx_state = rx_state_idle then + if rx_read = '1' then + bar_read := '1'; + bar_read_address := rx_address; + + elsif rx_write = '1' then + tmp_cmd := rx_address(4 downto 3); + tmp_buff := to_integer(unsigned(rx_address(5 + BUFF_BITS - 1 downto 5))); + tmp_length := unsigned(rx_address(18 downto 10)); + tmp_address := unsigned(rx_data(63 downto 3)); + + debug_address <= rx_address; + debug_data <= rx_data; + debug_cmd <= tmp_cmd; + debug_buff <= std_logic_vector(to_unsigned(tmp_buff, debug_buff'length)); + debug_length <= std_logic_vector(tmp_length); + + if tmp_cmd = CMD_SEND then + if send_buff(tmp_buff) = BUFF_EMPTY then + send_buff(tmp_buff) <= BUFF_ADDR; + send_address(tmp_buff) <= tmp_address; + send_length(tmp_buff) <= tmp_length; + end if; + + elsif tmp_cmd = CMD_RECV then + if recv_buff(tmp_buff) = BUFF_FULL then + recv_buff(tmp_buff) <= BUFF_ADDR; + + if tmp_buff = 0 then + recv_address0 <= tmp_address; + elsif tmp_buff = 1 then + recv_address1 <= tmp_address; + elsif tmp_buff = 2 then + recv_address2 <= tmp_address; + elsif tmp_buff = 3 then + recv_address3 <= tmp_address; + elsif tmp_buff = 4 then + recv_address4 <= tmp_address; + elsif tmp_buff = 5 then + recv_address5 <= tmp_address; + elsif tmp_buff = 6 then + recv_address6 <= tmp_address; + elsif tmp_buff = 7 then + recv_address7 <= tmp_address; + elsif tmp_buff = 8 then + recv_address8 <= tmp_address; + elsif tmp_buff = 9 then + recv_address9 <= tmp_address; + elsif tmp_buff = 10 then + recv_address10 <= tmp_address; + elsif tmp_buff = 11 then + recv_address11 <= tmp_address; + elsif tmp_buff = 12 then + recv_address12 <= tmp_address; + elsif tmp_buff = 13 then + recv_address13 <= tmp_address; + elsif tmp_buff = 14 then + recv_address14 <= tmp_address; + elsif tmp_buff = 15 then + recv_address15 <= tmp_address; + end if; + end if; + + elsif tmp_cmd = CMD_MDIO then + rx_state <= rx_state_mdio; + mdio_enable <= '1'; + mdio_command <= rx_data(27 downto 0); + end if; + + elsif rx_complete = '1' then + tmp_buff := to_integer(unsigned(rx_tag(BUFF_BITS - 1 downto 0))); + + debug_cmpl_count <= debug_cmpl_count + 1; + debug_cmpl_data <= rx_data; + debug_cmpl_tag <= rx_tag; + debug_cmpl_state <= x"00"; + + if send_buff(tmp_buff) = BUFF_DATA then + wr_en <= '1'; + wr_data <= rx_data; + wr_buff <= std_logic_vector(to_unsigned(tmp_buff, BUFF_BITS)); + send_remain(tmp_buff) <= send_remain(tmp_buff) - 1; + debug_cmpl_state <= x"01"; + + if send_remain(tmp_buff) = 1 then + read_decr := '1'; + + if send_length(tmp_buff) = 0 then + rx_state <= rx_state_write_done; + debug_cmpl_state <= x"02"; + else + send_buff(tmp_buff) <= BUFF_ADDR; + debug_cmpl_state <= x"03"; + end if; + end if; + end if; + end if; + + elsif rx_state = rx_state_write_done then + rx_state <= rx_state_idle; + wr_done <= '1'; + + elsif rx_state = rx_state_mdio then + if mdio_done = '1' then + rx_state <= rx_state_idle; + mdio_enable <= '0'; + end if; + end if; + + -- ENGINE: TX + if send_read_done = '1' then + send_read_done <= '0'; + send_buff(send_read_buff) <= BUFF_DATA; + send_length(send_read_buff) <= send_read_length - send_read_remain; + send_remain(send_read_buff) <= send_read_remain; + send_address(send_read_buff) <= send_read_address + send_read_remain; + send_read_time(send_read_buff) <= timer; + end if; + + if tx_state = tx_state_idle or + (tx_state = tx_state_read and tx_done = '1') or + (tx_state = tx_state_write and tx_done = '1') or + (tx_state = tx_state_complete and tx_done = '1') or + (tx_state = tx_state_interrupt and interrupt_rdy = '1') then + + tx_state <= tx_state_idle; + tx_read <= '0'; + tx_write <= '0'; + tx_complete <= '0'; + tx_data_i <= (others => '0'); + tx_address <= (others => '0'); + tx_length <= (others => '0'); + tx_tag <= (others => '0'); + interrupt <= '0'; + + if bar_read = '1' then + tx_state <= tx_state_complete; + tx_complete <= '1'; + tx_address <= bar_read_address; + tmp_cmd := bar_read_address(4 downto 3); + tmp_bar := unsigned(bar_read_address(3 + BAR_BITS - 1 downto 3)); + bar_read := '0'; + + if tmp_bar = 0 then + --if tmp_cmd = CMD_STATUS then + for i in 0 to BUFF_COUNT - 1 loop + tx_data_i(i*4 + 1 downto i*4 + 0) <= send_buff(i); + tx_data_i(i*4 + 3 downto i*4 + 2) <= recv_buff(i); + end loop; + send_int <= '0'; + send_int_needed <= '1'; + + elsif tmp_bar = 1 then + tx_data_i(63 downto 3) <= debug_address; + + elsif tmp_bar = 2 then + tx_data_i <= debug_data; + + elsif tmp_bar = 3 then + tx_data_i(1 downto 0) <= debug_cmd; + + elsif tmp_bar = 4 then + tx_data_i(BUFF_BITS - 1 downto 0) <= debug_buff; + + elsif tmp_bar = 5 then + tx_data_i(8 downto 0) <= debug_length; + + elsif tmp_bar = 10 then + tx_data_i(7 downto 0) <= std_logic_vector(debug_cmpl_count); + + elsif tmp_bar = 11 then + tx_data_i <= debug_cmpl_data; + + elsif tmp_bar = 12 then + tx_data_i(4 downto 0) <= debug_cmpl_tag; + + elsif tmp_bar = 13 then + tx_data_i(7 downto 0) <= debug_cmpl_state; + + elsif tmp_bar = 20 then + tx_data_i(7 downto 0) <= std_logic_vector(debug_write_count); + + elsif tmp_bar = 21 then + tx_data_i(8 downto 0) <= debug_write_length; + + elsif tmp_bar = 22 then + tx_data_i(63 downto 3) <= debug_write_addr; + + elsif tmp_bar = 23 then + tx_data_i(63 downto 0) <= debug_write_data; + + elsif tmp_bar = 24 then + tx_data_i(7 downto 0) <= std_logic_vector(debug_accept_count); + + elsif tmp_bar = 25 then + tx_data_i(7 downto 0) <= std_logic_vector(debug_done_count); + + elsif tmp_bar = 30 then + tx_data_i(15 downto 0) <= mdio_data; + + else + tx_data_i(63 downto 3) <= bar_read_address; + end if; + + elsif send_int = '1' and send_int_needed = '1' then + tx_state <= tx_state_interrupt; + interrupt <= '1'; + send_int_needed <= '0'; + + elsif send_read = '1' and read_count < READ_MAX then + tmp_buff := send_read_buff; + tmp_length := send_read_length; + tmp_address := send_read_address; + tmp_remain := 16 - resize(tmp_address(6 downto 3), tmp_remain'length); + + if max_read = "001" then + tmp_remain := 32 - resize(tmp_address(7 downto 3), tmp_remain'length); + elsif max_read = "010" then + tmp_remain := 64 - resize(tmp_address(8 downto 3), tmp_remain'length); + elsif max_read = "011" then + tmp_remain := 128 - resize(tmp_address(9 downto 3), tmp_remain'length); + elsif max_read = "100" then + tmp_remain := 256 - resize(tmp_address(10 downto 3), tmp_remain'length); + elsif max_read = "101" then + tmp_remain := 512 - resize(tmp_address(11 downto 3), tmp_remain'length); + end if; + + if tmp_remain > tmp_length then + tmp_remain := tmp_length; + end if; + + tx_state <= tx_state_read; + tx_read <= '1'; + tx_address <= std_logic_vector(tmp_address); + tx_length <= std_logic_vector(tmp_remain); + tx_tag <= std_logic_vector(to_unsigned(tmp_buff, tx_tag'length)); + + send_read <= '0'; + send_read_done <= '1'; + send_read_remain <= tmp_remain; + read_incr := '1'; + + elsif send_write = '1' then + if send_write_new = '1' then + tmp_length := unsigned(rd_length); + else + tmp_length := send_write_length; + end if; + tmp_address := send_write_address; + tmp_remain := 16 - resize(tmp_address(6 downto 3), tmp_remain'length); + + if max_write = "001" then + tmp_remain := 32 - resize(tmp_address(7 downto 3), tmp_remain'length); + elsif max_write = "010" then + tmp_remain := 64 - resize(tmp_address(8 downto 3), tmp_remain'length); + elsif max_write = "011" then + tmp_remain := 128 - resize(tmp_address(9 downto 3), tmp_remain'length); + elsif max_write = "100" then + tmp_remain := 256 - resize(tmp_address(10 downto 3), tmp_remain'length); + elsif max_write = "101" then + tmp_remain := 512 - resize(tmp_address(11 downto 3), tmp_remain'length); + end if; + + if tmp_remain > tmp_length then + tmp_remain := tmp_length; + end if; + + tx_state <= tx_state_write; + tx_write <= '1'; + tx_address <= std_logic_vector(tmp_address); + tx_length <= std_logic_vector(tmp_remain); + + debug_write_count <= debug_write_count + 1; + debug_write_length <= std_logic_vector(tmp_remain); + debug_write_addr <= std_logic_vector(tmp_address); + debug_write_data <= rd_data; + + tmp_length := tmp_length - tmp_remain; + tmp_address := tmp_address + tmp_remain; + + send_write_length <= tmp_length; + send_write_address <= tmp_address; + send_write_new <= '0'; + + if tmp_length = 0 then + send_write <= '0'; + end if; + end if; + end if; + + if read_decr = '1' and read_incr = '0' then + read_count := read_count - 1; + elsif read_decr = '0' and read_incr = '1' then + read_count := read_count + 1; + end if; + + if tx_accept = '1' then + debug_accept_count <= debug_accept_count + 1; + end if; + if tx_done = '1' then + debug_done_count <= debug_done_count + 1; + end if; + + for i in 0 to BUFF_COUNT - 1 loop + if send_buff(i) = BUFF_DATA and wr_accept(i) = '0' then + send_buff(i) <= BUFF_FULL; + -- no send_int here + end if; + if send_buff(i) = BUFF_FULL and wr_accept(i) = '1' then + send_buff(i) <= BUFF_EMPTY; + send_int <= '1'; + end if; + if recv_buff(i) = BUFF_EMPTY and rd_valid(i) = '1' then + recv_buff(i) <= BUFF_FULL; + send_int <= '1'; + end if; + if recv_buff(i) = BUFF_DATA and rd_valid(i) = '0' then + recv_buff(i) <= BUFF_EMPTY; + send_int <= '1'; + end if; + + if send_buff(i) = BUFF_DATA and send_read_time(i) = timer then + -- read timeout + wr_cancel(i) <= '1'; + end if; + end loop; + + if send_read = '0' and send_read_done = '0' then + for i in 0 to BUFF_COUNT - 1 loop + tmp_buff := (send_read_buff + i) mod BUFF_COUNT; + + if send_buff(tmp_buff) = BUFF_ADDR then + send_read <= '1'; + send_read_buff <= tmp_buff; + send_read_length <= send_length(tmp_buff); + send_read_address <= send_address(tmp_buff); + exit; + end if; + end loop; + end if; + + if send_write = '0' and (tx_state /= tx_state_write or tx_done = '1') then + for i in 0 to BUFF_COUNT - 1 loop + tmp_buff := (send_write_buff + i) mod BUFF_COUNT; + + if recv_buff(tmp_buff) = BUFF_ADDR then + recv_buff(tmp_buff) <= BUFF_DATA; + send_write <= '1'; + send_write_new <= '1'; + send_write_buff <= tmp_buff; + rd_buff <= std_logic_vector(to_unsigned(tmp_buff, BUFF_BITS)); + + if tmp_buff = 0 then + send_write_address <= recv_address0; + elsif tmp_buff = 1 then + send_write_address <= recv_address1; + elsif tmp_buff = 2 then + send_write_address <= recv_address2; + elsif tmp_buff = 3 then + send_write_address <= recv_address3; + elsif tmp_buff = 4 then + send_write_address <= recv_address4; + elsif tmp_buff = 5 then + send_write_address <= recv_address5; + elsif tmp_buff = 6 then + send_write_address <= recv_address6; + elsif tmp_buff = 7 then + send_write_address <= recv_address7; + elsif tmp_buff = 8 then + send_write_address <= recv_address8; + elsif tmp_buff = 9 then + send_write_address <= recv_address9; + elsif tmp_buff = 10 then + send_write_address <= recv_address10; + elsif tmp_buff = 11 then + send_write_address <= recv_address11; + elsif tmp_buff = 12 then + send_write_address <= recv_address12; + elsif tmp_buff = 13 then + send_write_address <= recv_address13; + elsif tmp_buff = 14 then + send_write_address <= recv_address14; + elsif tmp_buff = 15 then + send_write_address <= recv_address15; + end if; + exit; + end if; + end loop; + end if; + end if; + end process; +end arch; |