URL
https://opencores.org/ocsvn/funbase_ip_library/funbase_ip_library/trunk
Subversion Repositories funbase_ip_library
[/] [funbase_ip_library/] [trunk/] [TUT/] [ip.hwp.interface/] [eth_lan91c111_ctrl/] [1.0/] [vhd/] [lan91c111_send_module.vhd] - Rev 145
Compare with Previous | Blame | View Log
------------------------------------------------------------------------------- -- Title : LAN91C111 controller, sender module -- Project : ------------------------------------------------------------------------------- -- File : Original: DM9kA_send_module.vhd -- Author : Jussi Nieminen. Antti Alhonen for LAN91C111. -- Last update: 2011-11-08 ------------------------------------------------------------------------------- -- Description: Handles sending procedures ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2009/08/25 1.0 niemin95 Created -- 2011/07/?? lan91c111 alhonena ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.lan91c111_ctrl_pkg.all; entity lan91c111_send_module is generic ( mode_16bit_g : integer := 0); port ( clk : in std_logic; rst_n : in std_logic; -- from interrupt handler tx_completed_in : in std_logic; -- to and from comm module comm_req_out : out std_logic; comm_grant_in : in std_logic; reg_addr_out : out std_logic_vector( real_addr_width_c-1 downto 0 ); config_data_out : out std_logic_vector( lan91_data_width_c-1 downto 0 ); config_nBE_out : out std_logic_vector( 3 downto 0 ); read_not_write_out : out std_logic; config_valid_out : out std_logic; data_from_comm_in : in std_logic_vector( lan91_data_width_c-1 downto 0 ); data_from_comm_valid_in : in std_logic; comm_busy_in : in std_logic; -- from upper level tx_data_in : in std_logic_vector( lan91_data_width_c-1 downto 0 ); tx_data_valid_in : in std_logic; tx_re_out : out std_logic; tx_MAC_addr_in : in std_logic_vector( 47 downto 0 ); new_tx_in : in std_logic; tx_len_in : in std_logic_vector( tx_len_w_c-1 downto 0 ); tx_frame_type_in : in std_logic_vector( 15 downto 0 ) ); end lan91c111_send_module; architecture rtl of lan91c111_send_module is signal trgt_MAC_r : std_logic_vector(6*8-1 downto 0); type tx_state_type is (wait_tx, alloc_mem, wait_alloc, copy_packet_number, write_pointer, write_byte_count, write_MACs1, write_MACs2, write_MACs3, write_frame_type, write_payload, write_payload_last16, -- skipped if tx_len mod 4 = 0 or 1 write_padding, -- SMSC bug workaround: autopadding does not work. write_control_byte_and_last, enqueue_packet_number_to_tx_fifo); signal tx_state_r : tx_state_type; signal tx_len_r : std_logic_vector( tx_len_w_c-1 downto 0 ); signal payload_len_r : std_logic_vector( tx_len_w_c-1 downto 0 ); signal tx_len_r_int : integer range 0 to 2**tx_len_w_c-1; signal payload_len_int : integer range 0 to 2**tx_len_w_c-1; signal tx_data_cnt_r : integer range 0 to 2**tx_len_w_c-1; signal pad_cnt_r : integer range 0 to 46; signal tx_data_r : std_logic_vector( lan91_data_width_c-1 downto 0 ); signal tx_data_valid_r : std_logic; signal comm_req_r : std_logic; signal config_valid_r : std_logic; constant pnt_set_wait_cnt_c : integer := clk_hz_c/2702702; -- 370 ns wait after pointer is set. signal pnt_set_wait_cnt_r : integer range 0 to pnt_set_wait_cnt_c; signal got_the_odd_r : std_logic; signal odd_r : std_logic_vector(7 downto 0); signal need_padding_r : std_logic; -- Set if packet is short to overcome a bug/feature in lan91c111 ------------------------------------------------------------------------------- begin -- rtl ------------------------------------------------------------------------------- comm_req_out <= comm_req_r; tx_len_r_int <= to_integer( unsigned( tx_len_r )); payload_len_int <= to_integer( unsigned( payload_len_r )); config_valid_out <= config_valid_r; main: process (clk, rst_n) -- helping with odd length transfers variable odd_len_compensation_v : integer range 0 to 1; begin -- process main if rst_n = '0' then -- asynchronous reset (active low) tx_state_r <= wait_tx; trgt_MAC_r <= (others => '0'); reg_addr_out <= (others => '0'); config_data_out <= (others => '0'); config_valid_r <= '0'; read_not_write_out <= '0'; comm_req_r <= '0'; tx_data_r <= (others => '0'); tx_data_valid_r <= '0'; tx_len_r <= (others => '0'); got_the_odd_r <= '0'; need_padding_r <= '0'; elsif clk'event and clk = '1' then -- rising clock edge -- new_tx_in, tx_len_in and tx_MAC_addr_in must remain stable until -- the first data is read from the upper level. -- tx state machine -- Note: We must be in BANK 2; The initialization algorithm sets the correct -- bank. If any other module switch banks, you must either switch -- back in those modules (recommended as switches are not usually needed) -- or add a new state to switch to bank 2 by using the bank change register at location E. -- DEFAULTS: config_valid_r <= '0'; tx_re_out <= '0'; case tx_state_r is when wait_tx => got_the_odd_r <= '0'; -- new transfer waiting if new_tx_in = '1' then comm_req_r <= '1'; tx_len_r <= std_logic_vector( unsigned( tx_len_in ) + to_unsigned( eth_header_len_c, tx_len_w_c )); payload_len_r <= tx_len_in; trgt_MAC_r <= tx_MAC_addr_in; if comm_grant_in = '1' and comm_req_r = '1' then -- we got permission to use the comm module. tx_state_r <= alloc_mem; reg_addr_out <= "000"; config_nBE_out <= "1100"; -- 16 bit accesses follow. read_not_write_out <= '0'; config_data_out <= x"000000" & "00100000"; config_valid_r <= '1'; end if; end if; when alloc_mem => if comm_busy_in = '0' and config_valid_r = '0' then -- Comm not busy anymore; the next operation. tx_state_r <= wait_alloc; reg_addr_out <= "110"; read_not_write_out <= '1'; config_valid_r <= '1'; end if; if tx_len_r_int < 71 then need_padding_r <= '1'; pad_cnt_r <= 72 - tx_len_r_int; else need_padding_r <= '0'; end if; when wait_alloc => if data_from_comm_valid_in = '1' then -- data_valid = '1' means also -- busy = '0'. See comm module. if data_from_comm_in(3) = '1' then -- ALLOC INT flag = ready. tx_state_r <= copy_packet_number; reg_addr_out <= "001"; read_not_write_out <= '1'; config_valid_r <= '1'; else -- Not ready yet... tx_state_r <= alloc_mem; -- Poll again. end if; end if; when copy_packet_number => if data_from_comm_valid_in = '1' then reg_addr_out <= "001"; -- Copy from ALLOCATED PACKET NUMBER to PACKET NUMBER TX AREA. Both -- are within the same word. config_nBE_out <= "1100"; config_data_out <= x"000000" & "00" & data_from_comm_in(13 downto 8); read_not_write_out <= '0'; config_valid_r <= '1'; tx_state_r <= write_pointer; end if; when write_pointer => if comm_busy_in = '0' and config_valid_r = '0' then reg_addr_out <= "011"; -- Set pointer to RAM offset 2 (Byte count starts here), -- with Auto Increment on. config_nBE_out <= "1100"; config_data_out <= x"0000" & "01000" & "00000000010"; read_not_write_out <= '0'; config_valid_r <= '1'; tx_state_r <= write_byte_count; pnt_set_wait_cnt_r <= pnt_set_wait_cnt_c; end if; when write_byte_count => if comm_busy_in = '0' and config_valid_r = '0' then if pnt_set_wait_cnt_r = 0 then reg_addr_out <= "100"; -- All further operations go to this address. config_nBE_out <= "1100"; read_not_write_out <= '0'; -- Everything after this will be writes. if need_padding_r = '1' then config_data_out <= x"0000" & "00000" & "00001001000"; else config_data_out <= x"0000" & "00000" & tx_len_r; end if; config_valid_r <= '1'; tx_state_r <= write_MACs1; else pnt_set_wait_cnt_r <= pnt_set_wait_cnt_r - 1; end if; end if; when write_MACs1 => if comm_busy_in = '0' and config_valid_r = '0' then config_nBE_out <= "0000"; -- 32 bit access. config_data_out <= trgt_MAC_r(3*8-1 downto 2*8) & trgt_MAC_r(4*8-1 downto 3*8) & trgt_MAC_r(5*8-1 downto 4*8) & trgt_MAC_r(6*8-1 downto 5*8); config_valid_r <= '1'; tx_state_r <= write_MACs2; end if; when write_MACs2 => if comm_busy_in = '0' and config_valid_r = '0' then config_nBE_out <= "0000"; config_data_out <= MAC_addr_c(5*8-1 downto 4*8) & MAC_addr_c(6*8-1 downto 5*8) & trgt_MAC_r(1*8-1 downto 0) & trgt_MAC_r(2*8-1 downto 1*8); config_valid_r <= '1'; tx_state_r <= write_MACs3; end if; when write_MACs3 => if comm_busy_in = '0' and config_valid_r = '0' then config_nBE_out <= "0000"; config_data_out <= MAC_addr_c(1*8-1 downto 0*8) & MAC_addr_c(2*8-1 downto 1*8) & MAC_addr_c(3*8-1 downto 2*8) & MAC_addr_c(4*8-1 downto 3*8); config_valid_r <= '1'; tx_state_r <= write_frame_type; end if; when write_frame_type => if comm_busy_in = '0' and config_valid_r = '0' then config_nBE_out <= "1100"; -- 16 bit access! config_data_out <= x"0000" & tx_frame_type_in(7 downto 0) & tx_frame_type_in(15 downto 8); config_valid_r <= '1'; if payload_len_int = 1 then if need_padding_r = '1' then tx_state_r <= write_padding; else tx_state_r <= write_control_byte_and_last; end if; elsif mode_16bit_g = 0 and (payload_len_int = 2 or payload_len_int = 3) then tx_state_r <= write_payload_last16; else tx_state_r <= write_payload; end if; tx_data_cnt_r <= payload_len_int; end if; when write_payload => if comm_busy_in = '0' and config_valid_r = '0' and tx_data_valid_in = '1' then if mode_16bit_g = 1 then config_nBE_out <= "1100"; config_data_out <= tx_data_in; config_valid_r <= '1'; tx_re_out <= '1'; if tx_data_cnt_r = 2 or tx_data_cnt_r = 3 then if need_padding_r = '1' then tx_state_r <= write_padding; else tx_state_r <= write_control_byte_and_last; end if; end if; tx_data_cnt_r <= tx_data_cnt_r - 2; else -- 32 bit mode (original) config_nBE_out <= "0000"; config_data_out <= tx_data_in; config_valid_r <= '1'; tx_re_out <= '1'; if tx_data_cnt_r = 4 or tx_data_cnt_r = 5 then if need_padding_r = '1' then tx_state_r <= write_padding; else tx_state_r <= write_control_byte_and_last; end if; elsif tx_data_cnt_r = 6 or tx_data_cnt_r = 7 then tx_state_r <= write_payload_last16; end if; tx_data_cnt_r <= tx_data_cnt_r - 4; end if; end if; when write_payload_last16 => assert mode_16bit_g = 0 report "Shouldn't be here!" severity failure; if comm_busy_in = '0' and config_valid_r = '0' and tx_data_valid_in = '1' then config_nBE_out <= "1100"; config_data_out(15 downto 0) <= tx_data_in(15 downto 0); got_the_odd_r <= '1'; odd_r <= tx_data_in(23 downto 16); config_valid_r <= '1'; tx_re_out <= '1'; if need_padding_r = '1' then tx_state_r <= write_padding; else tx_state_r <= write_control_byte_and_last; end if; end if; when write_padding => if comm_busy_in = '0' and config_valid_r = '0' then -- Padding as 16-bit writes to simplify. config_nBE_out <= "1100"; config_data_out <= x"00000000"; config_valid_r <= '1'; if pad_cnt_r = 2 or pad_cnt_r = 3 then tx_state_r <= write_control_byte_and_last; end if; pad_cnt_r <= pad_cnt_r - 2; end if; when write_control_byte_and_last => if comm_busy_in = '0' and config_valid_r = '0' then if tx_data_cnt_r = 0 or tx_data_cnt_r = 2 then -- no odd byte. config_nBE_out <= "1100"; config_data_out <= x"0000" & "00010000" & x"00"; config_valid_r <= '1'; tx_state_r <= enqueue_packet_number_to_tx_fifo; else if tx_data_valid_in = '1' or got_the_odd_r = '1' then config_nBE_out <= "1100"; if got_the_odd_r = '1' then config_data_out <= x"0000" & "00110000" & odd_r; else config_data_out <= x"0000" & "00110000" & tx_data_in(7 downto 0); tx_re_out <= '1'; -- read the odd byte. end if; config_valid_r <= '1'; tx_state_r <= enqueue_packet_number_to_tx_fifo; end if; end if; end if; when enqueue_packet_number_to_tx_fifo => if comm_busy_in = '0' and config_valid_r = '0' then reg_addr_out <= "000"; read_not_write_out <= '0'; config_data_out <= x"000000" & "11000000"; config_valid_r <= '1'; tx_state_r <= wait_tx; comm_req_r <= '0'; end if; when others => null; end case; -- tx_state_r end if; end process main; end rtl;