OpenCores
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/] [udp_ip/] [1.0/] [vhd/] [udp.vhd] - Rev 145

Compare with Previous | Blame | View Log

-------------------------------------------------------------------------------
-- Title      : UDP/IP header handling
-- Project    : 
-------------------------------------------------------------------------------
-- File       : udp.vhd
-- Author     : Jussi Nieminen  <niemin95@galapagosinkeiju.cs.tut.fi>
-- Company    : 
-- Last update: 2010/01/06
-- Platform   : 
-------------------------------------------------------------------------------
-- Description: Adds and removes UDP and IP headers to data
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author  Description
-- 2009/09/16  1.0      niemin95        Created
-------------------------------------------------------------------------------
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.udp_ip_pkg.all;
 
 
entity udp is
 
  generic (
    data_width_g : integer := 16;
    tx_len_w_g   : integer := 11);
 
  port (
    clk                   : in  std_logic;
    rst_n                 : in  std_logic;
    -- from application to udp
    new_tx_in             : in  std_logic;
    tx_len_in             : in  std_logic_vector( tx_len_w_g-1 downto 0 );
    target_IP_in          : in  std_logic_vector( ip_addr_w_c-1 downto 0 );
    target_port_in        : in  std_logic_vector( port_w_c-1 downto 0 );
    source_port_in        : in  std_logic_vector( port_w_c-1 downto 0 );
    -- from udp to eth
    new_tx_out            : out std_logic;
    tx_MAC_addr_out       : out std_logic_vector( MAC_addr_w_c-1 downto 0 );
    tx_len_out            : out std_logic_vector( tx_len_w_g-1 downto 0 );
    tx_frame_type_out     : out std_logic_vector( frame_type_w_c-1 downto 0 );
    header_data_out       : out std_logic_vector( data_width_g-1 downto 0 );
    header_data_valid_out : out std_logic;
    ethernet_re_in        : in  std_logic;
    new_rx_in             : in  std_logic;
    rx_data_in            : in  std_logic_vector( data_width_g-1 downto 0 );
    rx_data_valid_in      : in  std_logic;
    rx_len_in             : in  std_logic_vector( tx_len_w_g-1 downto 0 );
    rx_frame_type_in      : in  std_logic_vector( frame_type_w_c-1 downto 0 );
    rx_re_out             : out std_logic;
    rx_erroneous_in       : in  std_logic;
    -- from udp to application
    rx_erroneous_out      : out std_logic;
    new_rx_out            : out std_logic;
    rx_len_out            : out std_logic_vector( tx_len_w_g-1 downto 0 );
    source_IP_out         : out std_logic_vector( ip_addr_w_c-1 downto 0 );
    source_port_out       : out std_logic_vector( port_w_c-1 downto 0 );
    dest_port_out         : out std_logic_vector( port_w_c-1 downto 0 );
    application_re_in     : in  std_logic;
    -- from udp to arpsnd
    request_MAC_out       : out std_logic;
    IP_to_arp_out         : out std_logic_vector( ip_addr_w_c-1 downto 0 );
    requested_MAC_in      : in  std_logic_vector( MAC_addr_w_c-1 downto 0 );
    req_MAC_valid_in      : in  std_logic;
    rx_arp_ready_in       : in  std_logic;
    snd_req_from_arp_in   : in  std_logic;
    tx_arp_ready_in       : in  std_logic;
    -- other control signals
    rx_error_out          : out std_logic;
    input_select_out      : out std_logic_vector( 1 downto 0 );
    output_select_out     : out std_logic_vector( 1 downto 0 )
    );
 
