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

Subversion Repositories fade_ether_protocol

[/] [fade_ether_protocol/] [trunk/] [stable_jumbo_frames_version/] [fpga/] [src/] [eth_receiver64.vhd] - Rev 44

Compare with Previous | Blame | View Log

-------------------------------------------------------------------------------
-- Title      : FPGA Ethernet interface - block receiving packets from MII PHY
-- Project    : 
-------------------------------------------------------------------------------
-- File       : eth_receiver4.vhd
-- Author     : Wojciech M. Zabolotny (wzab@ise.pw.edu.pl)
-- License    : BSD License
-- Company    : 
-- Created    : 2012-03-30
-- Last update: 2014-10-12
-- Platform   : 
-- Standard   : VHDL'93
-------------------------------------------------------------------------------
-- Description: This file implements the state machine, responsible for
-- reception of packets and passing them to the acknowledgements and commands
-- FIFO
-------------------------------------------------------------------------------
-- Copyright (c) 2012 
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author  Description
-- 2012-03-30  1.0      WZab      Created
-------------------------------------------------------------------------------
 
-- Uwaga! Tu mamy rzeczywiste problemy z obsluga odebranych pakietow!
-- 
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.desc_mgr_pkg.all;
use work.pkt_ack_pkg.all;
use work.pkg_newcrc32_d64.all;
use work.pkg_newcrc32_d32.all;
use work.pkg_newcrc32_d16.all;
 
 
entity eth_receiver is
 
  port (
    -- Configuration
    peer_mac       : out std_logic_vector(47 downto 0);
    my_mac         : in  std_logic_vector(47 downto 0);
    my_ether_type  : in  std_logic_vector(15 downto 0);
    transmit_data  : out std_logic;
    restart        : out std_logic;
    -- ACK FIFO interface
    ack_fifo_full  : in  std_logic;
    ack_fifo_wr_en : out std_logic;
    ack_fifo_din   : out std_logic_vector(pkt_ack_width-1 downto 0);
    -- System interface
    clk            : in  std_logic;
    rst_n          : in  std_logic;
    dbg            : out std_logic_vector(3 downto 0);
    cmd            : out std_logic_vector(31 downto 0);
    arg            : out std_logic_vector(31 downto 0);
    crc            : out std_logic_vector(31 downto 0);
    -- MAC interface
    Rx_Clk         : in  std_logic;
    RxC            : in  std_logic_vector(7 downto 0);
    RxD            : in  std_logic_vector(63 downto 0)
    );
 
