Tutorial Overview

The Virtex-5 Embedded Tri-mode Ethernet MAC is useful for designs requiring Ethernet connectivity. Fortunately, Xilinx has made it easy for us to start developing with the Ethernet MACs by providing several online examples and application notes. One of the examples can be obtained when you use CORE Generator to generate the Ethernet MAC wrapper. The generated example is a simple design that mirrors incoming Ethernet packets, swapping the source and destination MAC addresses. In this tutorial, we implement the example design provided by CORE Generator by working the example code into a custom peripheral for EDK 10.1.

This tutorial contains screenshots to guide you through the entire implementation process. Click on the images to view a higher resolution.

Requirements

Before following this tutorial, you will need to do the following:

  • Generate the Virtex-5 Embedded Tri-mode Ethernet MAC Wrapper using CORE Generator. For instructions on doing this, please refer to the tutorial Generating the Ethernet MAC
  • Set the J22 and J23 jumpers on the ML505 to positions 2-3 as shown below. This allows us to use an SGMII (serial) interface with the PHY.
     
  • Install a copy of Wireshark on a PC with a Gigabit Ethernet network card
  • Obtain a CAT5 Ethernet cable: regular or crossover, either will work because the PHY on the ML505 has an automatic switching feature that detects what type of cable you are using and switches the TX and RX pins if necessary.
  • Buy an ML505/ML506/ML507 or XUPV5 board if you don’t already have one. Xilinx supplies the ML50x boards, but the best deal is the XUPV5 from Digilent. Click the Digilent link on this page for more information.

Create the Basic Project

Follow these steps to create the basic project:

  1. Open XPS. From the dialog box, select “Base System Builder wizard” and OK.
  2. You will be asked to specify which folder to place the project. Click “Browse” and create a new folder for the project. Click “OK”.
     
  3. We are given the choice to create a new project or to create one using the template of another project. Tick “I would like to create a new design” and click “Next”.
  4. On the “Select Board” page, select “Xilinx” as the board vendor. Select “Virtex 5 ML505 Evaluation Platform” as the board name. Select “1” as the board revision. Click “Next”.
     
  5. On the “Select Processor” page, we normally have a choice between using the PowerPC “hard” processor, or the Microblaze “soft” processor. Since the Virtex-5 does not contain any PowerPCs, we can only select Microblaze. Click “Next”.
     
  6. On the “Configure Microblaze” page, select the clock frequency to be 125MHz. For the BRAM local memory, select “64KB”. We will use the RS232 port for debugging rather than the JTAG, so select “No debug”. Click “Next”.
     
  7. In selecting the Additional IO Interfaces, leave “RS232_Uart_1” ticked and un-tick everything else.



     
  8. On the “Add Internal Peripherals” page, click “Next”.
  9. On the “Software Setup” page, select “RS232_Uart_1” for both STDIN and STDOUT. Un-tick “Memory Test” and leave “Peripheral Test” ticked. Click “Next”.
     
  10. Click “Generate”.
  11. Click “Finish”.

Create the Ethernet MAC Peripheral

We now create our Ethernet MAC peripheral using the Peripheral Wizard.

  1. Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
  2. Select “Create templates for a new peripheral” and click “Next”.
     
  3. We must now decide where to place the files for the peripheral. They can be placed within this project, or they can be made accessible to other projects. Select “To an XPS project”. Click “Next”.
  4. On the “Name and Version” page, type “eth_mac” for the peripheral name. Click “Next”.
     
  5. On the “Bus Interface” page, select “Processor Local Bus” (PLB) and click “Next”.
     
  6. On the “IPIF Services” page, select “Include data phase timer”. Un-tick everything else and click “Next”.
     
  7. On the “Slave Interface” page, leave the defaults and click “Next”.
     
  8. On the “Peripheral Simulation Support” page, we can specify if we want the wizard to create a simulation platform for our peripheral. Click “Next” without ticking the option to generate.
  9. After the “Peripheral Implementation Support” page, the wizard will generate all the template files for us. Tick “Generate ISE and XST project files” and “Generate template driver files”. Click “Next”.
  10. Click “Finish”. Now our templates are created and we can modify them to include the code for the timer.

Copy the Ethernet MAC source files

We need to copy the Ethernet MAC source files generated by CORE Generator into the Ethernet MAC peripheral source folder. If you have not generated the source files using CORE Generator, please refer to the tutorial Generating the Ethernet MAC.

  1. Open Windows Explorer and browse to the folder “TEMACCore\v5_emac_v1_5”. This is the folder you created with CORE Generator.
     
  2. In that folder, you will find a subfolder called “example_design”. Copy the “example_design” folder into the “pcores\eth_mac_v1_00_a\hdl\vhdl” folder within your XPS project. This is the folder where you should find your “user_logic.vhd” file for the Ethernet MAC peripheral.

 

