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] - Diff between revs 40 and 44

Show entire file | Details | Blame | View Log

Rev 40 Rev 44
Line 1... Line 1...
 
-------------------------------------------------------------------------------
 
-- 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;
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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