Make design MII compatible

This commit is contained in:
2020-08-07 21:48:11 +02:00
parent a14dd6661e
commit 804ab415c3
9 changed files with 930 additions and 494 deletions

View File

@@ -2,7 +2,7 @@
-- Title : Ethernet RX Core
-- Project : EthMAC
-------------------------------------------------------------------------------
-- File : design/ethmac_rx.vhd
-- File : design/ethmac_rx.vhd
-- Author : Mario Hüttel <mario.huettel@gmx.net>
-- Standard : VHDL'93/02
-------------------------------------------------------------------------------
@@ -18,7 +18,7 @@
--
-- This code 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
-- 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
@@ -33,32 +33,38 @@ use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ethmac_rx is
generic(
IFACE_WIDTH : natural := 2);
port(
clk_50 : in std_logic;
rst : in std_logic;
rmii_rx : in std_logic_vector(1 downto 0);
rmii_dv : in std_logic;
start_of_frame : out std_logic;
end_of_frame : out std_logic;
data_out : out std_logic_vector(7 downto 0);
data_strb : out std_logic;
clk_50 : in std_logic;
rst : in std_logic;
rmii_rx : in std_logic_vector(IFACE_WIDTH - 1 downto 0);
rmii_dv : in std_logic;
start_of_frame : out std_logic;
end_of_frame : out std_logic;
data_out : out std_logic_vector(7 downto 0);
data_strb : out std_logic;
crc_check_valid : out std_logic
);
);
end entity ethmac_rx;
architecture RTL of ethmac_rx is
constant DIBIT_COUNT : natural := 8 / IFACE_WIDTH;
type ethstate_t is (ETH_INIT, ETH_PREAMBLE, ETH_DATA);
signal framestate : ethstate_t;
signal crc_data_in : std_logic_vector(7 downto 0);
signal crc_init : std_logic;
signal crc_calc_en : std_logic;
signal crc_data_valid : std_logic;
signal crc_valid : std_logic;
signal dibit_counter : integer range 0 to 3 := 0;
signal data_delay_in : std_logic_vector(7 downto 0);
signal framestate : ethstate_t;
signal crc_data_in : std_logic_vector(7 downto 0);
signal crc_init : std_logic;
signal crc_calc_en : std_logic;
signal crc_data_valid : std_logic;
signal crc_valid : std_logic;
signal dibit_counter : integer range 0 to (DIBIT_COUNT - 1) := 0;
signal data_delay_in : std_logic_vector(7 downto 0);
signal data_delay_in_strb : std_logic;
signal data_delay_truncate : std_logic;
signal end_of_frame_s : std_logic;
signal end_of_frame_s : std_logic;
type data_fifo_t is array (0 to 3) of std_logic_vector(7 downto 0);
signal data_delay_fifo : data_fifo_t;
@@ -68,14 +74,14 @@ architecture RTL of ethmac_rx is
begin
ethfcs_inst : entity work.ethfcs
port map(
CLOCK => clk_50,
RESET => rst,
DATA => crc_data_in,
CLOCK => clk_50,
RESET => rst,
DATA => crc_data_in,
LOAD_INIT => crc_init,
CALC => crc_calc_en,
D_VALID => crc_data_valid,
CRC => open,
CRC_REG => open,
CALC => crc_calc_en,
D_VALID => crc_data_valid,
CRC => open,
CRC_REG => open,
CRC_VALID => crc_valid);
rx_framefsm : process(clk_50, rst) is
@@ -83,63 +89,63 @@ begin
begin
if rst = '1' then
framestate <= ETH_INIT;
dibit_counter <= 0;
recv_byte := (others => '0');
crc_calc_en <= '0';
framestate <= ETH_INIT;
dibit_counter <= 0;
recv_byte := (others => '0');
crc_calc_en <= '0';
data_delay_truncate <= '0';
data_delay_in_strb <= '0';
data_delay_in <= (others => '0');
crc_init <= '0';
crc_data_in <= (others => '0');
crc_data_valid <= '0';
crc_calc_en <= '0';
start_of_frame <= '0';
end_of_frame_s <= '0';
data_delay_in <= (others => '0');
crc_init <= '0';
crc_data_in <= (others => '0');
crc_data_valid <= '0';
crc_calc_en <= '0';
start_of_frame <= '0';
end_of_frame_s <= '0';
elsif rising_edge(clk_50) then
end_of_frame_s <= '0';
crc_calc_en <= '0';
start_of_frame <= '0';
end_of_frame_s <= '0';
crc_calc_en <= '0';
start_of_frame <= '0';
data_delay_truncate <= '0';
data_delay_in_strb <= '0';
crc_init <= '0';
crc_data_valid <= '0';
if dibit_counter = 3 then
crc_init <= '0';
crc_data_valid <= '0';
if dibit_counter = DIBIT_COUNT - 1 then
dibit_counter <= 0;
else
dibit_counter <= dibit_counter + 1;
end if;
-- input data shift register (LSB first)
recv_byte := rmii_rx & recv_byte(7 downto 2);
recv_byte := rmii_rx & recv_byte(7 downto IFACE_WIDTH);
case framestate is
when ETH_INIT =>
if rmii_dv = '0' then -- Wait for inter frame gap for sync
if rmii_dv = '0' then -- Wait for inter frame gap for sync
crc_init <= '1';
framestate <= ETH_PREAMBLE;
end if;
when ETH_PREAMBLE =>
if rmii_dv = '1' and rmii_rx = "11" then -- Data valid and last dibit of preamble recieved
-- reset dibit counter
if rmii_dv = '1' and rmii_rx(rmii_rx'left downto rmii_rx'left - 1) = "11" then -- Data valid and last dibit of preamble recieved
-- reset dibit counter
dibit_counter <= 0;
start_of_frame <= '1';
framestate <= ETH_DATA;
-- crc_init <= '1';
-- crc_init <= '1';
end if;
when ETH_DATA =>
crc_calc_en <= '1';
if rmii_dv = '1' then
if dibit_counter = 3 then -- Data word received
data_delay_in <= recv_byte;
if dibit_counter = DIBIT_COUNT -1 then -- Data word received
data_delay_in <= recv_byte;
data_delay_in_strb <= '1';
crc_data_in <= recv_byte;
crc_data_valid <= '1';
crc_data_in <= recv_byte;
crc_data_valid <= '1';
end if;
else
framestate <= ETH_INIT;
end_of_frame_s <= '1';
crc_calc_en <= '0';
framestate <= ETH_INIT;
end_of_frame_s <= '1';
crc_calc_en <= '0';
data_delay_truncate <= '1';
end if;
end case;
@@ -147,7 +153,7 @@ begin
end if;
end process rx_framefsm;
data_delay : process(rst, clk_50) is -- This implements a four byte big delay buffer/FIFO used for removing the crc
data_delay : process(rst, clk_50) is -- This implements a four byte big delay buffer/FIFO used for removing the crc
variable data_count : integer range 0 to 4 := 0;
begin
if rst = '1' then
@@ -161,7 +167,7 @@ begin
elsif rising_edge(clk_50) then
data_strb <= '0';
if data_delay_truncate = '1' then
data_count := 0; -- resetting counter is enough. FIFO itself has not to be cleared
data_count := 0; -- resetting counter is enough. FIFO itself has not to be cleared
elsif data_delay_in_strb = '1' then
data_delay_fifo(0) <= data_delay_in;
for i in 3 downto 1 loop
@@ -170,7 +176,7 @@ begin
if data_count < 4 then
data_count := data_count + 1;
else -- Enable output
else -- Enable output
data_out <= data_delay_fifo(3);
data_strb <= '1';
end if;