Modify the .PAO file

The .pao file contains a list of all the source files that compose our peripheral. We use this list when we run the Peripheral Wizard in Import mode. Now that we have added the Ethernet MAC example source files to the project, we must include them in the .pao file. Note that files must be listed in the .pao file in hierarchical order. The components at the top of the hierarchy are listed at the bottom of the file.

  1. Select “File->Open” and browse to the “pcores\eth_mac_v1_00_a\data” folder. Select the file “eth_mac_v2_1_0.pao” and click “Open”.
  2. At the bottom of this file you will see these two lines:
lib eth_mac_v1_00_a user_logic vhdl
lib eth_mac_v1_00_a eth_mac vhdl
  1. Add the following lines just above those two lines. It is important to copy the lines exactly as shown and in the same order.
lib eth_mac_v1_00_a example_design/v5_emac_v1_5.vhd
lib eth_mac_v1_00_a example_design/physical/rx_elastic_buffer.vhd
lib eth_mac_v1_00_a example_design/physical/gtp_dual_1000X.vhd
lib eth_mac_v1_00_a example_design/physical/rocketio_wrapper_gtp.vhd
lib eth_mac_v1_00_a example_design/physical/rocketio_wrapper_gtp_tile.vhd
lib eth_mac_v1_00_a example_design/v5_emac_v1_5_block.vhd
lib eth_mac_v1_00_a example_design/client/fifo/tx_client_fifo_8.vhd
lib eth_mac_v1_00_a example_design/client/fifo/rx_client_fifo_8.vhd
lib eth_mac_v1_00_a example_design/client/fifo/eth_fifo_8.vhd
lib eth_mac_v1_00_a example_design/v5_emac_v1_5_locallink.vhd
lib eth_mac_v1_00_a example_design/client/address_swap_module_8.vhd
  1. Save the file.

Now we can use this .pao file with the Peripheral Wizard when we import the Ethernet MAC peripheral.

Modify the Ethernet MAC Peripheral

