diff --git a/README.md b/README.md index e7b36fe..700c9c1 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ The core fully works on Xilinx Spartan 6 family FPGAs only at the moment. It was The user interface is comprised of two FIFOs with a 8-bit data bus for packet transmission and reception, respectively. +Without FIFO the core is tested on Altera Cyclone III and Lattice ECP5 FPGAs. + This page is a short overview of the features and usage of the MAC. More information on the design and implementation can be found in the design document at . Features @@ -19,7 +21,9 @@ Finished: - Filtering received packets by destination MAC address - MAC address insertion into source address of outgoing packets (only when the first source address byte in the packet stream is `0xFF`) - **Simple 8 bit wide FIFO user interface** with arbitrary clock domains for packet transmission and reception - - **Media-independent interface (MII)** for 10/100 Mb/s and **gigabit media-independent interface (GMII)** connectivity + - **Media-independent interface (MII)** for 10/100 Mb/s + - **Reduced-Media-independent interface (RMII)** for 100 Mb/s + - **Gigabit-Media-independent interface (GMII)** for 1000 Mb/s - MII/GMII hardware I/O setup for Xilinx Spartan 6 family FPGAs - Basic **media-independent interface management (MIIM) interface support** that: - Configures the PHY auto-negotiation to use full-duplex modes only diff --git a/ethernet_rmii.vhd b/ethernet_rmii.vhd new file mode 100644 index 0000000..e656dee --- /dev/null +++ b/ethernet_rmii.vhd @@ -0,0 +1,254 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. + +library ieee; +use ieee.std_logic_1164.all; + +-- Prebuilt Ethernet MAC without FIFOs + +use work.ethernet_types.all; +use work.miim_types.all; + +entity ethernet_rmii is + generic( + MIIM_PHY_ADDRESS : t_phy_address := (others => '0'); + MIIM_RESET_WAIT_TICKS : natural := 0; + MIIM_POLL_WAIT_TICKS : natural := DEFAULT_POLL_WAIT_TICKS; + MIIM_CLOCK_DIVIDER : positive := 50; + MIIM_DISABLE : boolean := FALSE + ); + port( + -- Reset input synchronous to miim_clock_i + reset_i : in std_ulogic; + -- Asynchronous reset output + reset_o : out std_ulogic; + + -- MAC address of this station + -- Must not change after reset is deasserted + mac_address_i : in t_mac_address; + + -- RMII (Media-independent interface) + rmii_clk_i : in std_ulogic; + rmii_tx_er_o : out std_ulogic; + rmii_tx_en_o : out std_ulogic; + rmii_txd_o : out std_ulogic_vector(1 downto 0); + rmii_rx_er_i : in std_ulogic; + rmii_rx_crs_dv_i : in std_ulogic; + rmii_rxd_i : in std_ulogic_vector(1 downto 0); + + -- MII Management Interface + miim_clock_i : in std_ulogic; + mdc_o : out std_ulogic; + mdio_io : inout std_ulogic; + -- Status, synchronous to miim_clock_i + link_up_o : out std_ulogic; + + -- TX from client logic + tx_clock_o : out std_ulogic; + -- Asynchronous reset that deasserts synchronously to tx_clock_o + tx_reset_o : out std_ulogic; + tx_enable_i : in std_ulogic; + tx_data_i : in t_ethernet_data; + tx_byte_sent_o : out std_ulogic; + tx_busy_o : out std_ulogic; + + -- RX to client logic + rx_clock_o : out std_ulogic; + -- Asynchronous reset that deasserts synchronously to rx_clock_o + rx_reset_o : out std_ulogic; + rx_frame_o : out std_ulogic; + rx_data_o : out t_ethernet_data; + rx_byte_received_o : out std_ulogic; + rx_error_o : out std_ulogic + ); +end entity; + +architecture rtl of ethernet_rmii is + signal tx_clock : std_ulogic; + signal rx_clock : std_ulogic; + + signal reset : std_ulogic := '1'; + signal rx_reset : std_ulogic; + signal tx_reset : std_ulogic; + + -- Interface between rmii and framing + signal mac_tx_enable : std_ulogic := '0'; + signal mac_tx_data : t_ethernet_data; + signal mac_tx_byte_sent : std_ulogic; + signal mac_tx_gap : std_ulogic; + signal mac_rx_frame : std_ulogic; + signal mac_rx_data : t_ethernet_data; + signal mac_rx_byte_received : std_ulogic; + signal mac_rx_error : std_ulogic; + + -- Internal MII bus between mii_gmii and mii_gmii_io + signal int_rmii_tx_en : std_ulogic; + signal int_rmii_txd : std_ulogic_vector(1 downto 0); + signal int_rmii_rx_er : std_ulogic; + signal int_rmii_rx_crs_dv : std_ulogic; + signal int_rmii_rxd : std_ulogic_vector(1 downto 0); + + -- MIIM interconnection signals + signal miim_register_address : t_register_address; + signal miim_phy_address_sig : t_phy_address; + signal miim_data_read : t_data; + signal miim_data_write : t_data; + signal miim_req : std_ulogic; + signal miim_ack : std_ulogic; + signal miim_wr_en : std_ulogic; + signal miim_speed : t_ethernet_speed; + signal speed : t_ethernet_speed; + signal link_up : std_ulogic; +begin + reset_o <= reset; + rx_reset_o <= rx_reset; + tx_reset_o <= tx_reset; + tx_clock_o <= tx_clock; + rx_clock_o <= rx_clock; + + link_up_o <= link_up; + miim_phy_address_sig <= MIIM_PHY_ADDRESS; + -- Errors are never transmitted in full-duplex mode + rmii_tx_er_o <= '0'; + + speed <= SPEED_100MBPS; -- set to fixed 100MBit for RMII mode + + -- Generate MAC reset if necessary + reset_generator_inst : entity work.reset_generator + port map( + clock_i => miim_clock_i, + speed_i => speed, + reset_i => reset_i, + reset_o => reset + ); + + -- Bring reset into RX and TX clock domains, using: + -- * Asynchronous assertion of reset to guarantee resetting even when the MII clock is not running + -- * Synchronous deassertion of reset to guarantee meeting the reset recovery time of the flip flops + sync_rx_reset_inst : entity work.single_signal_synchronizer + port map( + clock_target_i => rx_clock, + preset_i => reset, + signal_i => '0', + signal_o => rx_reset + ); + + sync_tx_reset_inst : entity work.single_signal_synchronizer + port map( + clock_target_i => tx_clock, + preset_i => reset, + signal_i => '0', + signal_o => tx_reset + ); + + rmii_inst : entity work.rmii + port map( + rx_reset_i => rx_reset, + rx_clock_i => rx_clock, + tx_reset_i => tx_reset, + tx_clock_i => tx_clock, + + -- MII (Media-independent interface) + rmii_tx_en_o => int_rmii_tx_en, + rmii_txd_o => int_rmii_txd, + rmii_rx_er_i => int_rmii_rx_er, + rmii_rx_crs_dv_i => int_rmii_rx_crs_dv, + rmii_rxd_i => int_rmii_rxd, + + -- Interface control signals + tx_enable_i => mac_tx_enable, + tx_gap_i => mac_tx_gap, + tx_data_i => mac_tx_data, + tx_byte_sent_o => mac_tx_byte_sent, + rx_frame_o => mac_rx_frame, + rx_data_o => mac_rx_data, + rx_byte_received_o => mac_rx_byte_received, + rx_error_o => mac_rx_error + ); + + rmii_io_inst : entity work.rmii_io + port map( + clock_tx_o => tx_clock, + clock_rx_o => rx_clock, + rmii_clk_i => rmii_clk_i, + rmii_tx_en_o => rmii_tx_en_o, + rmii_txd_o => rmii_txd_o, + rmii_rx_er_i => rmii_rx_er_i, + rmii_rx_crs_dv_i => rmii_rx_crs_dv_i, + rmii_rxd_i => rmii_rxd_i, + int_rmii_tx_en_i => int_rmii_tx_en, + int_rmii_txd_i => int_rmii_txd, + int_rmii_rx_er_o => int_rmii_rx_er, + int_rmii_rx_crs_dv_o => int_rmii_rx_crs_dv, + int_rmii_rxd_o => int_rmii_rxd + ); + + framing_inst : entity work.framing + port map( + rx_reset_i => rx_reset, + tx_clock_i => tx_clock, + tx_reset_i => tx_reset, + rx_clock_i => rx_clock, + mac_address_i => mac_address_i, + tx_enable_i => tx_enable_i, + tx_data_i => tx_data_i, + tx_byte_sent_o => tx_byte_sent_o, + tx_busy_o => tx_busy_o, + rx_frame_o => rx_frame_o, + rx_data_o => rx_data_o, + rx_byte_received_o => rx_byte_received_o, + rx_error_o => rx_error_o, + mii_tx_enable_o => mac_tx_enable, + mii_tx_gap_o => mac_tx_gap, + mii_tx_data_o => mac_tx_data, + mii_tx_byte_sent_i => mac_tx_byte_sent, + mii_rx_frame_i => mac_rx_frame, + mii_rx_data_i => mac_rx_data, + mii_rx_byte_received_i => mac_rx_byte_received, + mii_rx_error_i => mac_rx_error + ); + + miim_gen : if MIIM_DISABLE = FALSE generate + miim_inst : entity work.miim + generic map( + CLOCK_DIVIDER => MIIM_CLOCK_DIVIDER + ) + port map( + reset_i => reset_i, + clock_i => miim_clock_i, + register_address_i => miim_register_address, + phy_address_i => miim_phy_address_sig, + data_read_o => miim_data_read, + data_write_i => miim_data_write, + req_i => miim_req, + ack_o => miim_ack, + wr_en_i => miim_wr_en, + mdc_o => mdc_o, + mdio_io => mdio_io + ); + + miim_control_inst : entity work.miim_control + generic map( + RESET_WAIT_TICKS => MIIM_RESET_WAIT_TICKS, + POLL_WAIT_TICKS => MIIM_POLL_WAIT_TICKS, + DEBUG_OUTPUT => FALSE + ) + port map( + reset_i => reset_i, + clock_i => miim_clock_i, + miim_register_address_o => miim_register_address, + miim_data_read_i => miim_data_read, + miim_data_write_o => miim_data_write, + miim_req_o => miim_req, + miim_ack_i => miim_ack, + miim_we_o => miim_wr_en, + link_up_o => link_up, + speed_o => miim_speed, + debug_fifo_we_o => open, + debug_fifo_write_data_o => open + ); + end generate; +end architecture; + diff --git a/framing.vhd b/framing.vhd index 8a9abec..a5893d9 100644 --- a/framing.vhd +++ b/framing.vhd @@ -145,8 +145,21 @@ begin when TX_IDLE => -- Handled above, cannot happen here null; - when TX_PREAMBLE2 | TX_PREAMBLE3 | TX_PREAMBLE4 | TX_PREAMBLE5 | TX_PREAMBLE6 => - tx_state <= t_tx_state'succ(tx_state); + when TX_PREAMBLE2 => + --tx_state <= t_tx_state'succ(tx_state); -- Xilinx ISE14.7 does not synthesize this line + tx_state <= TX_PREAMBLE3; + data_out := PREAMBLE_DATA; + when TX_PREAMBLE3 => + tx_state <= TX_PREAMBLE4; + data_out := PREAMBLE_DATA; + when TX_PREAMBLE4 => + tx_state <= TX_PREAMBLE5; + data_out := PREAMBLE_DATA; + when TX_PREAMBLE5 => + tx_state <= TX_PREAMBLE6; + data_out := PREAMBLE_DATA; + when TX_PREAMBLE6 => + tx_state <= TX_PREAMBLE7; data_out := PREAMBLE_DATA; when TX_PREAMBLE7 => tx_state <= TX_START_FRAME_DELIMITER; @@ -225,10 +238,12 @@ begin update_fcs := FALSE; end if; when TX_FRAME_CHECK_SEQUENCE2 => - tx_state <= t_tx_state'succ(tx_state); + --tx_state <= t_tx_state'succ(tx_state); -- ISE14.7 does not synthesize this + tx_state <= TX_FRAME_CHECK_SEQUENCE3; data_out := fcs_output_byte(tx_frame_check_sequence, 1); when TX_FRAME_CHECK_SEQUENCE3 => - tx_state <= t_tx_state'succ(tx_state); + --tx_state <= t_tx_state'succ(tx_state); -- ISE14.7 does not synthesize this + tx_state <= TX_FRAME_CHECK_SEQUENCE4; data_out := fcs_output_byte(tx_frame_check_sequence, 2); when TX_FRAME_CHECK_SEQUENCE4 => tx_state <= TX_INTERPACKET_GAP; diff --git a/intel/mii_gmii_io.vhd b/intel/mii_gmii_io.vhd new file mode 100644 index 0000000..a09b84d --- /dev/null +++ b/intel/mii_gmii_io.vhd @@ -0,0 +1,118 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. +-- +-- Device-specific IO setup needed for communicating with the PHY +-- +-- Copyright (c) 2015, Philipp Kerling +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, this +-- list of conditions and the following disclaimer. +-- +-- * Redistributions in binary form must reproduce the above copyright notice, +-- this list of conditions and the following disclaimer in the documentation +-- and/or other materials provided with the distribution. +-- +-- * Neither the name of ethernet\_mac nor the names of its +-- contributors may be used to endorse or promote products derived from +-- this software without specific prior written permission. +-- +-- * Neither the source code, nor any derivative product, may be used for military +-- purposes. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee; +use ieee.std_logic_1164.all; + +use work.ethernet_types.all; + +entity mii_gmii_io is + port( + -- 125 MHz clock input (exact requirements can vary by implementation) + -- Spartan 6: clock should be unbuffered + clock_125_i : in std_ulogic; + + -- RX and TX clocks + clock_tx_o : out std_ulogic; + clock_rx_o : out std_ulogic; + + -- Speed selection for clock switch + speed_select_i : in t_ethernet_speed; + + -- Signals connected directly to external ports + -- MII + mii_tx_clk_i : in std_ulogic; + mii_tx_en_o : out std_ulogic; + mii_txd_o : out t_ethernet_data; + mii_rx_clk_i : in std_ulogic; + mii_rx_er_i : in std_ulogic; + mii_rx_dv_i : in std_ulogic; + mii_rxd_i : in t_ethernet_data; + + -- GMII + gmii_gtx_clk_o : out std_ulogic; + + -- Signals connected to the mii_gmii module + int_mii_tx_en_i : in std_ulogic; + int_mii_txd_i : in t_ethernet_data; + int_mii_rx_er_o : out std_ulogic; + int_mii_rx_dv_o : out std_ulogic; + int_mii_rxd_o : out t_ethernet_data + ); +end entity; + +architecture Behavioral of mii_gmii_io is + signal clock_tx : std_ulogic := '0'; + signal clock_rx : std_ulogic := '0'; +begin + -- set tx-clock: switch between 125 Mhz reference clock and MII_TX_CLK for TX process + with speed_select_i select clock_tx <= + clock_125_i when SPEED_1000MBPS, + mii_tx_clk_i when others; + -- set rx-clock + clock_rx <= mii_rx_clk_i; + + -- output 1000Mbps-clock only when running GMII to reduce switching noise + with speed_select_i select gmii_gtx_clk_o <= + clock_tx when SPEED_1000MBPS, + '0' when others; + + -- output rx/tx-clocks + clock_tx_o <= clock_tx; + clock_rx_o <= clock_rx; + + process (clock_tx) + begin + if rising_edge(clock_tx) then + -- output data to PHY + mii_tx_en_o <= int_mii_tx_en_i; + mii_txd_o <= int_mii_txd_i; + end if; + end process; + + process (clock_rx) + begin + if rising_edge(clock_rx) then + -- receive data from PHY + int_mii_rx_dv_o <= mii_rx_dv_i; + int_mii_rx_er_o <= mii_rx_er_i; + int_mii_rxd_o <= mii_rxd_i; + end if; + end process; +end architecture; diff --git a/intel/single_signal_synchronizer.vhd b/intel/single_signal_synchronizer.vhd new file mode 100644 index 0000000..bf3d296 --- /dev/null +++ b/intel/single_signal_synchronizer.vhd @@ -0,0 +1,68 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. + +-- Synchronize a single bit from an arbitrary clock domain +-- into the clock_target domain +-- +-- Copyright (c) 2015, Philipp Kerling +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, this +-- list of conditions and the following disclaimer. +-- +-- * Redistributions in binary form must reproduce the above copyright notice, +-- this list of conditions and the following disclaimer in the documentation +-- and/or other materials provided with the distribution. +-- +-- * Neither the name of ethernet\_mac nor the names of its +-- contributors may be used to endorse or promote products derived from +-- this software without specific prior written permission. +-- +-- * Neither the source code, nor any derivative product, may be used for military +-- purposes. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- +library ieee; +use ieee.std_logic_1164.all; + +entity single_signal_synchronizer is + port( + clock_target_i : in std_ulogic; + -- Asynchronous preset of the output and synchronizer flip-flops + preset_i : in std_ulogic := '0'; + -- Asynchronous signal input + signal_i : in std_ulogic; + -- Synchronous signal output + signal_o : out std_ulogic + ); +end entity; + +architecture simple of single_signal_synchronizer is + signal signal_tmp : std_ulogic := '0'; +begin + process(clock_target_i, preset_i) + begin + if preset_i = '1' then + signal_tmp <= '1'; + signal_o <= '1'; + elsif rising_edge(clock_target_i) then + signal_tmp <= signal_i; + signal_o <= signal_tmp; + end if; + end process; +end architecture; diff --git a/intel/utility.vhd b/intel/utility.vhd new file mode 100644 index 0000000..0c52d06 --- /dev/null +++ b/intel/utility.vhd @@ -0,0 +1,120 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. + +-- Utility functions +-- +-- Copyright (c) 2015, Philipp Kerling +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, this +-- list of conditions and the following disclaimer. +-- +-- * Redistributions in binary form must reproduce the above copyright notice, +-- this list of conditions and the following disclaimer in the documentation +-- and/or other materials provided with the distribution. +-- +-- * Neither the name of ethernet\_mac nor the names of its +-- contributors may be used to endorse or promote products derived from +-- this software without specific prior written permission. +-- +-- * Neither the source code, nor any derivative product, may be used for military +-- purposes. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- +library ieee; +use ieee.std_logic_1164.all; + +package utility is + -- Return the reverse of the given vector + function reverse_vector(vec : in std_ulogic_vector) return std_ulogic_vector; + -- Return a vector with the bytes in opposite order but the content of the bytes unchanged (e.g. for big/little endian conversion) + function reverse_bytes(vec : in std_ulogic_vector) return std_ulogic_vector; + -- Extract a byte out of a vector + function extract_byte(vec : in std_ulogic_vector; byteno : in natural) return std_ulogic_vector; + -- Set a byte in a vector + procedure set_byte(vec : inout std_ulogic_vector; byteno : in natural; value : in std_ulogic_vector(7 downto 0)); +end package; + +package body utility is + function reverse_vector(vec : in std_ulogic_vector) return std_ulogic_vector is + variable result : std_ulogic_vector(vec'range); + alias rev_vec : std_ulogic_vector(vec'reverse_range) is vec; + begin + for i in rev_vec'range loop + result(i) := rev_vec(i); + end loop; + return result; + end function; + + function reverse_bytes(vec : in std_ulogic_vector) return std_ulogic_vector is + variable result : std_ulogic_vector(vec'range); + begin + assert vec'length mod 8 = 0 report "Vector length must be a multiple of 8 for byte reversal" severity failure; + assert vec'low = 0 report "Vector must start at 0 for byte reversal" severity failure; + for byte in 0 to vec'high / 8 loop + set_byte(result, vec'high / 8 - byte, extract_byte(vec, byte)); + end loop; + return result; + end function; + + function extract_byte(vec : in std_ulogic_vector; byteno : in natural) return std_ulogic_vector is + begin + -- Support both vector directions + if vec'ascending then + --return vec(byteno * 8 to (byteno + 1) * 8 - 1); -- quartus cannot synthesize this + if (byteno = 0) then + return vec(0 to 7); + elsif (byteno = 1) then + return vec(8 to 15); + elsif (byteno = 2) then + return vec(16 to 23); + elsif (byteno = 3) then + return vec(24 to 31); + elsif (byteno = 4) then + return vec(32 to 39); + else + return vec(40 to 47); + end if; + else + --return vec((byteno + 1) * 8 - 1 downto byteno * 8); -- quartus cannot synthesize this + if (byteno = 0) then + return vec(7 downto 0); + elsif (byteno = 1) then + return vec(15 downto 8); + elsif (byteno = 2) then + return vec(23 downto 16); + elsif (byteno = 3) then + return vec(31 downto 24); + elsif (byteno = 4) then + return vec(39 downto 32); + else + return vec(47 downto 40); + end if; + end if; + end function; + + procedure set_byte(vec : inout std_ulogic_vector; byteno : in natural; value : in std_ulogic_vector(7 downto 0)) is + begin + -- Support both vector directions + if vec'ascending then + vec(byteno * 8 to (byteno + 1) * 8 - 1) := value; + else + vec((byteno + 1) * 8 - 1 downto byteno * 8) := value; + end if; + end procedure; +end package body; diff --git a/lattice/mii_gmii_io.vhd b/lattice/mii_gmii_io.vhd new file mode 100644 index 0000000..a09b84d --- /dev/null +++ b/lattice/mii_gmii_io.vhd @@ -0,0 +1,118 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. +-- +-- Device-specific IO setup needed for communicating with the PHY +-- +-- Copyright (c) 2015, Philipp Kerling +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, this +-- list of conditions and the following disclaimer. +-- +-- * Redistributions in binary form must reproduce the above copyright notice, +-- this list of conditions and the following disclaimer in the documentation +-- and/or other materials provided with the distribution. +-- +-- * Neither the name of ethernet\_mac nor the names of its +-- contributors may be used to endorse or promote products derived from +-- this software without specific prior written permission. +-- +-- * Neither the source code, nor any derivative product, may be used for military +-- purposes. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee; +use ieee.std_logic_1164.all; + +use work.ethernet_types.all; + +entity mii_gmii_io is + port( + -- 125 MHz clock input (exact requirements can vary by implementation) + -- Spartan 6: clock should be unbuffered + clock_125_i : in std_ulogic; + + -- RX and TX clocks + clock_tx_o : out std_ulogic; + clock_rx_o : out std_ulogic; + + -- Speed selection for clock switch + speed_select_i : in t_ethernet_speed; + + -- Signals connected directly to external ports + -- MII + mii_tx_clk_i : in std_ulogic; + mii_tx_en_o : out std_ulogic; + mii_txd_o : out t_ethernet_data; + mii_rx_clk_i : in std_ulogic; + mii_rx_er_i : in std_ulogic; + mii_rx_dv_i : in std_ulogic; + mii_rxd_i : in t_ethernet_data; + + -- GMII + gmii_gtx_clk_o : out std_ulogic; + + -- Signals connected to the mii_gmii module + int_mii_tx_en_i : in std_ulogic; + int_mii_txd_i : in t_ethernet_data; + int_mii_rx_er_o : out std_ulogic; + int_mii_rx_dv_o : out std_ulogic; + int_mii_rxd_o : out t_ethernet_data + ); +end entity; + +architecture Behavioral of mii_gmii_io is + signal clock_tx : std_ulogic := '0'; + signal clock_rx : std_ulogic := '0'; +begin + -- set tx-clock: switch between 125 Mhz reference clock and MII_TX_CLK for TX process + with speed_select_i select clock_tx <= + clock_125_i when SPEED_1000MBPS, + mii_tx_clk_i when others; + -- set rx-clock + clock_rx <= mii_rx_clk_i; + + -- output 1000Mbps-clock only when running GMII to reduce switching noise + with speed_select_i select gmii_gtx_clk_o <= + clock_tx when SPEED_1000MBPS, + '0' when others; + + -- output rx/tx-clocks + clock_tx_o <= clock_tx; + clock_rx_o <= clock_rx; + + process (clock_tx) + begin + if rising_edge(clock_tx) then + -- output data to PHY + mii_tx_en_o <= int_mii_tx_en_i; + mii_txd_o <= int_mii_txd_i; + end if; + end process; + + process (clock_rx) + begin + if rising_edge(clock_rx) then + -- receive data from PHY + int_mii_rx_dv_o <= mii_rx_dv_i; + int_mii_rx_er_o <= mii_rx_er_i; + int_mii_rxd_o <= mii_rxd_i; + end if; + end process; +end architecture; diff --git a/lattice/rmii_io.vhd b/lattice/rmii_io.vhd new file mode 100644 index 0000000..ff65462 --- /dev/null +++ b/lattice/rmii_io.vhd @@ -0,0 +1,92 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. +-- +-- Device-specific IO setup needed for communicating with the PHY +-- +-- Copyright (c) 2015, Philipp Kerling +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, this +-- list of conditions and the following disclaimer. +-- +-- * Redistributions in binary form must reproduce the above copyright notice, +-- this list of conditions and the following disclaimer in the documentation +-- and/or other materials provided with the distribution. +-- +-- * Neither the name of ethernet\_mac nor the names of its +-- contributors may be used to endorse or promote products derived from +-- this software without specific prior written permission. +-- +-- * Neither the source code, nor any derivative product, may be used for military +-- purposes. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee; +use ieee.std_logic_1164.all; + +use work.ethernet_types.all; + +entity rmii_io is + port( + -- RX and TX clocks + clock_tx_o : out std_ulogic; + clock_rx_o : out std_ulogic; + + -- Signals connected directly to external ports + -- RMII + rmii_clk_i : in std_ulogic; + rmii_tx_en_o : out std_ulogic; + rmii_txd_o : out std_ulogic_vector(1 downto 0); + rmii_rx_er_i : in std_ulogic; + rmii_rx_crs_dv_i : in std_ulogic; + rmii_rxd_i : in std_ulogic_vector(1 downto 0); + + -- Signals connected to the mii_gmii module + int_rmii_tx_en_i : in std_ulogic; + int_rmii_txd_i : in std_ulogic_vector(1 downto 0); + int_rmii_rx_er_o : out std_ulogic; + int_rmii_rx_crs_dv_o : out std_ulogic; + int_rmii_rxd_o : out std_ulogic_vector(1 downto 0) + ); +end entity; + +architecture Behavioral of rmii_io is + signal clock : std_ulogic := '0'; +begin + -- set rx/tx-clock + --clock <= rmii_clk_i; + + -- output rx/tx-clocks + clock_tx_o <= rmii_clk_i; -- clock; + clock_rx_o <= rmii_clk_i; -- clock; + + process (rmii_clk_i) -- clock + begin + if rising_edge(rmii_clk_i) then -- clock + -- output data to PHY + rmii_tx_en_o <= int_rmii_tx_en_i; + rmii_txd_o <= int_rmii_txd_i; + + -- receive data from PHY + int_rmii_rx_crs_dv_o <= rmii_rx_crs_dv_i; + int_rmii_rx_er_o <= rmii_rx_er_i; + int_rmii_rxd_o <= rmii_rxd_i; + end if; + end process; +end architecture; diff --git a/lattice/single_signal_synchronizer.vhd b/lattice/single_signal_synchronizer.vhd new file mode 100644 index 0000000..bf3d296 --- /dev/null +++ b/lattice/single_signal_synchronizer.vhd @@ -0,0 +1,68 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. + +-- Synchronize a single bit from an arbitrary clock domain +-- into the clock_target domain +-- +-- Copyright (c) 2015, Philipp Kerling +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, this +-- list of conditions and the following disclaimer. +-- +-- * Redistributions in binary form must reproduce the above copyright notice, +-- this list of conditions and the following disclaimer in the documentation +-- and/or other materials provided with the distribution. +-- +-- * Neither the name of ethernet\_mac nor the names of its +-- contributors may be used to endorse or promote products derived from +-- this software without specific prior written permission. +-- +-- * Neither the source code, nor any derivative product, may be used for military +-- purposes. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- +library ieee; +use ieee.std_logic_1164.all; + +entity single_signal_synchronizer is + port( + clock_target_i : in std_ulogic; + -- Asynchronous preset of the output and synchronizer flip-flops + preset_i : in std_ulogic := '0'; + -- Asynchronous signal input + signal_i : in std_ulogic; + -- Synchronous signal output + signal_o : out std_ulogic + ); +end entity; + +architecture simple of single_signal_synchronizer is + signal signal_tmp : std_ulogic := '0'; +begin + process(clock_target_i, preset_i) + begin + if preset_i = '1' then + signal_tmp <= '1'; + signal_o <= '1'; + elsif rising_edge(clock_target_i) then + signal_tmp <= signal_i; + signal_o <= signal_tmp; + end if; + end process; +end architecture; diff --git a/lattice/utility.vhd b/lattice/utility.vhd new file mode 100644 index 0000000..3da04b1 --- /dev/null +++ b/lattice/utility.vhd @@ -0,0 +1,137 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. + +-- Utility functions +-- +-- Copyright (c) 2015, Philipp Kerling +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, this +-- list of conditions and the following disclaimer. +-- +-- * Redistributions in binary form must reproduce the above copyright notice, +-- this list of conditions and the following disclaimer in the documentation +-- and/or other materials provided with the distribution. +-- +-- * Neither the name of ethernet\_mac nor the names of its +-- contributors may be used to endorse or promote products derived from +-- this software without specific prior written permission. +-- +-- * Neither the source code, nor any derivative product, may be used for military +-- purposes. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- +library ieee; +use ieee.std_logic_1164.all; + +package utility is + -- Return the reverse of the given vector + function reverse_vector(vec : in std_ulogic_vector) return std_ulogic_vector; + -- Return a vector with the bytes in opposite order but the content of the bytes unchanged (e.g. for big/little endian conversion) + function reverse_bytes(vec : in std_ulogic_vector) return std_ulogic_vector; + -- Extract a byte out of a vector + function extract_byte(vec : in std_ulogic_vector; byteno : in natural) return std_ulogic_vector; + -- Set a byte in a vector + procedure set_byte(vec : inout std_ulogic_vector; byteno : in natural; value : in std_ulogic_vector(7 downto 0)); +end package; + +package body utility is + function reverse_vector(vec : in std_ulogic_vector) return std_ulogic_vector is + variable result : std_ulogic_vector(vec'range); + alias rev_vec : std_ulogic_vector(vec'reverse_range) is vec; + begin + for i in rev_vec'range loop + result(i) := rev_vec(i); + end loop; + return result; + end function; + + function reverse_bytes(vec : in std_ulogic_vector) return std_ulogic_vector is + variable result : std_ulogic_vector(vec'range); + begin + assert vec'length mod 8 = 0 report "Vector length must be a multiple of 8 for byte reversal" severity failure; + assert vec'low = 0 report "Vector must start at 0 for byte reversal" severity failure; + for byte in 0 to vec'high / 8 loop + set_byte(result, vec'high / 8 - byte, extract_byte(vec, byte)); + end loop; + return result; + end function; + +-- function extract_byte(vec : in std_ulogic_vector; byteno : in natural) return std_ulogic_vector is +-- variable res : std_ulogic_vector(7 downto 0); +-- variable base_idx : integer; +-- begin +-- if vec'ascending then +-- base_idx := vec'low + (byteno * 8); +-- for i in 0 to 7 loop +-- res(i) := vec(base_idx + i); +-- end loop; +-- else +-- base_idx := vec'low + (byteno * 8); +-- for i in 0 to 7 loop +-- res(i) := vec(base_idx + i); +-- end loop; +-- end if; +-- return res; +-- end function; + function extract_byte(vec : in std_ulogic_vector; byteno : in natural) return std_ulogic_vector is + begin + -- Support both vector directions + if vec'ascending then + --return vec(byteno * 8 to (byteno + 1) * 8 - 1); -- quartus cannot synthesize this + if (byteno = 0) then + return vec(0 to 7); + elsif (byteno = 1) then + return vec(8 to 15); + elsif (byteno = 2) then + return vec(16 to 23); + elsif (byteno = 3) then + return vec(24 to 31); + elsif (byteno = 4) then + return vec(32 to 39); + else + return vec(40 to 47); + end if; + else + --return vec((byteno + 1) * 8 - 1 downto byteno * 8); -- quartus cannot synthesize this + if (byteno = 0) then + return vec(7 downto 0); + elsif (byteno = 1) then + return vec(15 downto 8); + elsif (byteno = 2) then + return vec(23 downto 16); + elsif (byteno = 3) then + return vec(31 downto 24); + elsif (byteno = 4) then + return vec(39 downto 32); + else + return vec(47 downto 40); + end if; + end if; + end function; + + procedure set_byte(vec : inout std_ulogic_vector; byteno : in natural; value : in std_ulogic_vector(7 downto 0)) is + begin + -- Support both vector directions + if vec'ascending then + vec(byteno * 8 to (byteno + 1) * 8 - 1) := value; + else + vec((byteno + 1) * 8 - 1 downto byteno * 8) := value; + end if; + end procedure; +end package body; diff --git a/miim_types.vhd b/miim_types.vhd index b7e979d..c183f9b 100644 --- a/miim_types.vhd +++ b/miim_types.vhd @@ -11,7 +11,7 @@ use ieee.numeric_std.all; package miim_types is subtype t_register_address is unsigned(4 downto 0); - subtype t_phy_address is unsigned(4 downto 0); + subtype t_phy_address is std_ulogic_vector(4 downto 0); subtype t_data is std_ulogic_vector(15 downto 0); function to_register_address(c : natural) return t_register_address; diff --git a/rmii.vhd b/rmii.vhd new file mode 100644 index 0000000..3189779 --- /dev/null +++ b/rmii.vhd @@ -0,0 +1,203 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. + +-- Adaption layer for data transfer with RMII + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.framing_common.all; +use work.ethernet_types.all; + +entity rmii is + port( + tx_reset_i : in std_ulogic; + tx_clock_i : in std_ulogic; + rx_reset_i : in std_ulogic; + rx_clock_i : in std_ulogic; + + -- RMII (Reduced-Media-independent interface) + rmii_tx_en_o : out std_ulogic; + rmii_txd_o : out std_ulogic_vector(1 downto 0); + rmii_rx_er_i : in std_ulogic; + rmii_rx_crs_dv_i : in std_ulogic; + rmii_rxd_i : in std_ulogic_vector(1 downto 0); + + -- TX/RX control + -- TX signals synchronous to tx_clock + tx_enable_i : in std_ulogic; + -- When asserted together with tx_enable_i, tx_byte_sent_o works as normal, but no data is actually + -- put onto the media-independent interface (for IPG transmission) + tx_gap_i : in std_ulogic; + tx_data_i : in t_ethernet_data; + -- Put next data byte on tx_data_i when asserted + tx_byte_sent_o : out std_ulogic; + + -- RX signals synchronous to rx_clock + -- Asserted as long as one continuous frame is being received + rx_frame_o : out std_ulogic; + -- Valid when rx_byte_received_o is asserted + rx_data_o : out t_ethernet_data; + rx_byte_received_o : out std_ulogic; + rx_error_o : out std_ulogic + ); +end entity; + +architecture rtl of rmii is + -- Transmission + type t_rmii_tx_state is ( + TX_INIT, + TX_DIBIT_0, -- Bits 1:0 + TX_DIBIT_1, -- Bits 3:2 + TX_DIBIT_2, -- Bits 5:4 + TX_DIBIT_3 -- Bits 7:6 + ); + signal tx_state : t_rmii_tx_state := TX_INIT; + + -- Reception + type t_rmii_rx_state is ( + RX_INIT, + RX_DIBIT_0, -- Bits 1:0 + RX_DIBIT_1, -- Bits 3:2 + RX_DIBIT_2, -- Bits 5:4 + RX_DIBIT_3 -- Bits 7:6 + ); + signal rx_state : t_rmii_rx_state := RX_INIT; + + signal tx_data_reg : t_ethernet_data := (others => '0'); + signal tx_gap_reg : std_ulogic := '0'; +begin + + -- TX FSM is split into this synchronous process and the output process for tx_byte_sent_o + -- A strictly one-process FSM is impractical for MII transmission: Wait states would be needed + -- to correctly generate tx_byte_sent_o for GMII. + rmii_tx_sync : process(tx_reset_i, tx_clock_i) + begin + -- Use asynchronous reset, clock_tx is not guaranteed to be running during system initialization + if tx_reset_i = '1' then + tx_state <= TX_INIT; + tx_data_reg <= (others => '0'); + tx_gap_reg <= '0'; + rmii_tx_en_o <= '0'; + rmii_txd_o <= (others => '0'); + elsif rising_edge(tx_clock_i) then + rmii_tx_en_o <= '0'; + rmii_txd_o <= (others => '0'); + + case tx_state is + when TX_INIT => + tx_state <= TX_DIBIT_0; + when TX_DIBIT_0 => + if tx_enable_i = '1' then + tx_data_reg <= tx_data_i; + tx_gap_reg <= tx_gap_i; + + rmii_tx_en_o <= not tx_gap_i; + rmii_txd_o <= tx_data_i(1 downto 0); + tx_state <= TX_DIBIT_1; + end if; + when TX_DIBIT_1 => + rmii_tx_en_o <= not tx_gap_reg; + rmii_txd_o <= tx_data_reg(3 downto 2); + tx_state <= TX_DIBIT_2; + when TX_DIBIT_2 => + rmii_tx_en_o <= not tx_gap_reg; + rmii_txd_o <= tx_data_reg(5 downto 4); + tx_state <= TX_DIBIT_3; + when TX_DIBIT_3 => + rmii_tx_en_o <= not tx_gap_reg; + rmii_txd_o <= tx_data_reg(7 downto 6); + tx_state <= TX_DIBIT_0; + end case; + end if; + end process; + + -- TX output process + -- Generates only the tx_byte_sent_o output + rmii_tx_output : process(tx_state) + begin + -- Default output value + tx_byte_sent_o <= '0'; + + case tx_state is + when TX_DIBIT_3 => + tx_byte_sent_o <= '1'; + when others => + null; + end case; + end process; + + -- RMII packet reception + rmii_rx_fsm : process(rx_clock_i, rx_reset_i) + begin + if rx_reset_i = '1' then + rx_state <= RX_INIT; + rx_byte_received_o <= '0'; + + rx_frame_o <= '0'; + rx_data_o <= (others => '0'); + rx_error_o <= '0'; + elsif rising_edge(rx_clock_i) then + -- Default output values + rx_frame_o <= '0'; + rx_byte_received_o <= '0'; + rx_error_o <= '0'; + + if rx_state /= RX_INIT then + -- Hand indicators through + rx_error_o <= rmii_rx_er_i; + rx_frame_o <= rmii_rx_crs_dv_i; + end if; + + case rx_state is + when RX_INIT => + -- Wait for a pause in reception + if rmii_rx_crs_dv_i = '0' then + rx_state <= RX_DIBIT_0; + end if; + when RX_DIBIT_0 => + -- Wait until start of reception + if rmii_rx_crs_dv_i = '1' then + rx_state <= RX_DIBIT_1; + end if; + -- Capture first two bits + rx_data_o(1 downto 0) <= rmii_rxd_i(1 downto 0); + when RX_DIBIT_1 => + -- Wait until start of reception + if rmii_rx_crs_dv_i = '1' then + -- Capture second two bits + rx_data_o(3 downto 2) <= rmii_rxd_i(1 downto 0); + rx_state <= RX_DIBIT_2; + else + rx_error_o <= '1'; + rx_state <= RX_DIBIT_0; + end if; + when RX_DIBIT_2 => + -- Wait until start of reception + if rmii_rx_crs_dv_i = '1' then + -- Capture third two bits + rx_data_o(5 downto 4) <= rmii_rxd_i(1 downto 0); + rx_state <= RX_DIBIT_3; + else + rx_error_o <= '1'; + rx_state <= RX_DIBIT_0; + end if; + when RX_DIBIT_3 => + if rmii_rx_crs_dv_i = '1' then + -- Capture last two bits and mark it valid + rx_data_o(7 downto 6) <= rmii_rxd_i(1 downto 0); + rx_byte_received_o <= '1'; + rx_frame_o <= '1'; + else + -- Frame ended prematurely + rx_error_o <= '1'; + end if; + rx_state <= RX_DIBIT_0; + end case; + end if; + end process; + +end architecture; diff --git a/rmii_io.vhd b/rmii_io.vhd new file mode 100644 index 0000000..1a645ca --- /dev/null +++ b/rmii_io.vhd @@ -0,0 +1,36 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. + +-- Device-specific IO setup needed for communicating with the PHY + +library ieee; +use ieee.std_logic_1164.all; + +use work.ethernet_types.all; + +entity rmii_io is + port( + -- RX and TX clocks + clock_tx_o : out std_ulogic; + clock_rx_o : out std_ulogic; + + -- Signals connected directly to external ports + -- RMII + rmii_clk_i : in std_ulogic; + rmii_tx_en_o : out std_ulogic; + rmii_txd_o : out t_ethernet_data; + rmii_rx_er_i : in std_ulogic; + rmii_rx_crs_dv_i : in std_ulogic; + rmii_rxd_i : in t_ethernet_data; + + -- Signals connected to the mii_gmii module + int_rmii_tx_en_i : in std_ulogic; + int_rmii_txd_i : in t_ethernet_data; + int_rmii_rx_er_o : out std_ulogic; + int_rmii_rx_crs_dv_o : out std_ulogic; + int_rmii_rxd_o : out t_ethernet_data + ); +end entity; + diff --git a/xilinx/rmii_io.vhd b/xilinx/rmii_io.vhd new file mode 100644 index 0000000..ff65462 --- /dev/null +++ b/xilinx/rmii_io.vhd @@ -0,0 +1,92 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. +-- +-- Device-specific IO setup needed for communicating with the PHY +-- +-- Copyright (c) 2015, Philipp Kerling +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, this +-- list of conditions and the following disclaimer. +-- +-- * Redistributions in binary form must reproduce the above copyright notice, +-- this list of conditions and the following disclaimer in the documentation +-- and/or other materials provided with the distribution. +-- +-- * Neither the name of ethernet\_mac nor the names of its +-- contributors may be used to endorse or promote products derived from +-- this software without specific prior written permission. +-- +-- * Neither the source code, nor any derivative product, may be used for military +-- purposes. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee; +use ieee.std_logic_1164.all; + +use work.ethernet_types.all; + +entity rmii_io is + port( + -- RX and TX clocks + clock_tx_o : out std_ulogic; + clock_rx_o : out std_ulogic; + + -- Signals connected directly to external ports + -- RMII + rmii_clk_i : in std_ulogic; + rmii_tx_en_o : out std_ulogic; + rmii_txd_o : out std_ulogic_vector(1 downto 0); + rmii_rx_er_i : in std_ulogic; + rmii_rx_crs_dv_i : in std_ulogic; + rmii_rxd_i : in std_ulogic_vector(1 downto 0); + + -- Signals connected to the mii_gmii module + int_rmii_tx_en_i : in std_ulogic; + int_rmii_txd_i : in std_ulogic_vector(1 downto 0); + int_rmii_rx_er_o : out std_ulogic; + int_rmii_rx_crs_dv_o : out std_ulogic; + int_rmii_rxd_o : out std_ulogic_vector(1 downto 0) + ); +end entity; + +architecture Behavioral of rmii_io is + signal clock : std_ulogic := '0'; +begin + -- set rx/tx-clock + --clock <= rmii_clk_i; + + -- output rx/tx-clocks + clock_tx_o <= rmii_clk_i; -- clock; + clock_rx_o <= rmii_clk_i; -- clock; + + process (rmii_clk_i) -- clock + begin + if rising_edge(rmii_clk_i) then -- clock + -- output data to PHY + rmii_tx_en_o <= int_rmii_tx_en_i; + rmii_txd_o <= int_rmii_txd_i; + + -- receive data from PHY + int_rmii_rx_crs_dv_o <= rmii_rx_crs_dv_i; + int_rmii_rx_er_o <= rmii_rx_er_i; + int_rmii_rxd_o <= rmii_rxd_i; + end if; + end process; +end architecture; diff --git a/xilinx/single_signal_synchronizer.vhd b/xilinx/single_signal_synchronizer.vhd new file mode 100644 index 0000000..bf3d296 --- /dev/null +++ b/xilinx/single_signal_synchronizer.vhd @@ -0,0 +1,68 @@ +-- This file is part of the ethernet_mac project. +-- +-- For the full copyright and license information, please read the +-- LICENSE.md file that was distributed with this source code. + +-- Synchronize a single bit from an arbitrary clock domain +-- into the clock_target domain +-- +-- Copyright (c) 2015, Philipp Kerling +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, this +-- list of conditions and the following disclaimer. +-- +-- * Redistributions in binary form must reproduce the above copyright notice, +-- this list of conditions and the following disclaimer in the documentation +-- and/or other materials provided with the distribution. +-- +-- * Neither the name of ethernet\_mac nor the names of its +-- contributors may be used to endorse or promote products derived from +-- this software without specific prior written permission. +-- +-- * Neither the source code, nor any derivative product, may be used for military +-- purposes. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- +library ieee; +use ieee.std_logic_1164.all; + +entity single_signal_synchronizer is + port( + clock_target_i : in std_ulogic; + -- Asynchronous preset of the output and synchronizer flip-flops + preset_i : in std_ulogic := '0'; + -- Asynchronous signal input + signal_i : in std_ulogic; + -- Synchronous signal output + signal_o : out std_ulogic + ); +end entity; + +architecture simple of single_signal_synchronizer is + signal signal_tmp : std_ulogic := '0'; +begin + process(clock_target_i, preset_i) + begin + if preset_i = '1' then + signal_tmp <= '1'; + signal_o <= '1'; + elsif rising_edge(clock_target_i) then + signal_tmp <= signal_i; + signal_o <= signal_tmp; + end if; + end process; +end architecture;