View File

@@ -2,7 +2,7 @@
-- Title : Ethernet TX Core
-- Project : EthMAC
-------------------------------------------------------------------------------
-- File : design/ethmac_tx.vhd
-- File : design/ethmac_tx.vhd
-- Author : Mario Hüttel <mario.huettel@gmx.net>
-- Standard : VHDL'93/02
-------------------------------------------------------------------------------
@@ -18,7 +18,7 @@
--
-- This code 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
-- 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
@@ -33,50 +33,57 @@ use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ethmac_tx is
generic(
IFACE_WIDTH : natural := 2);
port(
clk_50 : in std_logic;
rst : in std_logic;
clk_50 : in std_logic;
rst : in std_logic;
tx_ready : out std_logic;
start_of_frame : in std_logic;
end_of_frame : in std_logic;
data_in : in std_logic_vector(7 downto 0);
data_in : in std_logic_vector(7 downto 0);
data_ack : out std_logic;
abort : in std_logic;
abort : in std_logic;
--- RMII Interface
rmii_tx : out std_logic_vector(1 downto 0);
rmii_tx : out std_logic_vector(IFACE_WIDTH -1 downto 0);
rmii_txen : out std_logic
);
);
end entity ethmac_tx;
architecture RTL of ethmac_tx is
constant DIBIT_COUNT : natural := 8 / IFACE_WIDTH;
constant PREAMBLE_BYTE : std_logic_vector(7 downto 0) := x"55";
constant PREAMBLE_SFD : std_logic_vector(7 downto 0) := x"D5";
type eth_tx_state_t is (INIT, PREAMBLE, DATA, CRC, IPG);
signal crc_data_in : std_logic_vector(7 downto 0);
signal crc_init : std_logic;
signal crc_init : std_logic;
signal crc_data_out : std_logic_vector(7 downto 0);
signal crc_data_valid : std_logic;
signal crc_calc : std_logic;
signal dibit_counter : integer range 0 to 3 := 0;
signal byte_counter : integer range 0 to 15 := 0;
signal tx_state : eth_tx_state_t;
signal crc_calc : std_logic;
signal dibit_counter : integer range 0 to DIBIT_COUNT - 1 := 0;
signal byte_counter : integer range 0 to 15 := 0;
signal tx_state : eth_tx_state_t;
signal data_reg : std_logic_vector(7 downto 0);
signal eof_reg : std_logic;
signal data_reg : std_logic_vector(7 downto 0);
signal eof_reg : std_logic;
signal byte_counter_disable : std_logic;
begin
ethfcs_inst : entity work.ethfcs
port map(
CLOCK => clk_50,
RESET => rst,
DATA => crc_data_in,
CLOCK => clk_50,
RESET => rst,
DATA => crc_data_in,
LOAD_INIT => crc_init,
CALC => crc_calc,
D_VALID => crc_data_valid,
CRC => crc_data_out,
CRC_REG => open,
CALC => crc_calc,
D_VALID => crc_data_valid,
CRC => crc_data_out,
CRC_REG => open,
CRC_VALID => open
);
);
eth_tx_fsm : process(clk_50, rst) is
begin
@@ -88,7 +95,7 @@ begin
dibit_counter <= 0;
byte_counter <= 0;
rmii_txen <= '0';
rmii_tx <= "00";
rmii_tx <= (others => '0');
tx_state <= INIT;
data_reg <= (others => '0');
data_ack <= '0';
@@ -100,10 +107,10 @@ begin
crc_data_valid <= '0';
-- Shift data register
data_reg <= "00" & data_reg(7 downto 2);
data_reg <= std_logic_vector(to_unsigned(0, IFACE_WIDTH)) & data_reg(7 downto IFACE_WIDTH);
-- Increment counters:
if dibit_counter = 3 then
if dibit_counter = DIBIT_COUNT - 1 then
dibit_counter <= 0;
if byte_counter_disable /= '1' then
if byte_counter = 15 then
@@ -123,73 +130,75 @@ begin
case tx_state is
when INIT =>
byte_counter_disable <= '1';
-- Wait for start of frame
-- Wait for start of frame
if start_of_frame = '1' then
crc_init <= '1';
tx_state <= PREAMBLE;
crc_init <= '1';
tx_state <= PREAMBLE;
byte_counter_disable <= '0';
dibit_counter <= 0;
byte_counter <= 0;
eof_reg <= '0';
dibit_counter <= 0;
byte_counter <= 0;
eof_reg <= '0';
end if;
when PREAMBLE =>
rmii_txen <= '1';
rmii_txen <= '1';
byte_counter_disable <= '0';
if (byte_counter = 7 and dibit_counter = 3) then -- Last dibit of preamble+SFD
rmii_tx <= "11";
-- latch data_in and continue to data phase
data_reg <= data_in;
data_ack <= '1';
tx_state <= DATA;
eof_reg <= end_of_frame;
if (byte_counter = 7 and dibit_counter = DIBIT_COUNT -1) then -- Last dibit of preamble+SFD
rmii_tx <= PREAMBLE_SFD(7 downto 8 - IFACE_WIDTH);
-- latch data_in and continue to data phase
data_reg <= data_in;
data_ack <= '1';
tx_state <= DATA;
eof_reg <= end_of_frame;
crc_data_valid <= '1';
crc_calc <= '1';
crc_data_in <= data_in;
else
rmii_tx <= "01";
rmii_tx <= PREAMBLE_BYTE(IFACE_WIDTH -1 downto 0);
end if;
when DATA =>
rmii_txen <= '1';
crc_calc <= '1';
rmii_txen <= '1';
crc_calc <= '1';
byte_counter_disable <= '1';
rmii_tx <= data_reg(1 downto 0);
if dibit_counter = 0 then -- first dibit to transmit => shift register yet intact => Load crc;
crc_data_in <= data_reg;
rmii_tx <= data_reg(IFACE_WIDTH - 1 downto 0);
if dibit_counter = DIBIT_COUNT - 1 and eof_reg = '0' then -- Ladt dibit sent => latch new data
data_reg <= data_in;
data_ack <= '1';
eof_reg <= end_of_frame;
crc_data_valid <= '1';
end if;
-- Output Least significant dibit of data reg
if dibit_counter = 3 and eof_reg = '0' then -- Ladt dibit sent => latch new data
data_reg <= data_in;
data_ack <= '1';
eof_reg <= end_of_frame;
elsif dibit_counter = 3 and eof_reg = '1' then -- Last dibit sent, no further data => CRC
tx_state <= CRC;
data_reg <= crc_data_out;
byte_counter <= 0;
crc_data_in <= data_in;
elsif dibit_counter = DIBIT_COUNT - 1 and eof_reg = '1' then -- Last dibit sent, no further data => CRC
tx_state <= CRC;
data_reg <= crc_data_out;
crc_data_valid <= '1';
byte_counter <= 0;
byte_counter_disable <= '0';
crc_calc <= '0';
crc_calc <= '0';
end if;
when CRC =>
byte_counter_disable <= '0';
rmii_txen <= '1';
rmii_tx <= data_reg(1 downto 0);
if dibit_counter = 1 and byte_counter /= 3 then -- Request new data byte
crc_data_valid <= '1';
elsif dibit_counter = 3 then -- Either latch new CRC data or proceed to IPG when CRC is finished.
rmii_txen <= '1';
rmii_tx <= data_reg(IFACE_WIDTH - 1 downto 0);
if dibit_counter = DIBIT_COUNT - 1 then -- Either latch new CRC data or proceed to IPG when CRC is finished.
if byte_counter = 3 then
byte_counter <= 0;
tx_state <= IPG;
else
data_reg <= crc_data_out;
data_reg <= crc_data_out;
crc_data_valid <= '1';
end if;
end if;
when IPG =>
rmii_txen <= '0';
rmii_txen <= '0';
byte_counter_disable <= '0';
if byte_counter = 11 and dibit_counter = 3 then
if byte_counter = 11 and dibit_counter = DIBIT_COUNT - 1 then
tx_state <= INIT;
end if;
end case;
end if; -- abort condition
end if; -- rising edge end process eth_tx_fsm;
end if; -- abort condition
end if; -- rising edge end process eth_tx_fsm;
end process eth_tx_fsm;
tx_ready <= '1' when tx_state = INIT else '0';