If you refer back to the example design source files created by CORE Generator, you will find the top module contained in the file “v5_emac_v1_5\example_design\v5_emac_v1_5_example_design.vhd”. We copied that file into our peripheral source folder, but we wont directly use it in our design (notice that we didn’t include it in our .pao file). Instead, we will take the code from this file and work it into our “user_logic.vhd” file, the top module for our peripheral.

  1. Select from the menu “File->Open” and look in the project folder.
  2. Open the folders: “pcores\eth_mac_v1_00_a\hdl\vhdl”.
  3. Open the file “eth_mac.vhd”.
  4. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  REFCLK_N_IN              : in std_logic;
  REFCLK_P_IN              : in std_logic;
  GTP_READY                : out std_logic;
  PHY_RESET_0              : out std_logic;
  RXP_IN                   : in std_logic;
  RXN_IN                   : in std_logic;
  TXP_OUT                  : out std_logic;
  TXN_OUT                  : out std_logic;
  1. Find the line of code that says “– MAP USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  REFCLK_N_IN  => REFCLK_N_IN,
  REFCLK_P_IN  => REFCLK_P_IN,
  GTP_READY    => GTP_READY,
  PHY_RESET_0  => PHY_RESET_0,
  RXP_IN       => RXP_IN,
  RXN_IN       => RXN_IN,
  TXP_OUT      => TXP_OUT,
  TXN_OUT      => TXN_OUT,
  1. Save and close the file.
  2. Open the file “user_logic.vhd”. We will need to modify this source code to include our example code.
  3. Find the line of code that says “–USER libraries added here” and add the following lines of code just below.
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;
  1. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  REFCLK_N_IN              : in std_logic;
  REFCLK_P_IN              : in std_logic;
  GTP_READY                : out std_logic;
  PHY_RESET_0              : out std_logic;
  RXP_IN                   : in std_logic;
  RXN_IN                   : in std_logic;
  TXP_OUT                  : out std_logic;
  TXN_OUT                  : out std_logic;
  1. Find the line of code that says “–USER signal declarations added here” and add the following lines of code just below.
  -- Component Declaration for the TEMAC wrapper with 
  -- Local Link FIFO.
  component v5_emac_v1_5_locallink is
   port(
      -- EMAC0 Clocking
      -- 125MHz clock output from transceiver
      CLK125_OUT                : out std_logic;
      -- 125MHz clock input from BUFG
      CLK125                    : in  std_logic;
      -- Tri-speed clock output from EMAC0
      CLIENT_CLK_OUT_0          : out std_logic;
      -- EMAC0 Tri-speed clock input from BUFG
      client_clk_0              : in  std_logic;

      -- Local link Receiver Interface - EMAC0
      RX_LL_CLOCK_0             : in  std_logic; 
      RX_LL_RESET_0             : in  std_logic;
      RX_LL_DATA_0              : out std_logic_vector(7 downto 0);
      RX_LL_SOF_N_0             : out std_logic;
      RX_LL_EOF_N_0             : out std_logic;
      RX_LL_SRC_RDY_N_0         : out std_logic;
      RX_LL_DST_RDY_N_0         : in  std_logic;
      RX_LL_FIFO_STATUS_0       : out std_logic_vector(3 downto 0);

      -- Local link Transmitter Interface - EMAC0
      TX_LL_CLOCK_0             : in  std_logic;
      TX_LL_RESET_0             : in  std_logic;
      TX_LL_DATA_0              : in  std_logic_vector(7 downto 0);
      TX_LL_SOF_N_0             : in  std_logic;
      TX_LL_EOF_N_0             : in  std_logic;
      TX_LL_SRC_RDY_N_0         : in  std_logic;
      TX_LL_DST_RDY_N_0         : out std_logic;

      -- Client Receiver Interface - EMAC0
      EMAC0CLIENTRXDVLD         : out std_logic;
      EMAC0CLIENTRXFRAMEDROP    : out std_logic;
      EMAC0CLIENTRXSTATS        : out std_logic_vector(6 downto 0);
      EMAC0CLIENTRXSTATSVLD     : out std_logic;
      EMAC0CLIENTRXSTATSBYTEVLD : out std_logic;

      -- Client Transmitter Interface - EMAC0
      CLIENTEMAC0TXIFGDELAY     : in  std_logic_vector(7 downto 0);
      EMAC0CLIENTTXSTATS        : out std_logic;
      EMAC0CLIENTTXSTATSVLD     : out std_logic;
      EMAC0CLIENTTXSTATSBYTEVLD : out std_logic;

      -- MAC Control Interface - EMAC0
      CLIENTEMAC0PAUSEREQ       : in  std_logic;
      CLIENTEMAC0PAUSEVAL       : in  std_logic_vector(15 downto 0);

      --EMAC-MGT link status
      EMAC0CLIENTSYNCACQSTATUS  : out std_logic;
      -- EMAC0 Interrupt
      EMAC0ANINTERRUPT          : out std_logic;

      -- Clock Signals - EMAC0

      -- SGMII Interface - EMAC0
      TXP_0                     : out std_logic;
      TXN_0                     : out std_logic;
      RXP_0                     : in  std_logic;
      RXN_0                     : in  std_logic;
      PHYAD_0                   : in  std_logic_vector(4 downto 0);
      RESETDONE_0               : out std_logic;

      -- unused transceiver
      TXN_1_UNUSED              : out std_logic;
      TXP_1_UNUSED              : out std_logic;
      RXN_1_UNUSED              : in  std_logic;
      RXP_1_UNUSED              : in  std_logic;

      -- SGMII RocketIO Reference Clock buffer inputs 
      CLK_DS                    : in  std_logic;

      -- Asynchronous Reset
      RESET                     : in  std_logic
   );
  end component;

   ---------------------------------------------------------------------
   --  Component Declaration for 8-bit address swapping module
   ---------------------------------------------------------------------
   component address_swap_module_8
   port (
      rx_ll_clock         : in  std_logic;
      rx_ll_reset         : in  std_logic;
      rx_ll_data_in       : in  std_logic_vector(7 downto 0);
      rx_ll_sof_in_n      : in  std_logic;
      rx_ll_eof_in_n      : in  std_logic;
      rx_ll_src_rdy_in_n  : in  std_logic;
      rx_ll_data_out      : out std_logic_vector(7 downto 0);
      rx_ll_sof_out_n     : out std_logic;
      rx_ll_eof_out_n     : out std_logic;
      rx_ll_src_rdy_out_n : out std_logic;
      rx_ll_dst_rdy_in_n  : in  std_logic
      );
   end component;

  ------------------------
  -- Signal Declarations
  ------------------------

  -- address swap transmitter connections - EMAC0
  signal tx_ll_data_0_i      : std_logic_vector(7 downto 0);
  signal tx_ll_sof_n_0_i     : std_logic;
  signal tx_ll_eof_n_0_i     : std_logic;
  signal tx_ll_src_rdy_n_0_i : std_logic;
  signal tx_ll_dst_rdy_n_0_i : std_logic;

  -- address swap receiver connections - EMAC0
  signal rx_ll_data_0_i      : std_logic_vector(7 downto 0);
  signal rx_ll_sof_n_0_i     : std_logic;
  signal rx_ll_eof_n_0_i     : std_logic;
  signal rx_ll_src_rdy_n_0_i : std_logic;
  signal rx_ll_dst_rdy_n_0_i : std_logic;

  -- create a synchronous reset in the transmitter clock domain
  signal ll_pre_reset_0_i    : std_logic_vector(5 downto 0);
  signal ll_reset_0_i        : std_logic;

  attribute async_reg : string;
  attribute async_reg of ll_pre_reset_0_i : signal is "true";

  signal resetdone_0_i       : std_logic;

  -- EMAC0 Clocking signals

  -- Transceiver output clock (REFCLKOUT at 125MHz)
  signal user_clk_out              : std_logic;
  -- 125MHz clock input to wrappers
  signal user_clk                  : std_logic;
  -- Input 125MHz differential clock for transceiver
  signal ref_clk                   : std_logic;

  -- 1.25/12.5/125MHz clock signals for tri-speed SGMII
  signal client_clk_0_o            : std_logic;
  signal client_clk_0              : std_logic;
  1. Find the line of code that says “–USER logic implementation added here” and add the following lines of code just below.
  -- PHY Reset logic
  PHY_RESET_0 <= not Bus2IP_Reset;   -- EMAC0 Clocking   -- Generate the clock input to the GTP   -- clk_ds can be shared between multiple MAC instances.   clkingen : IBUFDS port map (     I  => REFCLK_P_IN,
    IB => REFCLK_N_IN,
    O  => ref_clk);

  -- 125MHz from transceiver is routed through a BUFG and 
  -- input to the MAC wrappers.
  -- This clock can be shared between multiple MAC instances.
  bufg_clk125 : BUFG port map (I => user_clk_out, O => user_clk);

  -- 1.25/12.5/125MHz clock from the MAC is routed through a BUFG and  
  -- input to the MAC wrappers to clock the client interface.
  bufg_client_0 : BUFG port map (I => client_clk_0_o, O => client_clk_0);

  --------------------------------------------
  -- Instantiate the EMAC Wrapper with LL FIFO 
  -- (v5_emac_v1_5_locallink.v)
  --------------------------------------------
  v5_emac_ll : v5_emac_v1_5_locallink
  port map (
    -- EMAC0 Clocking
    -- 125MHz clock output from transceiver
    CLK125_OUT                => user_clk_out,
    -- 125MHz clock input from BUFG
    CLK125                    => user_clk,
    -- Tri-speed clock output from EMAC0
    CLIENT_CLK_OUT_0          => client_clk_0_o,
    -- EMAC0 Tri-speed clock input from BUFG
    CLIENT_CLK_0              => client_clk_0,
    -- Local link Receiver Interface - EMAC0
    RX_LL_CLOCK_0             => user_clk,
    RX_LL_RESET_0             => ll_reset_0_i,
    RX_LL_DATA_0              => rx_ll_data_0_i,
    RX_LL_SOF_N_0             => rx_ll_sof_n_0_i,
    RX_LL_EOF_N_0             => rx_ll_eof_n_0_i,
    RX_LL_SRC_RDY_N_0         => rx_ll_src_rdy_n_0_i,
    RX_LL_DST_RDY_N_0         => rx_ll_dst_rdy_n_0_i,
    RX_LL_FIFO_STATUS_0       => open,

    -- Unused Receiver signals - EMAC0
    EMAC0CLIENTRXDVLD         => open,
    EMAC0CLIENTRXFRAMEDROP    => open,
    EMAC0CLIENTRXSTATS        => open,
    EMAC0CLIENTRXSTATSVLD     => open,
    EMAC0CLIENTRXSTATSBYTEVLD => open,

    -- Local link Transmitter Interface - EMAC0
    TX_LL_CLOCK_0             => user_clk,
    TX_LL_RESET_0             => ll_reset_0_i,
    TX_LL_DATA_0              => tx_ll_data_0_i,
    TX_LL_SOF_N_0             => tx_ll_sof_n_0_i,
    TX_LL_EOF_N_0             => tx_ll_eof_n_0_i,
    TX_LL_SRC_RDY_N_0         => tx_ll_src_rdy_n_0_i,
    TX_LL_DST_RDY_N_0         => tx_ll_dst_rdy_n_0_i,

    -- Unused Transmitter signals - EMAC0
    CLIENTEMAC0TXIFGDELAY     => "00000000",
    EMAC0CLIENTTXSTATS        => open,
    EMAC0CLIENTTXSTATSVLD     => open,
    EMAC0CLIENTTXSTATSBYTEVLD => open,

    -- MAC Control Interface - EMAC0
    CLIENTEMAC0PAUSEREQ       => '0',
    CLIENTEMAC0PAUSEVAL       => "0000000000000000",

    --EMAC-MGT link status
    EMAC0CLIENTSYNCACQSTATUS  => GTP_READY,
    -- EMAC0 Interrupt
    EMAC0ANINTERRUPT          => open,

    -- Clock Signals - EMAC0
    -- SGMII Interface - EMAC0
    TXP_0                     => TXP_OUT,
    TXN_0                     => TXN_OUT,
    RXP_0                     => RXP_IN,
    RXN_0                     => RXN_IN,
    PHYAD_0                   => "00010",
    RESETDONE_0               => resetdone_0_i,

    -- unused transceiver
    TXN_1_UNUSED              => open,
    TXP_1_UNUSED              => open,
    RXN_1_UNUSED              => '1',
    RXP_1_UNUSED              => '0',

    -- SGMII RocketIO Reference Clock buffer inputs 
    CLK_DS                    => ref_clk,

    -- Asynchronous Reset
    RESET                     => Bus2IP_Reset
  );

  --------------------------------------------
  --  Instatiate the address swapping module
  --------------------------------------------
  client_side_asm_emac0 : address_swap_module_8
    port map (
      rx_ll_clock         => user_clk,
      rx_ll_reset         => ll_reset_0_i,
      rx_ll_data_in       => rx_ll_data_0_i,
      rx_ll_sof_in_n      => rx_ll_sof_n_0_i,
      rx_ll_eof_in_n      => rx_ll_eof_n_0_i,
      rx_ll_src_rdy_in_n  => rx_ll_src_rdy_n_0_i,
      rx_ll_data_out      => tx_ll_data_0_i,
      rx_ll_sof_out_n     => tx_ll_sof_n_0_i,
      rx_ll_eof_out_n     => tx_ll_eof_n_0_i,
      rx_ll_src_rdy_out_n => tx_ll_src_rdy_n_0_i,
      rx_ll_dst_rdy_in_n  => tx_ll_dst_rdy_n_0_i
  );

  rx_ll_dst_rdy_n_0_i     <= tx_ll_dst_rdy_n_0_i;

  -- Create synchronous reset in the transmitter clock domain.
  gen_ll_reset_emac0 : process (user_clk, Bus2IP_Reset)
  begin
    if Bus2IP_Reset = '1' then
      ll_pre_reset_0_i <= (others => '1');
      ll_reset_0_i     <= '1';
    elsif user_clk'event and user_clk = '1' then
      if resetdone_0_i = '1' then
        ll_pre_reset_0_i(0)          <= '0';
        ll_pre_reset_0_i(5 downto 1) <= ll_pre_reset_0_i(4 downto 0);
        ll_reset_0_i                 <= ll_pre_reset_0_i(5);
      end if;
    end if;
  end process gen_ll_reset_emac0;
  1. Save and close the file.