end eth_receiver;
 
 
architecture beh1 of eth_receiver is
 
  type T_STATE is (ST_RCV_IDLE, ST_RCV_PREAMB, ST_CHECK_PREAMB,
                   ST_RCV_HEADER1, ST_RCV_HEADER2, ST_RCV_CMD,
                   ST_RCV_WAIT_IDLE, ST_RCV_ARGS, ST_RCV_PROCESS, ST_RCV_UPDATE,
                   ST_RCV_TRAILER);
 
 
 
  function rev(a : in std_logic_vector)
    return std_logic_vector is
    variable result : std_logic_vector(a'range);
    alias aa        : std_logic_vector(a'reverse_range) is a;
  begin
    for i in aa'range loop
      result(i) := aa(i);
    end loop;
    return result;
  end;  -- function reverse_any_bus
 
  constant C_PROTO_ID : std_logic_vector(31 downto 0) := x"fade0100";
 
  type T_RCV_REGS is record
    state         : T_STATE;
    swap_lanes    : std_logic;
    transmit_data : std_logic;
    restart       : std_logic;
    update_flag   : std_logic;
    count         : integer;
    dbg           : std_logic_vector(3 downto 0);
    crc32         : std_logic_vector(31 downto 0);
    cmd           : std_logic_vector(31 downto 0);
    arg           : std_logic_vector(31 downto 0);
    mac_addr      : std_logic_vector(47 downto 0);
    peer_mac      : std_logic_vector(47 downto 0);
  end record;
 
  constant RCV_REGS_INI : T_RCV_REGS := (
    state         => ST_RCV_IDLE,
    swap_lanes    => '0',
    transmit_data => '0',
    restart       => '0',
    update_flag   => '0',
    count         => 0,
    dbg           => (others => '0'),
    crc32         => (others => '0'),
    cmd           => (others => '0'),
    arg           => (others => '0'),
    mac_addr      => (others => '0'),
    peer_mac      => (others => '0')
    );
 
  signal r, r_n : T_RCV_REGS := RCV_REGS_INI;
 
  type T_RCV_COMB is record
    ack_fifo_wr_en : std_logic;
    Rx_mac_rd      : std_logic;
    ack_fifo_din   : std_logic_vector(pkt_ack_width-1 downto 0);
    restart        : std_logic;
  end record;
 
  constant RCV_COMB_DEFAULT : T_RCV_COMB := (
    ack_fifo_wr_en => '0',
    Rx_mac_rd      => '0',
    ack_fifo_din   => (others => '0'),
    restart        => '0'
    );
 
  signal c : T_RCV_COMB := RCV_COMB_DEFAULT;
 
  signal rxd_sw, rxd_del : std_logic_vector(63 downto 0);
  signal rxc_sw, rxc_del : std_logic_vector(7 downto 0);
 
  signal rx_rst_n, rx_rst_n_0, rx_rst_n_1          : std_logic := '0';
  signal update_flag_0, update_flag_1, update_flag : std_logic := '0';
 
begin  -- beh1
 
  ack_fifo_din   <= c.ack_fifo_din;
  ack_fifo_wr_en <= c.ack_fifo_wr_en;
 
  --dbg <= r.dbg;
  crc <= r.crc32;
  cmd <= r.cmd;
  arg <= r.arg;
  -- Lane switcher processes
  lsw_c1 : process (RxC, RxC(3 downto 0), RxC_del(7 downto 4), RxD,
                    RxD(31 downto 0), RxD_del(63 downto 32), r.swap_lanes) is
  begin  -- process lsw_c1
    if r.swap_lanes = '1' then
      RxD_Sw(63 downto 32) <= RxD(31 downto 0);
      RxD_Sw(31 downto 0)  <= RxD_del(63 downto 32);
      RxC_Sw(7 downto 4)   <= RxC(3 downto 0);
      RxC_Sw(3 downto 0)   <= RxC_del(7 downto 4);
    else
      RxD_Sw <= RxD;
      RxC_Sw <= RxC;
    end if;
  end process lsw_c1;
 
  process (Rx_Clk, rx_rst_n) is
  begin  -- process
    if rx_rst_n = '0' then              -- asynchronous reset (active low)
      RxD_del <= (others => '0');
      RxC_del <= (others => '0');
    elsif Rx_Clk'event and Rx_Clk = '1' then  -- rising clock edge
      RxD_del <= RxD;
      RxC_del <= RxC;
    end if;
  end process;
 
  -- Reading of ethernet data
  rdp1 : process (Rx_Clk, rx_rst_n)
  begin  -- process rdp1
    if rx_rst_n = '0' then              -- asynchronous reset (active low)
      r <= RCV_REGS_INI;
    elsif Rx_Clk'event and Rx_Clk = '1' then  -- rising clock edge
      r <= r_n;
    end if;
  end process rdp1;
 
  rdp2 : process (RxC, RxC_Sw, RxD, RxD_Sw, ack_fifo_full, my_ether_type,
                  my_mac, r, r.arg(15 downto 10), r.arg(31 downto 16),
                  r.cmd(15 downto 0), r.cmd(31 downto 16), r.crc32, r.dbg(0),
                  r.dbg(1), r.dbg(2), r.dbg(3), r.mac_addr, r.state,
                  r.update_flag)
 
    variable ack_pkt_in   : pkt_ack;
    variable v_mac_addr   : std_logic_vector(47 downto 0);
    variable v_cmd, v_arg : std_logic_vector(31 downto 0);
    variable v_crc        : std_logic_vector(31 downto 0);
    variable v_proto      : std_logic_vector(31 downto 0);
 
  begin  -- process
    c   <= RCV_COMB_DEFAULT;
    r_n <= r;
    dbg <= "1111";
    case r.state is
      when ST_RCV_IDLE =>
        dbg <= "0000";
        -- We must be prepared to one of two possible events
        -- Either we receive the SOF in the 0-th lane (and then we proceed
        -- normally) or we receive the SOF in the 4-th lane (and then we have
        -- to switch lanes, delaying 4 of them).
        if RxC = b"00011111" and RxD = x"55_55_55_fb_07_07_07_07" then
          -- shifted lanes
          -- switch on the "lane shifter" and go to the state,
          -- where we can check the proper preamble after lane switching
          r_n.swap_lanes <= '1';
          r_n.state      <= ST_CHECK_PREAMB;
        elsif RxC = b"00000001" and RxD = x"d5_55_55_55_55_55_55_fb" then
          -- normal lanes
          r_n.swap_lanes <= '0';
          r_n.crc32      <= (others => '1');
          r_n.state      <= ST_RCV_HEADER1;
        end if;
      when ST_CHECK_PREAMB =>
        dbg <= "0001";
        if RxC_Sw = b"00000001" and RxD_Sw = x"d5_55_55_55_55_55_55_fb" then
          r_n.crc32 <= (others => '1');
          r_n.state <= ST_RCV_HEADER1;
        else
          -- interrupted preamble reception
          r_n.state <= ST_RCV_IDLE;
        end if;
      when ST_RCV_HEADER1 =>
        dbg <= "0010";
        if RxC_Sw = b"00000000" then
          r_n.crc32 <= newcrc32_d64(RxD_Sw, r.crc32);
          -- Change the order of bytes!
          for i in 0 to 5 loop
            v_mac_addr(47-i*8 downto 40-i*8) := RxD_Sw(i*8+7 downto i*8);
          end loop;  -- i
          if v_mac_addr /= my_mac then
            -- This packet is not for us - ignore it!
            r_n.state <= ST_RCV_WAIT_IDLE;
          else
            -- Our packet!
            r_n.count                  <= 0;
            -- Read the lower 16 bits of the sender address
            -- Again, we have to change the order of bytes!
            r_n.mac_addr(39 downto 32) <= RxD_Sw(63 downto 56);
            r_n.mac_addr(47 downto 40) <= RxD_Sw(55 downto 48);
            r_n.state                  <= ST_RCV_HEADER2;
          end if;
        else
          -- packet broken?
          r_n.state <= ST_RCV_IDLE;
        end if;
      when ST_RCV_HEADER2 =>
        dbg <= "0010";
        if RxC_Sw = b"00000000" then
          r_n.crc32  <= newcrc32_d64(RxD_Sw, r.crc32);
          v_mac_addr := r.mac_addr;
          for i in 0 to 3 loop
            v_mac_addr(31-i*8 downto 24-i*8) := RxD_Sw(i*8+7 downto i*8);
          end loop;  -- i
          --v_mac_addr(47 downto 16) := RxD_Sw(31 downto 0);
          r_n.mac_addr <= v_mac_addr;
          -- In the rest of this 64-bit word, we receive the protocol ID
          -- and version
          for i in 0 to 3 loop
            v_proto(i*8+7 downto i*8) := RxD_Sw(63-i*8 downto 56-i*8);
          end loop;  -- i
          -- Check if the proto id is correct
          if v_proto = C_PROTO_ID then
            r_n.state <= ST_RCV_CMD;
          else
            r_n.state <= ST_RCV_IDLE;
          end if;
        else
          -- packet broken?
          r_n.state <= ST_RCV_IDLE;
        end if;
      when ST_RCV_CMD =>
        if RxC_Sw = b"0000_0000" then
          r_n.crc32 <= newcrc32_d64(RxD_Sw, r.crc32);
          -- Copy the command, changing order of bytes!
          for i in 0 to 3 loop
            r_n.cmd(i*8+7 downto i*8) <= RxD_Sw(31-i*8 downto 24-i*8);
          end loop;  -- i          
          -- Copy the argument, changing order of bytes!
          for i in 0 to 3 loop
            r_n.arg(i*8+7 downto i*8) <= RxD_Sw(63-i*8 downto 56-i*8);
          end loop;  -- i
          r_n.state <= ST_RCV_TRAILER;
        -- Currently we ignore rest of the packet!
        else
          -- packet broken?
          r_n.state <= ST_RCV_IDLE;
        end if;
      when ST_RCV_TRAILER =>
        -- No detection of too long frames!
        dbg <= "0110";
        if RxC_Sw /= b"0000_0000" then
          -- It should be a packet with the checksum
          -- The EOF may be on any of 8th positions.
          -- To avoid too big combinational functions,
          -- we handle it in a few states (but this increases requirements
          -- on IFC!)
          -- Current implementation assumes fixed length of frames
          -- but the optimal one should probably pass received data for further
          -- checking, why this machine continues to receive next frame...
          if RxC_Sw = b"1111_1100" then
            v_crc     := r.crc32;
            v_crc     := newcrc32_d16(RxD_Sw(15 downto 0), v_crc);
            r_n.crc32 <= v_crc;
            if (RxD_Sw(23 downto 16) = x"fd") and
              (v_crc = x"c704dd7b") then
              -- Correct packet, go to processing
              r_n.peer_mac <= r.mac_addr;
              r_n.state    <= ST_RCV_PROCESS;
            else
              -- Wrong CRC or EOF
              r_n.state <= ST_RCV_IDLE;
            end if;
          else
            -- Wrong packet
            r_n.state <= ST_RCV_IDLE;
          end if;
        else
          -- Ignore received data, only updating the checksum
          r_n.crc32 <= newcrc32_d64(RxD_Sw, r.crc32);
        end if;
      when ST_RCV_PROCESS =>
        dbg <= "0111";
        case to_integer(unsigned(r.cmd(31 downto 16))) is
          -- Handle commands, which require immediate action
          when FCMD_START =>
            r_n.dbg(0)        <= not r.dbg(0);
            -- Start transmission command
            r_n.transmit_data <= '1';
          when FCMD_STOP =>
            r_n.dbg(1)        <= not r.dbg(1);
            -- Stop transmission command
            r_n.transmit_data <= '0';
          when FCMD_RESET =>
            r_n.dbg(3)  <= not r.dbg(3);
            -- Restart the whole block(?)
            r_n.restart <= '1';
          when others =>
            null;
        end case;
        -- All commands are written to the acknowledge and commands
        -- FIFO, so that they will be handled by the descriptor manager
        if ack_fifo_full = '0' then
          ack_pkt_in.cmd   := unsigned(r.cmd(31 downto 16));
          ack_pkt_in.pkt   := unsigned(r.arg);
          ack_pkt_in.seq   := unsigned(r.cmd(15 downto 0));
          c.ack_fifo_din   <= pkt_ack_to_stlv(ack_pkt_in);
          c.ack_fifo_wr_en <= '1';
        end if;
        r_n.state <= ST_RCV_UPDATE;
      when ST_RCV_UPDATE =>
        dbg             <= "1000";
        r_n.update_flag <= not r.update_flag;
        r_n.state       <= ST_RCV_IDLE;
      when ST_RCV_WAIT_IDLE =>
        dbg <= "1001";
        if RxC_Sw = b"1111_1111" then
          r_n.state <= ST_RCV_IDLE;
        end if;
      when others => null;
    end case;
  end process rdp2;
 
  -- Synchronization of the reset signal for the Rx_Clk domain
  process (Rx_Clk, rst_n)
  begin  -- process
    if rst_n = '0' then                 -- asynchronous reset (active low)
      rx_rst_n_0 <= '0';
      rx_rst_n_1 <= '0';
      rx_rst_n   <= '0';
    elsif Rx_Clk'event and Rx_Clk = '1' then  -- rising clock edge
      rx_rst_n_0 <= rst_n;
      rx_rst_n_1 <= rx_rst_n_0;
      rx_rst_n   <= rx_rst_n_1;
    end if;
  end process;
 
 
  -- Synchronization of output signals between the clock domains
  process (clk, rst_n)
  begin  -- process
    if rst_n = '0' then                 -- asynchronous reset (active low)
      peer_mac      <= (others => '0');
      transmit_data <= '0';
      restart       <= '0';
      update_flag_0 <= '0';
      update_flag_1 <= '0';
      update_flag   <= '0';
    elsif clk'event and clk = '1' then  -- rising clock edge
      -- Synchronization of the update_flag
      update_flag_0 <= r.update_flag;
      update_flag_1 <= update_flag_0;
      update_flag   <= update_flag_1;
      -- When update flag has changed, rewrite synchronized fields
      if update_flag /= update_flag_1 then
        peer_mac      <= r.peer_mac;
        transmit_data <= r.transmit_data;
        restart       <= r.restart;
      end if;
    end if;
  end process;
 
end beh1;
 

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.