OpenCores
URL https://opencores.org/ocsvn/funbase_ip_library/funbase_ip_library/trunk

Subversion Repositories funbase_ip_library

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /funbase_ip_library
    from Rev 49 to Rev 50
    Reverse comparison

Rev 49 → Rev 50

/trunk/TUT/ip.hwp.interface/eth_lan91c111_ctrl/1.0/vhd/lan91c111_send_module.vhd
0,0 → 1,402
-------------------------------------------------------------------------------
-- 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;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.