If you examine the “v5_emac_v1_5_example_design.vhd” from the CORE Generator output, you will see that most of the code we inserted into “user_logic.vhd” was directly copied from the example code. The main differences are:

  • PHY Reset: We needed to add a signal (PHY_RESET_0) to drive the external Ethernet PHY reset pin. The PHY on the ML505 board has an active low reset input, so we connect it to the logical “not” of the bus reset signal.
  • The clock signal names were changed for clarity. Most Xilinx documents refer to these clocks as REFCLK and USERCLK.

Import the Ethernet MAC Peripheral

Now we will use the Peripheral Wizard again, but this time using the import function.

  1. Select from the menu “Hardware->Create or Import Peripheral” and click “Next”.
  2. Select “Import existing peripheral” and click “Next”.
     
  3. Select “To an XPS project”, ensure that the folder chosen is the project folder, and click “Next”.
  4. For the name of the peripheral, type “eth_mac”. Tick “Use version” and select the same version number that we originally created. Click “Next”. It will ask if we are willing to overwrite the existing peripheral and we should answer “Yes”.
     
  5. Tick “HDL source files” and click “Next”.
     
  6. Select “Use existing Peripheral Analysis Order file (*.pao)” and click “Browse”. From the project folder, go to “pcores\eth_mac_v1_00_a\data” and select the “eth_mac_v2_1_0.pao” file. Click “Next”.
     
  7. On the “HDL analysis information” page, click “Next”. The wizard will mention if any errors are found in the design.
  8. On the “Bus Interfaces” page, tick “PLB Slave” and click “Next”.
     
  9. On the “SPLB: Port” page, click “Next”.
  10. On the “SPLB: Parameter” page, click “Next”.
  11. On the “Identify Interrupt Signals” page, untick “Select and Configure Interrupts” and click “Next”.
     
  12. On the “Parameter Attributes” page, click “Next”.
  13. On the “Port Attributes” page, click “Next”.
  14. Click “Finish”.

