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;