end udp;
 
 
architecture rtl of udp is
 
  type tx_state_type is (tx_idle, write_IP_headers, write_UDP_headers, relay_tx_data, tx_arp);
  type rx_state_type is (rx_idle, read_IP_headers, read_UDP_headers, relay_rx_data,
                         rx_arp, rx_discard, rx_error);
  type IP_header_state_type is (version_IHL_DS, IP_length, ID, flags_offset, TTL_protocol,
                                header_checksum, source_addr1, source_addr2,
                                dest_addr1, dest_addr2, discard);
  type UDP_header_state_type is (source_port, dest_port, UDP_length, UDP_checksum);
 
  signal rx_state_r     : rx_state_type;
  signal tx_state_r     : tx_state_type;
  signal tx_IP_state_r  : IP_header_state_type;
  signal tx_UDP_state_r : UDP_header_state_type;
  signal rx_IP_state_r  : IP_header_state_type;
  signal rx_UDP_state_r : UDP_header_state_type;
 
 
  signal rx_len_r        : integer range 0 to 2**tx_len_w_g-1;
  signal rx_re_r         : std_logic;
 
  signal discard_rx_r : std_logic;
 
  signal tx_len_r      : integer range 0 to 2**tx_len_w_g-1;
  signal target_port_r : std_logic_vector( port_w_c-1 downto 0 );
  signal source_port_r : std_logic_vector( port_w_c-1 downto 0 );
  signal target_addr_r : std_logic_vector( ip_addr_w_c-1 downto 0 );
 
  signal ip_checksum : std_logic_vector( ip_checksum_w_c-1 downto 0 );
 
  signal discard_xtra_bytes_r : std_logic;
  signal num_xtra_bytes_r : integer range 0 to 63;
 
  constant IP_header_words_c : integer := 5;  -- 32bit words
  constant UDP_header_length_c : integer := 8;  -- bytes
 
  -- precounted part of IP checksum, including field version_IHL_DS, ID,
  -- flags_offset and TTL_protocol
  constant pre_counted_part_of_checksum_c : std_logic_vector( ip_checksum_w_c-1 downto 0 )
    := "0100101000010001";
 
  signal tx_len_for_checksum : std_logic_vector( 15 downto 0 );
 
-------------------------------------------------------------------------------
begin  -- rtl
-------------------------------------------------------------------------------
 
  -- *********************************************************************************
  -- REMEMBER!! rx_data_in(15 downto 8) = LSByte and rx_data_in(7 downto 0) = MSByte!!
  -- Same goes for the tx_data_out too!
  -- *********************************************************************************
 
 