The Ethernet MAC peripheral is now ready to use and it should be accessible through the “IP Catalog->Project Local pcores” in the XPS interface. Note that although we can access it through the IP Catalog, other projects will not find it there because it is only associated with our project, as we specified in the Peripheral Wizard.

Create an Instance of the Peripheral

Now we are ready to create an instance of the peripheral into our project.

  1. From the “IP Catalog” find the “eth_mac” IP core in the “Project Local pcores” group. Right click on the core and select “Add IP”.
     
  2. From the “System Assembly View” using the “Bus Interface” filter, connect the “eth_mac_0” to the PLB bus.
     
  3. Click on the “Ports” filter. Click on the “+” for “eth_mac_0” to view its ports.
  4. Click on the “Net” field for the “PHY_RESET_0” port. Type “PHY_RESET_0” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External” and press “Enter”.
  5. Click on the “Net” field for the “GTP_READY” port. Type “GTP_READY” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External” and press “Enter”.
  6. Click on the “Net” field for the “REFCLK_P_IN” port. Type “REFCLK_P_IN” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External” and press “Enter”.
  7. Click on the “Net” field for the “REFCLK_N_IN” port. Type “REFCLK_N_IN” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External” and press “Enter”.
     
  8. Click on the “Addresses” filter. Change the “Size” for “eth_mac_0” to 64K. Then click “Generate Addresses”.

