------------------------------------------------------------------ -- _____ ______ _____ - -- |_ _| | ____|/ ____| 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;