-------------------------------------------------------------------------------
  rx_re_out <= rx_re_r;
 
  rx_process : process (clk, rst_n)
 
    variable incoming_len_v : integer range 0 to 2**tx_len_w_g-1;
 
  begin  -- process rx_process
    if rst_n = '0' then                 -- asynchronous reset (active low)
 
      rx_state_r <= rx_idle;
      rx_IP_state_r <= version_IHL_DS;
      rx_UDP_state_r <= source_port;
 
      rx_re_r               <= '0';
      rx_erroneous_out      <= '0';
      new_rx_out            <= '0';
      rx_len_out            <= (others => '0');
      source_IP_out         <= (others => '0');
      source_port_out       <= (others => '0');
      dest_port_out         <= (others => '0');
      discard_rx_r          <= '0';
      discard_xtra_bytes_r  <= '0';
      num_xtra_bytes_r      <= 0;
 
      input_select_out <= (others => '0');
 
      rx_error_out <= '0';
 
    elsif clk'event and clk = '1' then  -- rising clock edge
 
      case rx_state_r is
        when rx_idle =>
 
          new_rx_out       <= '0';
          rx_len_out       <= (others => '0');
          source_IP_out    <= (others => '0');
          source_port_out  <= (others => '0');
          dest_port_out    <= (others => '0');
          rx_erroneous_out <= '0';
 
          discard_rx_r         <= '0';
          discard_xtra_bytes_r <= '0';
          num_xtra_bytes_r     <= 0;
 
          if new_rx_in = '1' then
 
            if rx_frame_type_in = ARP_frame_type_c then
              -- arp packet goes straight to arp
              rx_state_r <= rx_arp;
 
            elsif rx_frame_type_in = IP_frame_type_c then
              -- data transfer coming, start reading the headers
              rx_state_r <= read_IP_headers;
              rx_IP_state_r <= version_IHL_DS;
 
              rx_len_r <= to_integer( unsigned( rx_len_in ));
              rx_erroneous_out <= rx_erroneous_in;
 
            else
              -- whoaa, unknown protocol, discard
              rx_len_r <= to_integer( unsigned( rx_len_in ));
              rx_state_r <= rx_discard;
 
            end if;
          end if;
 
        when read_IP_headers =>
 
          if rx_data_valid_in = '1' and rx_re_r = '0' then
            rx_re_r <= '1';
          end if;
 
          if rx_data_valid_in = '1' and rx_re_r = '1' then
            rx_re_r <= '0';
 
            -------------------------------------------------------------------
            -- sub FSM handling the different fields of tx
            case rx_IP_state_r is
              when version_IHL_DS =>
 
                -- 0_____________4_______________8_________________________16
                -- |   version   | header length | Differentiated Services |
 
                -- only thing we are interested of is the header length
                -- if there's options-fields (over 5 32bit words in the header)
                -- we simply discard this transmission
                if to_integer( unsigned( rx_data_in(3 downto 0) )) /= IP_header_words_c then
                  discard_rx_r <= '1';
                end if;
 
                rx_IP_state_r <= IP_length;
 
              when IP_length =>
 
                -- total length of the packet, including header and the data.
                incoming_len_v := to_integer( unsigned( rx_data_in(7 downto 0 ) & rx_data_in( 15 downto 8 ) ));
 
                -- +1, because when reading two bytes at a time, we don't need
                -- to read any xtra if rx_len = incoming_len_v + 1
                if rx_len_r > incoming_len_v + 1 then
                  -- amount of data is less than ethernet minimum frame size (64 bytes)
                  -- we have to discard the extra bytes after data has been relayed.
                  discard_xtra_bytes_r <= '1';
 
                  -- getting rid of the last bit, because with odd lengths one
                  -- of the xtra bytes is already read out with the last databyte
                  num_xtra_bytes_r <= (( rx_len_r - incoming_len_v ) / 2 ) * 2;
 
                elsif rx_len_r /= incoming_len_v and rx_len_r /= incoming_len_v + 1 then
                  -- there's something wrong
                  rx_state_r <= rx_error;
                end if;
 
                rx_len_r <= incoming_len_v;
                rx_IP_state_r <= ID;
 
              when ID =>
                -- we don't care about this field
                rx_IP_state_r <= flags_offset;
              when flags_offset =>
                -- we don't care about the flags or the offset either
                rx_IP_state_r <= TTL_protocol;
 
              when TTL_protocol =>
 
                -- 0______________8______________16
                -- | Time To Live |   Protocol   |
 
                -- check that the protocol is UDP and TTL /= 0,
                -- otherwise discard this transmission
                if to_integer( unsigned( rx_data_in( 7 downto 0 ) )) = 0 or
                  rx_data_in( 15 downto 8 ) /= UDP_protocol_c
                then
                  discard_rx_r <= '1';
                end if;
                rx_IP_state_r <= header_checksum;
 
              when header_checksum =>
 
                -- checksum check not implemented yet, maybe some day...
                rx_IP_state_r <= source_addr1;
 
              when source_addr1 =>
 
                source_IP_out( 31 downto 24 ) <= rx_data_in( 7 downto 0 );
                source_IP_out( 23 downto 16 ) <= rx_data_in( 15 downto 8 );
                rx_IP_state_r <= source_addr2;
 
              when source_addr2 =>
 
                source_IP_out( 15 downto 8 ) <= rx_data_in( 7 downto 0 );
                source_IP_out( 7 downto 0 )  <= rx_data_in( 15 downto 8 );
                rx_IP_state_r <= dest_addr1;
 
              when dest_addr1 =>
 
                -- just check that the addr matches
                if rx_data_in( 7 downto 0 ) /= own_ip_c( 31 downto 24 ) or
                  rx_data_in( 15 downto 8 ) /= own_ip_c( 23 downto 16 )
                then
                  -- some multicast messages contain a certain IP, so we might
                  -- get packets with wrong address
                  discard_rx_r <= '1';
                end if;
                rx_IP_state_r <= dest_addr2;
 
              when dest_addr2 =>
 
                if (rx_data_in( 7 downto 0 ) /= own_ip_c( 15 downto 8 ) or
                  rx_data_in( 15 downto 8 ) /= own_ip_c( 7 downto 0 ))
                  or discard_rx_r = '1'
                then
                  -- if message is to be discarded, go and discard it, otherwise
                  -- start reading UDP headers
                  rx_IP_state_r <= discard;
                  -- there might also be extra bytes to discard, so add them to
                  -- the length and remove IP header length
                  rx_len_r <= rx_len_r + num_xtra_bytes_r - ( IP_header_words_c*4 );
 
                else
                  rx_state_r     <= read_UDP_headers;
                  rx_UDP_state_r <= source_port;
                  rx_IP_state_r  <= version_IHL_DS;
 
                  -- remove IP header length
                  rx_len_r <= rx_len_r - ( IP_header_words_c * 4 );
                end if;
 
 
 
 
              when discard =>
 
                -- just pretend to be reading
                if rx_len_r <= 2 then
                  -- all done
                  rx_len_r <= 0;
                  rx_IP_state_r <= version_IHL_DS;
                  rx_state_r <= rx_idle;
                else
                  rx_len_r <= rx_len_r - 2;
                end if;
 
              when others => null;
            end case;
            -- /rx_IP_state_r
            -------------------------------------------------------------------            
          end if;
 
 
 
        when read_UDP_headers =>
 
          if rx_data_valid_in = '1' and rx_re_r = '0' then
            rx_re_r <= '1';
          end if;
 
          if rx_data_valid_in = '1' and rx_re_r = '1' then
            rx_re_r <= '0';
 
            -- FSM to read the UDP header
            -------------------------------------------------------------------
            case rx_UDP_state_r is
              when source_port =>
 
                source_port_out( 15 downto 8 ) <= rx_data_in( 7 downto 0 );
                source_port_out( 7 downto 0 )  <= rx_data_in( 15 downto 8 );
                rx_UDP_state_r <= dest_port;
 
              when dest_port =>
 
                dest_port_out( 15 downto 8 ) <= rx_data_in( 7 downto 0 );
                dest_port_out( 7 downto 0 )  <= rx_data_in( 15 downto 8 );
                rx_UDP_state_r <= UDP_length;
 
              when UDP_length =>
 
                -- check that the length field is correct
                if rx_len_r /=
                  to_integer( unsigned( rx_data_in(7 downto 0 ) & rx_data_in( 15 downto 8 ) ))
                then
                  rx_state_r <= rx_error;
                end if;
                rx_UDP_state_r <= UDP_checksum;
 
              when UDP_checksum =>
 
                -- umm, it's propably correct...
                -- give rx_data to application
                input_select_out <= "10";
                rx_state_r <= relay_rx_data;
                -- notify application about new tx
                new_rx_out <= '1';
                rx_len_out <= std_logic_vector( to_unsigned( rx_len_r -
                                                             UDP_header_length_c,
                                                             tx_len_w_g ));
 
 
                rx_UDP_state_r <= source_port;
                rx_len_r <= rx_len_r - UDP_header_length_c;
 
              when others => null;
            end case;
            -- /rx_UDP_state_r
            -------------------------------------------------------------------
          end if;
 
 
        when relay_rx_data =>
 
          -- monitor application_re
          if application_re_in = '1' and rx_data_valid_in = '1' then
 
            new_rx_out <= '0';
 
            if rx_len_r <= 2 then
              -- all received
              input_select_out <= "00";
 
              -- if there is extra bytes
              if discard_xtra_bytes_r = '1' then
 
                rx_state_r           <= rx_discard;
                rx_len_r             <= num_xtra_bytes_r;
                discard_xtra_bytes_r <= '0';
                num_xtra_bytes_r     <= 0;
 
              else
                rx_state_r <= rx_idle;
                rx_len_r   <= 0;
              end if;
 
            else
              rx_len_r <= rx_len_r - 2;
            end if;
          end if;
 
 
        when rx_arp =>
 
          -- give turn to arp until it says it's ready
          input_select_out <= "01";
          if rx_arp_ready_in = '1' then
            input_select_out <= "00";
            rx_state_r <= rx_idle;
          end if;
 
 
        when rx_discard =>
          -- we come here, if the frame type of ethernet frame is something
          -- else than ARP or IP or if there is extra bytes in the frame (less
          -- data than minimum ethernet frame size)
 
          if rx_data_valid_in = '1' and rx_re_r = '0' then
            rx_re_r <= '1';
          end if;
 
          if rx_data_valid_in = '1' and rx_re_r = '1' then
            rx_re_r <= '0';
 
            -- just pretend to be reading
            if rx_len_r <= 2 then
              -- all done
              rx_len_r <= 0;
              rx_state_r <= rx_idle;
            else
              rx_len_r <= rx_len_r - 2;
            end if;
          end if;
 
        when rx_error =>
 
          -- shit just hit the fan
          rx_error_out <= '1';
 
        when others => null;
      end case;
 
    end if;
  end process rx_process;