Now we have created an instance of the Ethernet MAC peripheral in our design.

Modify the Constraints file

The Ethernet MAC peripheral requires timing and pin constraints, as well as a constraint to select the RocketIO GTP we will use for a link to the PHY. The clocks used must be constrained to 125MHz while the PHY reset and GTP ready signals must be assigned to specific pins. The GTP and pins that we select here were obtained from the schematic for the ML505.

  1. Click the “Project” tab and double click on the UCF file to open it.
  2. Add the following lines to the end of the file:
##################################
# These constraints were adapted from the example
# design produced by CORE Generator:
# v5_emac_v1_5_example_design.ucf
##################################

CONFIG PART = 5vlx50tff1136-1;

##################################
# BLOCK Level constraints
##################################

# EMAC0 Clocking
# 125MHz clock input from BUFG
NET "*user_clk" TNM_NET = "clk_gtp";
TIMEGRP  "v5_emac_v1_5_gtp_clk" = "clk_gtp";
TIMESPEC "TS_v5_emac_v1_5_gtp_clk" = PERIOD "v5_emac_v1_5_gtp_clk" 7700 ps HIGH 50 %;
# EMAC0 Tri-speed clock input from BUFG
NET "*CLIENT_CLK_0" TNM_NET    = "clk_client0";
TIMEGRP  "v5_emac_v1_5_gtp_clk_client0"    = "clk_client0";
TIMESPEC "TS_v5_emac_v1_5_gtp_clk_client0" = PERIOD "v5_emac_v1_5_gtp_clk_client0" 7700 ps HIGH 50 %;

#-----------------------------------------------------------              
# EMAC0 Fabric Rx Elastic Buffer Timing Constraints:       - 
#-----------------------------------------------------------
NET "*GTP_DUAL_1000X_inst?RXRECCLK_0_BUFR" TNM_NET = "clk_rec_clk0";
TIMEGRP  "v5_emac_v1_5_client_rec_clk0" = "clk_rec_clk0";
TIMESPEC "TS_v5_emac_v1_5_rec_clk0"     = PERIOD "v5_emac_v1_5_client_rec_clk0" 7700 ps HIGH 50 %;

# Control Gray Code delay and skew 
INST "*GTP_DUAL_1000X_inst?rx_elastic_buffer_inst_0?rd_addr_gray_?" TNM = "rx_elastic_rd_to_wr_0";
TIMESPEC "TS_rx_elastic_rd_to_wr_0" = FROM "rx_elastic_rd_to_wr_0" TO "clk_rec_clk0" 7500 ps DATAPATHONLY;
INST "*GTP_DUAL_1000X_inst?rx_elastic_buffer_inst_0?wr_addr_gray_?" TNM = "elastic_metastable_0";
TIMESPEC "ts_elastic_meta_protect_0" = FROM "elastic_metastable_0" 5 ns DATAPATHONLY;

# Reduce clock period to allow 3 ns for metastability settling time
INST "*GTP_DUAL_1000X_inst?rx_elastic_buffer_inst_0?rd_wr_addr_gray*" TNM = "rx_graycode_0";
INST "*GTP_DUAL_1000X_inst?rx_elastic_buffer_inst_0?rd_occupancy*"    TNM = "rx_binary_0";
TIMESPEC "ts_rx_buf_meta_protect_0" = FROM "rx_graycode_0" TO "rx_binary_0" 5 ns;

##################################
# LocalLink Level constraints
##################################

# EMAC0 LocalLink client FIFO constraints.

