summaryrefslogtreecommitdiff
path: root/lib/ethernet
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ethernet')
-rw-r--r--lib/ethernet/components/mdio_interface.vhd349
-rw-r--r--lib/ethernet/components/mii_management_transmit.vhd178
-rw-r--r--lib/ethernet/components/rmii_in_out.vhd339
-rw-r--r--lib/ethernet/components/rmii_phy_to_mii_mac.vhd217
4 files changed, 1083 insertions, 0 deletions
diff --git a/lib/ethernet/components/mdio_interface.vhd b/lib/ethernet/components/mdio_interface.vhd
new file mode 100644
index 0000000..483dcf1
--- /dev/null
+++ b/lib/ethernet/components/mdio_interface.vhd
@@ -0,0 +1,349 @@
+------------------------------------------------------------------
+-- _____ ______ _____ -
+-- |_ _| | ____|/ ____| Institute of Embedded Systems -
+-- | | _ __ | |__ | (___ Zuercher Hochschule fuer -
+-- | | | '_ \| __| \___ \ angewandte Wissenschaften -
+-- _| |_| | | | |____ ____) | (University of Applied Sciences) -
+-- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
+------------------------------------------------------------------
+--
+-- Project : SInet
+-- Module :
+-- Description : MDIO Interface and Link status check
+--
+-- $LastChangedDate: 2010-03-02 12:22:00 +0100 (Tue, 02 Mar 2010) $
+-- $Rev: 3094 $
+-- $Author: beut $
+-----------------------------------------------------------------
+--
+-- Change History
+-- Date |Name |Modification
+------------|----------|-----------------------------------------
+-- 2.05.07 | GLC | file created
+-----------------------------------------------------------------
+-- 02.11.07 | ffar | adaptation for SInet
+-----------------------------------------------------------------
+-- 01.03.10 | ffar | add state write Mode (RMII/MII selectabel)
+-----------------------------------------------------------------
+
+library ieee;
+ use ieee.numeric_std.all;
+ use ieee.std_logic_1164.all;
+library ines_ethernet;
+ use ines_ethernet.mii_management_transmit_pkg.all;
+library ines_misc;
+ use ines_misc.ines_vhdl_lib_base_pkg.all;
+ use ines_misc.reduce_pack.all;
+
+package mdio_interface_pkg is
+ component mdio_interface
+ generic(
+ C_SET_TO_MII : boolean := false;
+ CLK_DIVIDER : natural := 10; -- divider for MDC
+ CHK_INTERVAL : natural := 50e6; -- link check interval in clk_i cycles
+ NO_OF_PORTS : natural := 1; -- number of ports to poll => max 4
+ ADDR_PORT_1 : natural := 1;
+ ADDR_PORT_2 : natural := 2;
+ ADDR_PORT_3 : natural := 3;
+ ADDR_PORT_4 : natural := 4
+ );
+ port(
+ clk_i : in std_logic;
+ reset_n_i : in std_logic;
+ -- manual access
+ phy_addr_i : in std_logic_vector(4 downto 0);
+ phy_reg_i : in std_logic_vector(4 downto 0);
+ phy_data_i : in std_logic_vector(15 downto 0);
+ phy_data_o : out std_logic_vector(15 downto 0);
+ send_i : in std_logic;
+ read_i : in std_logic;
+ busy_n_o : out std_logic;
+ -- Status out
+ link_o : out std_logic_vector(3 downto 0); -- 1= link OK
+ reset_phy_i : in std_logic_vector(3 downto 0); -- 1= reset phy
+ -- MDIO
+ mdio_i : in std_logic;
+ mdio_o : out std_logic;
+ mdio_oe_o : out std_logic;
+ mdc_o : out std_logic
+ );
+ end component;
+end package mdio_interface_pkg;
+
+
+
+
+library ieee;
+ use ieee.numeric_std.all;
+ use ieee.std_logic_1164.all;
+library ines_ethernet;
+ use ines_ethernet.mii_management_transmit_pkg.all;
+library ines_misc;
+ use ines_misc.ines_vhdl_lib_base_pkg.all;
+ use ines_misc.reduce_pack.all;
+
+
+entity mdio_interface is
+ generic(
+ C_SET_TO_MII : boolean := false;-- set to mii mode (otherwise mii mode, otherwise rmii is enabled)
+ CLK_DIVIDER : natural := 10; -- divider for MDC
+ CHK_INTERVAL : natural := 50e6; -- link check interval in clk_i cycles
+ NO_OF_PORTS : natural := 1; -- number of ports to poll => max 4
+ ADDR_PORT_1 : natural := 1;
+ ADDR_PORT_2 : natural := 2;
+ ADDR_PORT_3 : natural := 3;
+ ADDR_PORT_4 : natural := 4
+ );
+ port(
+ clk_i : in std_logic;
+ reset_n_i : in std_logic;
+ -- manual access
+ phy_addr_i : in std_logic_vector(4 downto 0);
+ phy_reg_i : in std_logic_vector(4 downto 0);
+ phy_data_i : in std_logic_vector(15 downto 0);
+ phy_data_o : out std_logic_vector(15 downto 0);
+ send_i : in std_logic;
+ read_i : in std_logic;
+ busy_n_o : out std_logic;
+ -- Status out
+ link_o : out std_logic_vector(3 downto 0); -- 1= link OK
+ reset_phy_i : in std_logic_vector(3 downto 0); -- 1= reset phy
+ -- MDIO
+ mdio_i : in std_logic;
+ mdio_o : out std_logic;
+ mdio_oe_o : out std_logic;
+ mdc_o : out std_logic
+ );
+end mdio_interface;
+
+
+
+architecture rtl of mdio_interface is
+
+ type states is (S_IDLE, S_WAIT, S_RESET, S_RESTART, S_GETLINK, S_WAIT_GETLINK,
+ S_RMII_READ, S_RMII_READ_WAIT, S_RMII_WRITE, S_RMII_WRITE_WAIT, S_READ, S_WRITE);
+ signal current_state : states;
+
+ signal interval_cnt : integer range 0 to CHK_INTERVAL;
+ signal chk_link : std_logic;
+ signal write_mode : std_logic;
+
+ signal curr_phy_no : integer range 1 to NO_OF_PORTS;
+
+ signal phy_addr : std_logic_vector(4 downto 0);
+ signal phy_reg : std_logic_vector(4 downto 0);
+ signal phy_dat_i : std_logic_vector(15 downto 0);
+ signal phy_dat_o : std_logic_vector(15 downto 0);
+ signal rmii_reg_dat : std_logic_vector(15 downto 0);
+ signal phy_write : std_logic;
+ signal phy_read : std_logic;
+ signal phy_done : std_logic;
+ signal done_f : std_logic;
+
+ constant CONTROL_REG : std_logic_vector(4 downto 0) := "00000"; -- 0x00
+ constant STATUS_REG : std_logic_vector(4 downto 0) := "10000"; -- 0x10
+ constant RMII_REG : std_logic_vector(4 downto 0) := "10111"; -- 0x17
+
+ constant C_RMII_MII_BITMASK : std_logic_vector(15 downto 0) := "0000000000010000"; -- 0x10
+
+ constant MII_ADDR : std_logic_array_5(1 to 4) := (std_logic_vector(to_unsigned(ADDR_PORT_1,5)),
+ std_logic_vector(to_unsigned(ADDR_PORT_2,5)),
+ std_logic_vector(to_unsigned(ADDR_PORT_3,5)),
+ std_logic_vector(to_unsigned(ADDR_PORT_4,5)));
+
+begin
+
+ phy_data_o <= phy_dat_o;
+ busy_n_o <= phy_done;
+
+ sm_proc : process (clk_i, reset_n_i, current_state, chk_link, reset_phy_i, send_i, read_i, phy_done, curr_phy_no)
+ begin
+ if reset_n_i = '0' then
+ phy_addr <= (others => '0');
+ phy_reg <= (others => '0');
+ phy_dat_o <= (others => '0');
+ phy_write <= '0';
+ phy_read <= '0';
+ current_state <= S_IDLE;
+ link_o <= (others => '0');
+ curr_phy_no <= 1;
+ done_f <= '0';
+ elsif clk_i'event and clk_i = '1' then
+
+ phy_write <= '0';
+ phy_read <= '0';
+
+ case current_state is
+
+ when S_IDLE =>
+ if chk_link = '1' then
+ current_state <= S_GETLINK;
+ elsif write_mode = '1' then
+ current_state <= S_RMII_READ;
+ elsif or_reduce(reset_phy_i) = '1' then -- /= "0000" then
+ current_state <= S_RESET;
+ elsif send_i = '1' then
+ current_state <= S_WRITE;
+ elsif read_i = '1' then
+ current_state <= S_READ;
+ end if;
+
+
+ when S_GETLINK =>
+ phy_addr <= MII_ADDR(curr_phy_no);
+ phy_reg <= STATUS_REG;
+ phy_read <= '1';
+
+ current_state <= S_WAIT_GETLINK;
+
+
+ when S_WAIT_GETLINK =>
+ if phy_done = '1' and done_f = '0' and curr_phy_no < NO_OF_PORTS then
+ link_o(curr_phy_no-1) <= phy_dat_i(0);
+ curr_phy_no <= curr_phy_no + 1;
+ current_state <= S_GETLINK;
+ elsif phy_done = '1' and done_f = '0' then
+ link_o(curr_phy_no-1) <= phy_dat_i(0);
+ curr_phy_no <= 1;
+ current_state <= S_IDLE;
+ end if;
+
+
+ when S_RMII_READ =>
+ phy_addr <= MII_ADDR(curr_phy_no);
+ phy_reg <= RMII_REG;
+ phy_read <= '1';
+
+ current_state <= S_RMII_READ_WAIT;
+
+
+ when S_RMII_READ_WAIT =>
+ if phy_done = '1' and done_f = '0' then
+ rmii_reg_dat <= phy_dat_i;
+ current_state <= S_RMII_WRITE;
+ end if;
+
+
+ when S_RMII_WRITE =>
+ phy_addr <= MII_ADDR(curr_phy_no);
+ phy_reg <= RMII_REG;
+ if C_SET_TO_MII = true then
+ -- Clear Bit Nr 5 and set PHY in MII MODE
+ phy_dat_o <= rmii_reg_dat and (not C_RMII_MII_BITMASK);
+ else
+ -- Set Bit Nr 5 and set PHY in RMII MODE
+ phy_dat_o <= rmii_reg_dat or C_RMII_MII_BITMASK;
+ end if;
+ phy_write <= '1';
+
+ current_state <= S_RMII_WRITE_WAIT;
+
+
+ when S_RMII_WRITE_WAIT =>
+ if phy_done = '1' and done_f = '0' and curr_phy_no < NO_OF_PORTS then
+ curr_phy_no <= curr_phy_no + 1;
+ -- Start Read and Write for other PHY's
+ current_state <= S_RMII_READ;
+ elsif phy_done = '1' and done_f = '0' then
+ curr_phy_no <= 1;
+ current_state <= S_IDLE;
+ end if;
+
+
+ when S_READ =>
+ phy_addr <= phy_addr_i;
+ phy_reg <= phy_reg_i;
+ phy_read <= '1';
+
+ current_state <= S_WAIT;
+
+
+ when S_WRITE =>
+ phy_addr <= phy_addr_i;
+ phy_reg <= phy_reg_i;
+ phy_dat_o <= phy_data_i;
+ phy_write <= '1';
+
+ current_state <= S_WAIT;
+
+
+ when S_RESET =>
+ if reset_phy_i(0) = '1' then
+ phy_addr <= MII_ADDR(1);
+ elsif reset_phy_i(1) = '1' then
+ phy_addr <= MII_ADDR(2);
+ elsif reset_phy_i(2) = '1' then
+ phy_addr <= MII_ADDR(3);
+ elsif reset_phy_i(3) = '1' then
+ phy_addr <= MII_ADDR(4);
+ end if;
+ phy_reg <= CONTROL_REG;
+ phy_dat_o <= X"8000";
+ phy_write <= '1';
+
+ current_state <= S_WAIT;
+
+
+ when S_RESTART =>
+ current_state <= S_IDLE;
+
+
+ when S_WAIT =>
+ if phy_done = '1' and done_f = '0' then
+ current_state <= S_IDLE;
+ end if;
+
+ end case;
+ done_f <= phy_done;
+ end if;
+ end process;
+
+ interval_proc : process (clk_i, reset_n_i)
+ begin
+ if reset_n_i = '0' then
+ interval_cnt <= 0;
+ chk_link <= '0';
+ write_mode <= '0';
+ elsif clk_i'event and clk_i = '1' then
+ chk_link <= '0';
+ write_mode <= '0';
+
+ if interval_cnt < CHK_INTERVAL then
+ interval_cnt <= interval_cnt + 1;
+ else
+ interval_cnt <= 0;
+ chk_link <= '1';
+ end if;
+
+ if interval_cnt = CHK_INTERVAL - 10000 then
+ write_mode <= '1';
+ end if;
+
+ end if;
+ end process;
+
+
+ mdio_transceiver : mii_management_transmit
+ generic map(
+ G_CLK_DIVIDER => CLK_DIVIDER
+ )
+ port map(
+ clk => clk_i,
+ reset_n => reset_n_i,
+
+ phy_addr_i => phy_addr,
+ phy_reg_i => phy_reg,
+ phy_data_i => phy_dat_o,
+ phy_data_o => phy_dat_i,
+ send_i => phy_write,
+ read_i => phy_read,
+ done_o => phy_done,
+
+ mdc_pad_o => mdc_o,
+ md_pad_i => mdio_i,
+ md_pad_o => mdio_o,
+ md_padoe_o => mdio_oe_o
+ );
+
+end rtl;
+
diff --git a/lib/ethernet/components/mii_management_transmit.vhd b/lib/ethernet/components/mii_management_transmit.vhd
new file mode 100644
index 0000000..4a81d8f
--- /dev/null
+++ b/lib/ethernet/components/mii_management_transmit.vhd
@@ -0,0 +1,178 @@
+------------------------------------------------------------------
+-- _____ ______ _____ -
+-- |_ _| | ____|/ ____| Institute of Embedded Systems -
+-- | | _ __ | |__ | (___ Zuercher Hochschule fuer -
+-- | | | '_ \| __| \___ \ angewandte Wissenschaften -
+-- _| |_| | | | |____ ____) | (University of Applied Sciences) -
+-- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
+------------------------------------------------------------------
+--
+-- Project : SInet
+-- Module :
+-- Description : MDIO low level protocol
+--
+-- $LastChangedDate: 2008-10-31 12:06:00 +0100 (Fri, 31 Oct 2008) $
+-- $Rev: 1905 $
+-- $Author: ffar $
+-----------------------------------------------------------------
+--
+-- Change History
+-- Date |Name |Modification
+-----------------------------------------------------------------
+-- 02.11.07 | ffar | file created based on library component
+-- | | from glc (27.09.05)
+-----------------------------------------------------------------
+
+
+library ieee;
+ use ieee.numeric_std.all;
+ use ieee.std_logic_1164.all;
+
+package mii_management_transmit_pkg is
+ component mii_management_transmit
+ generic(
+ G_CLK_DIVIDER : in integer
+ );
+ port(
+ clk : in std_logic;
+ reset_n : in std_logic;
+
+ phy_addr_i : in std_logic_vector(4 downto 0);
+ phy_reg_i : in std_logic_vector(4 downto 0);
+ phy_data_i : in std_logic_vector(15 downto 0);
+ phy_data_o : out std_logic_vector(15 downto 0);
+ send_i : in std_logic;
+ read_i : in std_logic;
+ done_o : out std_logic;
+
+ mdc_pad_o : out std_logic;
+ md_pad_i : in std_logic;
+ md_pad_o : out std_logic;
+ md_padoe_o : out std_logic
+ );
+ end component mii_management_transmit;
+end package mii_management_transmit_pkg;
+
+
+
+library ieee;
+ use ieee.numeric_std.all;
+ use ieee.std_logic_1164.all;
+
+entity mii_management_transmit is
+ generic(
+ G_CLK_DIVIDER : in integer
+ );
+ port(
+ clk : in std_logic;
+ reset_n : in std_logic;
+
+ phy_addr_i : in std_logic_vector(4 downto 0);
+ phy_reg_i : in std_logic_vector(4 downto 0);
+ phy_data_i : in std_logic_vector(15 downto 0);
+ phy_data_o : out std_logic_vector(15 downto 0);
+ send_i : in std_logic;
+ read_i : in std_logic;
+ done_o : out std_logic;
+
+ mdc_pad_o : out std_logic;
+ md_pad_i : in std_logic;
+ md_pad_o : out std_logic;
+ md_padoe_o : out std_logic
+ );
+end mii_management_transmit;
+
+architecture rtl of mii_management_transmit is
+
+
+ signal confdata : std_logic_vector(32 downto 0) := (others => '0');
+ signal rec_data : std_logic_vector(15 downto 0);
+ signal conf_v : integer range 0 to 64;
+ signal cnt_v : integer range 0 to G_CLK_DIVIDER;
+ signal mdc : std_logic;
+ signal send : std_logic;
+
+begin
+
+ phy_data_o <= rec_data;
+
+ phy_config : process(clk, reset_n, mdc, send_i, read_i, phy_addr_i, phy_reg_i, phy_data_i, md_pad_i, conf_v)
+ begin
+ if reset_n = '0' then
+ conf_v <= 0;
+ md_pad_o <= '0';
+ md_padoe_o <= '0';
+ done_o <= '1';
+ confdata <= (others => '0');
+ rec_data <= (others => '0');
+ send <= '0';
+ elsif clk'event and clk = '1' then
+ if conf_v > 32 then -- send preamble
+ done_o <= '0';
+ md_pad_o <= '1';
+ if mdc = '1' then
+ conf_v <= conf_v - 1;
+ end if;
+ elsif conf_v > 0 and send = '1' then -- send data
+ if mdc = '1' then
+ md_pad_o <= confdata(conf_v);
+ conf_v <= conf_v - 1;
+ end if;
+ elsif conf_v > 16 and send = '0' then -- receive data
+ if mdc = '1' then
+ md_pad_o <= confdata(conf_v);
+ conf_v <= conf_v - 1;
+ end if;
+ elsif conf_v > 0 and send = '0' then -- store data
+ if mdc = '1' then
+ rec_data(15 downto 1) <= rec_data(14 downto 0);
+ rec_data(0) <= md_pad_i;
+ conf_v <= conf_v - 1;
+ end if;
+ elsif send_i = '1' then
+ confdata <= "0101" & phy_addr_i & phy_reg_i & "10" & phy_data_i & "0";
+ conf_v <= 64;
+ send <= '1';
+ done_o <= '0';
+ elsif read_i = '1' then
+ confdata <= "0110" & phy_addr_i & phy_reg_i & X"0000" & "000";
+ conf_v <= 64;
+ send <= '0';
+ done_o <= '0';
+ else
+ send <= '0';
+ md_pad_o <= '0';
+ done_o <= '1';
+ end if;
+
+ if send = '1' OR conf_v >= 18 then
+ md_padoe_o <= '1';
+ else
+ md_padoe_o <= '0';
+ end if;
+
+ end if;
+ end process;
+
+ clk_div : process(clk, reset_n, cnt_v)
+ begin
+ if reset_n = '0' then
+ cnt_v <= 0;
+ mdc_pad_o <= '0';
+ mdc <= '0';
+ elsif clk'event and clk = '1' then
+ mdc <= '0';
+ if cnt_v = G_CLK_DIVIDER/2+1 then
+ mdc_pad_o <= '0';
+ mdc <= '1';
+ cnt_v <= cnt_v - 1;
+ elsif cnt_v <= 1 then
+ mdc_pad_o <= '1';
+ cnt_v <= G_CLK_DIVIDER;
+ else
+ cnt_v <= cnt_v - 1;
+ end if;
+ end if;
+ end process;
+
+end rtl; \ No newline at end of file
diff --git a/lib/ethernet/components/rmii_in_out.vhd b/lib/ethernet/components/rmii_in_out.vhd
new file mode 100644
index 0000000..13db067
--- /dev/null
+++ b/lib/ethernet/components/rmii_in_out.vhd
@@ -0,0 +1,339 @@
+------------------------------------------------------------------
+-- _____ ______ _____ -
+-- |_ _| | ____|/ ____| Institute of Embedded Systems -
+-- | | _ __ | |__ | (___ Zuercher Hochschule fuer -
+-- | | | '_ \| __| \___ \ angewandte Wissenschaften -
+-- _| |_| | | | |____ ____) | (University of Applied Sciences) -
+-- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
+------------------------------------------------------------------
+--
+-- Project : SInet
+-- Module : synthesis library ines_ethernet
+--! \file
+--! \brief RMII to byte stream converter
+--
+-- $LastChangedDate: 2010-04-14 15:27:24 +0200 (Wed, 14 Apr 2010) $
+-- $Rev: 3244 $
+-- $Author: beut $
+-----------------------------------------------------------------
+--
+-- Change History
+-- Date |Name |Modification
+-----------------------------------------------------------------
+-- 13.02.07 | GLC | file created
+-----------------------------------------------------------------
+-- 02.11.07 | ffar | adaptation for SInet
+-----------------------------------------------------------------
+-- 20.06.08 | beut | preambel and SFD Generator added
+-----------------------------------------------------------------
+-- 14.04.10 | beut | Interframe gap counter added
+-----------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+
+--! \brief This packages provides an interface to an RMII 100BaseTX phy
+package rmii_in_out_pkg is
+ component rmii_in_out
+ generic(
+ G_AMOUNT_OF_PREAMBEL_AND_SFD_BYTES : natural := 4;
+ G_IFG_CLOCKS : natural := 48 -- 96 Bit ==> 960ns @ 100Mbit ==> IFG = 48 @ 20ns Clockperiode
+ );
+ port (
+ clk_i : in std_logic; -- 50 Mhz
+ reset_n_i : in std_logic;
+ -- RMII in
+ rxd_i : in std_logic_vector(1 downto 0);
+ rx_dv_i : in std_logic;
+ crs_dv_i : in std_logic;
+ col_i : in std_logic;
+ -- RMII out
+ txd_o : out std_logic_vector(1 downto 0);
+ tx_en_o : out std_logic;
+ -- Data out
+ rx_data_o : out std_logic_vector(7 downto 0);
+ rx_stb_o : out std_logic;
+ rx_dv_o : out std_logic;
+ -- Data in
+ tx_data_i : in std_logic_vector(7 downto 0);
+ tx_en_i : in std_logic;
+ tx_ack_o : out std_logic;
+ -- Other
+ get_time_o : out std_logic;
+ frame_start_o : out std_logic;
+ frame_end_o : out std_logic
+ );
+ end component rmii_in_out;
+end package rmii_in_out_pkg;
+
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+
+--! \brief Interface to RMII 100BaseTX phy
+--! \details This interface is a bidirectional converter between byte stream
+--! interface and RMII. It also provides start of frame and end of
+--! frame signals.
+--! Because of generic byte stream interface it can be easily
+--! replaced by coresponding MII interface.
+entity rmii_in_out is
+ generic(
+ G_AMOUNT_OF_PREAMBEL_AND_SFD_BYTES : natural := 4; --! number of preamble bytes which are sent
+ G_IFG_CLOCKS : natural := 48 -- 96 Bit ==> 960ns @ 100Mbit ==> IFG = 48 @ 20ns Clockperiode
+ );
+ port (
+ --!@name Clock and reset inputs
+ --@{
+ clk_i : in std_logic; --! This clock must run at 50 Mhz
+ reset_n_i : in std_logic; --! negative, asynchronous reset
+ --!@}
+
+ --!@name RMII input (from Network)
+ --@{
+ rxd_i : in std_logic_vector(1 downto 0); --! Data input
+ rx_dv_i : in std_logic; --! Receive data valid
+ crs_dv_i : in std_logic; --! carrier sense (not used)
+ col_i : in std_logic; --! collision detected (not used)
+ --!@}
+
+ --!@name RMII out (to Network)
+ --@{
+ txd_o : out std_logic_vector(1 downto 0); --! Transmit data out
+ tx_en_o : out std_logic; --! Transmit data enable
+ --!@}
+
+ --!@name Data out to FPGA
+ --@{
+ rx_data_o : out std_logic_vector(7 downto 0); --! Receive data
+ rx_stb_o : out std_logic; --! Receive data strobe
+ rx_dv_o : out std_logic; --! Receive data valid
+ --!@}
+
+ --!@name Data in from FPGA
+ --@{
+ tx_data_i : in std_logic_vector(7 downto 0); --! Transmit data out
+ tx_en_i : in std_logic; --! Transmit data enable
+ tx_ack_o : out std_logic; --! Transmit data acknowledge
+ --!@}
+
+ --!@name Additional information signals
+ --@{
+ get_time_o : out std_logic; --! Frame start in preamble detected --> take 1588 time stamp
+ frame_start_o : out std_logic; --! Pulse at frame start, after preamble
+ frame_end_o : out std_logic --! Pulse at frame end
+ --!@}
+ );
+end rmii_in_out;
+
+--! \brief The pincount optimised RMII interface is converted to 8 Bit byte stream interface
+--! \details Data are received at 50MHz from phy. There is no separate clock signal between
+--! phy and FPGA. Instead of using a separate clock signal, both chips are connected to
+--! the same clock source. The output data stream which is delivered to the FPGA internal
+--! components is 8 Bit wide, with clock signal. The send path does the oposite.
+architecture rtl of rmii_in_out is
+
+ --! \name Receive signals
+ --!@{
+ --! receive fsm states enumeration
+ type states is (Wait_For_Start_Of_Frame, Wait_For_End_Of_Frame,
+ Preamble, Sfd, Frame, Toggle_Or_End_Of_Frame);
+ --! receive fsm states
+ signal state : states;
+ --! Used for edge detection at end of frame
+ signal rx_dv_i_f : std_logic;
+ --! shows active frame stream (same as rx_dv_o)
+ signal frame_in : std_logic;
+ --! frame_in edge pulse
+ signal frame_in_f : std_logic;
+ --! parallelise the 2 bit input stream to 8 bit
+ signal data_buffer : std_logic_vector(7 downto 0);
+ --! pointer to data_buffer
+ signal data_i_position : integer range 0 to 3;
+ --!@}
+
+ --! \name Transmit signals
+ --!@{
+ --! pointer to tx_data
+ signal nibble_cnt : integer range 0 to 3 := 3;
+ --! transmit data
+ signal tx_data : std_logic_vector(7 downto 0);
+ --! transmit enable
+ signal tx_en : std_logic;
+ --! transmit enable one clock delayed
+ signal tx_en_f : std_logic;
+ --! preamble byte counter
+ signal preamble_cnt : integer range 0 to 7;
+ --!@}
+
+ --! \name IFG signals
+ --!@{
+ --! counts the IFG
+ signal ifg_cnt : natural range 0 to G_IFG_CLOCKS;
+ --!@}
+
+begin
+
+ rx_dv_o <= frame_in;
+
+ frame_start_o <= frame_in and (not frame_in_f);
+ frame_end_o <= (not frame_in) and frame_in_f;
+ tx_en_o <= tx_en;
+
+ --! receive frames and cut off pramble
+ rmii_in_out_proc : process (reset_n_i, clk_i)
+ begin
+ if (reset_n_i = '0') then
+ get_time_o <= '0';
+ rx_dv_i_f <= '0';
+ frame_in <= '0';
+ state <= Wait_For_Start_Of_Frame;
+ elsif (clk_i'event and clk_i = '1') then
+
+ rx_dv_i_f <= rx_dv_i;
+
+ case state is
+ when Wait_For_Start_Of_Frame =>
+ get_time_o <= '0';
+ if rx_dv_i = '1' then
+ state <= Preamble;
+ else
+ state <= Wait_For_Start_Of_Frame;
+ end if;
+
+ when Preamble =>
+ if rx_dv_i /= '1' then
+ state <= Wait_For_End_Of_Frame;
+ elsif rxd_i = "01" then -- preamble detected
+ state <= Sfd;
+ else
+ state <= Preamble;
+ end if;
+
+ when Sfd =>
+ if rx_dv_i /= '1' then
+ state <= Wait_For_End_Of_Frame;
+ elsif rxd_i = "11" then -- SFD detected
+ get_time_o <= '1';
+ state <= Frame;
+ else
+ state <= Sfd;
+ end if;
+
+ when Frame =>
+ frame_in <= '1';
+ if rx_dv_i /= '1' then
+ state <= Wait_For_End_Of_Frame;
+ else
+ state <= Frame;
+ end if;
+
+ when Wait_For_End_Of_Frame =>
+ if (rx_dv_i /= '1' and rx_dv_i_f /= '1') then
+ get_time_o <= '0';
+ frame_in <= '0';
+ state <= Wait_For_Start_Of_Frame;
+ else
+ state <= Wait_For_End_Of_Frame;
+ end if;
+
+ when others =>
+ state <= Wait_For_End_Of_Frame;
+
+ end case;
+ end if;
+ end process;
+
+ --! converts 2 bit RMII data to bytes
+ conv_2_to_8bit_proc : process (reset_n_i, clk_i)
+ begin
+
+ if (reset_n_i = '0') then
+ rx_stb_o <= '0';
+ rx_data_o <= (others => '0');
+ data_buffer <= (others => '0');
+ data_i_position <= 0;
+ frame_in_f <= '0';
+ elsif (clk_i'event and clk_i = '1') then
+
+ rx_stb_o <= '0';
+ frame_in_f <= frame_in;
+
+ data_buffer(5 downto 0) <= data_buffer(7 downto 2);
+ data_buffer(7 downto 6) <= rxd_i;
+
+ if rx_dv_i = '1' and rx_dv_i_f = '0' then -- reset at start of frame
+ data_i_position <= 0;
+ rx_data_o <= (others => '0');
+ elsif frame_in = '1' then -- store data
+
+ if data_i_position < 3 then
+ data_i_position <= data_i_position + 1;
+ else
+ data_i_position <= 0;
+ rx_data_o <= data_buffer;
+ rx_stb_o <= '1'; -- indicates a valid byte
+ end if;
+
+ end if;
+ end if;
+ end process;
+
+ txd_o <= tx_data(1 downto 0);
+
+ --! send frames and generate preamble
+ rmii_out_proc : process (reset_n_i, clk_i)
+ begin
+ if (reset_n_i = '0') then
+ tx_data <= (others => '0');
+ tx_en <= '0';
+ tx_ack_o <= '0';
+ nibble_cnt <= 3;
+ preamble_cnt <= 0;
+ elsif (clk_i'event and clk_i = '1') then
+ tx_ack_o <= '0';
+ if (tx_en_i = '1' or nibble_cnt < 3) and ifg_cnt = 0 then -- framestart or send last nibble
+ tx_en <= '1'; -- start
+ if nibble_cnt < 3 then -- continute byte
+ tx_data(5 downto 0) <= tx_data(7 downto 2);
+ tx_data(7 downto 6) <= "00";
+ nibble_cnt <= nibble_cnt + 1;
+ elsif preamble_cnt + 1 < G_AMOUNT_OF_PREAMBEL_AND_SFD_BYTES then -- send preamble
+ tx_data <= b"0101_0101";
+ preamble_cnt <= preamble_cnt + 1;
+ nibble_cnt <= 0;
+ elsif preamble_cnt + 1 = G_AMOUNT_OF_PREAMBEL_AND_SFD_BYTES then -- send sfd
+ tx_data <= b"1101_0101";
+ preamble_cnt <= preamble_cnt + 1;
+ nibble_cnt <= 0;
+ else -- send data
+ tx_data <= tx_data_i;
+ tx_ack_o <= '1';
+ nibble_cnt <= 0;
+ end if;
+ else -- stop
+ tx_en <= '0';
+ preamble_cnt <= 0;
+ nibble_cnt <= 3;
+ end if;
+ end if;
+ end process;
+
+ --! Interframe Gap Counter
+ ifg_counter : process(clk_i, reset_n_i)
+ begin
+ if reset_n_i = '0' then
+ ifg_cnt <= 0;
+ tx_en_f <= '0';
+ elsif clk_i'event and clk_i = '1' then
+ tx_en_f <= tx_en; -- tx_en one clock delayed
+ if tx_en = '0' and tx_en_f = '1' then -- end of frame
+ ifg_cnt <= G_IFG_CLOCKS;
+ elsif ifg_cnt > 0 then
+ ifg_cnt <= ifg_cnt -1;
+ end if;
+ end if;
+ end process ifg_counter;
+
+end rtl; \ No newline at end of file
diff --git a/lib/ethernet/components/rmii_phy_to_mii_mac.vhd b/lib/ethernet/components/rmii_phy_to_mii_mac.vhd
new file mode 100644
index 0000000..09227c6
--- /dev/null
+++ b/lib/ethernet/components/rmii_phy_to_mii_mac.vhd
@@ -0,0 +1,217 @@
+------------------------------------------------------------------
+-- _____ ______ _____ -
+-- |_ _| | ____|/ ____| -
+-- | | _ __ | |__ | (___ Institute of Embedded Systems -
+-- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
+-- _| |_| | | | |____ ____) | (University of Applied Sciences) -
+-- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
+------------------------------------------------------------------
+--
+-- Project : SInet
+-- Description : Connects the data interface of a PHY in RMMI Mode and a MAC
+-- in MII Mode
+-- $LastChangedDate: 2006-11-14 12:14:54 +0100 (Tue, 14 Nov 2006) $
+-- $Rev: 1358 $
+-- $Author: beut $
+-----------------------------------------------------------------
+--
+-- Change History
+-- Date |Name |Modification
+------------|----------|-----------------------------------------
+-- 20.02.09 | beut | file ceated
+-----------------------------------------------------------------
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+package rmii_phy_to_mii_mac_pkg is
+ component rmii_phy_to_mii_mac
+ port (
+ reset_n_i : in std_logic;
+ clk_25_i : in std_logic;
+ clk_50_i : in std_logic;
+ rmii_crs_i : in std_logic;
+
+ -- Transmit Path
+ mii_tx_en_i : in std_logic;
+ mii_txd_i : in std_logic_vector(3 downto 0);
+ rmii_tx_en_o : out std_logic;
+ rmii_txd_o : out std_logic_vector(1 downto 0);
+
+ -- Receive Path
+ rmii_rx_dv_i : in std_logic;
+ rmii_rxd_i : in std_logic_vector(1 downto 0);
+ mii_rx_dv_o : out std_logic;
+ mii_rxd_o : out std_logic_vector(3 downto 0)
+ );
+ end component rmii_phy_to_mii_mac;
+end package rmii_phy_to_mii_mac_pkg;
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+entity rmii_phy_to_mii_mac is
+ port (
+ reset_n_i : in std_logic;
+ clk_25_i : in std_logic;
+ clk_50_i : in std_logic;
+ rmii_crs_i : in std_logic;
+
+ -- Transmit Path
+ mii_tx_en_i : in std_logic;
+ mii_txd_i : in std_logic_vector(3 downto 0);
+ rmii_tx_en_o : out std_logic;
+ rmii_txd_o : out std_logic_vector(1 downto 0);
+
+ -- Receive Path
+ rmii_rx_dv_i : in std_logic;
+ rmii_rxd_i : in std_logic_vector(1 downto 0);
+ mii_rx_dv_o : out std_logic;
+ mii_rxd_o : out std_logic_vector(3 downto 0)
+ );
+end rmii_phy_to_mii_mac;
+
+
+architecture behavior of rmii_phy_to_mii_mac is
+
+ signal rmii_txd_next, rmii_txd_curr : std_logic;
+ signal clk_25_sync_to_data : std_logic;
+ signal clk_25_toggle, clk_50_toggle : std_logic;
+ signal rmii_rxd_buffer : std_logic_vector(5 downto 0);
+ signal mii_txd_buffer : std_logic_vector(3 downto 0);
+ signal buffer_cnt : integer range 0 to 1;
+ signal clk_50_en : std_logic;
+ signal rmii_rx_dv_f : std_logic;
+ signal mii_rx_dv_f : std_logic;
+ signal mii_rx_dv_ff : std_logic;
+ signal rmii_valid_sof : std_logic;
+
+begin
+
+ -----------------------------------------------------------------
+ -- Clock 50 Enable Gnerating (is high if clock 25Mhz and Clock 50 MHz are rising
+ -----------------------------------------------------------------
+
+ clock_25_proc: process (clk_25_i)
+ begin
+ if rising_edge(clk_25_i) then
+ clk_25_toggle <= not clk_25_toggle;
+ end if;
+ end process;
+
+ -- The clock enable muxes data in 25MHz freqency and has the same timing like data and not the clock!
+ clock_50_proc: process (reset_n_i, clk_50_i)
+ begin
+ if reset_n_i = '0' then
+ clk_50_toggle <= '0';
+ clk_50_en <= '0';
+ elsif rising_edge(clk_50_i) then
+ clk_50_toggle <= clk_25_toggle;
+ -- edge detection
+ clk_50_en <= clk_25_toggle xor clk_50_toggle; --25 MHz clk sync to data of 50MHz
+ end if;
+ end process;
+ -----------------------------------------------------------------
+
+
+ -----------------------------------------------------------------
+ -- Data Muxing from MAC to PHY
+ -----------------------------------------------------------------
+ mii_to_rmii_proc : process (clk_50_en, mii_txd_i, mii_txd_buffer)
+ begin
+ if clk_50_en = '0' then
+ rmii_txd_o <= mii_txd_buffer(1 downto 0);
+ else
+ rmii_txd_o <= mii_txd_buffer(3 downto 2);
+ end if;
+ end process;
+
+ rmii_tx_en_proc: process (reset_n_i, clk_50_i)
+ begin
+ if reset_n_i = '0' then
+ rmii_tx_en_o <= '0';
+ elsif rising_edge(clk_50_i) then
+ if clk_50_en = '1' then -- data changes after a beginning of 25MHz cycle
+ mii_txd_buffer <= mii_txd_i;
+ rmii_tx_en_o <= mii_tx_en_i;
+ end if;
+ end if;
+ end process;
+
+ -----------------------------------------------------------------
+
+
+ -----------------------------------------------------------------
+ -- Data Muxing from PHY to MAC
+ -----------------------------------------------------------------
+
+ -- Data buffern
+ buffer_proc: process (reset_n_i, clk_50_i)
+ begin
+ if reset_n_i = '0' then
+ rmii_rxd_buffer <= (others => '0');
+ elsif rising_edge(clk_50_i) then
+ rmii_rxd_buffer(1 downto 0) <= rmii_rxd_buffer(3 downto 2);
+ rmii_rxd_buffer(3 downto 2) <= rmii_rxd_buffer(5 downto 4);
+ rmii_rxd_buffer(5 downto 4) <= rmii_rxd_i;
+ end if;
+ end process;
+
+ rmii_rx_dv_proc: process (reset_n_i, clk_50_i)
+ begin
+ if reset_n_i = '0' then
+ mii_rx_dv_f <= '0';
+ mii_rx_dv_ff <= '0';
+ mii_rxd_o <= (others => '0');
+ elsif rising_edge(clk_50_i) then
+ if clk_50_en = '1' then
+
+ if rmii_valid_sof = '1' then --only valid if the packet from phy is valid
+ mii_rx_dv_f <= rmii_rx_dv_i;
+ mii_rx_dv_ff <= mii_rx_dv_f; -- valid is two 25 MHz clockcycles later
+ end if;
+
+ if buffer_cnt = 1 then -- depends on the rmii dv signal
+ mii_rxd_o <= rmii_rxd_buffer(3 downto 0); -- Three step buffer
+ else
+ mii_rxd_o <= rmii_rxd_buffer(5 downto 2); -- Two step buffer
+ end if;
+ end if;
+ end if;
+ end process;
+ mii_rx_dv_o <= mii_rx_dv_ff ;
+
+ -- counts the 50MHz clocks before rmii dv signal goes high before a 25MHZ Clock
+ buffer_cnt_proc: process (reset_n_i, clk_50_i)
+ begin
+ if reset_n_i = '0' then
+ buffer_cnt <= 0;
+ elsif rising_edge(clk_50_i) then
+ if (rmii_rx_dv_i = '1' and rmii_rx_dv_f = '0') and clk_50_en = '0' then
+ buffer_cnt <= 1;
+ elsif (rmii_rx_dv_i = '1' and rmii_rx_dv_f = '0') and clk_50_en = '1' then
+ buffer_cnt <= 0;
+ end if;
+ end if;
+ end process;
+
+ rmii_valid_sof_proc: process (reset_n_i, clk_50_i)
+ begin
+ if reset_n_i = '0' then
+ rmii_valid_sof <= '0';
+ rmii_rx_dv_f <= '0';
+ elsif rising_edge(clk_50_i) then
+ rmii_rx_dv_f <= rmii_rx_dv_i;
+ if rmii_crs_i = '1' and rmii_rx_dv_f = '0' and rmii_rx_dv_i = '1' then -- start of a valid frame
+ rmii_valid_sof <= '1';
+ end if;
+ end if;
+ end process;
+
+
+
+
+
+
+end behavior;