mirror of
https://github.com/lcbcFoo/ReonV.git
synced 2025-04-21 20:17:18 -04:00
376 lines
11 KiB
VHDL
376 lines
11 KiB
VHDL
------------------------------------------------------------------------------
|
|
-- This file is a part of the GRLIB VHDL IP LIBRARY
|
|
-- Copyright (C) 2003 - 2008, Gaisler Research
|
|
-- Copyright (C) 2008 - 2014, Aeroflex Gaisler
|
|
-- Copyright (C) 2015 - 2017, Cobham Gaisler
|
|
--
|
|
-- This program is free software; you can redistribute it and/or modify
|
|
-- it under the terms of the GNU General Public License as published by
|
|
-- the Free Software Foundation; either version 2 of the License, or
|
|
-- (at your option) any later version.
|
|
--
|
|
-- This program is distributed in the hope that it will be useful,
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-- GNU General Public License for more details.
|
|
--
|
|
-- You should have received a copy of the GNU General Public License
|
|
-- along with this program; if not, write to the Free Software
|
|
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
-----------------------------------------------------------------------------
|
|
-- Entity: greth_rx
|
|
-- File: greth_rx.vhd
|
|
-- Author: Marko Isomaki
|
|
-- Description: Ethernet receiver
|
|
------------------------------------------------------------------------------
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
library grlib;
|
|
use grlib.stdlib.all;
|
|
library eth;
|
|
use eth.grethpkg.all;
|
|
|
|
entity greth_rx is
|
|
generic(
|
|
nsync : integer range 1 to 2 := 2;
|
|
rmii : integer range 0 to 1 := 0;
|
|
multicast : integer range 0 to 1 := 0;
|
|
maxsize : integer := 1500;
|
|
gmiimode : integer range 0 to 1 := 0
|
|
);
|
|
port(
|
|
rst : in std_ulogic;
|
|
clk : in std_ulogic;
|
|
rxi : in host_rx_type;
|
|
rxo : out rx_host_type
|
|
);
|
|
attribute sync_set_reset of rst : signal is "true";
|
|
end entity;
|
|
|
|
architecture rtl of greth_rx is
|
|
-- constant maxsize : integer := 1518;
|
|
constant maxsizerx : unsigned(15 downto 0) :=
|
|
to_unsigned(maxsize + 18, 16);
|
|
constant minsize : integer := 64;
|
|
|
|
--receiver types
|
|
type rx_state_type is (idle, wait_sfd, data1, data2, errorst, report_status,
|
|
wait_report, check_crc, discard_packet);
|
|
|
|
type rx_reg_type is record
|
|
er : std_ulogic;
|
|
en : std_ulogic;
|
|
rxd : std_logic_vector(3 downto 0);
|
|
rxdp : std_logic_vector(3 downto 0);
|
|
crc : std_logic_vector(31 downto 0);
|
|
sync_start : std_ulogic;
|
|
gotframe : std_ulogic;
|
|
start : std_ulogic;
|
|
write : std_ulogic;
|
|
done : std_ulogic;
|
|
odd_nibble : std_ulogic;
|
|
lentype : std_logic_vector(15 downto 0);
|
|
ltfound : std_ulogic;
|
|
byte_count : std_logic_vector(10 downto 0);
|
|
data : std_logic_vector(31 downto 0);
|
|
dataout : std_logic_vector(31 downto 0);
|
|
rx_state : rx_state_type;
|
|
status : std_logic_vector(3 downto 0);
|
|
write_ack : std_logic_vector(nsync-1 downto 0);
|
|
done_ack : std_logic_vector(nsync downto 0);
|
|
rxen : std_logic_vector(1 downto 0);
|
|
got4b : std_ulogic;
|
|
mcasthash : std_logic_vector(5 downto 0);
|
|
hashlock : std_ulogic;
|
|
|
|
--rmii
|
|
enold : std_ulogic;
|
|
act : std_ulogic;
|
|
dv : std_ulogic;
|
|
cnt : std_logic_vector(3 downto 0);
|
|
rxd2 : std_logic_vector(1 downto 0);
|
|
speed : std_logic_vector(1 downto 0);
|
|
zero : std_ulogic;
|
|
end record;
|
|
|
|
--receiver signals
|
|
signal r, rin : rx_reg_type;
|
|
signal rxrst : std_ulogic;
|
|
signal vcc : std_ulogic;
|
|
|
|
-- attribute sync_set_reset : string;
|
|
attribute sync_set_reset of rxrst : signal is "true";
|
|
|
|
begin
|
|
vcc <= '1';
|
|
|
|
rx_rst : eth_rstgen
|
|
port map(rst, clk, vcc, rxrst, open);
|
|
|
|
rx : process(rxrst, r, rxi) is
|
|
variable v : rx_reg_type;
|
|
variable index : integer range 0 to 3;
|
|
variable crc_en : std_ulogic;
|
|
variable write_req : std_ulogic;
|
|
variable write_ack : std_ulogic;
|
|
variable done_ack : std_ulogic;
|
|
|
|
variable er : std_ulogic;
|
|
variable dv : std_ulogic;
|
|
variable act : std_ulogic;
|
|
variable rxd : std_logic_vector(3 downto 0);
|
|
begin
|
|
v := r; v.rxd := rxi.rxd(3 downto 0);
|
|
if rmii = 0 then
|
|
v.en := rxi.rx_dv;
|
|
else
|
|
v.en := rxi.rx_crs;
|
|
end if;
|
|
v.er := rxi.rx_er; write_req := '0'; crc_en := '0';
|
|
index := conv_integer(r.byte_count(1 downto 0));
|
|
|
|
--synchronization
|
|
v.rxen(1) := r.rxen(0); v.rxen(0) := rxi.enable;
|
|
|
|
v.write_ack(0) := rxi.writeack;
|
|
v.done_ack(0) := rxi.doneack;
|
|
|
|
if nsync = 2 then
|
|
v.write_ack(1) := r.write_ack(0);
|
|
v.done_ack(1) := r.done_ack(0);
|
|
end if;
|
|
|
|
write_ack := not (r.write xor r.write_ack(nsync-1));
|
|
done_ack := not (r.done xor r.done_ack(nsync-1));
|
|
|
|
--rmii/mii
|
|
if rmii = 0 then
|
|
er := r.er; dv := r.en; act := r.en; rxd := r.rxd;
|
|
else
|
|
--sync
|
|
v.speed(1) := r.speed(0); v.speed(0) := rxi.speed;
|
|
|
|
rxd := r.rxd(1 downto 0) & r.rxd2;
|
|
|
|
if r.cnt = "0000" then
|
|
v.cnt := "1001";
|
|
else
|
|
v.cnt := r.cnt - 1;
|
|
end if;
|
|
|
|
if v.cnt = "0000" then
|
|
v.zero := '1';
|
|
else
|
|
v.zero := '0';
|
|
end if;
|
|
|
|
act := r.act; er := '0';
|
|
|
|
if r.speed(1) = '0' then
|
|
if r.zero = '1' then
|
|
v.enold := r.en;
|
|
dv := r.en and r.dv;
|
|
v.dv := r.act and not r.dv;
|
|
if r.dv = '0' then
|
|
v.rxd2 := r.rxd(1 downto 0);
|
|
end if;
|
|
if (r.enold or r.en) = '0' then
|
|
v.act := '0';
|
|
end if;
|
|
else
|
|
dv := '0';
|
|
end if;
|
|
else
|
|
v.enold := r.en;
|
|
dv := r.en and r.dv;
|
|
v.dv := r.act and not r.dv;
|
|
v.rxd2 := r.rxd(1 downto 0);
|
|
if (r.enold or r.en) = '0' then
|
|
v.act := '0';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
if (r.en and not r.act) = '1' then
|
|
if (rxd = "0101") and (r.speed(1) or
|
|
(not r.speed(1) and r.zero)) = '1' then
|
|
v.act := '1'; v.dv := '0'; v.rxdp := rxd;
|
|
end if;
|
|
end if;
|
|
|
|
if (dv = '1') then
|
|
v.rxdp := rxd;
|
|
end if;
|
|
|
|
if multicast = 1 then
|
|
if (r.byte_count(2 downto 0) = "110") and (r.hashlock = '0') then
|
|
v.mcasthash := r.crc(5 downto 0); v.hashlock := '1';
|
|
end if;
|
|
end if;
|
|
|
|
--fsm
|
|
case r.rx_state is
|
|
when idle =>
|
|
v.gotframe := '0'; v.status := (others => '0'); v.got4b := '0';
|
|
v.byte_count := (others => '0'); v.odd_nibble := '0';
|
|
v.ltfound := '0';
|
|
if multicast = 1 then
|
|
v.hashlock := '0';
|
|
end if;
|
|
if (dv and r.rxen(1)) = '1' then
|
|
if (rxd = "1101") and (r.rxdp = "0101") then
|
|
v.rx_state := data1; v.sync_start := not r.sync_start;
|
|
end if;
|
|
v.start := '0'; v.crc := (others => '1');
|
|
if er = '1' then v.status(2) := '1'; end if;
|
|
elsif dv = '1' then
|
|
v.rx_state := discard_packet;
|
|
end if;
|
|
when discard_packet =>
|
|
if act = '0' then v.rx_state := idle; end if;
|
|
when data1 =>
|
|
if (act and dv) = '1' then
|
|
crc_en := '1';
|
|
v.odd_nibble := not r.odd_nibble; v.rx_state := data2;
|
|
case index is
|
|
when 0 => v.data(27 downto 24) := rxd;
|
|
when 1 => v.data(19 downto 16) := rxd;
|
|
when 2 => v.data(11 downto 8) := rxd;
|
|
when 3 => v.data(3 downto 0) := rxd;
|
|
end case;
|
|
elsif act = '0' then
|
|
v.rx_state := check_crc;
|
|
end if;
|
|
if (r.byte_count(1 downto 0) = "00" and (r.start and act and dv) = '1') then
|
|
write_req := '1';
|
|
end if;
|
|
if er = '1' then v.status(2) := '1'; end if;
|
|
if conv_integer(r.byte_count) > maxsizerx then
|
|
v.rx_state := errorst; v.status(1) := '1';
|
|
v.byte_count := r.byte_count - 4;
|
|
end if;
|
|
v.got4b := v.byte_count(2) or r.got4b;
|
|
when data2 =>
|
|
if (act and dv) = '1' then
|
|
crc_en := '1';
|
|
v.odd_nibble := not r.odd_nibble; v.rx_state := data1;
|
|
v.byte_count := r.byte_count + 1; v.start := '1';
|
|
case index is
|
|
when 0 => v.data(31 downto 28) := rxd;
|
|
when 1 => v.data(23 downto 20) := rxd;
|
|
when 2 => v.data(15 downto 12) := rxd;
|
|
when 3 => v.data(7 downto 4) := rxd;
|
|
end case;
|
|
elsif act = '0' then
|
|
v.rx_state := check_crc;
|
|
end if;
|
|
if er = '1' then v.status(2) := '1'; end if;
|
|
v.got4b := v.byte_count(2) or r.got4b;
|
|
when check_crc =>
|
|
if r.crc /= X"C704DD7B" then
|
|
if r.odd_nibble = '1' then v.status(0) := '1';
|
|
else v.status(2) := '1'; end if;
|
|
end if;
|
|
if write_ack = '1' then
|
|
if r.got4b = '1' then
|
|
v.byte_count := r.byte_count - 4;
|
|
else
|
|
v.byte_count := (others => '0');
|
|
end if;
|
|
v.rx_state := report_status;
|
|
if conv_integer(r.byte_count) < minsize then
|
|
v.rx_state := wait_report; v.done := not r.done;
|
|
end if;
|
|
end if;
|
|
when errorst =>
|
|
if act = '0' then
|
|
v.rx_state := wait_report; v.done := not r.done;
|
|
v.gotframe := '1';
|
|
end if;
|
|
when report_status =>
|
|
v.done := not r.done; v.rx_state := wait_report;
|
|
v.gotframe := '1';
|
|
when wait_report =>
|
|
if done_ack = '1' then
|
|
if act = '1' then
|
|
v.rx_state := discard_packet;
|
|
else
|
|
v.rx_state := idle;
|
|
end if;
|
|
end if;
|
|
when others => null;
|
|
end case;
|
|
|
|
--write to fifo
|
|
if write_req = '1' then
|
|
if (r.status(3) or not write_ack) = '1' then
|
|
v.status(3) := '1';
|
|
else
|
|
v.dataout := r.data; v.write := not r.write;
|
|
end if;
|
|
if (r.byte_count(4 downto 2) = "100") and (r.ltfound = '0') then
|
|
v.lentype := r.data(31 downto 16) + 14; v.ltfound := '1';
|
|
end if;
|
|
end if;
|
|
|
|
if write_ack = '1' then
|
|
if rxi.writeok = '0' then v.status(3) := '1'; end if;
|
|
end if;
|
|
|
|
--crc generation
|
|
if crc_en = '1' then
|
|
v.crc := calccrc(rxd, r.crc);
|
|
end if;
|
|
|
|
if rxrst = '0' then
|
|
v.rx_state := idle; v.write := '0'; v.done := '0'; v.sync_start := '0';
|
|
v.done_ack := (others => '0');
|
|
v.gotframe := '0'; v.write_ack := (others => '0');
|
|
v.dv := '0'; v.cnt := (others => '0'); v.zero := '0';
|
|
v.byte_count := (others => '0'); v.lentype := (others => '0');
|
|
v.status := (others => '0'); v.got4b := '0'; v.odd_nibble := '0';
|
|
v.ltfound := '0';
|
|
if multicast = 1 then
|
|
v.hashlock := '0';
|
|
end if;
|
|
|
|
end if;
|
|
if rmii = 0 then
|
|
v.cnt := (others => '0'); v.zero := '0';
|
|
end if;
|
|
|
|
rin <= v;
|
|
rxo.dataout <= r.dataout;
|
|
rxo.start <= r.sync_start;
|
|
rxo.done <= r.done;
|
|
rxo.write <= r.write;
|
|
rxo.status <= r.status;
|
|
rxo.gotframe <= r.gotframe;
|
|
rxo.byte_count <= r.byte_count;
|
|
rxo.lentype <= r.lentype;
|
|
rxo.mcasthash <= r.mcasthash;
|
|
|
|
end process;
|
|
|
|
gmiimode0 : if gmiimode = 0 generate
|
|
rxregs0 : process(clk) is
|
|
begin
|
|
if rising_edge(clk) then
|
|
r <= rin;
|
|
end if;
|
|
end process;
|
|
end generate;
|
|
|
|
gmiimode1 : if gmiimode = 1 generate
|
|
rxregs1 : process(clk) is
|
|
begin
|
|
if rising_edge(clk) then
|
|
if (rxi.rx_en = '1' or rxrst = '0') then r <= rin; end if;
|
|
end if;
|
|
end process;
|
|
end generate;
|
|
|
|
|
|
end architecture;
|
|
|