INST "*client_side_FIFO_emac0?tx_fifo_i?rd_tran_frame_tog"    TNM = "tx_fifo_rd_to_wr_0";
INST "*client_side_FIFO_emac0?tx_fifo_i?rd_retran_frame_tog"  TNM = "tx_fifo_rd_to_wr_0";
INST "*client_side_FIFO_emac0?tx_fifo_i?rd_col_window_pipe_1" TNM = "tx_fifo_rd_to_wr_0";
INST "*client_side_FIFO_emac0?tx_fifo_i?rd_addr_txfer*"       TNM = "tx_fifo_rd_to_wr_0";
INST "*client_side_FIFO_emac0?tx_fifo_i?rd_txfer_tog"         TNM = "tx_fifo_rd_to_wr_0";
INST "*client_side_FIFO_emac0?tx_fifo_i?wr_frame_in_fifo"     TNM = "tx_fifo_wr_to_rd_0";

TIMESPEC "TS_tx_fifo_rd_to_wr_0" = FROM "tx_fifo_rd_to_wr_0" TO "v5_emac_v1_5_gtp_clk_client0" 8000 ps DATAPATHONLY;
TIMESPEC "TS_tx_fifo_wr_to_rd_0" = FROM "tx_fifo_wr_to_rd_0" TO "v5_emac_v1_5_gtp_clk_client0" 8000 ps DATAPATHONLY;

# Reduce clock period to allow 3 ns for metastability settling time
INST "*client_side_FIFO_emac0?tx_fifo_i?wr_tran_frame_tog"    TNM = "tx_metastable_0";
INST "*client_side_FIFO_emac0?tx_fifo_i?wr_rd_addr*"          TNM = "tx_metastable_0";
INST "*client_side_FIFO_emac0?tx_fifo_i?wr_txfer_tog"         TNM = "tx_metastable_0";
INST "*client_side_FIFO_emac0?tx_fifo_i?frame_in_fifo"        TNM = "tx_metastable_0";
INST "*client_side_FIFO_emac0?tx_fifo_i?wr_retran_frame_tog*" TNM = "tx_metastable_0";
INST "*client_side_FIFO_emac0?tx_fifo_i?wr_col_window_pipe_0" TNM = "tx_metastable_0";

TIMESPEC "ts_tx_meta_protect_0" = FROM "tx_metastable_0" 5 ns DATAPATHONLY;

INST "*client_side_FIFO_emac0?tx_fifo_i?rd_addr_txfer*"       TNM = "tx_addr_rd_0";
INST "*client_side_FIFO_emac0?tx_fifo_i?wr_rd_addr*"          TNM = "tx_addr_wr_0";
TIMESPEC "TS_tx_fifo_addr_0" = FROM "tx_addr_rd_0" TO "tx_addr_wr_0" 10ns;

## RX Client FIFO
# Group the clock crossing signals into timing groups
INST "*client_side_FIFO_emac0?rx_fifo_i?wr_store_frame_tog"   TNM = "rx_fifo_wr_to_rd_0";
INST "*client_side_FIFO_emac0?rx_fifo_i?rd_addr_gray*"        TNM = "rx_fifo_rd_to_wr_0";

TIMESPEC "TS_rx_fifo_wr_to_rd_0" = FROM "rx_fifo_wr_to_rd_0" TO "v5_emac_v1_5_gtp_clk_client0" 8000 ps DATAPATHONLY;
TIMESPEC "TS_rx_fifo_rd_to_wr_0" = FROM "rx_fifo_rd_to_wr_0" TO "v5_emac_v1_5_gtp_clk_client0" 8000 ps DATAPATHONLY;

# Reduce clock period to allow for metastability settling time
INST "*client_side_FIFO_emac0?rx_fifo_i?wr_rd_addr_gray_sync*" TNM = "rx_metastable_0";
INST "*client_side_FIFO_emac0?rx_fifo_i?rd_store_frame_tog"    TNM = "rx_metastable_0";

TIMESPEC "ts_rx_meta_protect_0" = FROM "rx_metastable_0" 5 ns;

##################################
# EXAMPLE DESIGN Level constraints
##################################

# Place the transceiver components. Please alter to your chosen transceiver.
INST "*GTP_DUAL_1000X_inst?GTP_1000X?tile0_rocketio_wrapper_i?gtp_dual_i" LOC = "GTP_DUAL_X0Y3";
NET REFCLK_N_IN_pin  LOC = P3;
NET REFCLK_P_IN_pin  LOC = P4;

##################################
# Additions by FPGA Developer
# http://www.fpgadeveloper.com
##################################

# GTP Ready pin
NET "GTP_READY_pin" LOC = AE24; # LED 7

# PHY Reset pin
NET "PHY_RESET_0_pin" LOC = J14; # ML505 PHY Reset 