-------------------------------------------------------------------------------
 
  tx_len_for_checksum <= std_logic_vector( to_unsigned( tx_len_r, 16 ));
 
  -- IP checksum computation
  checksum_adder: entity work.ip_checksum
    generic map (
        pre_counted_part_g => pre_counted_part_of_checksum_c
        )
    port map (
        total_length_field_in => tx_len_for_checksum,
        source_addr_field_in  => own_ip_c,
        dest_addr_field_in    => target_addr_r,
        header_checksum_out   => ip_checksum
        );
 
-------------------------------------------------------------------------------
 
 
  tx_process: process (clk, rst_n)
 
    variable tx_len_v : integer range 0 to 2**tx_len_w_g-1;
    variable tx_len_slv_v : std_logic_vector( 15 downto 0 );
 
  begin  -- process tx_process
    if rst_n = '0' then                 -- asynchronous reset (active low)
 
      tx_state_r <= tx_idle;
      tx_IP_state_r <= version_IHL_DS;
      tx_UDP_state_r <= source_port;
 
      output_select_out <= (others => '0');
      tx_len_r <= 0;
      target_addr_r <= (others => '0');
      target_port_r <= (others => '0');
      source_port_r <= (others => '0');
 
      request_MAC_out       <= '0';
      IP_to_arp_out         <= (others => '0');
      new_tx_out            <= '0';
      tx_MAC_addr_out       <= (others => '0');
      tx_len_out            <= (others => '0');
      tx_frame_type_out     <= (others => '0');
      header_data_out       <= (others => '0');
      header_data_valid_out <= '0';
 
 
    elsif clk'event and clk = '1' then  -- rising clock edge
 
      case tx_state_r is
        when tx_idle =>
 
          -- if arp want's to send, give it the output
          if snd_req_from_arp_in = '1' then
            tx_state_r <= tx_arp;
 
          elsif new_tx_in = '1' then
 
            if req_MAC_valid_in = '1' then
              -- MAC found from the ARP table, start sending
              tx_state_r <= write_IP_headers;
              -- write first word here already (version_IHL_DS)
              -- first the version, IPv4
              header_data_out( 7 downto 4 ) <= "0100";
              -- then header length in words
              header_data_out( 3 downto 0 ) <= std_logic_vector( to_unsigned( IP_header_words_c, 4 ));
              -- then Differentiated Services (just zeros)
              header_data_out( 15 downto 8 ) <= (others => '0');
 
              header_data_valid_out <= '1';
 
              tx_len_v   := to_integer( unsigned( tx_len_in )) +
                            IP_header_words_c*4 + UDP_header_length_c;
              tx_len_r   <= tx_len_v;
              tx_len_out <= std_logic_vector( to_unsigned( tx_len_v, tx_len_w_g ));
              new_tx_out <= '1';
              tx_frame_type_out <= IP_frame_type_c;
 
              source_port_r    <= source_port_in;
              target_port_r    <= target_port_in;
              target_addr_r    <= target_IP_in;
              tx_MAC_addr_out  <= requested_MAC_in;
 
              request_MAC_out <= '0';
 
            else
              -- We must get the MAC address before we can start sending
              request_MAC_out <= '1';
              IP_to_arp_out   <= target_IP_in;
            end if;
          end if;
 
 
        when write_IP_headers =>
 
          if ethernet_re_in = '1' then
            -- the data of the next state is written during the previous one
            case tx_IP_state_r is
              when version_IHL_DS =>
 
                new_tx_out <= '0';
                tx_IP_state_r <= IP_length;
 
                -- remember, data goes in as 2 bytes, not as single 16-bit word
                tx_len_slv_v := std_logic_vector( to_unsigned( tx_len_r, 16 ));
                header_data_out <= tx_len_slv_v( 7 downto 0 ) & tx_len_slv_v( 15 downto 8 );
 
              when IP_length =>
                tx_IP_state_r <= ID;
                header_data_out <= (others => '0');
 
              when ID =>
                tx_IP_state_r <= flags_offset;
                header_data_out <= (others => '0');
 
              when flags_offset =>
 
                tx_IP_state_r <= TTL_protocol;
                -- this block is made for direct communication, not router
                -- networks, so 1 to TTL field should do. Still, just in case,
                -- we'll put there a 5.
                header_data_out( 7 downto 0 )  <= "00000101";
                -- protocol is UDP
                header_data_out( 15 downto 8 ) <= UDP_protocol_c;
 
              when TTL_protocol =>
                tx_IP_state_r <= header_checksum;
                header_data_out <= ip_checksum( 7 downto 0 ) & ip_checksum( 15 downto 8 );
 
              when header_checksum =>
                tx_IP_state_r <= source_addr1;
                header_data_out <= own_ip_c( 23 downto 16 ) & own_ip_c( 31 downto 24 );
 
              when source_addr1 =>
                tx_IP_state_r <= source_addr2;
                header_data_out <= own_ip_c( 7 downto 0 ) & own_ip_c( 15 downto 8 );
 
              when source_addr2 =>
                tx_IP_state_r <= dest_addr1;
                header_data_out <= target_addr_r( 23 downto 16 ) & target_addr_r( 31 downto 24 );
 
              when dest_addr1 =>
                tx_IP_state_r <= dest_addr2;
                header_data_out <= target_addr_r( 7 downto 0 ) & target_addr_r( 15 downto 8 );
 
              when dest_addr2 =>
                -- all written, move on to write the UDP addr
                tx_state_r <= write_UDP_headers;
                tx_IP_state_r <= version_IHL_DS;
                -- first UDP data
                header_data_out <= source_port_r( 7 downto 0 ) & source_port_r( 15 downto 8 );
 
              when others => null;
            end case;
          end if;
 
 
        when write_UDP_headers =>
 
          if ethernet_re_in = '1' then
 
            case tx_UDP_state_r is
              when source_port =>
 
                tx_UDP_state_r <= dest_port;
                header_data_out <= target_port_r( 7 downto 0 ) & target_port_r( 15 downto 8 );
 
              when dest_port =>
 
                tx_UDP_state_r <= UDP_length;
                tx_len_slv_v := std_logic_vector( to_unsigned( tx_len_r -
                                                               IP_header_words_c*4, 16 ));
                header_data_out <= tx_len_slv_v( 7 downto 0 ) & tx_len_slv_v( 15 downto 8 );
 
              when UDP_length =>
                tx_UDP_state_r <= UDP_checksum;
                -- not used
                header_data_out <= (others => '0');
 
              when UDP_checksum =>
 
                -- all done, start relaying the data
                header_data_valid_out <= '0';
                header_data_out       <= (others => '0');
                tx_UDP_state_r        <= source_port;
                tx_state_r            <= relay_tx_data;
                output_select_out     <= "10";
                -- remove headers from length
                tx_len_r <= tx_len_r - IP_header_words_c*4 - UDP_header_length_c;
 
              when others => null;
            end case;
          end if;
 
 
        when relay_tx_data =>
 
          -- count the amount of sent data and go back to idle after all is sent
          if ethernet_re_in = '1' then
 
            if tx_len_r <= 2 then
              -- all sent
              tx_len_r          <= 0;
              tx_state_r        <= tx_idle;
              output_select_out <= "00";
 
            else
              tx_len_r <= tx_len_r - 2;
            end if;
          end if;
 
 
        when tx_arp =>
 
          -- give output to arp
          output_select_out <= "01";
 
          -- wait until it's idle again
          if tx_arp_ready_in = '1' then
            output_select_out <= "00";
            tx_state_r <= tx_idle;
          end if;
 
        when others => null;
      end case;
 
    end if;
  end process tx_process;
 
 
 
end rtl;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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