# PHY Autonegotiate ON
INST *?v5_emac EMAC0_PHYINITAUTONEG_ENABLE = TRUE;
  1. Save and close the file.

Modify the Software Application

In this example, our software application will not do anything other than send a message to Hyperterminal to let you know that it is running. All processing of Ethernet packets is done in hardware through the Ethernet MAC peripheral.

  1. From the “Applications” tab, open “Sources” within the “Project: TestApp_Peripheral” tree. Open the “TestApp_Peripheral.c” source file.
  2. Replace all the code in this file with the following source and save the file.
#include "xparameters.h"
#include "xbasic_types.h"
#include "xstatus.h"

int main (void)
{
  // Display message
  xil_printf("%c[2J",27);
  xil_printf("Tri-mode Ethernet MAC Loop-back");
  xil_printf(" by FPGA Developer\n\r");
  xil_printf("http://www.fpgadeveloper.com\n\r");

  // Stay in an infinite loop
  while(1){
  }
}

 

Download and Test the Project

  1. Open a Hyperterminal window with the required settings. For the correct settings, see Hyperterminal Settings.
  2. Turn on the ML505 board.
  3. From the XPS software, select “Device Configuration->Download Bitstream”.

The Hyperterminal output should display the message “Tri-mode Ethernet MAC Loop-back by FPGA Developer”. When you get this message, you can continue with the following steps.

  1. Open Wireshark on the PC to be used for testing. You can use any PC with a Gigabit Ethernet network card installed and working.
  2. From the menu select “Edit->Preferences”. In the dialog box that opens, select “User Interface->Columns” and set the columns as shown in the screenshot below. Then click “OK”.
     
  3. From the menu select “Capture->Options”. In the dialog box that opens, select the Gigabit Ethernet network card to which you will connect the ML505, then click “Start”.
     
  4. Connect the CAT5 Ethernet cable between the ML505 and the PC running Wireshark.
  5. You should notice that the Ethernet connection LEDs light up on both the ML505 and the PC. The connection LEDs on the PC should be on the Ethernet (RJ45) connector on the back of your PC. The connection LEDs on the ML505 are located next to the PCI edge connector and they are shown in the photo below.

    In order from left to right, as shown in the photo, the LEDs indicate: CONNECTION, TX, RX, 10Mbps, 100Mbps, 1000Mbps. 
  6. We will produce Ethernet packets from the PC by using “ping”. From Windows, select “Start->Run” and type “cmd”. Press “Enter” and you should have a command prompt. From the command line, type “ping www.google.com”. Note that even before running “ping”, you may already see Ethernet packets in Wireshark. This can happen when your PC is trying to connect to a network.
     
  7. Observe the packets in Wireshark by clicking on them. In the screenshot below, we see that the PC sent packets 1, 3 and 5, while the ML505 sent back packets 2, 4 and 6 with the MAC destination and source addresses swapped. Notice also the short time delay of 225us between the sent packet and the received copy.
     
  8. Also observe that the RX and TX LEDs on the ML505 will light up at the same time, indicating that each packet received is immediately transmitted back to the sender (after swapping the MAC sender/destination addresses).

You can download the project files for this tutorial and try it on your ML50x board. Please select the file corresponding to your board, right-click on it and select “Save Link As”.

Board Virtex-5 Version Project files
ML505 XC5VLX50T EthernetMAC-ML505-EDK10-1.zip
ML506 XC5VSX50T EthernetMAC-ML506-EDK10-1.zip
ML507 XC5VFX70T EthernetMAC-ML507-EDK10-1.zip
XUPV5 XC5VLX110T EthernetMAC-ML509-EDK10-1.zip

 

You now have a working Ethernet connection running at 1Gbps. To develop the project further, remove the address swap module and try some of these ideas:

  • TCP/IP stack: Connect the Ethernet MAC LocalLink interface to read/write FIFOs and run a TCP/IP stack on the Microblaze. A lightweight TCP/IP stack for the Microblaze is discussed in the application note XAPP1026.
  • Ethernet-to-Aurora Bridge: Add an Aurora core to the design and create a transparent bridge.
  • Gigabit PC interface: Don’t bother with TCP/IP and use the Ethernet MAC for a high-speed PC link.
  • Video/audio processing: Use VLC Media Player to stream video into the Virtex-5, then process it and send it out of the DVI interface.

Remember that the interface to the Ethernet MAC is LocalLink, so you can virtually hook up anything with an 8-bit wide LocalLink interface.

Jeff is passionate about FPGAs, SoCs and high-performance computing, and has been writing the FPGA Developer blog since 2008. As the owner of Opsero, he leads a small team of FPGA all-stars providing start-ups and tech companies with FPGA design capability that they can call on when needed.

Facebook Twitter LinkedIn