Tutorial Overview

In the last tutorial we implemented the embedded Tri-mode Ethernet MAC and tested it by looping back Ethernet packets and monitoring them with Wireshark. In this tutorial, we will again implement the EMAC but this time we will link it to an Aurora core, to implement an Aurora to Ethernet Bridge. With the bridge, we can link two PCs as shown in the diagram below.

To connect the EMAC and Aurora cores we have to use two FIFOs to cross clock domains. The EMAC has a user clock of 125MHz and a data interface of 8 bits, while the Aurora core will have a user clock of 62.5MHz and a data interface of 16 bits. The diagram below illustrates the connections between the EMAC and Aurora core and the clock domain crossing FIFOs.

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:

  • Ideally, to test the Bridge you should have two (2) FPGA boards and two (2) PCs, however this design has an optional loopback feature that allows the design to be tested with only one FPGA board and one PC.
  • 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
  • Generate the Aurora Core using CORE Generator. For instructions on doing this, please refer to the tutorial Generating the Aurora Core
  • Generate the Clock Domain Crossing FIFOs using CORE Generator. For instructions on doing this, please refer to the tutorial Generating Clock Domain Crossing FIFOs
  • 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 (or two if you have two FPGA boards and two PCs): 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.
  • Obtain a crossover SATA cable if you have two FPGA boards and two PCs that you can use for testing. If you bought the ML505/ML506/ML507 or XUPV5 board, you should have one included in the box.

 

Try Out the BIT File on Your Board

If you want to test this design before building it, you can download the bit file and try it on your ML50x board. Please click the link below for the file corresponding to your board.

Board Virtex-5 Version Bit file
ML505 XC5VLX50T AEBridge-ML505.zip
ML506 XC5VSX50T AEBridge-ML506.zip
XUPV5 XC5VLX110T AEBridge-XUPV5.zip

To program your FPGA with the bit file, first extract the contents of your ZIP file to your hard drive (eg. C:\AEBridge-XUPV5\).

  1. From Windows, select “Start->Run” and type “cmd”. Press “Enter” and you should have a command prompt.
  2. Use the “cd” command to reach the folder where you extracted the bit file (eg. “cd AEBridge-XUPV5″). In this example, the prompt should now read “C:\AEBridge-XUPV5>”.
  3. Turn on your ML505 board and ensure that the JTAG programmer is connected.
  4. From the command line, type “impact -batch download.cmd”.

The FPGA should be programmed and the LCD should be displaying “Aurora to Ethernet Bridge”. For instructions on testing the design, scroll down to the end of the tutorial or click here.

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 “DIP_Switches_8Bit” ticked and un-tick everything else.



     
  8. On the “Add Internal Peripherals” page, click “Next”.
  9. On the “Software Setup” page, un-tick “Memory Test” and leave “Peripheral Test” ticked. Click “Next”.
     
  10. Click “Generate”.
  11. Click “Finish”.

Create the Bridge Peripheral

We now create our Bridge 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 “bridge” 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 “User logic software register” and “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 “User S/W Register” page, we can specify the number of slave registers we want to implement in our peripheral. Leave the default “1″ and click “Next”.
     
  9. 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.
  10. 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”.
  11. Click “Finish”. Now our templates are created and we can modify them to include the code for the EMAC and Aurora core.

Copy the Ethernet MAC source files

We need to copy the Ethernet MAC source files generated by CORE Generator into the Bridge 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”. Select the “example_design” folder, copy and paste it into the “pcores\bridge_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 Bridge peripheral.

 

Copy the Aurora core source files

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

  1. Open Windows Explorer and browse to the folder “AuroraCore”. This is the folder you created with CORE Generator.
     
  2. In that folder, you will find a subfolder called “aurora_201″. Select the “aurora_201″ folder, copy and paste it into the “pcores\bridge_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 Bridge 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 and Aurora core 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\bridge_v1_00_a\data” folder. Select the file “bridge_v2_1_0.pao” and click “Open”.
  2. At the bottom of this file you will see these two lines:
lib bridge_v1_00_a user_logic vhdl
lib bridge_v1_00_a bridge 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 bridge_v1_00_a aurora_201\src\aurora_201_aurora_lane.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_aurora_pkg.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_channel_error_detect.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_channel_init_sm.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_chbond_count_dec.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_error_detect.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_global_logic.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_gtp_wrapper.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_idle_and_ver_gen.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_lane_init_sm.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_rx_ll.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_rx_ll_pdu_datapath.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_sym_dec.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_sym_gen.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_tx_ll.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_tx_ll_control.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201_tx_ll_datapath.vhd
lib bridge_v1_00_a aurora_201\cc_manager\aurora_201_standard_cc_module.vhd
lib bridge_v1_00_a aurora_201\clock_module\aurora_201_clock_module.vhd
lib bridge_v1_00_a aurora_201\src\aurora_201.vhd
lib bridge_v1_00_a example_design/v5_emac_v1_5.vhd
lib bridge_v1_00_a example_design/physical/rx_elastic_buffer.vhd
lib bridge_v1_00_a example_design/physical/gtp_dual_1000X.vhd
lib bridge_v1_00_a example_design/physical/rocketio_wrapper_gtp.vhd
lib bridge_v1_00_a example_design/physical/rocketio_wrapper_gtp_tile.vhd
lib bridge_v1_00_a example_design/v5_emac_v1_5_block.vhd
lib bridge_v1_00_a example_design/client/fifo/tx_client_fifo_8.vhd
lib bridge_v1_00_a example_design/client/fifo/rx_client_fifo_8.vhd
lib bridge_v1_00_a example_design/client/fifo/eth_fifo_8.vhd
lib bridge_v1_00_a example_design/v5_emac_v1_5_locallink.vhd
lib bridge_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 Bridge peripheral.

Modify the Bridge Peripheral

Now we will insert code into the “user_logic.vhd” file for our Bridge peripheral to instantiate and connect the Ethernet MAC and Aurora core. The code for defining and instantiating the cores is derived from the example designs that were generated by CORE Generator. If you refer back to the files created by CORE Generator, you will find the top module of the EMAC example in the file “v5_emac_v1_5\example_design\v5_emac_v1_5_example_design.vhd”. You will find the top module of the Aurora core example in the file “aurora_201\examples\aurora_201_aurora_example.vhd”.

  1. Select from the menu “File->Open” and look in the project folder.
  2. Open the folders: “pcores\bridge_v1_00_a\hdl\vhdl”.
  3. Open the file “bridge.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;
  EMAC_READY               : out std_logic;
  PHY_RESET_0              : out std_logic;
  HARD_ERROR               : out std_logic;
  SOFT_ERROR               : out std_logic;
  FRAME_ERROR              : out std_logic;
  LANE_UP                  : out std_logic;
  CHANNEL_UP               : out std_logic;
  RXP_IN                   : in std_logic_vector(1 downto 0);
  RXN_IN                   : in std_logic_vector(1 downto 0);
  TXP_OUT                  : out std_logic_vector(1 downto 0);
  TXN_OUT                  : out std_logic_vector(1 downto 0);
  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,
  EMAC_READY  => EMAC_READY,
  PHY_RESET_0 => PHY_RESET_0,
  HARD_ERROR  => HARD_ERROR,
  SOFT_ERROR  => SOFT_ERROR,
  FRAME_ERROR => FRAME_ERROR,
  LANE_UP     => LANE_UP,
  CHANNEL_UP  => CHANNEL_UP,
  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;
  EMAC_READY               : out std_logic;
  PHY_RESET_0              : out std_logic;
  HARD_ERROR               : out std_logic;
  SOFT_ERROR               : out std_logic;
  FRAME_ERROR              : out std_logic;
  LANE_UP                  : out std_logic;
  CHANNEL_UP               : out std_logic;
  RXP_IN                   : in std_logic_vector(1 downto 0);
  RXN_IN                   : in std_logic_vector(1 downto 0);
  TXP_OUT                  : out std_logic_vector(1 downto 0);
  TXN_OUT                  : out std_logic_vector(1 downto 0);
  1. Find the line of code that says “–USER signal declarations added here” and add the following lines of code just below.
  -- Clock signals
  signal ref_clk            : std_logic;
  signal user_clk_eth       : std_logic;
  signal user_clk_out       : std_logic;

  -- Reset signals
  signal rst_gtp            : std_logic;
  signal rst_fifos          : std_logic;
  signal reset_aurora       : std_logic;
  signal pre_reset_aurora   : std_logic_vector(5 downto 0);

  -- Registers for the status outputs
  signal HARD_ERROR_Buffer  : std_logic;
  signal SOFT_ERROR_Buffer  : std_logic;
  signal FRAME_ERROR_Buffer : std_logic;
  signal LANE_UP_Buffer     : std_logic;
  signal CHANNEL_UP_Buffer  : std_logic;

  -- LocalLink TX Interface
  signal tx_d_i             : std_logic_vector(0 to 15);
  signal tx_rem_i           : std_logic;
  signal tx_src_rdy_n_i     : std_logic;
  signal tx_sof_n_i         : std_logic;
  signal tx_eof_n_i         : std_logic;
  signal tx_dst_rdy_n_i     : std_logic;

  -- LocalLink RX Interface
  signal rx_d_i             : std_logic_vector(0 to 15);
  signal rx_rem_i           : std_logic;
  signal rx_src_rdy_n_i     : std_logic;
  signal rx_sof_n_i         : std_logic;
  signal rx_eof_n_i         : std_logic;

  -- Error Detection Interface
  signal hard_error_i       : std_logic;
  signal soft_error_i       : std_logic;
  signal frame_error_i      : std_logic;

  -- Status
  signal channel_up_i       : std_logic;
  signal lane_up_i          : std_logic;
  signal lane_up_i_i        : std_logic;

  -- Clock Compensation Control Interface
  signal warn_cc_i          : std_logic;
  signal do_cc_i            : std_logic;

  -- System Interface
  signal dcm_not_locked_i   : std_logic;
  signal user_clk_aur       : std_logic;
  signal sync_clk_i         : std_logic;
  signal power_down_i       : std_logic;
  signal loopback_i         : std_logic_vector(0 to 2);
  signal tx_lock_i          : std_logic;
  signal tx_out_clk_i       : std_logic;
  signal buf_tx_out_clk_i   : std_logic; 

  -- Aurora Component Declarations

  component aurora_201_CLOCK_MODULE
  port (
      GTP_CLK        : in std_logic;
      GTP_CLK_LOCKED : in std_logic;
      USER_CLK       : out std_logic;
      SYNC_CLK       : out std_logic;
      DCM_NOT_LOCKED : out std_logic
    );
  end component;

  component aurora_201
  generic(
        SIM_GTPRESET_SPEEDUP :integer := 0
    );
  port(
      -- LocalLink TX Interface
        TX_D             : in std_logic_vector(0 to 15);
        TX_REM           : in std_logic;
        TX_SRC_RDY_N     : in std_logic;
        TX_SOF_N         : in std_logic;
        TX_EOF_N         : in std_logic;
        TX_DST_RDY_N     : out std_logic;
      -- LocalLink RX Interface
        RX_D             : out std_logic_vector(0 to 15);
        RX_REM           : out std_logic;
        RX_SRC_RDY_N     : out std_logic;
        RX_SOF_N         : out std_logic;
        RX_EOF_N         : out std_logic;
      -- GTP Serial I/O
        RXP              : in std_logic;
        RXN              : in std_logic;
        TXP              : out std_logic;
        TXN              : out std_logic;
      -- GTP Reference Clock Interface
        GTPD1            : in std_logic;
      -- Error Detection Interface
        HARD_ERROR       : out std_logic;
        SOFT_ERROR       : out std_logic;
        FRAME_ERROR      : out std_logic;
      -- Status
        CHANNEL_UP       : out std_logic;
        LANE_UP          : out std_logic;
      -- Clock Compensation Control Interface
        WARN_CC          : in std_logic;
        DO_CC            : in std_logic;
      -- System Interface
        DCM_NOT_LOCKED   : in std_logic;
        USER_CLK         : in std_logic;
        SYNC_CLK         : in std_logic;
        PMA_INIT         : in std_logic;
        RESET            : in std_logic;
        POWER_DOWN       : in std_logic;
        LOOPBACK         : in std_logic_vector(2 downto 0);
        TX_LOCK          : out std_logic;
        TX_OUT_CLK       : out std_logic
    );
  end component;

  component aurora_201_STANDARD_CC_MODULE
  port(
      -- Clock Compensation Control Interface
        WARN_CC        : out std_logic;
        DO_CC          : out std_logic;
      -- System Interface
        DCM_NOT_LOCKED : in std_logic;
        USER_CLK       : in std_logic;
        CHANNEL_UP     : in std_logic
    );
  end component;

  -- EMAC Component Declarations

  -- 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;

  -- EMAC 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;
  signal rx_ll_fifo_status_0_i    : std_logic_vector(3 downto 0);

  -- 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

  -- 1.25/12.5/125MHz clock signals for tri-speed SGMII
  signal client_clk_0_o            : std_logic;
  signal client_clk_0              : std_logic;

  -- Clock Domain Crossing FIFO declarations

  -- FIFO 32 bit to 16 bit
  signal fifo1_din            : std_logic_VECTOR(31 downto 0);
  signal fifo1_rd_en          : std_logic;
  signal fifo1_wr_en          : std_logic;
  signal fifo1_almost_full    : std_logic;
  signal fifo1_dout           : std_logic_VECTOR(15 downto 0);
  signal fifo1_valid          : std_logic;

  component fifo_32b_to_16b
  port (
    din            : IN std_logic_VECTOR(31 downto 0);
    rd_clk         : IN std_logic;
    rd_en          : IN std_logic;
    rst            : IN std_logic;
    wr_clk         : IN std_logic;
    wr_en          : IN std_logic;
    almost_full    : OUT std_logic;
    dout           : OUT std_logic_VECTOR(15 downto 0);
    empty          : OUT std_logic;
    full           : OUT std_logic;
    valid          : OUT std_logic);
  end component;

  -- FIFO 16 bit to 32 bit
  signal fifo2_din            : std_logic_VECTOR(15 downto 0);
  signal fifo2_rd_en          : std_logic;
  signal fifo2_wr_en          : std_logic;
  signal fifo2_almost_full    : std_logic;
  signal fifo2_dout           : std_logic_VECTOR(31 downto 0);
  signal fifo2_valid          : std_logic;
  signal fifo2_full           : std_logic;
  signal odd_bytes            : std_logic;
  signal insert_blank         : std_logic;

  component fifo_16b_to_32b
  port (
    din            : IN std_logic_VECTOR(15 downto 0);
    rd_clk         : IN std_logic;
    rd_en          : IN std_logic;
    rst            : IN std_logic;
    wr_clk         : IN std_logic;
    wr_en          : IN std_logic;
    almost_full    : OUT std_logic;
    dout           : OUT std_logic_VECTOR(31 downto 0);
    empty          : OUT std_logic;
    full           : OUT std_logic;
    valid          : OUT std_logic);
  end component;
  1. Find the line of code that says “–USER logic implementation added here” and add the following lines of code just below.
  -- Clock buffering

  ref_clk_ibufds_i : IBUFDS
  port map(
      O  => ref_clk,
      I  => REFCLK_P_IN,
      IB => REFCLK_N_IN
  );

  emac_out_clk_bufg_i : BUFG
  port map(
      I  => user_clk_out,
      O  => user_clk_eth
  );

  aurora_out_clk_bufg_i : BUFG
  port map(
      I  => tx_out_clk_i,
      O  => buf_tx_out_clk_i
  );

  -- Aurora clock module for clock division
  clock_module_i : aurora_201_CLOCK_MODULE
  port map(
      GTP_CLK        => buf_tx_out_clk_i,
      GTP_CLK_LOCKED => tx_lock_i,
      USER_CLK       => user_clk_aur,
      SYNC_CLK       => sync_clk_i,
      DCM_NOT_LOCKED => dcm_not_locked_i
  );

  -- Reset logic
  rst_gtp <= Bus2IP_Reset;
  rst_fifos <= ll_reset_0_i or reset_aurora;
  PHY_RESET_0 <= not rst_gtp;   -- 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);

  -- Status outputs
  HARD_ERROR  <= HARD_ERROR_Buffer;
  SOFT_ERROR  <= SOFT_ERROR_Buffer;
  FRAME_ERROR <= FRAME_ERROR_Buffer;
  LANE_UP     <= LANE_UP_Buffer;
  CHANNEL_UP  <= CHANNEL_UP_Buffer;

  -- Register Status Outputs from core
  process (user_clk_aur)
  begin
    if (user_clk_aur 'event and user_clk_aur = '1') then
      HARD_ERROR_Buffer  <= hard_error_i;
      SOFT_ERROR_Buffer  <= soft_error_i;
      FRAME_ERROR_Buffer <= frame_error_i;
      LANE_UP_Buffer     <= lane_up_i;
      CHANNEL_UP_Buffer  <= channel_up_i;
    end if;
  end process;

  -- System Interface
  power_down_i     <= '0';
  loopback_i       <= "00" & slv_reg0(31);   -- Aurora Module Instantiation   aurora_module_i : aurora_201   port map(     -- LocalLink TX Interface       TX_D             => tx_d_i,
      TX_REM           => tx_rem_i,
      TX_SRC_RDY_N     => tx_src_rdy_n_i,
      TX_SOF_N         => tx_sof_n_i,
      TX_EOF_N         => tx_eof_n_i,
      TX_DST_RDY_N     => tx_dst_rdy_n_i,

    -- LocalLink RX Interface
      RX_D             => rx_d_i,
      RX_REM           => rx_rem_i,
      RX_SRC_RDY_N     => rx_src_rdy_n_i,
      RX_SOF_N         => rx_sof_n_i,
      RX_EOF_N         => rx_eof_n_i,

    -- GTP Serial I/O
      RXP              => RXP_IN(0),
      RXN              => RXN_IN(0),
      TXP              => TXP_OUT(0),
      TXN              => TXN_OUT(0),

    -- GTP Reference Clock Interface
      GTPD1            => ref_clk,

    -- Error Detection Interface
      HARD_ERROR       => hard_error_i,
      SOFT_ERROR       => soft_error_i,
      FRAME_ERROR      => frame_error_i,

    -- Status
      CHANNEL_UP       => channel_up_i,
      LANE_UP          => lane_up_i,

    -- Clock Compensation Control Interface
      WARN_CC          => warn_cc_i,
      DO_CC            => do_cc_i,

    -- System Interface
      DCM_NOT_LOCKED   => dcm_not_locked_i,
      USER_CLK         => user_clk_aur,
      SYNC_CLK         => sync_clk_i,
      RESET            => reset_aurora,
      POWER_DOWN       => power_down_i,
      LOOPBACK         => loopback_i,
      PMA_INIT         => rst_gtp,
      TX_LOCK          => tx_lock_i,
      TX_OUT_CLK       => tx_out_clk_i
  );

  standard_cc_module_i : aurora_201_STANDARD_CC_MODULE
  port map (
    -- Clock Compensation Control Interface
      WARN_CC        => warn_cc_i,
      DO_CC          => do_cc_i,
    -- System Interface
      DCM_NOT_LOCKED => dcm_not_locked_i,
      USER_CLK       => user_clk_aur,
      CHANNEL_UP     => channel_up_i
  );

  -- Create synchronous reset in the USER_CLK_AUR domain
  gen_reset_aurora : process (user_clk_aur, rst_gtp)
  begin
    if rst_gtp = '1' then
      pre_reset_aurora <= (others => '1');
      reset_aurora <= '1';
    elsif user_clk_aur'event and user_clk_aur = '1' then
      if tx_lock_i = '1' then
        pre_reset_aurora(0)          <= '0';
        pre_reset_aurora(5 downto 1) <= pre_reset_aurora(4 downto 0);
        reset_aurora                 <= pre_reset_aurora(5);       end if;     end if;   end process gen_reset_aurora;   ------------------------------------------------------------------------   -- 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_eth,
    -- 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_eth,
      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       => rx_ll_fifo_status_0_i,

    -- 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_eth,
      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  => EMAC_READY,
    -- EMAC0 Interrupt
      EMAC0ANINTERRUPT          => open,

    -- Clock Signals - EMAC0
    -- SGMII Interface - EMAC0
      TXP_0                     => TXP_OUT(1),
      TXN_0                     => TXN_OUT(1),
      RXP_0                     => RXP_IN(1),
      RXN_0                     => RXN_IN(1),
      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                     => rst_gtp
  );

  -- Create synchronous reset in the transmitter clock domain.
  gen_ll_reset_emac0 : process (user_clk_eth, rst_gtp)
  begin
    if rst_gtp = '1' then
      ll_pre_reset_0_i <= (others => '1');
      ll_reset_0_i     <= '1';
    elsif user_clk_eth'event and user_clk_eth = '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;

  ----------------------------------------------------
  -- FIFO1 Instantiation and connections
  ----------------------------------------------------
  -- EMAC TX (8 bits) <- FIFO1 <- Aurora RX (16 bits)   fifo1_i : fifo_32b_to_16b     port map (       din            => fifo1_din,
      rd_clk         => user_clk_eth,
      rd_en          => fifo1_rd_en,
      rst            => rst_fifos,
      wr_clk         => user_clk_aur,
      wr_en          => fifo1_wr_en,
      almost_full    => fifo1_almost_full,
      dout           => fifo1_dout,
      empty          => open,
      full           => open,
      valid          => fifo1_valid);

  -- Connections between EMAC TX and FIFO1
  tx_ll_data_0_i <= fifo1_dout(7 downto 0);
  tx_ll_sof_n_0_i <= not fifo1_dout(8);
  tx_ll_eof_n_0_i <= not fifo1_dout(9);
  tx_ll_src_rdy_n_0_i <= (not fifo1_valid) or fifo1_dout(10);
  fifo1_rd_en <= not tx_ll_dst_rdy_n_0_i;

  -- Connections between FIFO1 and Aurora
  fifo1_din(23 downto 16) <= rx_d_i(0 to 7);
  fifo1_din(7 downto 0) <= rx_d_i(8 to 15);
  fifo1_din(24) <= not rx_sof_n_i;
  fifo1_din(25) <= (not rx_eof_n_i) and (not rx_rem_i);
  fifo1_din(9) <= (not rx_eof_n_i) and rx_rem_i;
  fifo1_din(10) <= (not rx_eof_n_i) and (not rx_rem_i);
  fifo1_wr_en <= not rx_src_rdy_n_i;   ----------------------------------------------------   -- FIFO2 Instantiation and connections   ----------------------------------------------------   -- EMAC RX (8 bits) -> FIFO2 -> Aurora TX (16 bits)

  fifo2_i : fifo_16b_to_32b
    port map (
      din            => fifo2_din,
      rd_clk         => user_clk_aur,
      rd_en          => fifo2_rd_en,
      rst            => rst_fifos,
      wr_clk         => user_clk_eth,
      wr_en          => fifo2_wr_en,
      almost_full    => fifo2_almost_full,
      dout           => fifo2_dout,
      empty          => open,
      full           => fifo2_full,
      valid          => fifo2_valid);

  -- Connections between FIFO2 and EMAC RX
  fifo2_din(7 downto 0) <= rx_ll_data_0_i;
  fifo2_din(8) <= (not rx_ll_sof_n_0_i) and (not insert_blank);
  fifo2_din(9) <= (not rx_ll_eof_n_0_i) and (not insert_blank);
  fifo2_wr_en <= (not rx_ll_src_rdy_n_0_i) or insert_blank;
  rx_ll_dst_rdy_n_0_i <= fifo2_almost_full;

  -- Connections between Aurora TX and FIFO2
  tx_d_i(0 to 7) <= fifo2_dout(23 downto 16);
  tx_d_i(8 to 15) <= fifo2_dout(7 downto 0);
  tx_sof_n_i <= not fifo2_dout(24);
  tx_eof_n_i <= not (fifo2_dout(9) or fifo2_dout(25));
  tx_rem_i <= fifo2_dout(9);
  tx_src_rdy_n_i <= not fifo2_valid;
  fifo2_rd_en <= not tx_dst_rdy_n_i;

  -- Logic to generate "odd_bytes" signal that is asserted for
  -- every ODD byte of an Ethernet frame written into FIFO2.
  process (user_clk_eth, rst_fifos)
  begin
    if rst_fifos = '1' then
      odd_bytes <= '1';
    elsif user_clk_eth'event and user_clk_eth = '1' then
      if rx_ll_src_rdy_n_0_i = '0' and fifo2_almost_full = '0' then
        odd_bytes <= (not odd_bytes) or (not rx_ll_eof_n_0_i);
      end if;
    end if;
  end process;

  -- Logic to generate "insert_blank" signal to write an extra byte
  -- into FIFO2 when the frame contained an ODD number of bytes.
  process (user_clk_eth, rst_fifos)
  begin
    if rst_fifos = '1' then
      insert_blank <= '0';
    elsif user_clk_eth'event and user_clk_eth = '1' then
      insert_blank <= odd_bytes and (not rx_ll_eof_n_0_i) and (not rx_ll_src_rdy_n_0_i) and (not fifo2_almost_full);
    end if;
  end process;
  1. Save and close the file.

Import the Bridge 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 “bridge”. 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 “Netlist files” and click “Next”.
     
  6. Select “Use existing Peripheral Analysis Order file (*.pao)” and click “Browse”. From the project folder, go to “pcores\bridge_v1_00_a\data” and select the “bridge_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. On the “Netlist Files” page, click “Select Files” and browse to the “ClockCrossFIFO” folder. You should have created this folder earlier in the Clock Domain Crossing FIFO tutorial. Select both NGC files and click “OK. You should now see the two FIFO netlist files listed in the dialog box as shown below. Click “Next”.
     
  15. Click “Finish”.

The Bridge peripheral is now ready to use and it should be accessible through the “IP Catalog->Project Local pcores” in the XPS interface.

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 “bridge” 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 “bridge_0″ to the PLB bus.
     
  3. Click on the “Ports” filter. Click on the “+” for “bridge_0″ to view its ports.
  4. Click on the “Net” field for the “CHANNEL_UP” port. Type “CHANNEL_UP” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External”.
  5. Click on the “Net” field for the “LANE_UP” port. Type “LANE_UP” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External”.
  6. Click on the “Net” field for the “FRAME_ERROR” port. Type “FRAME_ERROR” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External”.
  7. Click on the “Net” field for the “SOFT_ERROR” port. Type “SOFT_ERROR” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External”.
  8. Click on the “Net” field for the “HARD_ERROR” port. Type “HARD_ERROR” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External”.
  9. 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”.
  10. Click on the “Net” field for the “EMAC_READY” port. Type “EMAC_READY” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External”.
  11. 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”.
  12. 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”.
     
  13. Click on the “Addresses” filter. Change the “Size” for “bridge_0″ to 64K. Then click “Generate Addresses”.

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

Create a GPIO Instance for the LCD

Our software application will control the LCD so we need to instantiate a GPIO peripheral to connect to it.

  1. From the “IP Catalog” find the “XPS General Purpose IO” peripheral in the “General Purpose IO” group. Right click on the core and select “Add IP”.
     
  2. From the “System Assembly View”, using the “Bus Interface” filter you will notice that the GPIO was added as “xps_gpio_0″. Click on the “xps_gpio_0″ peripheral and rename it to “LCD”, then connect it to the PLB bus.
     
  3. Double click on the “LCD” to bring up the peripheral settings. Set the “GPIO Data Channel Width” to 7 bits then click “OK”.
     
  4. Click on the “Ports” filter. Click on the “+” for “LCD” to view its ports.
  5. Click on the “Net” field for the “GPIO_IO” port. Type “LCD_IO” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External”.
     
  6. Click on the “Addresses” filter. Change the “Size” for “LCD” to 64K. Then click “Generate Addresses”.

Our GPIO for the LCD is now instantiated in our project.

Modify the Constraints file

The Bridge peripheral requires timing and pin constraints, as well as a constraint to select the RocketIO GTPs we will use for a link to the PHY and the SATA HOST 1 connector. The clocks used must be constrained to 125MHz and 62.5MHz while the PHY reset and status 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:
##### Constraints added by tutorial #####

##### Clock Constraints #################

# User Clock Constraints
# GTP reference clock
NET "*ref_clk" PERIOD = 8.0 ns;
# 125MHz EMAC user clock
NET "*user_clk_eth" 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 %;
# 62.5MHz Aurora user clock
NET "*user_clk_aur" PERIOD = 16.0 ns;

####### LEDs, LCD and PHY reset #########

# Error pins
NET "FRAME_ERROR_pin"  LOC = AD25;   #LED 5
NET "FRAME_ERROR_pin"  IOSTANDARD=LVCMOS18;
NET "FRAME_ERROR_pin"  PULLDOWN;
NET "FRAME_ERROR_pin"  SLEW=SLOW;
NET "FRAME_ERROR_pin"  DRIVE=2;
NET "SOFT_ERROR_pin"  LOC = G16;    #LED 4
NET "SOFT_ERROR_pin"  IOSTANDARD=LVCMOS33;
NET "SOFT_ERROR_pin"  PULLDOWN;
NET "SOFT_ERROR_pin"  SLEW=SLOW;
NET "SOFT_ERROR_pin"  DRIVE=2;
NET "HARD_ERROR_pin"  LOC = AD26;   #LED 3
NET "HARD_ERROR_pin"  IOSTANDARD=LVCMOS18;
NET "HARD_ERROR_pin"  PULLDOWN;
NET "HARD_ERROR_pin"  SLEW=SLOW;
NET "HARD_ERROR_pin"  DRIVE=2;

# Status pins
NET "CHANNEL_UP_pin"  LOC = G15;    #LED 2
NET "CHANNEL_UP_pin"  IOSTANDARD=LVCMOS33;
NET "CHANNEL_UP_pin"  PULLDOWN;
NET "CHANNEL_UP_pin"  SLEW=SLOW;
NET "CHANNEL_UP_pin"  DRIVE=2;
NET "LANE_UP_pin"  LOC = L18;    #LED 1
NET "LANE_UP_pin"  IOSTANDARD=LVCMOS33;
NET "LANE_UP_pin"  PULLDOWN;
NET "LANE_UP_pin"  SLEW=SLOW;
NET "LANE_UP_pin"  DRIVE=2;
NET "EMAC_READY_pin"  LOC = H18;    #LED 0
NET "EMAC_READY_pin"  IOSTANDARD=LVCMOS33;
NET "EMAC_READY_pin"  PULLDOWN;
NET "EMAC_READY_pin"  SLEW=SLOW;
NET "EMAC_READY_pin"  DRIVE=2;

# PHY Reset signal
NET "PHY_RESET_0_pin" LOC = J14;   # ML505 PHY Reset 
Net "PHY_RESET_0_pin" IOSTANDARD=LVCMOS33;

# Module LCD_IO constraints

# LCD_FPGA_DB4
Net LCD_IO_pin<6> LOC = T9;
Net LCD_IO_pin<6> IOSTANDARD=LVCMOS33;
Net LCD_IO_pin<6> PULLDOWN;
Net LCD_IO_pin<6> SLEW=SLOW;
Net LCD_IO_pin<6> DRIVE=2;
# LCD_FPGA_DB5
Net LCD_IO_pin<5> LOC = G7;
Net LCD_IO_pin<5> IOSTANDARD=LVCMOS33;
Net LCD_IO_pin<5> PULLDOWN;
Net LCD_IO_pin<5> SLEW=SLOW;
Net LCD_IO_pin<5> DRIVE=2;
# LCD_FPGA_DB6
Net LCD_IO_pin<4> LOC = G6;
Net LCD_IO_pin<4> IOSTANDARD=LVCMOS33;
Net LCD_IO_pin<4> PULLDOWN;
Net LCD_IO_pin<4> SLEW=SLOW;
Net LCD_IO_pin<4> DRIVE=2;
# LCD_FPGA_DB7
Net LCD_IO_pin<3> LOC = T11;
Net LCD_IO_pin<3> IOSTANDARD=LVCMOS33;
Net LCD_IO_pin<3> PULLDOWN;
Net LCD_IO_pin<3> SLEW=SLOW;
Net LCD_IO_pin<3> DRIVE=2;
# LCD_FPGA_RW
Net LCD_IO_pin<2> LOC = AC10;
Net LCD_IO_pin<2> IOSTANDARD=LVCMOS33;
Net LCD_IO_pin<2> PULLDOWN;
Net LCD_IO_pin<2> SLEW=SLOW;
Net LCD_IO_pin<2> DRIVE=2;
# LCD_FPGA_RS
Net LCD_IO_pin<1> LOC = J17;
Net LCD_IO_pin<1> IOSTANDARD=LVCMOS33;
Net LCD_IO_pin<1> PULLDOWN;
Net LCD_IO_pin<1> SLEW=SLOW;
Net LCD_IO_pin<1> DRIVE=2;
# LCD_FPGA_E
Net LCD_IO_pin<0> LOC = AC9;
Net LCD_IO_pin<0> IOSTANDARD=LVCMOS33;
Net LCD_IO_pin<0> PULLDOWN;
Net LCD_IO_pin<0> SLEW=SLOW;
Net LCD_IO_pin<0> DRIVE=2;

######################### mgt clock module constraints ########################

NET REFCLK_N_IN_pin  LOC=P3;
NET REFCLK_P_IN_pin  LOC=P4;

################################# mgt wrapper constraints #####################

## GTP_DUAL for the SATA HOST 1 connector
INST */aurora_module_i/gtp_wrapper_i/GTP_DUAL_INST LOC=GTP_DUAL_X0Y2;

## GTP_DUAL for the Tri-mode EMAC
INST "*GTP_DUAL_1000X_inst?GTP_1000X?tile0_rocketio_wrapper_i?gtp_dual_i" LOC=GTP_DUAL_X0Y3;

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

# EMAC0 Clocking
# 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;

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

The constraints given above that assign the GTP for the EMAC and the Aurora core are specific to the ML505 board. We have reiterated those constraints below just so that you can see them. It is important that you change these assignments if you are using another board such as the ML506, ML507 or XUPV5.

## GTP_DUAL for the SATA HOST 1 connector
INST */aurora_module_i/gtp_wrapper_i/GTP_DUAL_INST LOC=GTP_DUAL_X0Y2;

## GTP_DUAL for the Tri-mode EMAC
INST "*GTP_DUAL_1000X_inst?GTP_1000X?tile0_rocketio_wrapper_i?gtp_dual_i" LOC=GTP_DUAL_X0Y3;

Make sure that the GTP assignments are the right ones for your particular board by checking the table below. We need to assign the GTP_DUAL for the EMAC to SGMII (BANK112) and the Aurora core to SATA (BANK114).

ML505 ML506 ML507 XUPV5
XC5VLX50T XC5VSX50T XC5VFX70T XC5VLX110T
SGMII (BANK112) GTP_DUAL X0Y3 GTP_DUAL X0Y3 GTX_DUAL X0Y4 GTP_DUAL X0Y4
SATA (BANK114) GTP_DUAL X0Y2 GTP_DUAL X0Y2 GTX_DUAL X0Y3 GTP_DUAL X0Y3

 

Modify the Software Application

Our software application will write a message on the LCD and control the loopback setting. In the main loop, the program polls the DIP switches for a change in switch 1. When switch 1 is ON, the loopback mode is enabled. When switch 1 is OFF, the loopback mode is disabled.

  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 "xgpio.h"
#include "xstatus.h"
#include "bridge.h"

// DIP Switch flags
#define DIPS_1  0x00000080
#define DIPS_2  0x00000040
#define DIPS_3  0x00000020
#define DIPS_4  0x00000010
#define DIPS_5  0x00000008
#define DIPS_6  0x00000004
#define DIPS_7  0x00000002
#define DIPS_8  0x00000001

// LCD Display strings
#define INIT_LCD1   "Design by FPGA"
#define INIT_LCD2   "   Developer.com"
#define WELCOME_LCD1  "Aurora to"
#define WELCOME_LCD2  " Ethernet Bridge"

// Masks to the pins on the GPIO port
#define LCD_DB4    0x01
#define LCD_DB5    0x02
#define LCD_DB6    0x04
#define LCD_DB7    0x08
#define LCD_RW     0x10
#define LCD_RS     0x20
#define LCD_E      0x40
#define LCD_TEST   0x80

// Global variables

// Pointer and base address of Bridge peripheral
Xuint32 *bridge_0_baseaddr_p = (Xuint32 *) XPAR_BRIDGE_0_BASEADDR;
Xuint32 bridge_0_baseaddr;

// LCD GPIO peripheral
XGpio LCD;

// LCD Control Function prototypes
void writeLCD(Xuint8 *str1, Xuint8 *str2);
void delay(Xuint32 period);
void gpio_write(Xuint32 c);
Xuint32 gpio_read(void);
void lcd_clk(void);
void lcd_set_test(void);
void lcd_reset_test(void);
void lcd_set_rs(void);
void lcd_reset_rs(void);
void lcd_set_rw(void);
void lcd_reset_rw(void);
void lcd_write(Xuint32 c);
void lcd_clear(void);
void lcd_puts(const char * s);
void lcd_putch(Xuint32 c);
void lcd_goto(Xuint32 line,Xuint32 pos);
void lcd_init(void);

// Loopback mode function prototypes
void enable_loopback(void);
void disable_loopback(void);

// ------------------------------------------------------------------
// Main function
// ------------------------------------------------------------------

int main (void)
{
  XGpio DIPs;
  XStatus status;
  Xuint32 value;
  Xuint32 oldvalue;

  // Check the peripheral pointers
  XASSERT_NONVOID(bridge_0_baseaddr_p != XNULL);
  bridge_0_baseaddr = (Xuint32) bridge_0_baseaddr_p;

  // Initialize the GPIO driver for the DIP switches
  status = XGpio_Initialize(&DIPs,XPAR_DIP_SWITCHES_8BIT_DEVICE_ID);
  if (status != XST_SUCCESS)
    return XST_FAILURE;
  // Set the direction for all signals to be inputs
  XGpio_SetDataDirection(&DIPs, 1, 0xFFFFFFFF);
  // Read the initial state of the DIP switches
  value = XGpio_DiscreteRead(&DIPs,1);
  // Enable loopback if set by DIP switches
  if(value & DIPS_1)
    enable_loopback();
  else
    disable_loopback();

  // Initialize the GPIO driver for the LCD
  status = XGpio_Initialize(&LCD,XPAR_LCD_DEVICE_ID);
  if (status != XST_SUCCESS)
    return XST_FAILURE;
  // Set the direction for all signals to be outputs
  XGpio_SetDataDirection(&LCD, 1, 0x00);

  // Initialize the LCD
  lcd_init();
  writeLCD(INIT_LCD1,INIT_LCD2);
  delay(12500000);
  writeLCD(WELCOME_LCD1,WELCOME_LCD2);

  while(1){
    // Record the old DIP settings
    oldvalue = value;
    // Read the new DIP settings
    value = XGpio_DiscreteRead(&DIPs,1);
    // If DIP settings have changed, then change loopback mode
    if(value != oldvalue){
      // Enable loopback if set by DIP switches
      if(value & DIPS_1)
        enable_loopback();
      else
        disable_loopback();
    }
  }
}

// LCD Control Functions

void writeLCD(Xuint8 *str1, Xuint8 *str2)
{
  lcd_clear();
  lcd_puts(str1);
  lcd_goto(1,0);
  lcd_puts(str2);
}

// Simple delay function
// Very approximately 1 period = 80ns
void delay(Xuint32 period)
{
  volatile Xuint32 i;
  for(i = 0; i < period; i++){} } // Write to GPIO outputs void gpio_write(Xuint32 c) {   // Write to the GP IOs   XGpio_DiscreteWrite(&LCD, 1, c & 0x0FF); } // Read the GPIO outputs Xuint32 gpio_read() {   // Read from the GP IOs   return(XGpio_DiscreteRead(&LCD, 1)); } // Clock the LCD (toggles E) void lcd_clk() {   Xuint32 c;   // Get existing outputs   c = gpio_read();   delay(10);   // Assert clock signal   gpio_write(c | LCD_E);   delay(10);   // Deassert the clock signal   gpio_write(c & (~LCD_E));   delay(10); } // Assert the RS signal void lcd_set_rs() {   Xuint32 c;   // Get existing outputs   c = gpio_read();   // Assert RS   gpio_write(c | LCD_RS);   delay(10); } // Deassert the RS signal void lcd_reset_rs() {   Xuint32 c;   // Get existing outputs   c = gpio_read();   // Assert RS   gpio_write(c & (~LCD_RS));   delay(10); } // Assert the RW signal void lcd_set_rw() {   Xuint32 c;   // Get existing outputs   c = gpio_read();   // Assert RS   gpio_write(c | LCD_RW);   delay(10); } // Deassert the RW signal void lcd_reset_rw() {   Xuint32 c;   // Get existing outputs   c = gpio_read();   // Assert RS   gpio_write(c & (~LCD_RW));   delay(10); } // Write a byte to LCD (4 bit mode) void lcd_write(Xuint32 c) {   Xuint32 temp;   // Get existing outputs   temp = gpio_read();   temp = temp & 0xF0;   // Set the high nibble   temp = temp | ((c >> 4) & 0x0F);
  gpio_write(temp);
  // Clock
  lcd_clk();
  // Delay for "Write data into internal RAM 43us"
  delay(2500);
  // Set the low nibble
  temp = temp & 0xF0;
  temp = temp | (c & 0x0F);
  gpio_write(temp);
  // Clock
  lcd_clk();
  // Delay for "Write data into internal RAM 43us"
  delay(2500);
}

// Clear LCD
void lcd_clear(void)
{
  lcd_reset_rs();
  // Clear LCD
  lcd_write(0x01);
  // Delay for "Clear display 1.53ms"
  delay(125000);
}

// Write a string to the LCD
void lcd_puts(const char * s)
{
  lcd_set_rs();
  while(*s)
    lcd_write(*s++);
}

// Write character to the LCD
void lcd_putch(Xuint32 c)
{
  lcd_set_rs();
  lcd_write(c);
}

// Change cursor position
// (line = 0 or 1, pos = 0 to 15)
void lcd_goto(Xuint32 line, Xuint32 pos)
{
  lcd_reset_rs();
  pos = pos & 0x3F;
  if(line == 0)
    lcd_write(0x80 | pos);
  else
    lcd_write(0xC0 | pos);
}

// Initialize the LCD
void lcd_init(void)
{
  Xuint32 temp;

  // Write mode (always)
  lcd_reset_rw();
  // Write control bytes
  lcd_reset_rs();

  // Delay 15ms
  delay(200000);

  // Initialize
  temp = gpio_read();
  temp = temp | LCD_DB5;
  gpio_write(temp);
  lcd_clk();
  lcd_clk();
  lcd_clk();

  // Delay 15ms
  delay(200000);

  // Function Set: 4 bit mode, 1/16 duty, 5x8 font, 2 lines
  lcd_write(0x28);
  // Display ON/OFF Control: ON
  lcd_write(0x0C);
  // Entry Mode Set: Increment (cursor moves forward)
  lcd_write(0x06);

  // Clear the display
  lcd_clear();
}

// Enable loopback mode
void enable_loopback(void)
{
  BRIDGE_mWriteSlaveReg0(bridge_0_baseaddr,0,1);
}

// Disable loopback mode
void disable_loopback(void)
{
  BRIDGE_mWriteSlaveReg0(bridge_0_baseaddr,0,0);
}

 

Download Project to your Board

Follow these steps to compile the project and program the FPGA.

  1. Turn on the ML505 board.
  2. From the XPS software, select “Device Configuration->Download Bitstream”.

EDK will now compile the project and when finished it will program the FPGA. When completed, the LCD output should display the message “Aurora to Ethernet Bridge”. When you get this message, you can continue with the following tests.

Test the Bridge in Loopback Mode

  1. To perform this test you only need one ML505 board, one PC and one CAT5 Ethernet cable.
  2. Locate the DIP switches (SW8) in the corner of the ML505 board, next to the LCD. Turn switch 1 to the ON position to enable loopback mode.
  3. Ensure that LEDs 0, 1 and 2 are ON. These LEDs can be found below the LCD and are numbered 0, 1 and 2. These LEDs correspond to EMAC_READY, LANE_UP and CHANNEL_UP respectively.
  4. Open Wireshark on the PC to be used for testing. You can use any PC with a Gigabit Ethernet network card installed and working.
  5. 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”.
     
  6. 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”.
     
  7. Connect the CAT5 Ethernet cable between the ML505 and the PC running Wireshark.
  8. 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. 
  9. 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.
     
  10. Observe that when you run the ping command, the RX and TX LEDs on the ML505 will light up at the same time, indicating that each frame received is looped back and transmitted to the PC.
  11. 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. Notice also the short time delay of 240us between the sent packet and the received copy.
     
  12. If you like, you can set switch 1 of the DIP switches to OFF to disable the loopback function and try running ping again. You should see this time that only three new Ethernet frames appear. You should also notice that only the EMAC RX LED lights up.

 

Test the Bridge between Two PCs

  1. To perform this test you will need two (2) ML505 boards, two (2) PCs with Gigabit Ethernet connections, two (2) CAT5 Ethernet cables and one (1) crossover SATA cable.
  2. On BOTH ML505 boards, locate the DIP switches (SW8) in the corner of the ML505 board, next to the LCD. Turn switch 1 to the OFF position to DISABLE loopback mode.
  3. Connect a crossover SATA cable from one ML505 board’s “SATA HOST 1″ connector to the other ML505 board’s “SATA HOST 1″ connector.
  4. Connect CAT5 Ethernet cables from each ML505 board to each PC.
  5. The connections should be as shown in the diagram below:
     
  6. Turn ON both ML505 boards and download the bit files to each board. Ensure that both boards are running and displaying the message “Aurora to Ethernet Bridge” message on their LCDs. The LEDs 0, 1 and 2 should also be ON.
  7. Turn on both PCs.
  8. From one PC, use Windows Explorer to locate a folder on the hard drive that you would like to access from the other PC. Right click on that folder and click “Sharing and Security”. For our example, we will assume the folder name is “fpgadeveloper”.
  9. From the “Properties” dialog box, tick “Share this folder” and click “OK”.
  10. From Windows, select “Start->Run” and type “cmd”. Press “Enter” and you should have a command prompt. From the command line, type “ipconfig” to get the IP address of the current PC. Record the IP address of the PC. For our example, we will assume the IP address is 123.456.789.012
  11. Now go to the OTHER PC, open Windows Explorer and type in the “Address” field the following line without the quotation marks: “//123.456.789.012/fpgadeveloper”
  12. Obviously you should replace the IP address and folder name with the ones you have used. You should see the folder contents appear in Windows Explorer.
  13. Click on one of the files to access it. You should see that the EMAC RX/TX LEDs will be lighting up as Ethernet packets flow through both Bridges.

You can experiment with this setup by doing other things such as video streaming from one PC to another, or you can replace one of the PCs with a router to connect you to a network. Let me know if you find any interesting uses.

If you have problems setting up file sharing with your computers, there are plenty of resources on the internet that you could try. Make sure to check that the problem is really the file sharing by connecting the two computers directly through a single Ethernet cable.

You now have a working Aurora to Ethernet Bridge running at 1Gbps. To develop the project further, try this idea:

  • Assign the Aurora GTP to the SFP connector (rather than the SATA connector), buy yourself an SFP Optical Transceiver and communicate with another board over an optical fiber. The benefit of this is distance, with some SFP optical transceivers you can communicate over kilometers of fiber!

 

Download the Project Folder

If you had problems with this tutorial, you can download the Aurora to Ethernet Bridge project folder for EDK version 10.1.03. Click on the link below corresponding to the project files for your ML50x board.

Board Virtex-5 Version Project files
ML505 XC5VLX50T AEBridge-ML505-EDK10-1.zip
ML506 XC5VSX50T AEBridge-ML506-EDK10-1.zip
XUPV5 XC5VLX110T AEBridge-XUPV5-EDK10-1.zip

 

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.

Overview
In this tutorial we will create a peripheral containing the Aurora core to implement a high speed serial transceiver with a RocketIO MGT. It will be an improved version of the Aurora transceiver developed in the tutorial titled Create an Aurora Transceiver. The improvement is achieved by connecting the peripheral to the PLB rather than the OPB, which allows much faster data transfer by virtue of a wider bus and Direct Memory Access capability.

To test the design, we will instantiate two Aurora peripherals, assign them to different RocketIO MGTs and place a SATA cable between them to create a loop-back connection. The PowerPC will transfer data between the two Aurora peripherals simply by reading and writing to the read and write FIFOs. To test the design, the test application will write data to the write FIFO of the first Aurora peripheral and read it back from the read FIFO of the second Aurora peripheral. To take advantage of the full PLB bandwidth, the PowerPC will read and write to the FIFOs using DMA transfers. The Aurora peripheral will also have outputs indicating the status of the link. These outputs will be connected to the LEDs on the XUPV2P board.

Figure: The Aurora peripheral

The diagram above illustrates the design of the Aurora peripheral. It uses a read and write FIFO to transfer data between the PowerPC and the user logic. It also uses a second pair of FIFOs called the RX and TX FIFOs. The RX and TX FIFOs create a buffered link between the read/write FIFOs and the Aurora core. This buffered link is necessary because the PLB clock and the RocketIO clock are independent on the XUPV2P board. The PLB clocks data in and out of the read/write FIFOs at 100MHz while the user logic clocks data in and out of the Aurora core at 75MHz. For this reason, we use RX and TX FIFOs with independent read and write clock inputs.

The TX and RX FIFOs are connected to the Aurora core through a multiplexer and demultiplexer respectively. The FIFOs have a width of 64 bits to utilize the complete PLB data width. We will generate an Aurora core with a 16 bit wide interface because the MGTs are optimized for a width of 2 words, that is 16 bits if we are using 8B/10B encoding. The MUX and DEMUX are needed to connect the 64 bit FIFO interface to the 16 bit Aurora core interface. The MUX converts each 64 bit entry from the TX FIFO into groups of 16 bits spread over 4 clock cycles. The DEMUX buffers 4 x 16 bit words from the Aurora core into one 64 bit entry to the RX FIFO. This configuration allows us to make full use of the PLB bandwidth.

As in the MGT Oscillator project, we will also create a Digital Clock Manager (DCM) peripheral for the RocketIO MGTs. The DCM peripheral will only contain two clock buffers and will not require registers or FIFOs.

This tutorial starts the user from scratch, assuming that the Aurora core license has been installed, and contains screenshots to guide the user through the entire implementation process. You can click on the images to view a higher resolution when necessary.

Requirements
Apart from the obvious requirements (XPS software and XUPV2P board) this project requires the following:

  1. SATA cable: If you are using the XUPV2P board, a SATA cable is necessary to be able to verify this design. If you do not have a SATA cable, you can buy one from most computer/electronics stores or from Digikey (part number 3M5568-ND). If you are not using the XUPV2P board, you must have a way to physically connect two MGTs.
  2. CORE Generator: Both the Aurora core and the TX/RX FIFOs will be created with the CORE Generator. Before beginning this tutorial, you will need to register with Xilinx to obtain a license to use the Aurora core. It is a free and simple process that involves accepting the license agreement after which you are emailed a license with instructions on unlocking the Aurora core in your CORE Generator. To start your registration, follow this link:http://www.xilinx.com/aurora/register_aurora.htm

Create the Basic Project
Follow these steps to create the basic project:

  1. Open XPS and from the dialog box, select “Base System Builder wizard” and OK.
  2. Create a new folder for the project and select it using “Browse”. In “Advanced Options” tick “Use repository paths” and select the “C:\XUPV2P\lib” folder using “Browse”. Click “OK”.
  3. Tick “I would like to create a new design” and click “Next”.
  4. Select “Xilinx” as the board vendor. Select “XUP Virtex II Pro Development System” as the board name. Select “C” as the board revision. Click “Next”.
  5. Tick “PowerPC” and click “Next”.
  6. Select all clock frequencies to be 100MHz. Select “No debug”. Click “Next”.
  7. In selecting the Additional IO Interfaces, tick “onewire_0″ and “RS232_Uart_1″. Untick everything else. We will not actually use the “onewire_0″ interface in this project, but leaving it in has shown to be important. For an explanation, refer to “The Onewire Problem” on the Known Issues page.
  8. When Adding Internal Peripherals, select 64KB for the “plb_bram_if_cntlr_1″ and click “Next”.
  9. Select “RS232_Uart_1″ for both STDIN and STDOUT. Un-tick “Memory Test” and leave “Peripheral Test” ticked. Click “Next”.
  10. On the “Configure Peripheral Test Application” page, select “plb_bram_if_cntlr_1″ for the Instruction, Data, Stack and Heap memories. Click “Next”.
  11. Click “Generate”.
  12. Click “Finish”.
  13. Tick “Start using Platform Studio” and click “OK”.

Create the DCM Peripheral
Follow these steps to create the DCM peripheral:

  1. Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
  2. Select “Create templates for a new peripheral” and click “Next”.
  3. Select “To an XPS project” and click “Next”.
  4. Type “mgt_dcm” for the peripheral name. Click “Next”.
  5. Select “On-chip Peripheral Bus” (OPB) and click “Next”.
  6. The DCM peripheral is very simple and doesn’t need interrupts, registers or FIFOs. Un-tick everything and click “Next”.
  7. On the “IP Interconnect” page, leave everything as is. Click “Next”.
  8. On the “Peripheral Simulation Support” page, 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.

Modify the DCM Peripheral
Now we will add code in our peripheral template to instantiate two clock buffers that will generate the clock sources REF_CLK and USER_CLK for the RocketIO MGTs. This DCM example originates from the Xilinx RocketIO Transceiver User Guide (ug024), see section “Digital Clock Manager (DCM) Examples”.

  1. Select from the menu “File->Open” and from the project folder, browse to “pcores\mgt_dcm_v1_00_a\hdl\vhdl”.
  2. Open the file “mgt_dcm.vhd”.
  3. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK_P : in std_logic;
  TOP_BREF_CLK_N : in std_logic;
  TOP_BREF_CLK   : out std_logic;
  USER_CLK       : 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.
  TOP_BREF_CLK_P => TOP_BREF_CLK_P,
  TOP_BREF_CLK_N => TOP_BREF_CLK_N,
  TOP_BREF_CLK => TOP_BREF_CLK,
  USER_CLK => USER_CLK,
  1. Save and close the file.
  2. Select from the menu “File->Open” and from the project folder, browse to “pcores\mgt_dcm_v1_00_a\hdl\vhdl”.
  3. Open the file “user_logic.vhd”.
  4. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK_P : in std_logic;
  TOP_BREF_CLK_N : in std_logic;
  TOP_BREF_CLK   : out std_logic;
  USER_CLK       : 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 IBUFGDS_LVDS_25
  port(
    O  : out std_ulogic;
    I  : in  std_ulogic;
    IB : in  std_ulogic
  );
end component;

component BUFG
  port(
    O : out std_ulogic;
    I : in  std_ulogic
  );
end component;

signal top_bref_clk_i : std_logic;
signal user_clk_i  : std_logic;
  1. Find the line of code that says “–USER logic implementation added here” and add the following lines of code just below.
-- Differential Clock Buffer for top BREF_CLK
diff_clk_buff_top_i : IBUFGDS_LVDS_25
  port map(
    I  => TOP_BREF_CLK_P,
    IB => TOP_BREF_CLK_N,
    O  => top_bref_clk_i
  );

-- BUFG used to drive USER_CLK on global clock net
user_clock_bufg_i : BUFG
  port map(
    I => top_bref_clk_i,
    O => user_clk_i
  );

TOP_BREF_CLK <= top_bref_clk_i;
USER_CLK <= user_clk_i;
  1. Save and close the file.

Import the DCM Peripheral
Now we will use the Peripheral Wizard to import the DCM peripheral.

  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 “mgt_dcm”. 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\mgt_dcm_v1_00_a\data” and select the “mgt_dcm_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 “OPB Slave” and click “Next”.
  9. On the SOPB: Port page, click “Next”.
  10. On the SOPB: Parameter page, click “Next”.
  11. On the “Identify Interrupt Signals” page, un-tick “Select and configure interrupt(s)” and click “Next”.
  12. On the “Parameter Attributes” page, click “Next”.
  13. On the “Port Attributes” page, click “Next”.
  14. Click “Finish”.

The DCM peripheral should now be accessible through the “IP Catalog->Project Repository” in the XPS interface.

Create an Instance of the DCM Peripheral
Follow these steps to create an instance of the peripheral in the project.

  1. From the “IP Catalog” find the “mgt_dcm” IP core in the “Project Repository” group. Right click on the core and select “Add IP”.
  2. From the “System Assembly View” using the “Bus Interface” filter, connect the “mgt_dcm_0″ to the OPB bus.
  3. Click on the “Ports” filter. Click on the “+” for “mgt_dcm_0″ to view its ports.
  4. Click on the “Net” field for the “TOP_BREF_CLK_P” port. Type “TOP_BREF_CLK_P” 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 “TOP_BREF_CLK_N” port. Type “TOP_BREF_CLK_N” 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 “TOP_BREF_CLK” port. Type “TOP_BREF_CLK” in this field and press “Enter”.
  7. Click on the “Net” field for the “USER_CLK” port. Type “USER_CLK” in this field and press “Enter”. The result should look like the image below.
  8. Now if you click the “+” for “External Ports”, you should be able to find the two ports “TOP_BREF_CLK_P_pin” and “TOP_BREF_CLK_N_pin”, with nets called “TOP_BREF_CLK_P” and “TOP_BREF_CLK_N” respectively.
  9. Click on the “Addresses” filter. Change the “Size” for “mgt_dcm_0″ to 64K. Then click “Generate Addresses”.

Now we have an instance of the DCM peripheral in the project. The single DCM peripheral will supply the reference clock to all the MGTs accessible on the XUPV2P board.

Create the Aurora Peripheral
Now we will start the creation of the Aurora peripheral by using the Peripheral Wizard. The Wizard will create a template for us with the read and write FIFOs fully implemented. We will then modify the template to include the Aurora core and RX/TX FIFOs. Follow these steps to create the Aurora peripheral.

  1. Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
  2. Select “Create templates for a new peripheral” and click “Next”.
  3. Select “To an XPS project” and click “Next”.
  4. Type “aurora_plb” for the peripheral name. Click “Next”.
  5. Select “Processor Local Bus” (PLB) and click “Next”.
  6. On the “IPIF Services” page, tick “Burst transaction support”, “FIFO” and “DMA”. Un-tick everything else and click “Next”.
  7. For the FIFO Service settings, leave the defaults ticked: Include read FIFO, Include write FIFO, Use packet mode, Use vacancy calculation. Choose 64-bits for the width of the FIFOs, and choose a depth of 512.
  8. On the “IP Interconnect” page leave everything as is. Click “Next”.
  9. On the “Peripheral Simulation Support” page, click “Next” without ticking the option to generate.
  10. After the “Peripheral Implementation Support” page, tick “Generate ISE and XST project files” and “Generate template driver files”. Click “Next”.
  11. Click “Finish”. Now our templates are created.

Now the template is created, we now need to use CORE Generator to create our RX/TX FIFOs and the Aurora core.

Create the FIFO Component in CORE Generator
The read and write FIFOs of our Aurora peripheral were created by the Peripheral Wizard and they are ready for us to use in the user_logic.vhd file. The TX and RX FIFOs however must be created by us and placed into the user_logic.vhd file manually. Fortunately, the CORE Generator provides a good FIFO component that suits our needs. Follow these steps to create the FIFO component that we will use to implement the TX and RX FIFOs.

  1. Run the Xilinx CORE Generator. Note that you do not have to close the XPS software.
  2. Select “File->New Project”.
  3. Click “Browse” and select an appropriate location for a Coregen project. Within a Coregen project, you can create several cores that don’t necessarily relate to each other. Just select the folder where you normally place your projects, and leave the project name as “coregen”. Click “OK”.
  4. CORE Generator will ask you if you want to create the “coregen” folder. Click “OK”.
  5. You will be asked for the specifications of the FPGA you are using. Under the “Part” tab, select these options: Family “Virtex2P”, Device “xc2vp30″, Package “ff896″, Speed grade “-7″. Click “OK”.
  6. When you have created your Coregen project, click on the “View by Function” tab to get a list of cores that you are able to generate.
  7. Open “Memories and Storage Elements->FIFOs” and double-click on “FIFO Generator 3.2″.
  8. A dialog box should open to allow you to select the features of the FIFO you want. On the first page we select the read and write clock setting. We want asynchronous clocks so we must select “Independent Clocks” using memory type “Block RAM”. Click “Next”.
  9. On the second page, we want to select “Standard FIFO” with a “Write width” of 64, a “Write depth” of 512 and a “Read width” of 64. Click “Next”.
  10. On the third page, tick “Almost Full Flag”, “Valid Flag” and “Reset Pin”. Click “Finish”. Pages 4, 5 and 6 do not contain any features that we desire.
  11. Now use Windows Explorer to browse the “coregen” folder just created. You will find the generated files. One of those files is a netlist file called “fifo_generator_v3_2_fifo_generator_v3_2_xst_1.ngc”. Rename the file to “fifo_generator_v3_2.ngc”. This is the file that we will use in our Aurora peripheral to implement the TX and RX FIFOs.

You can leave the CORE Generator open, because in the next section we will use it again to generate the Aurora core. The FIFO will now be listed under the tab “Generated IP”.

Create the Aurora core in CORE Generator
Once you have a license to use the Aurora core and you have gone through the instructions provided by Xilinx, you should be able to use the CORE Generator to produce an Aurora core. The CORE Generator can generate VHDL code for the Aurora core with many variations as you will see in the creation wizard. Follow these steps to create an Aurora core:

  1. Run the Xilinx CORE Generator if it is not already open.
  2. We will create the Aurora core in the Coregen project that we created for the FIFO component. If you have not left the Coregen project open from the previous section, click “File->Open Project” and browse to the “coregen” project folder that we just created for the FIFO. Select the “coregen.cgp” file and click “Open”.
  3. From the “View by Function” tab, open “Communication and Networking->Serial Interfaces” and double-click on the “Aurora” IP. If you have not registered for a license to use the Aurora core, you will be given a message saying that you do not have permission to generate the core. If you have registered, received and installed the license, you may be given this message: “License for component allows you to use this component, but does not give you access to source code implementing this component”. You can ignore this message as the CORE Generator will in fact give you source code. A dialog box will open that you will use to select the features of the Aurora core.
  4. Specify the number of “Aurora Lanes” to be 1, “Bytes per Lane” to be 2, and “Interface” to Streaming. Leave “Special Features” un-ticked. Click “Next”.
  5. On the second page we select the reference clock and the MGT we wish to use. The specific MGT to use is not so important because we will be able to change this in our .ucf file later. The row of the clock however is important because the XUPV2P board is wired to use the TOP row. Ignore the comment saying Row 0 is the bottom and Row 1 is the top. For “Row 0 Clock” select “BREF_CLK”. For “Row 1 Clock” select “none”. To select the MGT, put a “1″ in Row 0, Column 0, and place an “X” in all the other squares. Click “Finish”.
  6. The Aurora core will be generated and you will see it listed in the “Generated IP” tab.
  7. Close CORE Generator.

Exploring the Generated Files
Now if you explore the contents of the “coregen” project folder that CORE Generator created, you should find the files as shown below: The FIFO files of importance to us are the netlist (.ngc) file and the “fifo_generator_v3_2.vho” file. The latter file gives us an example of the FIFO component declaration and instantiation. We will use these examples in the “user_logic.vhd” of our Aurora peripheral code later.

In the “aurora_201″ folder you will find useful documentation and examples for using the Aurora core. The user guide for the Aurora core is the file called “ug061.pdf” and it is recommended that you read this file to better understand the work in this tutorial. Another interesting document is the Getting Started Guide in the file “aurora_gs_ug173.pdf”. This guide explains the example that was generated by the CORE Generator and how to simulate and implement it. In the “aurora_201\examples” folder, you will find the “aurora_sample.vhd” file which is the top-level of the example design. It is important to understand the example because in this tutorial, we will use the example code in our Aurora peripheral “user_logic.vhd” file.

Copy the Aurora core source files
We need to copy the Aurora core source files into the Aurora peripheral source folder. We just generated the source files for the Aurora core with CORE Generator and they should be found in the “coregen” project folder. The image below shows two explorer windows browsing the source code files.

  1. Open Windows Explorer and browse to the folder “coregen\aurora_201\src”. Copy all the files in that folder and paste them into the “pcores\aurora_plb_v1_00_a\hdl\vhdl” folder within your XPS project. You will be copying these files into the same folder as your “user_logic.vhd” file for the Aurora peripheral is contained.
  2. Now browse to the folder “coregen\aurora_201\cc_manager”. Copy the file “standard_cc_module.vhd” in that folder and paste it into the “pcores\aurora_plb_v1_00_a\hdl\vhdl” folder within your XPS project.
  3. Make sure that you have copied all the files listed below.
aurora_201.vhd
aurora_lane.vhd
aurora_pkg.vhd
channel_error_detect.vhd
channel_init_sm.vhd
chbond_count_dec.vhd
error_detect.vhd
global_logic.vhd
idle_and_ver_gen.vhd
lane_init_sm.vhd
phase_align.vhd
rx_stream.vhd
sym_dec.vhd
sym_gen.vhd
tx_stream.vhd
standard_cc_module.vhd

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 Aurora core 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\aurora_plb_v1_00_a\data” folder. Select the file “aurora_plb_v2_1_0.pao” and click “Open”.
  2. At the bottom of this file you will see these two lines:
lib aurora_plb_v1_00_a user_logic vhdl
lib aurora_plb_v1_00_a aurora_plb 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 aurora_plb_v1_00_a aurora_pkg vhdl
lib aurora_plb_v1_00_a channel_error_detect vhdl
lib aurora_plb_v1_00_a idle_and_ver_gen vhdl
lib aurora_plb_v1_00_a channel_init_sm vhdl
lib aurora_plb_v1_00_a error_detect vhdl
lib aurora_plb_v1_00_a sym_dec vhdl
lib aurora_plb_v1_00_a sym_gen vhdl
lib aurora_plb_v1_00_a chbond_count_dec vhdl
lib aurora_plb_v1_00_a lane_init_sm vhdl
lib aurora_plb_v1_00_a rx_stream vhdl
lib aurora_plb_v1_00_a tx_stream vhdl
lib aurora_plb_v1_00_a global_logic vhdl
lib aurora_plb_v1_00_a phase_align vhdl
lib aurora_plb_v1_00_a aurora_lane vhdl
lib aurora_plb_v1_00_a standard_cc_module vhdl
lib aurora_plb_v1_00_a aurora_201 vhdl
  1. Save the file.

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

Modify the Aurora Peripheral
Now we will add code to our peripheral template to instantiate an Aurora core and the TX and RX FIFOs. The TX and RX FIFOs will be wired to the write and read FIFOs such that data is automatically passed along when any of the FIFOs receives data. We will also include two state machines for multiplexing and demultiplexing the data between the TX/RX FIFOs and the Aurora core.

  1. Select from the menu “File->Open” and from the project folder, browse to “pcores\aurora_plb_v1_00_a\hdl\vhdl”.
  2. Open the file “aurora_plb.vhd”.
  3. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK      : in std_logic;
  USER_CLK          : in std_logic;
  HARD_ERROR        : out std_logic;
  SOFT_ERROR        : out std_logic;
  LANE_UP           : out std_logic;
  CHANNEL_UP        : out std_logic;
  RXP               : in std_logic;
  RXN               : in std_logic;
  TXP               : out std_logic;
  TXN               : 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.
  TOP_BREF_CLK => TOP_BREF_CLK,
  USER_CLK => USER_CLK,
  HARD_ERROR => HARD_ERROR,
  SOFT_ERROR => SOFT_ERROR,
  LANE_UP => LANE_UP,
  CHANNEL_UP => CHANNEL_UP,
  RXP => RXP,
  RXN => RXN,
  TXP => TXP,
  TXN => TXN,
  1. Save and close the file.
  2. Select from the menu “File->Open” and browse from the project folder to “pcores\aurora_plb_v1_00_a\hdl\vhdl”.
  3. Open the file “user_logic.vhd”. We will need to modify this source code to instantiate the Aurora core and TX/RX FIFOs.
  4. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK      : in std_logic;
  USER_CLK          : in std_logic;
  HARD_ERROR        : out std_logic;
  SOFT_ERROR        : out std_logic;
  LANE_UP           : out std_logic;
  CHANNEL_UP        : out std_logic;
  RXP               : in std_logic;
  RXN               : in std_logic;
  TXP               : out std_logic;
  TXN               : 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. You will recognize this code from the “aurora_sample.vhd” file.
  -- External Register Declarations --
  signal HARD_ERROR_Buffer  : std_logic;
  signal SOFT_ERROR_Buffer  : std_logic;
  signal LANE_UP_Buffer     : std_logic;
  signal CHANNEL_UP_Buffer  : std_logic;
  signal TXP_Buffer         : std_logic;
  signal TXN_Buffer         : std_logic;

  -- Wire Declarations --
  -- Stream TX Interface
  signal tx_d_i         : std_logic_vector(0 to 15);
  signal tx_src_rdy_n_i : std_logic;
  signal tx_dst_rdy_n_i : std_logic;

  -- Stream RX Interface
  signal rx_d_i         : std_logic_vector(0 to 15);
  signal rx_src_rdy_n_i : std_logic;

  -- Error Detection Interface
  signal hard_error_i   : std_logic;
  signal soft_error_i   : std_logic;

  -- Status
  signal channel_up_i   : std_logic;
  signal lane_up_i      : std_logic;

  -- Clock Compensation Control Interface
  signal warn_cc_i      : std_logic;
  signal do_cc_i        : std_logic;

  --TX & RX FIFO signals
  signal tx_fifo_empty : std_logic;
  signal rx_fifo_empty : std_logic;
  signal tx_fifo_we    : std_logic := '0';
  signal rx_fifo_we    : std_logic := '0';
  signal tx_fifo_re    : std_logic := '0';
  signal rx_fifo_re    : std_logic := '0';
  signal tx_fifo_valid : std_logic;
  signal rx_fifo_valid : std_logic;
  signal tx_fifo_almost_full : std_logic;
  signal rx_fifo_almost_full : std_logic;
  signal tx_fifo_dout  : std_logic_vector(63 downto 0);
  signal rx_fifo_dout  : std_logic_vector(63 downto 0);
  signal tx_fifo_din   : std_logic_vector(63 downto 0);
  signal rx_fifo_din   : std_logic_vector(63 downto 0);

  -- State type for MUX and DEMUX state machines
  type STATE_TYPE is (
    IDLE,WAITDATA,WORD0,WORD1,WORD2,WORD3);

  -- MUX state machine signals
  signal mux_c_state        : STATE_TYPE;
  signal mux_n_state        : STATE_TYPE;
  signal mux_din            : std_logic_vector(63 downto 0);
  signal mux_din_buf        : std_logic_vector(63 downto 0);
  signal mux_din_buf_cmb    : std_logic_vector(63 downto 0);
  signal mux_we             : std_logic;
  signal mux_wrreq          : std_logic;
  signal mux_dout           : std_logic_vector(15 downto 0);
  signal mux_dout_cmb       : std_logic_vector(15 downto 0);
  signal mux_dout_valid     : std_logic;
  signal mux_dout_valid_cmb : std_logic;
  signal mux_rdreq          : std_logic;
  signal mux_rdreq_cmb      : std_logic;

  -- DEMUX state machine signals
  signal demux_c_state   : STATE_TYPE;
  signal demux_n_state   : STATE_TYPE;
  signal demux_we        : std_logic;
  signal demux_din       : std_logic_vector(15 downto 0);
  signal demux_dout      : std_logic_vector(63 downto 0);
  signal demux_dout_cmb  : std_logic_vector(63 downto 0);
  signal demux_valid     : std_logic;
  signal demux_valid_cmb : std_logic;

  -- Component Declarations --

  component aurora_201
    generic (
      EXTEND_WATCHDOGS   : boolean := FALSE
    );
    port (
      -- LocalLink TX Interface
        TX_D           : in std_logic_vector(0 to 15);
        TX_SRC_RDY_N   : in std_logic;
        TX_DST_RDY_N   : out std_logic;
      -- LocalLink RX Interface
        RX_D           : out std_logic_vector(0 to 15);
        RX_SRC_RDY_N   : out std_logic;
      -- MGT Serial I/O
        RXP            : in std_logic;
        RXN            : in std_logic;
        TXP            : out std_logic;
        TXN            : out std_logic;
      -- MGT Reference Clock Interface
        TOP_BREF_CLK   : in std_logic;
      -- Error Detection Interface
        HARD_ERROR     : out std_logic;
        SOFT_ERROR     : out std_logic;
      -- Status
        CHANNEL_UP     : out std_logic;
        LANE_UP        : out std_logic;
      -- Clock Compensation Control Interface
        WARN_CC        : in std_logic;
        DO_CC          : in std_logic;
      -- System Interface
        DCM_NOT_LOCKED : in std_logic;
        USER_CLK       : in std_logic;
        RESET          : in std_logic;
        POWER_DOWN     : in std_logic;
        LOOPBACK       : in std_logic_vector(1 downto 0)
      );
  end component;

  component STANDARD_CC_MODULE
    port (
      -- Clock Compensation Control Interface
        WARN_CC        : out std_logic;
        DO_CC          : out std_logic;
      -- System Interface
        DCM_NOT_LOCKED : in std_logic;
        USER_CLK       : in std_logic;
        CHANNEL_UP     : in std_logic
      );
  end component;

  -- FIFO component from CORE Generator
  component fifo_generator_v3_2
    port (
      din         : IN std_logic_VECTOR(63 downto 0);
      rd_clk      : IN std_logic;
      rd_en       : IN std_logic;
      rst         : IN std_logic;
      wr_clk      : IN std_logic;
      wr_en       : IN std_logic;
      almost_full : OUT std_logic;
      dout        : OUT std_logic_VECTOR(63 downto 0);
      empty       : OUT std_logic;
      full        : OUT std_logic;
      valid       : OUT std_logic
    );
  end component;
  1. Find the line of code that says “–USER logic implementation added here” and add the following lines of code just below.
  HARD_ERROR  <= HARD_ERROR_Buffer;
  SOFT_ERROR  <= SOFT_ERROR_Buffer;
  LANE_UP     <= LANE_UP_Buffer;
  CHANNEL_UP  <= CHANNEL_UP_Buffer;
  TXP         <= TXP_Buffer;
  TXN         <= TXN_Buffer;

  -- Register User I/O --
  -- Register User Outputs from core.
  process (USER_CLK)
  begin
    if (USER_CLK 'event and USER_CLK = '1') then
      HARD_ERROR_Buffer  <= hard_error_i;
      SOFT_ERROR_Buffer  <= soft_error_i;
      LANE_UP_Buffer     <= lane_up_i;
      CHANNEL_UP_Buffer  <= channel_up_i;
    end if;
  end process;

  -- Aurora core instantiation
  aurora_module_i : aurora_201
    port map (
      -- LocalLink TX Interface
        TX_D           => tx_d_i,
        TX_SRC_RDY_N   => tx_src_rdy_n_i,
        TX_DST_RDY_N   => tx_dst_rdy_n_i,
      -- LocalLink RX Interface
        RX_D           => rx_d_i,
        RX_SRC_RDY_N   => rx_src_rdy_n_i,
      -- MGT Serial I/O
        RXP            => RXP,
        RXN            => RXN,
        TXP            => TXP_Buffer,
        TXN            => TXN_Buffer,
      -- MGT Reference Clock Interface
        TOP_BREF_CLK   => TOP_BREF_CLK,
      -- Error Detection Interface
        HARD_ERROR     => hard_error_i,
        SOFT_ERROR     => soft_error_i,
      -- Status
        CHANNEL_UP     => channel_up_i,
        LANE_UP        => lane_up_i,
      -- Clock Compensation Control Interface
        WARN_CC        => warn_cc_i,
        DO_CC          => do_cc_i,
      -- System Interface
        DCM_NOT_LOCKED => '0',
        USER_CLK       => USER_CLK,
        RESET          => Bus2IP_Reset,
        POWER_DOWN     => '0',
        LOOPBACK       => "00"
      );

  standard_cc_module_i : STANDARD_CC_MODULE
    port map (
      -- Clock Compensation Control Interface
        WARN_CC        => warn_cc_i,
        DO_CC          => do_cc_i,
      -- System Interface
        DCM_NOT_LOCKED => '0',
        USER_CLK       => USER_CLK,
        CHANNEL_UP     => channel_up_i
      );

  -----------------------------------------
  -- FIFOs:
  --  Write FIFO -> TX FIFO -> Aurora TX
  --  Read FIFO <- RX FIFO <- Aurora RX
  --
  -- Write FIFO: Single CLK: Bus2IP_Clk
  -- Read FIFO:  Single CLK: Bus2IP_Clk
  -- TX FIFO:    In CLK: Bus2IP_Clk, Out CLK: USER_CLK
  -- RX FIFO:    In CLK: USER_CLK, Out CLK: Bus2IP_Clk
  --
  tx_fifo_i : fifo_generator_v3_2
    port map (
      din => tx_fifo_din,
      rd_clk => USER_CLK,
      rd_en => tx_fifo_re,
      rst => Bus2IP_Reset,
      wr_clk => Bus2IP_Clk,
      wr_en => tx_fifo_we,
      almost_full => tx_fifo_almost_full,
      dout => tx_fifo_dout,
      empty => tx_fifo_empty,
      full => open,
      valid => tx_fifo_valid);

  rx_fifo_i : fifo_generator_v3_2
    port map (
      din => rx_fifo_din,
      rd_clk => Bus2IP_Clk,
      rd_en => rx_fifo_re,
      rst => Bus2IP_Reset,
      wr_clk => USER_CLK,
      wr_en => rx_fifo_we,
      almost_full => rx_fifo_almost_full,
      dout => rx_fifo_dout,
      empty => rx_fifo_empty,
      full => open,
      valid => rx_fifo_valid);

  ----------------------------------------------------
  -- MUX state machine
  MUX_SM_COMB : process (mux_wrreq, mux_we, mux_c_state) is
  begin
    -- set defaults
    mux_rdreq_cmb <= '0';
    mux_din_buf_cmb <= mux_din_buf;
    mux_dout_cmb <= (others => '0');
    mux_dout_valid_cmb <= '0';
    mux_n_state <= mux_c_state;

    case mux_c_state is
      -- Idle state - waiting for data in tx_fifo
      when IDLE =>
        if mux_wrreq = '1' then
          mux_rdreq_cmb <= '1';
          mux_n_state <= WAITDATA;
        end if;
      -- WAITDATA state - wait a clock cycle
      when WAITDATA =>
        mux_n_state <= WORD0;
      -- WORD0 state - transfer the first word
      when WORD0 =>
        if mux_we = '1' then
          mux_din_buf_cmb <= mux_din;
          mux_dout_cmb <= mux_din(63 downto 48);
          mux_dout_valid_cmb <= '1';
          mux_n_state <= WORD1;
        else
          mux_n_state <= IDLE;
        end if;
      -- WORD1 state - transfer the second word
      when WORD1 =>
        mux_dout_cmb <= mux_din_buf(47 downto 32);
        mux_dout_valid_cmb <= '1';
        mux_n_state <= WORD2;
      -- WORD2 state - transfer the third word
      when WORD2 =>
        mux_dout_cmb <= mux_din_buf(31 downto 16);
        mux_dout_valid_cmb <= '1';
        if mux_wrreq = '1' then
          mux_rdreq_cmb <= '1';
        end if;
        mux_n_state <= WORD3;
      -- WORD3 state - transfer the fourth word
      when WORD3 =>
        mux_dout_cmb <= mux_din_buf(15 downto 0);
        mux_dout_valid_cmb <= '1';
        if mux_rdreq = '1' then
          mux_n_state <= WORD0;
        else
          mux_n_state <= IDLE;
        end if;
      when others =>
        mux_n_state <= IDLE;
    end case;
  end process MUX_SM_COMB;

  -- MUX state controller
  MUX_SM_SEQ : process (USER_CLK) is
  begin
    if USER_CLK'event and USER_CLK = '1' then
      if Bus2IP_Reset = '1' then
        mux_rdreq <= '0';
        mux_din_buf <= (others => '0');
        mux_dout <= (others => '0');
        mux_dout_valid <= '0';
        mux_c_state <= IDLE;
      else
        mux_rdreq <= mux_rdreq_cmb;
        mux_din_buf <= mux_din_buf_cmb;
        mux_dout <= mux_dout_cmb;
        mux_dout_valid <= mux_dout_valid_cmb;
        mux_c_state <= mux_n_state;
      end if;
    end if;
  end process MUX_SM_SEQ;

  ----------------------------------------------------
  -- DEMUX state machine
  DEMUX_SM_COMB : process (demux_we, demux_c_state) is
  begin
    -- set defaults
    demux_valid_cmb <= '0';
    demux_dout_cmb <= demux_dout;
    demux_n_state <= demux_c_state;

    case demux_c_state is
      -- Idle state - waiting for data in tx_fifo
      when IDLE =>
        if demux_we = '1' then
      demux_dout_cmb(63 downto 48) <= demux_din;
          demux_n_state <= WORD1;
        end if;
      -- WORD1 state - copy the second word
      when WORD1 =>
        if demux_we = '1' then
      demux_dout_cmb(47 downto 32) <= demux_din;
          demux_n_state <= WORD2;
        else
      demux_dout_cmb(47 downto 0) <= (others => '0');
          demux_valid_cmb <= '1';
          demux_n_state <= IDLE;
        end if;
      -- WORD2 state - copy the third word
      when WORD2 =>
        if demux_we = '1' then
      demux_dout_cmb(31 downto 16) <= demux_din;
          demux_n_state <= WORD3;
        else
      demux_dout_cmb(31 downto 0) <= (others => '0');
          demux_valid_cmb <= '1';
          demux_n_state <= IDLE;
        end if;
      -- WORD3 state - copy the fourth word
      when WORD3 =>
        if demux_we = '1' then
      demux_dout_cmb(15 downto 0) <= demux_din;
        else
      demux_dout_cmb(15 downto 0) <= (others => '0');
        end if;
        demux_valid_cmb <= '1';
        demux_n_state <= IDLE;
      when others =>
        demux_n_state <= IDLE;
    end case;
  end process DEMUX_SM_COMB;

  -- DEMUX state controller
  DEMUX_SM_SEQ : process (USER_CLK) is
  begin
    if USER_CLK'event and USER_CLK = '1' then
      if Bus2IP_Reset = '1' then
        demux_valid <= '0';
        demux_dout <= (others => '0');
        demux_c_state <= IDLE;
      else
        demux_valid <= demux_valid_cmb;
        demux_dout <= demux_dout_cmb;
        demux_c_state <= demux_n_state;
      end if;
    end if;
  end process DEMUX_SM_SEQ;

  ----------------------------------------------------
  -- Connections between modules

  -- Connection between Write FIFO and TX FIFO
  tx_fifo_we <= WFIFO2IP_RdAck;
  tx_fifo_din <= WFIFO2IP_Data;
  IP2WFIFO_RdReq <= (not WFIFO2IP_empty) and (not tx_fifo_almost_full);

  -- Connection between Read FIFO and RX FIFO
  IP2RFIFO_WrReq <= rx_fifo_valid;
  IP2RFIFO_Data <= rx_fifo_dout;
  rx_fifo_re <= (not rx_fifo_empty) and (not RFIFO2IP_AlmostFull);

  -- Connection between TX FIFO and MUX
  tx_fifo_re <= mux_rdreq;
  mux_din <= tx_fifo_dout;
  mux_we <= tx_fifo_valid;
  mux_wrreq <= not tx_fifo_empty;

  -- Connection between RX FIFO and DEMUX
  rx_fifo_we <= demux_valid;
  rx_fifo_din <= demux_dout;

  -- Connection between MUX and Aurora TX
  tx_src_rdy_n_i <= not mux_dout_valid;
  tx_d_i <= mux_dout;

  -- Connection between DEMUX and Aurora RX
  -- (the Aurora RX has no read request signal)
  demux_we <= not rx_src_rdy_n_i;
  demux_din <= rx_d_i;
  1. Now we must remove the example code for the read and write FIFOs. The “user_logic.vhd” file is always generated with code that connects the read and write FIFOs in loop-back. It is intended to provide an example of usage of the FIFOs and also allows for easy testing of a new peripheral. In our design, we have connected the read and write FIFOs to the RX and TX FIFOs respectively, so we must remove the example code. Comment out, or delete all the lines of code from the line that reads “FIFO_CNTL_SM_COMB : process(…” to the line that reads “IP2RFIFO_Data <= WFIFO2IP_Data;” inclusively.
  2. Save and close the file.

The MUX and DEMUX state machines that we placed into the “user_logic.vhd” file could be better organized by creating separate components and .vhd files for them. It is only for simplicity of this tutorial that they are placed directly in the “user_logic.vhd” file.

Import the Aurora Peripheral
Now we will use the Peripheral Wizard in Import mode.

  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 “aurora_plb”. 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 “Netlist files”. We need to click Netlist files because the FIFO component that we use for the TX and RX FIFO is contained in a .ngc file. Click “Next”.
  6. Select “Use existing Peripheral Analysis Order file (*.pao)” and click “Browse”. From the project folder, go to “pcores\aurora_plb_v1_00_a\data” and select the “aurora_plb_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 Master and Slave” and click “Next”.
  9. On the MSPLB: Port page, click “Next”.
  10. On the MSPLB: Parameter page, click “Next”.
  11. On the “Identify Interrupt Signals” page, leave the default settings and click “Next”.
  12. On the “Parameter Attributes” page, click “Next”.
  13. On the “Port Attributes” page, click “Next”.
  14. On the “Netlist Files” page, we must specify the location of the .ngc file for the FIFO that we generated earlier with CORE Generator. Click “Select Files” and browse to the “coregen” project folder. Select the file “fifo_generator_v3_2.ngc” and click “Open”. The .ngc file should be listed as shown in the image below. Click “Next”.
  15. Click “Finish”.

The peripheral wizard will make a copy of the .ngc file we specified and place it in the “pcores\aurora_plb_v1_00_a\netlist” in our project folder. It will also create a file called “aurora_plb_v2_1_0.bbd” in “pcores\aurora_plb_v1_00_a\data” which is a text file that lists the .ngc files used by the peripheral. The Aurora peripheral should now be accessible through the “IP Catalog->Project Repository” in the XPS interface.

Create two Instances of the Aurora Peripheral
We will create two instances of the Aurora peripheral in this project so that we can connect them with a loop-back SATA cable and transfer data between them. Follow these steps to create two instances of the peripheral in the project.

  1. From the “IP Catalog” find the “aurora_plb” IP core in the “Project Repository” group. Right click on the core and select “Add IP”. Do this a second time to add another Aurora peripheral.
  2. From the “System Assembly View” using the “Bus Interface” filter, connect the “aurora_plb_0″ and “aurora_plb_1″ to the PLB.
  3. Click on the “Ports” filter. Click on the “+” for “aurora_plb_0″ and “aurora_plb_1″ to view their ports.
  4. Click on the “Net” field for the “TOP_BREF_CLK” port. Type “TOP_BREF_CLK” in this field and press “Enter”. Do this for both “aurora_plb_0″ and “aurora_plb_1″.
  5. Click on the “Net” field for the “USER_CLK” port. Type “USER_CLK” in this field and press “Enter”. Do this for both “aurora_plb_0″ and “aurora_plb_1″.
  6. For “aurora_plb_0″ ONLY, click on the “Net” field for the “HARD_ERROR” port. Type “HARD_ERROR” 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. For “aurora_plb_0″ ONLY, click on the “Net” field for the “SOFT_ERROR” port. Type “SOFT_ERROR” 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. For “aurora_plb_0″ ONLY, click on the “Net” field for the “LANE_UP” port. Type “LANE_UP” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External” and press “Enter”. The ports should now look as shown in the image below.
  9. For “aurora_plb_0″ ONLY, click on the “Net” field for the “CHANNEL_UP” port. Type “CHANNEL_UP” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External” and press “Enter”. The ports for both peripherals should be as shown in the screenshot below.
  10. Click on the “Addresses” filter. Change the “Size” for “aurora_plb_0″ and “aurora_plb_1″ to 64K. Then click “Generate Addresses”.

Now we have two instances of the Aurora peripheral in the project. Both Aurora peripherals have status outputs (CHANNEL_UP, HARD_ERROR, SOFT_ERROR and LANE_UP) which we would like to connect to the LEDs. We only externalized those ports for the “aurora_plb_0″ peripheral because we only have 4 LEDs to use on the XUPV2P board. As we are going to connect the Aurora peripherals to each other with a loop-back SATA cable, the status outputs of both peripherals should be the same anyway.

Modify the UCF Constraints File
Now we must add some lines to the project’s .ucf file to tell XPS: (1) which physical RocketIO MGT to use, (2) where the external reference clock pins are, (3) the frequency or period of the reference clock, and (4) where the external LED pins are to connect our status outputs.

  1. Click on the “Project” tab and double-click on “UCF File: data/system.ucf” from within the “Project Files” tree. The .ucf file should open.
  2. Insert the following code at the end of the .ucf file.
##### Timing Contraints for the MGT Recovered clock ######

NET aurora_plb_0/aurora_plb_0/USER_LOGIC_I/aurora_module_i/lane_0_mgt_i/RXRECCLK PERIOD=75 MHz;
NET aurora_plb_1/aurora_plb_1/USER_LOGIC_I/aurora_module_i/lane_0_mgt_i/RXRECCLK PERIOD=75 MHz;

##### Timing Contraints for the MGT reference clock ######

NET USER_CLK PERIOD = 75 MHz;
NET TOP_BREF_CLK PERIOD = 75 MHz;

###### Connect the external MGT clock inputs #######

NET TOP_BREF_CLK_P_pin LOC=F16;
NET TOP_BREF_CLK_P_pin IOSTANDARD = LVDS_25;
NET TOP_BREF_CLK_N_pin LOC=G16;
NET TOP_BREF_CLK_N_pin IOSTANDARD = LVDS_25;

###### MGT Locations #######

# X0Y1 (SATA 0 HOST) aurora_plb_0
INST aurora_plb_0/aurora_plb_0/USER_LOGIC_I/aurora_module_i/lane_0_mgt_i LOC=GT_X0Y1;
# X1Y1 (SATA 1 TARGET) aurora_plb_1
INST aurora_plb_1/aurora_plb_1/USER_LOGIC_I/aurora_module_i/lane_0_mgt_i LOC=GT_X1Y1;

###### Connect LEDs to the Aurora Status outputs ########

# LED 0
NET CHANNEL_UP_pin LOC = AC4;
Net CHANNEL_UP_pin IOSTANDARD = LVTTL;
Net CHANNEL_UP_pin SLEW = SLOW;
Net CHANNEL_UP_pin DRIVE = 12;
# LED 1
NET HARD_ERROR_pin LOC = AC3;
Net HARD_ERROR_pin IOSTANDARD = LVTTL;
Net HARD_ERROR_pin SLEW = SLOW;
Net HARD_ERROR_pin DRIVE = 12;
# LED 2
NET SOFT_ERROR_pin LOC = AA6;
Net SOFT_ERROR_pin IOSTANDARD = LVTTL;
Net SOFT_ERROR_pin SLEW = SLOW;
Net SOFT_ERROR_pin DRIVE = 12;
# LED 3
NET LANE_UP_pin LOC = AA5;
Net LANE_UP_pin IOSTANDARD = LVTTL;
Net LANE_UP_pin SLEW = SLOW;
Net LANE_UP_pin DRIVE = 12;
  1. Save and close the file.

Modify the Software Application
Now all we need to do is modify the software application to test our Aurora peripherals.

  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"
#include "aurora_plb.h"

Xuint32 *aurora_plb_0_baseaddr_p =
                  (Xuint32 *) XPAR_AURORA_PLB_0_BASEADDR;
Xuint32 *aurora_plb_1_baseaddr_p =
                  (Xuint32 *) XPAR_AURORA_PLB_1_BASEADDR;
Xuint32 aurora_plb_0_baseaddr;
Xuint32 aurora_plb_1_baseaddr;

int main (void)
{
  Xuint32 i;
  Xuint16 data[20];
  Xuint32 data_byte_len;
  Xuint32 data_word_len;

  // Check that the Aurora peripherals exist
  XASSERT_NONVOID(aurora_plb_0_baseaddr_p != XNULL);
  aurora_plb_0_baseaddr = (Xuint32) aurora_plb_0_baseaddr_p;
  XASSERT_NONVOID(aurora_plb_1_baseaddr_p != XNULL);
  aurora_plb_1_baseaddr = (Xuint32) aurora_plb_1_baseaddr_p;

  // Reset read and write FIFOs to initial state
  AURORA_PLB_mResetWriteFIFO(aurora_plb_0_baseaddr);
  AURORA_PLB_mResetReadFIFO(aurora_plb_0_baseaddr);
  AURORA_PLB_mResetWriteFIFO(aurora_plb_1_baseaddr);
  AURORA_PLB_mResetReadFIFO(aurora_plb_1_baseaddr);

  // set data for transmission
  data[0] = 0x1111;
  data[1] = 0x2222;
  data[2] = 0x3333;
  data[3] = 0x4444;
  data[4] = 0x5555;
  data[5] = 0x6666;
  data[6] = 0x7777;
  data[7] = 0x8888;
  data[8] = 0x9999;
  data[9] = 0xAAAA;
  data_word_len = 10;
  data_byte_len = data_word_len * 2;

  // Clear screen
  xil_printf("%c[2J",27);

  xil_printf("Test 1: Transmit data from ");
  xil_printf("AURORA_PLB_0 to AURORA_PLB_1\n\r");
  xil_printf("---------------------------");
  xil_printf("----------------------------\n\r");

  // Write data to AURORA_PLB_0 write FIFO
  xil_printf("  Writing data to the AURORA_PLB_0 peripheral:");
  xil_printf("\n\r    ");
  // Setup DMA transfer from data buffer to aurora_plb_0
  AURORA_PLB_mResetDMA0(aurora_plb_0_baseaddr);
  AURORA_PLB_mSetDMA0Control(aurora_plb_0_baseaddr,
           DMA_SINC_MASK | DMA_DLOCAL_MASK);
  AURORA_PLB_DMA0Transfer(aurora_plb_0_baseaddr, (Xuint32)data,
           aurora_plb_0_baseaddr+AURORA_PLB_WRFIFO_DATA_OFFSET,
           data_byte_len);
  // Wait for the transfer to finish
  while(AURORA_PLB_mDMA0Done(aurora_plb_0_baseaddr) == 0){
  }
  // Check if there was an error with the transaction
  if(AURORA_PLB_mDMA0Error(aurora_plb_0_baseaddr))
    xil_printf("Error writing to AURORA_PLB_0");
  else{
    // Display the written data
    for(i = 0; i < data_word_len; i++)
      xil_printf("0x%04x ", data[i]);
  }
  // Get data from AURORA_PLB_1 read FIFO
  xil_printf("\n\r\n\r  ");
  xil_printf("Reading data from the AURORA_PLB_1 peripheral:");
  xil_printf("\n\r    ");
  // Setup DMA transfer from aurora_plb_1 to data buffer
  AURORA_PLB_mResetDMA0(aurora_plb_1_baseaddr);
  AURORA_PLB_mSetDMA0Control(aurora_plb_1_baseaddr,
           DMA_DINC_MASK | DMA_SLOCAL_MASK);
  AURORA_PLB_DMA0Transfer(aurora_plb_1_baseaddr,
           aurora_plb_1_baseaddr+AURORA_PLB_RDFIFO_DATA_OFFSET,
           (Xuint32)data, data_byte_len);
  // Wait for the transfer to finish
  while(AURORA_PLB_mDMA0Done(aurora_plb_1_baseaddr) == 0){
  }
  // Check if there was an error with the transaction
  if(AURORA_PLB_mDMA0Error(aurora_plb_1_baseaddr))
    xil_printf("Error reading from AURORA_PLB_1");
  else{
    // Display the read data
    for(i = 0; i < data_word_len; i++)
      xil_printf("0x%04x ", data[i]);
  }

  xil_printf("\n\r\n\rTest 2: Transmit data from ");
  xil_printf("AURORA_PLB_1 to AURORA_PLB_0\n\r");
  xil_printf("----------------------------");
  xil_printf("---------------------------\n\r");

  // Write data to AURORA_PLB_1 write FIFO
  xil_printf("  Writing data to the AURORA_PLB_1 peripheral:");
  xil_printf("\n\r    ");
  // Setup DMA transfer from data buffer to aurora_plb_1
  AURORA_PLB_mResetDMA0(aurora_plb_1_baseaddr);
  AURORA_PLB_mSetDMA0Control(aurora_plb_1_baseaddr,
           DMA_SINC_MASK | DMA_DLOCAL_MASK);
  AURORA_PLB_DMA0Transfer(aurora_plb_1_baseaddr, (Xuint32)data,
           aurora_plb_1_baseaddr+AURORA_PLB_WRFIFO_DATA_OFFSET,
           data_byte_len);
  // Wait for the transfer to finish
  while(AURORA_PLB_mDMA0Done(aurora_plb_1_baseaddr) == 0){
  }
  // Check if there was an error with the transaction
  if(AURORA_PLB_mDMA0Error(aurora_plb_1_baseaddr))
    xil_printf("Error writing to AURORA_PLB_1");
  else{
    // Display the written data
    for(i = 0; i < data_word_len; i++)
      xil_printf("0x%04x ", data[i]);
  }
  // Get data from AURORA_PLB_0 Read FIFO
  xil_printf("\n\r\n\r  ");
  xil_printf("Reading data from the AURORA_PLB_0 peripheral:");
  xil_printf("\n\r    ");
  // Setup DMA transfer from aurora_plb_0 to data buffer
  AURORA_PLB_mResetDMA0(aurora_plb_0_baseaddr);
  AURORA_PLB_mSetDMA0Control(aurora_plb_0_baseaddr,
           DMA_DINC_MASK | DMA_SLOCAL_MASK);
  AURORA_PLB_DMA0Transfer(aurora_plb_0_baseaddr,
           aurora_plb_0_baseaddr+AURORA_PLB_RDFIFO_DATA_OFFSET,
           (Xuint32)data, data_byte_len);
  // Wait for the transfer to finish
  while(AURORA_PLB_mDMA0Done(aurora_plb_0_baseaddr) == 0){
  }
  // Check if there was an error with the transaction
  if(AURORA_PLB_mDMA0Error(aurora_plb_0_baseaddr))
    xil_printf("Error reading from AURORA_PLB_0");
  else{
    // Display the read data
    for(i = 0; i < data_word_len; i++)
      xil_printf("0x%04x ", data[i]);
  }

  xil_printf("\n\r\n\r");

  while(1){
  }
}
  1. Save and close the file.

Download and Test the Project

  1. Open a Hyperterminal window with the required settings. For the correct settings, see Hyperterminal Settings.
  2. Connect a SATA cable between the SATA connectors “SATA 0 HOST” and “SATA 1 TARGET” on the XUPV2P board. Note: Never connect a standard SATA cable between “SATA 0 HOST” and “SATA 2 HOST” because this would short together two MGT transmit outputs. In other words, only connect “HOST” to “TARGET”, never “HOST” to “HOST”.
  3. Turn on the XUPV2P board.
  4. From the XPS software, select “Device Configuration->Download Bitstream”.

The Hyperterminal output will show the results of two data transfer tests between “aurora_plb_0″ and “aurora_plb_1″. In the first test we transfer arbitrary data from “aurora_plb_0″ to “aurora_plb_1″. In the second test we transfer the same data from “aurora_plb_1″ to “aurora_plb_0″. The Hyperterminal output should look as shown in the image below:


The LEDs should display the status outputs: LED 0 – CHANNEL_UP, LED 1 – HARD_ERROR, LED 2 – SOFT_ERROR and LED 3 – LANE_UP. Note that due to the wiring of the LEDs on the XUPV2P, a logic high (“1″) turns the LED OFF, while a logic low (“0″) turns the LED ON. Try disconnecting the SATA cable and see how the status outputs change. The CHANNEL_UP and LANE_UP LEDs should turn ON. If we re-connect the SATA cable, the channel should be re-established and the CHANNEL_UP and LANE_UP LEDs should turn OFF.

By connecting the Aurora peripheral to the PLB, we eliminated the bottleneck of the OPB that limited the “real” data rate of our previous design in Create an Aurora Transceiver. As a further advantage, by using DMA transfers, the PowerPC is free to do other processing while data is automatically transferred to and from the Aurora peripherals.

 

Overview
In this tutorial we will create a peripheral containing the Aurora core to implement a high speed serial transceiver with a RocketIO MGT. The peripheral can be used to connect two XUPV2P boards using the SATA connectors and transfer data between them at 1.5Gbps. To test the design using only one XUPV2P board, we will instantiate two Aurora peripherals, assign them to different RocketIO MGTs and place a SATA cable between them to create a loop-back connection. The PowerPC will transfer data between the two Aurora peripherals simply by reading and writing to the read and write FIFOs. To test the design, the test application will write data to the write FIFO of the first Aurora peripheral and read it back from the read FIFO of the second Aurora peripheral. The Aurora peripheral will also have outputs indicating the status of the link. These outputs will be connected to the LEDs on the XUPV2P board.

Figure: The Aurora peripheral

The diagram above illustrates the design of the Aurora peripheral. It uses a read and write FIFO to transfer data between the PowerPC and the user logic. It also uses a second pair of FIFOs called the RX and TX FIFOs. The RX and TX FIFOs create a buffered link between the read/write FIFOs and the Aurora core. This buffered link is necessary because the OPB clock and the RocketIO clock are independent on the XUPV2P board. The OPB clocks data in and out of the read/write FIFOs at 100MHz while the user logic clocks data in and out of the Aurora core at 75MHz. For this reason, we use RX and TX FIFOs with independent read and write clock inputs.

As in the MGT Oscillator project, we will also create a Digital Clock Manager (DCM) peripheral for the RocketIO MGTs. The DCM peripheral will only contain two clock buffers and will not require registers or FIFOs.

This tutorial starts the user from scratch, assuming that the Aurora core license has been installed, and contains screenshots to guide the user through the entire implementation process. You can click on the images to view a higher resolution when necessary.

Requirements
Apart from the obvious requirements (XPS software and XUPV2P board) this project requires the following:

  1. SATA cable: If you are using the XUPV2P board, a SATA cable is necessary to be able to verify this design. If you do not have a SATA cable, you can buy one from most computer/electronics stores or from Digikey (part number 3M5568-ND). If you are not using the XUPV2P board, you must have a way to physically connect two MGTs.
  2. CORE Generator: Both the Aurora core and the TX/RX FIFOs will be created with the CORE Generator. Before beginning this tutorial, you will need to register with Xilinx to obtain a license to use the Aurora core. It is a free and simple process that involves accepting the license agreement after which you are emailed a license with instructions on unlocking the Aurora core in your CORE Generator. To start your registration, follow this link:http://www.xilinx.com/aurora/register_aurora.htm

Create the Basic Project
Follow these steps to create the basic project:

  1. Open XPS and from the dialog box, select “Base System Builder wizard” and OK.
  2. Create a new folder for the project and select it using “Browse”. In “Advanced Options” tick “Use repository paths” and select the “C:\XUPV2P\lib” folder using “Browse”. Click “OK”.
  3. Tick “I would like to create a new design” and click “Next”.
  4. Select “Xilinx” as the board vendor. Select “XUP Virtex II Pro Development System” as the board name. Select “C” as the board revision. Click “Next”.
  5. Tick “PowerPC” and click “Next”.
  6. Select all clock frequencies to be 100MHz. Select “No debug”. Click “Next”.
  7. In selecting the Additional IO Interfaces, tick “onewire_0″ and “RS232_Uart_1″. Untick everything else. We will not actually use the “onewire_0″ interface in this project, but leaving it in has shown to be important. For an explanation, refer to “The Onewire Problem” on the Known Issues page.
  8. When Adding Internal Peripherals, select 64KB for the “plb_bram_if_cntlr_1″ and click “Next”.
  9. Select “RS232_Uart_1″ for both STDIN and STDOUT. Un-tick “Memory Test” and leave “Peripheral Test” ticked. Click “Next”.
  10. On the “Configure Peripheral Test Application” page, select “plb_bram_if_cntlr_1″ for the Instruction, Data, Stack and Heap memories. Click “Next”.
  11. Click “Generate”.
  12. Click “Finish”.
  13. Tick “Start using Platform Studio” and click “OK”.

Create the DCM Peripheral
Follow these steps to create the DCM peripheral:

  1. Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
  2. Select “Create templates for a new peripheral” and click “Next”.
  3. Select “To an XPS project” and click “Next”.
  4. Type “mgt_dcm” for the peripheral name. Click “Next”.
  5. Select “On-chip Peripheral Bus” (OPB) and click “Next”.
  6. The DCM peripheral is very simple and doesn’t need interrupts, registers or FIFOs. Un-tick everything and click “Next”.
  7. On the “IP Interconnect” page, leave everything as is. Click “Next”.
  8. On the “Peripheral Simulation Support” page, 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.

Modify the DCM Peripheral
Now we will add code in our peripheral template to instantiate two clock buffers that will generate the clock sources REF_CLK and USER_CLK for the RocketIO MGTs. This DCM example originates from the Xilinx RocketIO Transceiver User Guide (ug024), see section “Digital Clock Manager (DCM) Examples”.

  1. Select from the menu “File->Open” and from the project folder, browse to “pcores\mgt_dcm_v1_00_a\hdl\vhdl”.
  2. Open the file “mgt_dcm.vhd”.
  3. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK_P : in std_logic;
  TOP_BREF_CLK_N : in std_logic;
  TOP_BREF_CLK   : out std_logic;
  USER_CLK       : 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.
  TOP_BREF_CLK_P => TOP_BREF_CLK_P,
  TOP_BREF_CLK_N => TOP_BREF_CLK_N,
  TOP_BREF_CLK => TOP_BREF_CLK,
  USER_CLK => USER_CLK,
  1. Save and close the file.
  2. Select from the menu “File->Open” and from the project folder, browse to “pcores\mgt_dcm_v1_00_a\hdl\vhdl”.
  3. Open the file “user_logic.vhd”.
  4. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK_P : in std_logic;
  TOP_BREF_CLK_N : in std_logic;
  TOP_BREF_CLK   : out std_logic;
  USER_CLK       : 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 IBUFGDS_LVDS_25
  port(
    O  : out std_ulogic;
    I  : in  std_ulogic;
    IB : in  std_ulogic
  );
end component;

component BUFG
  port(
    O : out std_ulogic;
    I : in  std_ulogic
  );
end component;

signal top_bref_clk_i : std_logic;
signal user_clk_i  : std_logic;
  1. Find the line of code that says “–USER logic implementation added here” and add the following lines of code just below.
-- Differential Clock Buffer for top BREF_CLK
diff_clk_buff_top_i : IBUFGDS_LVDS_25
  port map(
    I  => TOP_BREF_CLK_P,
    IB => TOP_BREF_CLK_N,
    O  => top_bref_clk_i
  );

-- BUFG used to drive USER_CLK on global clock net
user_clock_bufg_i : BUFG
  port map(
    I => top_bref_clk_i,
    O => user_clk_i
  );

TOP_BREF_CLK <= top_bref_clk_i;
USER_CLK <= user_clk_i;
  1. Save and close the file.

Import the DCM Peripheral
Now we will use the Peripheral Wizard to import the DCM peripheral.

  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 “mgt_dcm”. 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\mgt_dcm_v1_00_a\data” and select the “mgt_dcm_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 “OPB Slave” and click “Next”.
  9. On the SOPB: Port page, click “Next”.
  10. On the SOPB: Parameter page, click “Next”.
  11. On the “Identify Interrupt Signals” page, un-tick “Select and configure interrupt(s)” and click “Next”.
  12. On the “Parameter Attributes” page, click “Next”.
  13. On the “Port Attributes” page, click “Next”.
  14. Click “Finish”.

The DCM peripheral should now be accessible through the “IP Catalog->Project Repository” in the XPS interface.

Create an Instance of the DCM Peripheral
Follow these steps to create an instance of the peripheral in the project.

  1. From the “IP Catalog” find the “mgt_dcm” IP core in the “Project Repository” group. Right click on the core and select “Add IP”.
  2. From the “System Assembly View” using the “Bus Interface” filter, connect the “mgt_dcm_0″ to the OPB bus.
  3. Click on the “Ports” filter. Click on the “+” for “mgt_dcm_0″ to view its ports.
  4. Click on the “Net” field for the “TOP_BREF_CLK_P” port. Type “TOP_BREF_CLK_P” 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 “TOP_BREF_CLK_N” port. Type “TOP_BREF_CLK_N” 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 “TOP_BREF_CLK” port. Type “TOP_BREF_CLK” in this field and press “Enter”.
  7. Click on the “Net” field for the “USER_CLK” port. Type “USER_CLK” in this field and press “Enter”. The result should look like the image below.
  8. Now if you click the “+” for “External Ports”, you should be able to find the two ports “TOP_BREF_CLK_P_pin” and “TOP_BREF_CLK_N_pin”, with nets called “TOP_BREF_CLK_P” and “TOP_BREF_CLK_N” respectively.
  9. Click on the “Addresses” filter. Change the “Size” for “mgt_dcm_0″ to 64K. Then click “Generate Addresses”.

Now we have an instance of the DCM peripheral in the project. The single DCM peripheral will supply the reference clock to all the MGTs accessible on the XUPV2P board.

Create the Aurora Peripheral
Now we will start the creation of the Aurora peripheral by using the Peripheral Wizard. The Wizard will create a template for us with the read and write FIFOs fully implemented. We will then modify the template to include the Aurora core and RX/TX FIFOs. Follow these steps to create the Aurora peripheral.

  1. Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
  2. Select “Create templates for a new peripheral” and click “Next”.
  3. Select “To an XPS project” and click “Next”.
  4. Type “aurora_mgt” for the peripheral name. Click “Next”.
  5. Select “On-chip Peripheral Bus” (OPB) and click “Next”.
  6. Tick “FIFO”, un-tick everything else and click “Next”.
  7. For the FIFO Service settings, leave the defaults ticked: Include read FIFO, Include write FIFO, Use packet mode, Use vacancy calculation. Choose 32-bits for the width of the FIFOs, and choose a depth of 512.
  8. On the “IP Interconnect” page leave everything as is. Click “Next”.
  9. On the “Peripheral Simulation Support” page, click “Next” without ticking the option to generate.
  10. After the “Peripheral Implementation Support” page, tick “Generate ISE and XST project files” and “Generate template driver files”. Click “Next”.
  11. Click “Finish”. Now our templates are created.

Now the template is created, we now need to use CORE Generator to create our RX/TX FIFOs and the Aurora core.

Create the FIFO Component in CORE Generator
The read and write FIFOs of our Aurora peripheral were created by the Peripheral Wizard and they are ready for us to use in the user_logic.vhd file. The TX and RX FIFOs however must be created by us and placed into the user_logic.vhd file manually. Fortunately, the CORE Generator provides a good FIFO component that suits our needs. Follow these steps to create the FIFO component that we will use to implement the TX and RX FIFOs.

  1. Run the Xilinx CORE Generator. Note that you do not have to close the XPS software.
  2. Select “File->New Project”.
  3. Click “Browse” and select an appropriate location for a Coregen project. Within a Coregen project, you can create several cores that don’t necessarily relate to each other. Just select the folder where you normally place your projects, and leave the project name as “coregen”. Click “OK”.
  4. CORE Generator will ask you if you want to create the “coregen” folder. Click “OK”.
  5. You will be asked for the specifications of the FPGA you are using. Under the “Part” tab, select these options: Family “Virtex2P”, Device “xc2vp30″, Package “ff896″, Speed grade “-7″. Click “OK”.
  6. When you have created your Coregen project, click on the “View by Function” tab to get a list of cores that you are able to generate.
  7. Open “Memories and Storage Elements->FIFOs” and double-click on “FIFO Generator 3.2″.
  8. A dialog box should open to allow you to select the features of the FIFO you want. On the first page we select the read and write clock setting. We want asynchronous clocks so we must select “Independent Clocks” using memory type “Block RAM”. Click “Next”.
  9. On the second page, we want to select “Standard FIFO” with a “Write width” of 32, a “Write depth” of 512 and a “Read width” of 32. Click “Next”.
  10. On the third page, tick “Almost Full Flag”, “Valid Flag” and “Reset Pin”. Click “Finish”. Pages 4, 5 and 6 do not contain any features that we desire.
  11. Now use Windows Explorer to browse the “coregen” folder just created. You will find the generated files. One of those files is a netlist file called “fifo_generator_v3_2_fifo_generator_v3_2_xst_1.ngc”. Rename the file to “fifo_generator_v3_2.ngc”. This is the file that we will use in our Aurora peripheral to implement the TX and RX FIFOs.

You can leave the CORE Generator open, because in the next section we will use it again to generate the Aurora core. The FIFO will now be listed under the tab “Generated IP”.

Create the Aurora core in CORE Generator
Once you have a license to use the Aurora core and you have gone through the instructions provided by Xilinx, you should be able to use the CORE Generator to produce an Aurora core. The CORE Generator can generate VHDL code for the Aurora core with many variations as you will see in the creation wizard. Follow these steps to create an Aurora core:

  1. Run the Xilinx CORE Generator if it is not already open.
  2. We will create the Aurora core in the Coregen project that we created for the FIFO component. If you have not left the Coregen project open from the previous section, click “File->Open Project” and browse to the “coregen” project folder that we just created for the FIFO. Select the “coregen.cgp” file and click “Open”.
  3. From the “View by Function” tab, open “Communication and Networking->Serial Interfaces” and double-click on the “Aurora” IP. If you have not registered for a license to use the Aurora core, you will be given a message saying that you do not have permission to generate the core. If you have registered, received and installed the license, you may be given this message: “License for component allows you to use this component, but does not give you access to source code implementing this component”. You can ignore this message as the CORE Generator will in fact give you source code. A dialog box will open that you will use to select the features of the Aurora core.
  4. Specify the number of “Aurora Lanes” to be 1, “Bytes per Lane” to be 2, and “Interface” to Streaming. Leave “Special Features” un-ticked. Click “Next”.
  5. On the second page we select the reference clock and the MGT we wish to use. The specific MGT to use is not so important because we will be able to change this in our .ucf file later. The row of the clock however is important because the XUPV2P board is wired to use the TOP row. Ignore the comment saying Row 0 is the bottom and Row 1 is the top. For “Row 0 Clock” select “BREF_CLK”. For “Row 1 Clock” select “none”. To select the MGT, put a “1″ in Row 0, Column 0, and place an “X” in all the other squares. Click “Finish”.
  6. The Aurora core will be generated and you will see it listed in the “Generated IP” tab.
  7. Close CORE Generator.

Exploring the Generated Files
Now if you explore the contents of the “coregen” project folder that CORE Generator created, you should find the files as shown below: The FIFO files of importance to us are the netlist (.ngc) file and the “fifo_generator_v3_2.vho” file. The latter file gives us an example of the FIFO component declaration and instantiation. We will use these examples in the “user_logic.vhd” of our Aurora peripheral code later.

In the “aurora_201″ folder you will find useful documentation and examples for using the Aurora core. The user guide for the Aurora core is the file called “ug061.pdf” and it is recommended that you read this file to better understand the work in this tutorial. Another interesting document is the Getting Started Guide in the file “aurora_gs_ug173.pdf”. This guide explains the example that was generated by the CORE Generator and how to simulate and implement it. In the “aurora_201\examples” folder, you will find the “aurora_sample.vhd” file which is the top-level of the example design. It is important to understand the example because in this tutorial, we will use the example code in our Aurora peripheral “user_logic.vhd” file.

Copy the Aurora core source files
We need to copy the Aurora core source files into the Aurora peripheral source folder. We just generated the source files for the Aurora core with CORE Generator and they should be found in the “coregen” project folder. The image below shows two explorer windows browsing the source code files.

  1. Open Windows Explorer and browse to the folder “coregen\aurora_201\src”. Copy all the files in that folder and paste them into the “pcores\aurora_mgt_v1_00_a\hdl\vhdl” folder within your XPS project. You will be copying these files into the same folder as your “user_logic.vhd” file for the Aurora peripheral is contained.
  2. Now browse to the folder “coregen\aurora_201\cc_manager”. Copy the file “standard_cc_module.vhd” in that folder and paste it into the “pcores\aurora_mgt_v1_00_a\hdl\vhdl” folder within your XPS project.
  3. Make sure that you have copied all the files listed below.
aurora_201.vhd
aurora_lane.vhd
aurora_pkg.vhd
channel_error_detect.vhd
channel_init_sm.vhd
chbond_count_dec.vhd
error_detect.vhd
global_logic.vhd
idle_and_ver_gen.vhd
lane_init_sm.vhd
phase_align.vhd
rx_stream.vhd
sym_dec.vhd
sym_gen.vhd
tx_stream.vhd
standard_cc_module.vhd

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 Aurora core 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\aurora_mgt_v1_00_a\data” folder. Select the file “aurora_mgt_v2_1_0.pao” and click “Open”.
  2. At the bottom of this file you will see these two lines:
lib aurora_mgt_v1_00_a user_logic vhdl
lib aurora_mgt_v1_00_a aurora_mgt 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 aurora_mgt_v1_00_a aurora_pkg vhdl
lib aurora_mgt_v1_00_a channel_error_detect vhdl
lib aurora_mgt_v1_00_a idle_and_ver_gen vhdl
lib aurora_mgt_v1_00_a channel_init_sm vhdl
lib aurora_mgt_v1_00_a error_detect vhdl
lib aurora_mgt_v1_00_a sym_dec vhdl
lib aurora_mgt_v1_00_a sym_gen vhdl
lib aurora_mgt_v1_00_a chbond_count_dec vhdl
lib aurora_mgt_v1_00_a lane_init_sm vhdl
lib aurora_mgt_v1_00_a rx_stream vhdl
lib aurora_mgt_v1_00_a tx_stream vhdl
lib aurora_mgt_v1_00_a global_logic vhdl
lib aurora_mgt_v1_00_a phase_align vhdl
lib aurora_mgt_v1_00_a aurora_lane vhdl
lib aurora_mgt_v1_00_a standard_cc_module vhdl
lib aurora_mgt_v1_00_a aurora_201 vhdl
  1. Save the file.

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

Modify the Aurora Peripheral
Now we will add code to our peripheral template to instantiate an Aurora core and the TX and RX FIFOs. The TX and RX FIFOs will be wired to the write and read FIFOs respectively. The FIFO connections are made such that data is automatically passed along when any of the FIFOs receives data.

  1. Select from the menu “File->Open” and from the project folder, browse to “pcores\aurora_mgt_v1_00_a\hdl\vhdl”.
  2. Open the file “aurora_mgt.vhd”.
  3. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK      : in std_logic;
  USER_CLK          : in std_logic;
  HARD_ERROR        : out std_logic;
  SOFT_ERROR        : out std_logic;
  LANE_UP           : out std_logic;
  CHANNEL_UP        : out std_logic;
  RXP               : in std_logic;
  RXN               : in std_logic;
  TXP               : out std_logic;
  TXN               : 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.
  TOP_BREF_CLK => TOP_BREF_CLK,
  USER_CLK => USER_CLK,
  HARD_ERROR => HARD_ERROR,
  SOFT_ERROR => SOFT_ERROR,
  LANE_UP => LANE_UP,
  CHANNEL_UP => CHANNEL_UP,
  RXP => RXP,
  RXN => RXN,
  TXP => TXP,
  TXN => TXN,
  1. Save and close the file.
  2. Select from the menu “File->Open” and browse from the project folder to “pcores\aurora_mgt_v1_00_a\hdl\vhdl”.
  3. Open the file “user_logic.vhd”. We will need to modify this source code to instantiate the Aurora core and TX/RX FIFOs.
  4. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK      : in std_logic;
  USER_CLK          : in std_logic;
  HARD_ERROR        : out std_logic;
  SOFT_ERROR        : out std_logic;
  LANE_UP           : out std_logic;
  CHANNEL_UP        : out std_logic;
  RXP               : in std_logic;
  RXN               : in std_logic;
  TXP               : out std_logic;
  TXN               : 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. You will recognize this code from the “aurora_sample.vhd” file.
  -- External Register Declarations --
  signal HARD_ERROR_Buffer  : std_logic;
  signal SOFT_ERROR_Buffer  : std_logic;
  signal LANE_UP_Buffer     : std_logic;
  signal CHANNEL_UP_Buffer  : std_logic;
  signal TXP_Buffer         : std_logic;
  signal TXN_Buffer         : std_logic;

  -- Wire Declarations --
  -- Stream TX Interface
  signal tx_d_i         : std_logic_vector(0 to 15);
  signal tx_src_rdy_n_i : std_logic;
  signal tx_dst_rdy_n_i : std_logic;

  -- Stream RX Interface
  signal rx_d_i         : std_logic_vector(0 to 15);
  signal rx_src_rdy_n_i : std_logic;

  -- Error Detection Interface
  signal hard_error_i   : std_logic;
  signal soft_error_i   : std_logic;

  -- Status
  signal channel_up_i   : std_logic;
  signal lane_up_i      : std_logic;

  -- Clock Compensation Control Interface
  signal warn_cc_i      : std_logic;
  signal do_cc_i        : std_logic;

  --TX & RX FIFO signals
  signal tx_fifo_empty : std_logic;
  signal rx_fifo_empty : std_logic;
  signal tx_fifo_we    : std_logic := '0';
  signal rx_fifo_we    : std_logic := '0';
  signal tx_fifo_re    : std_logic := '0';
  signal rx_fifo_re    : std_logic := '0';
  signal tx_fifo_valid : std_logic;
  signal rx_fifo_valid : std_logic;
  signal tx_fifo_almost_full : std_logic;
  signal rx_fifo_almost_full : std_logic;
  signal tx_fifo_dout  : std_logic_vector(31 downto 0);
  signal rx_fifo_dout  : std_logic_vector(31 downto 0);
  signal tx_fifo_din   : std_logic_vector(31 downto 0);
  signal rx_fifo_din   : std_logic_vector(31 downto 0);

  -- Component Declarations --

  component aurora_201
    generic (                    
      EXTEND_WATCHDOGS   : boolean := FALSE
    );
    port (
      -- LocalLink TX Interface
        TX_D           : in std_logic_vector(0 to 15);
        TX_SRC_RDY_N   : in std_logic;
        TX_DST_RDY_N   : out std_logic;
      -- LocalLink RX Interface
        RX_D           : out std_logic_vector(0 to 15);
        RX_SRC_RDY_N   : out std_logic;
      -- MGT Serial I/O
        RXP            : in std_logic;
        RXN            : in std_logic;
        TXP            : out std_logic;
        TXN            : out std_logic;
      -- MGT Reference Clock Interface
        TOP_BREF_CLK   : in std_logic;
      -- Error Detection Interface
        HARD_ERROR     : out std_logic;
        SOFT_ERROR     : out std_logic;
      -- Status
        CHANNEL_UP     : out std_logic;
        LANE_UP        : out std_logic;
      -- Clock Compensation Control Interface
        WARN_CC        : in std_logic;
        DO_CC          : in std_logic;
      -- System Interface
        DCM_NOT_LOCKED : in std_logic;
        USER_CLK       : in std_logic;
        RESET          : in std_logic;
        POWER_DOWN     : in std_logic;
        LOOPBACK       : in std_logic_vector(1 downto 0)
      );
  end component;

  component STANDARD_CC_MODULE
    port (
      -- Clock Compensation Control Interface
        WARN_CC        : out std_logic;
        DO_CC          : out std_logic;
      -- System Interface
        DCM_NOT_LOCKED : in std_logic;
        USER_CLK       : in std_logic;
        CHANNEL_UP     : in std_logic
      );
  end component;

  -- FIFO component from CORE Generator
  component fifo_generator_v3_2
    port (
      din         : IN std_logic_VECTOR(31 downto 0);
      rd_clk      : IN std_logic;
      rd_en       : IN std_logic;
      rst         : IN std_logic;
      wr_clk      : IN std_logic;
      wr_en       : IN std_logic;
      almost_full : OUT std_logic;
      dout        : OUT std_logic_VECTOR(31 downto 0);
      empty       : OUT std_logic;
      full        : OUT std_logic;
      valid       : OUT std_logic
    );
  end component;
  1. Find the line of code that says “–USER logic implementation added here” and add the following lines of code just below.
  HARD_ERROR  <= HARD_ERROR_Buffer;
  SOFT_ERROR  <= SOFT_ERROR_Buffer;
  LANE_UP     <= LANE_UP_Buffer;
  CHANNEL_UP  <= CHANNEL_UP_Buffer;
  TXP         <= TXP_Buffer;
  TXN         <= TXN_Buffer;

  -- Register User I/O --
  -- Register User Outputs from core.
  process (USER_CLK)
  begin
    if (USER_CLK 'event and USER_CLK = '1') then
      HARD_ERROR_Buffer  <= hard_error_i;
      SOFT_ERROR_Buffer  <= soft_error_i;
      LANE_UP_Buffer     <= lane_up_i;
      CHANNEL_UP_Buffer  <= channel_up_i;
    end if;
  end process;

  -- Aurora core instantiation
  aurora_module_i : aurora_201
    port map (
      -- LocalLink TX Interface
        TX_D           => tx_d_i,
        TX_SRC_RDY_N   => tx_src_rdy_n_i,
        TX_DST_RDY_N   => tx_dst_rdy_n_i,
      -- LocalLink RX Interface
        RX_D           => rx_d_i,
        RX_SRC_RDY_N   => rx_src_rdy_n_i,
      -- MGT Serial I/O
        RXP            => RXP,
        RXN            => RXN,
        TXP            => TXP_Buffer,
        TXN            => TXN_Buffer,
      -- MGT Reference Clock Interface
        TOP_BREF_CLK   => TOP_BREF_CLK,
      -- Error Detection Interface
        HARD_ERROR     => hard_error_i,
        SOFT_ERROR     => soft_error_i,
      -- Status
        CHANNEL_UP     => channel_up_i,
        LANE_UP        => lane_up_i,
      -- Clock Compensation Control Interface
        WARN_CC        => warn_cc_i,
        DO_CC          => do_cc_i,
      -- System Interface
        DCM_NOT_LOCKED => '0',
        USER_CLK       => USER_CLK,
        RESET          => Bus2IP_Reset,
        POWER_DOWN     => '0',
        LOOPBACK       => "00"
      );

  standard_cc_module_i : STANDARD_CC_MODULE
    port map (
      -- Clock Compensation Control Interface
        WARN_CC        => warn_cc_i,
        DO_CC          => do_cc_i,
      -- System Interface
        DCM_NOT_LOCKED => '0',
        USER_CLK       => USER_CLK,
        CHANNEL_UP     => channel_up_i
      );

  -----------------------------------------
  -- FIFOs:
  --  Write FIFO -> TX FIFO -> Aurora TX
  --  Read FIFO <- RX FIFO <- Aurora RX
  --
  -- Write FIFO: Single CLK: Bus2IP_Clk
  -- Read FIFO:  Single CLK: Bus2IP_Clk
  -- TX FIFO:    In CLK: Bus2IP_Clk, Out CLK: USER_CLK
  -- RX FIFO:    In CLK: USER_CLK, Out CLK: Bus2IP_Clk
  --
  tx_fifo_i : fifo_generator_v3_2
    port map (
      din => tx_fifo_din,
      rd_clk => USER_CLK,
      rd_en => tx_fifo_re,
      rst => Bus2IP_Reset,
      wr_clk => Bus2IP_Clk,
      wr_en => tx_fifo_we,
      almost_full => tx_fifo_almost_full,
      dout => tx_fifo_dout,
      empty => tx_fifo_empty,
      full => open,
      valid => tx_fifo_valid);

  rx_fifo_i : fifo_generator_v3_2
    port map (
      din => rx_fifo_din,
      rd_clk => Bus2IP_Clk,
      rd_en => rx_fifo_re,
      rst => Bus2IP_Reset,
      wr_clk => USER_CLK,
      wr_en => rx_fifo_we,
      almost_full => rx_fifo_almost_full,
      dout => rx_fifo_dout,
      empty => rx_fifo_empty,
      full => open,
      valid => rx_fifo_valid);

  -----------------------------------------
  -- FIFO Connections:
  --  Write Enable <= Valid Data
  --  Data In <= Data Out
  --  Read Enable <= (not Empty) and (not Almost Full)

  -- Connection between Write FIFO and TX FIFO
  tx_fifo_we <= WFIFO2IP_RdAck;
  tx_fifo_din <= WFIFO2IP_Data;
  IP2WFIFO_RdReq <= (not WFIFO2IP_empty) and (not tx_fifo_almost_full);

  -- Connection between Read FIFO and RX FIFO
  IP2RFIFO_WrReq <= rx_fifo_valid;
  IP2RFIFO_Data <= rx_fifo_dout;
  rx_fifo_re <= (not rx_fifo_empty) and (not RFIFO2IP_AlmostFull);

  -- Connection between TX FIFO and Aurora TX
  tx_src_rdy_n_i <= not tx_fifo_valid;
  tx_d_i <= tx_fifo_dout(15 downto 0);
  tx_fifo_re <= not tx_fifo_empty;

  -- Connection between RX FIFO and Aurora RX
  -- (the Aurora RX has no read request signal)
  rx_fifo_we <= not rx_src_rdy_n_i;
  rx_fifo_din(31 downto 16) <= (others => '0');
  rx_fifo_din(15 downto 0) <= rx_d_i;
  1. Now we must remove the example code for the read and write FIFOs. The “user_logic.vhd” file is always generated with code that connects the read and write FIFOs in loop-back. It is intended to provide an example of usage of the FIFOs and also allows for easy testing of a new peripheral. In our design, we have connected the read and write FIFOs to the RX and TX FIFOs respectively, so we must remove the example code. Comment out, or delete all the lines of code from the line that reads “FIFO_CNTL_SM_COMB : process(…” to the line that reads “IP2RFIFO_Data <= WFIFO2IP_Data;” inclusively.
  2. Save and close the file.

Import the Aurora Peripheral
Now we will use the Peripheral Wizard in Import mode.

  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 “aurora_mgt”. 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 “Netlist files”. We need to click Netlist files because the FIFO component that we use for the TX and RX FIFO is contained in a .ngc file. Click “Next”.
  6. Select “Use existing Peripheral Analysis Order file (*.pao)” and click “Browse”. From the project folder, go to “pcores\aurora_mgt_v1_00_a\data” and select the “aurora_mgt_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 “OPB Slave” and click “Next”.
  9. On the SOPB: Port page, click “Next”.
  10. On the SOPB: Parameter page, click “Next”.
  11. On the “Identify Interrupt Signals” page, un-tick “Select and configure interrupt(s)” and click “Next”.
  12. On the “Parameter Attributes” page, click “Next”.
  13. On the “Port Attributes” page, click “Next”.
  14. On the “Netlist Files” page, we must specify the location of the .ngc file for the FIFO that we generated earlier with CORE Generator. Click “Select Files” and browse to the “coregen” project folder. Select the file “fifo_generator_v3_2.ngc” and click “Open”. The .ngc file should be listed as shown in the image below. Click “Next”.
  15. Click “Finish”.

The peripheral wizard will make a copy of the .ngc file we specified and place it in the “pcores\aurora_mgt_v1_00_a\netlist” in our project folder. It will also create a file called “aurora_mgt_v2_1_0.bbd” in “pcores\aurora_mgt_v1_00_a\data” which is a text file that lists the .ngc files used by the peripheral. The Aurora peripheral should now be accessible through the “IP Catalog->Project Repository” in the XPS interface.

Create two Instances of the Aurora Peripheral
We will create two instances of the Aurora peripheral in this project so that we can connect them with a loop-back SATA cable and transfer data between them. Follow these steps to create two instances of the peripheral in the project.

  1. From the “IP Catalog” find the “aurora_mgt” IP core in the “Project Repository” group. Right click on the core and select “Add IP”. Do this a second time to add another Aurora peripheral.
  2. From the “System Assembly View” using the “Bus Interface” filter, connect the “aurora_mgt_0″ and “aurora_mgt_1″ to the OPB bus.
  3. Click on the “Ports” filter. Click on the “+” for “aurora_mgt_0″ and “aurora_mgt_1″ to view their ports.
  4. Click on the “Net” field for the “TOP_BREF_CLK” port. Type “TOP_BREF_CLK” in this field and press “Enter”. Do this for both “aurora_mgt_0″ and “aurora_mgt_1″.
  5. Click on the “Net” field for the “USER_CLK” port. Type “USER_CLK” in this field and press “Enter”. Do this for both “aurora_mgt_0″ and “aurora_mgt_1″.
  6. For “aurora_mgt_0″ ONLY, click on the “Net” field for the “HARD_ERROR” port. Type “HARD_ERROR” 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. For “aurora_mgt_0″ ONLY, click on the “Net” field for the “SOFT_ERROR” port. Type “SOFT_ERROR” 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. For “aurora_mgt_0″ ONLY, click on the “Net” field for the “LANE_UP” port. Type “LANE_UP” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External” and press “Enter”. The ports should now look as shown in the image below.
  9. For “aurora_mgt_0″ ONLY, click on the “Net” field for the “CHANNEL_UP” port. Type “CHANNEL_UP” in this field and press “Enter”. Now click again the same field and open the drop down menu. Select “Make External” and press “Enter”.
  10. Click on the “Addresses” filter. Change the “Size” for “aurora_mgt_0″ and “aurora_mgt_1″ to 64K. Then click “Generate Addresses”.

Now we have two instances of the Aurora peripheral in the project. Both Aurora peripherals have status outputs (CHANNEL_UP, HARD_ERROR, SOFT_ERROR and LANE_UP) which we would like to connect to the LEDs. We only externalized those ports for the “aurora_mgt_0″ peripheral because we only have 4 LEDs to use on the XUPV2P board. As we are going to connect the Aurora peripherals to each other with a loop-back SATA cable, the status outputs of both peripherals should be the same anyway.

Modify the UCF Constraints File
Now we must add some lines to the project’s .ucf file to tell XPS: (1) which physical RocketIO MGT to use, (2) where the external reference clock pins are, (3) the frequency or period of the reference clock, and (4) where the external LED pins are to connect our status outputs.

  1. Click on the “Project” tab and double-click on “UCF File: data/system.ucf” from within the “Project Files” tree. The .ucf file should open.
  2. Insert the following code at the end of the .ucf file.
##### Timing Contraints for the MGT Recovered clock ######

NET aurora_mgt_0/aurora_mgt_0/USER_LOGIC_I/aurora_module_i/lane_0_mgt_i/RXRECCLK PERIOD=75 MHz;
NET aurora_mgt_1/aurora_mgt_1/USER_LOGIC_I/aurora_module_i/lane_0_mgt_i/RXRECCLK PERIOD=75 MHz;

##### Timing Contraints for the MGT reference clock ######

NET USER_CLK PERIOD = 75 MHz;
NET TOP_BREF_CLK PERIOD = 75 MHz;

###### Connect the external MGT clock inputs #######

NET TOP_BREF_CLK_P_pin LOC=F16;
NET TOP_BREF_CLK_P_pin IOSTANDARD = LVDS_25;
NET TOP_BREF_CLK_N_pin LOC=G16;
NET TOP_BREF_CLK_N_pin IOSTANDARD = LVDS_25;

###### MGT Locations #######

# X0Y1 (SATA 0 HOST) aurora_mgt_0
INST aurora_mgt_0/aurora_mgt_0/USER_LOGIC_I/aurora_module_i/lane_0_mgt_i LOC=GT_X0Y1;
# X1Y1 (SATA 1 TARGET) aurora_mgt_1
INST aurora_mgt_1/aurora_mgt_1/USER_LOGIC_I/aurora_module_i/lane_0_mgt_i LOC=GT_X1Y1;

###### Connect LEDs to the Aurora Status outputs ########

# LED 0
NET CHANNEL_UP_pin LOC = AC4;
Net CHANNEL_UP_pin IOSTANDARD = LVTTL;
Net CHANNEL_UP_pin SLEW = SLOW;
Net CHANNEL_UP_pin DRIVE = 12;
# LED 1
NET HARD_ERROR_pin LOC = AC3;   
Net HARD_ERROR_pin IOSTANDARD = LVTTL;
Net HARD_ERROR_pin SLEW = SLOW;
Net HARD_ERROR_pin DRIVE = 12;
# LED 2
NET SOFT_ERROR_pin LOC = AA6;   
Net SOFT_ERROR_pin IOSTANDARD = LVTTL;
Net SOFT_ERROR_pin SLEW = SLOW;
Net SOFT_ERROR_pin DRIVE = 12;
# LED 3
NET LANE_UP_pin LOC = AA5;   
Net LANE_UP_pin IOSTANDARD = LVTTL;
Net LANE_UP_pin SLEW = SLOW;
Net LANE_UP_pin DRIVE = 12;
  1. Save and close the file.

Modify the Software Application
Now all we need to do is modify the software application to test our Aurora peripherals.

  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"
#include "aurora_mgt.h"

Xuint32 *aurora_mgt_0_baseaddr_p = 
                  (Xuint32 *) XPAR_AURORA_MGT_0_BASEADDR;
Xuint32 *aurora_mgt_1_baseaddr_p = 
                  (Xuint32 *) XPAR_AURORA_MGT_1_BASEADDR;
Xuint32 aurora_mgt_0_baseaddr;
Xuint32 aurora_mgt_1_baseaddr;

int main (void)
{
  Xuint32 i;
  Xuint32 data[10];
  Xuint32 temp;

  // Check that the Aurora peripherals exist
  XASSERT_NONVOID(aurora_mgt_0_baseaddr_p != XNULL);
  aurora_mgt_0_baseaddr = (Xuint32) aurora_mgt_0_baseaddr_p;
  XASSERT_NONVOID(aurora_mgt_1_baseaddr_p != XNULL);
  aurora_mgt_1_baseaddr = (Xuint32) aurora_mgt_1_baseaddr_p;

  // Reset read and write FIFOs to initial state
  AURORA_MGT_mResetWriteFIFO(aurora_mgt_0_baseaddr);
  AURORA_MGT_mResetReadFIFO(aurora_mgt_0_baseaddr);
  AURORA_MGT_mResetWriteFIFO(aurora_mgt_1_baseaddr);
  AURORA_MGT_mResetReadFIFO(aurora_mgt_1_baseaddr);

  // Clear screen
  xil_printf("%c[2J",27);

  xil_printf("Test 1: Transmit data from ");
  xil_printf("AURORA_MGT_0 to AURORA_MGT_1\n\r");
  xil_printf("---------------------------");
  xil_printf("----------------------------\n\r");

  // set data for transmission
  data[0] = (Xuint32) 0x0123;
  data[1] = (Xuint32) 0x4567;
  data[2] = (Xuint32) 0x89AB;
  data[3] = (Xuint32) 0xCDEF;
  data[4] = (Xuint32) 0x0123;
  data[5] = (Xuint32) 0x4567;
  data[6] = (Xuint32) 0x89AB;
  data[7] = (Xuint32) 0xCDEF;
  data[8] = (Xuint32) 0x0123;
  data[9] = (Xuint32) 0x4567;

  // Push data to write packet FIFO
  xil_printf("  Writing data to the AURORA_MGT_0 peripheral:");
  xil_printf("\n\r    ");
  for(i = 0; i < 10; i++){
    xil_printf("0x%04x ", data[i]);
    AURORA_MGT_mWriteToFIFO(aurora_mgt_0_baseaddr, data[i]);
  }

  // pop data out from read packet FIFO
  xil_printf("\n\r\n\r  ");
  xil_printf("Reading data from the AURORA_MGT_1 peripheral:");
  xil_printf("\n\r    ");
  while(!AURORA_MGT_mReadFIFOEmpty(aurora_mgt_1_baseaddr)){
    temp = AURORA_MGT_mReadFromFIFO(aurora_mgt_1_baseaddr);
    xil_printf("0x%04x ", temp);
  }

  xil_printf("\n\r\n\rTest 2: Transmit text from ");
  xil_printf("AURORA_MGT_1 to AURORA_MGT_0\n\r");
  xil_printf("----------------------------");
  xil_printf("---------------------------\n\r");

  // set data for transmission
  data[0] = (Xuint32) 'H';
  data[1] = (Xuint32) 'e';
  data[2] = (Xuint32) 'l';
  data[3] = (Xuint32) 'l';
  data[4] = (Xuint32) 'o';
  data[5] = (Xuint32) ' ';
  data[6] = (Xuint32) 'M';
  data[7] = (Xuint32) 'G';
  data[8] = (Xuint32) 'T';
  data[9] = (Xuint32) '!';

  // Push data to write packet FIFO
  xil_printf("  Writing data to the AURORA_MGT_1 peripheral:");
  xil_printf("\n\r    ");
  for(i = 0; i < 10; i++){
    xil_printf("%c ", data[i]);
    AURORA_MGT_mWriteToFIFO(aurora_mgt_1_baseaddr, data[i]);
  }

  // pop data out from read packet FIFO
  xil_printf("\n\r\n\r  ");
  xil_printf("Reading data from the AURORA_MGT_0 peripheral:");
  xil_printf("\n\r    ");
  while(!AURORA_MGT_mReadFIFOEmpty(aurora_mgt_0_baseaddr)){
    temp = AURORA_MGT_mReadFromFIFO(aurora_mgt_0_baseaddr);
    xil_printf("%c ", temp);
  }

  xil_printf("\n\r\n\r");

  while(1){
  }
}
  1. Save and close the file.

Download and Test the Project

  1. Open a Hyperterminal window with the required settings. For the correct settings, see Hyperterminal Settings.
  2. Connect a SATA cable between the SATA connectors “SATA 0 HOST” and “SATA 1 TARGET” on the XUPV2P board. Note: Never connect a standard SATA cable between “SATA 0 HOST” and “SATA 2 HOST” because this would short together two MGT transmit outputs. In other words, only connect “HOST” to “TARGET”, never “HOST” to “HOST”.
  3. Turn on the XUPV2P board.
  4. From the XPS software, select “Device Configuration->Download Bitstream”.

The Hyperterminal output will show the results of two data transfer tests between “aurora_mgt_0″ and “aurora_mgt_1″. In the first test we transfer arbitrary data from “aurora_mgt_0″ to “aurora_mgt_1″. In the second test we transfer text from “aurora_mgt_1″ to “aurora_mgt_0″. The Hyperterminal output should look as shown in the image below:


The LEDs should display the status outputs: LED 0 – CHANNEL_UP, LED 1 – HARD_ERROR, LED 2 – SOFT_ERROR and LED 3 – LANE_UP. Note that due to the wiring of the LEDs on the XUPV2P, a logic high (“1″) turns the LED OFF, while a logic low (“0″) turns the LED ON. Try disconnecting the SATA cable and see how the status outputs change. The CHANNEL_UP and LANE_UP LEDs should turn ON. If we re-connect the SATA cable, the channel should be re-established and the CHANNEL_UP and LANE_UP LEDs should turn OFF.

The data rate of our MGT in this example is 1.5Gbps because we are using a reference clock of 75MHz which gets multiplied by 20. The effective data rate however would be much less than that because our data comes from the PowerPC. The PowerPC must send data to the Aurora peripheral through the OPB which uses a clock of 100MHz. The best way to make full use of the 1.5Gbps bandwidth is to source the data from the FPGA fabric or another high-speed interface. If however we must source our data from the PowerPC, we could improve this design by connecting the Aurora peripheral through the PLB and using Direct Memory Access (DMA) transfers. This improved version of the Aurora peripheral is developed in the next tutorial Aurora Transceiver for the PLB.

Overview

In this tutorial we will use a RocketIO MGT for possibly its simplest application, a programmable oscillator. This can be achieved by feeding the MGT with a repetitive data pattern (e.g. “10101010101010101010″). By changing the data pattern we can adjust the output frequency and duty cycle.

Figure: The Oscillator peripheral

–>

The diagram above illustrates the oscillator peripheral. In it we use 4 registers to store a 4 x 32 bit repeating pattern to be fed to the RocketIO primitive (GT_CUSTOM). Note that we could have used any number of registers to store the pattern. In our user_logic.vhd file we instantiate the GT_CUSTOM and create a counter which we use for loading the GT_CUSTOM. The counter counts from 1 to 4 and each time it loads the corresponding register contents into the GT_CUSTOM for transmission.

We will also create a Digital Clock Manager (DCM) peripheral to generate the reference clocks for the RocketIO MGT. The DCM peripheral will only contain two clock buffers and will not require registers or FIFOs.

In our design, the GT_CUSTOM is configured for a width of 2 bytes and the 8b10b encoder/decoder is bypassed, so our data width is 10 x 2 = 20 bits. The registers in our peripheral are 32 bits wide, chosen to be the same width as the OPB data bus. Because of this mismatch, we don’t use all the bits in the registers. Instead, we only use the 20 least significant bits of each register.

This tutorial contains screenshots to guide you through the entire implementation process. You can click on the images to view a higher resolution when necessary.

Requirements

Apart from the obvious requirements (XPS software and XUPV2P board) this project requires the following:

  1. SMA Connectors: To be able to verify the oscillator output, you will need to install SMA connectors at J19 and J20 of your XUPV2P board.
  2. Two coaxial cables: To connect the oscillator output to an oscilloscope, two SMA coaxial cables are required.

Create the Basic Project

Follow these steps to create the basic project:

  1. Open XPS and from the dialog box, select “Base System Builder wizard” and OK.
  2. Create a new folder for the project and select it using “Browse”. In “Advanced Options” tick “Use repository paths” and select the “C:\XUPV2P\lib” folder using “Browse”. Click “OK”.
  3. Tick “I would like to create a new design” and click “Next”.
  4. Select “Xilinx” as the board vendor. Select “XUP Virtex II Pro Development System” as the board name. Select “C” as the board revision. Click “Next”.
  5. Tick “PowerPC” and click “Next”.
  6. Select all clock frequencies to be 100MHz. Select “No debug”. Click “Next”.
  7. In selecting the Additional IO Interfaces, tick “onewire_0″ and “RS232_Uart_1″. Untick everything else. We will not actually use the “onewire_0″ interface in this project, but leaving it in has shown to be important. For an explanation, refer to “The Onewire Problem” on the Known Issues page.



  8. When Adding Internal Peripherals, select 64KB for the “plb_bram_if_cntlr_1″ and click “Next”.
  9. Select “RS232_Uart_1″ for both STDIN and STDOUT. Un-tick “Memory Test” and leave “Peripheral Test” ticked. Click “Next”.
  10. On the “Configure Peripheral Test Application” page, select “plb_bram_if_cntlr_1″ for the Instruction, Data, Stack and Heap memories. Click “Next”.
  11. Click “Generate”.
  12. Click “Finish”.
  13. Tick “Start using Platform Studio” and click “OK”.

Create the DCM Peripheral

Follow these steps to create the DCM peripheral:

  1. Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
  2. Select “Create templates for a new peripheral” and click “Next”.
  3. Select “To an XPS project” and click “Next”.
  4. Type “mgt_dcm” for the peripheral name. Click “Next”.
  5. Select “On-chip Peripheral Bus” (OPB) and click “Next”.
  6. The DCM peripheral is very simple and doesn’t need interrupts, registers or FIFOs. Un-tick everything and click “Next”.
  7. On the “IP Interconnect” page, leave everything as is. Click “Next”.
  8. On the “Peripheral Simulation Support” page, 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.

Modify the DCM Peripheral

Now we will add code in our peripheral template to instantiate two clock buffers that will generate the clock sources REF_CLK and USER_CLK for the RocketIO MGTs. This DCM example originates from the Xilinx RocketIO Transceiver User Guide (ug024), see section “Digital Clock Manager (DCM) Examples”.

  1. Select from the menu “File->Open” and from the project folder, browse to “pcores\mgt_dcm_v1_00_a\hdl\vhdl”.
  2. Open the file “mgt_dcm.vhd”.
  3. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK_P : in std_logic;
  TOP_BREF_CLK_N : in std_logic;
  TOP_BREF_CLK   : out std_logic;
  USER_CLK       : 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.
  TOP_BREF_CLK_P => TOP_BREF_CLK_P,
  TOP_BREF_CLK_N => TOP_BREF_CLK_N,
  TOP_BREF_CLK => TOP_BREF_CLK,
  USER_CLK => USER_CLK,
  1. Save and close the file.
  2. Select from the menu “File->Open” and from the project folder, browse to “pcores\mgt_dcm_v1_00_a\hdl\vhdl”.
  3. Open the file “user_logic.vhd”.
  4. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK_P : in std_logic;
  TOP_BREF_CLK_N : in std_logic;
  TOP_BREF_CLK   : out std_logic;
  USER_CLK       : 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 IBUFGDS_LVDS_25
  port(
    O  : out std_ulogic;
    I  : in  std_ulogic;
    IB : in  std_ulogic
  );
end component;

component BUFG
  port(
    O : out std_ulogic;
    I : in  std_ulogic
  );
end component;

signal top_bref_clk_i : std_logic;
signal user_clk_i  : std_logic;
  1. Find the line of code that says “–USER logic implementation added here” and add the following lines of code just below.
-- Differential Clock Buffer for top BREF_CLK
diff_clk_buff_top_i : IBUFGDS_LVDS_25
  port map(
    I  => TOP_BREF_CLK_P,
    IB => TOP_BREF_CLK_N,
    O  => top_bref_clk_i
  );

-- BUFG used to drive USER_CLK on global clock net
user_clock_bufg_i : BUFG
  port map(
    I => top_bref_clk_i,
    O => user_clk_i
  );

TOP_BREF_CLK <= top_bref_clk_i;
USER_CLK <= user_clk_i;
  1. Save and close the file.

Import the DCM Peripheral

Now we will use the Peripheral Wizard to import the DCM peripheral.

  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 “mgt_dcm”. 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\mgt_dcm_v1_00_a\data” and select the “mgt_dcm_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 “OPB Slave” and click “Next”.
  9. On the SOPB: Port page, click “Next”.
  10. On the SOPB: Parameter page, click “Next”.
  11. On the “Identify Interrupt Signals” page, un-tick “Select and configure interrupt(s)” and click “Next”.
  12. On the “Parameter Attributes” page, click “Next”.
  13. On the “Port Attributes” page, click “Next”.
  14. Click “Finish”.

The DCM peripheral should now be accessible through the “IP Catalog->Project Repository” in the XPS interface.

Create an Instance of the DCM Peripheral

Follow these steps to create an instance of the peripheral in the project.

  1. From the “IP Catalog” find the “mgt_dcm” IP core in the “Project Repository” group. Right click on the core and select “Add IP”.
  2. From the “System Assembly View” using the “Bus Interface” filter, connect the “mgt_dcm_0″ to the OPB bus.
  3. Click on the “Ports” filter. Click on the “+” for “mgt_dcm_0″ to view its ports.
  4. Click on the “Net” field for the “TOP_BREF_CLK_P” port. Type “TOP_BREF_CLK_P” 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 “TOP_BREF_CLK_N” port. Type “TOP_BREF_CLK_N” 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 “TOP_BREF_CLK” port. Type “TOP_BREF_CLK” in this field and press “Enter”.
  7. Click on the “Net” field for the “USER_CLK” port. Type “USER_CLK” in this field and press “Enter”. The result should look like the image below.
  8. Now if you click the “+” for “External Ports”, you should be able to find the two ports “TOP_BREF_CLK_P_pin” and “TOP_BREF_CLK_N_pin”, with nets called “TOP_BREF_CLK_P” and “TOP_BREF_CLK_N” respectively.
  9. Click on the “Addresses” filter. Change the “Size” for “mgt_dcm_0″ to 64K. Then click “Generate Addresses”.

Now we have an instance of the DCM peripheral in the project. The single DCM peripheral will supply the reference clock to all the MGTs accessible on the XUPV2P board.

Create the Oscillator Peripheral

Follow these steps to create the Oscillator peripheral.

  1. Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
  2. Select “Create templates for a new peripheral” and click “Next”.
  3. Select “To an XPS project” and click “Next”.
  4. Type “oscillator” for the peripheral name. Click “Next”.
  5. Select “On-chip Peripheral Bus” (OPB) and click “Next”.
  6. Tick “User logic S/W register support”, un-tick everything else and click “Next”.
  7. Choose “4″ for the number of software accessible registers. Choose 32-bits for the size of the registers.
  8. On the “IP Interconnect” page leave everything as is. Click “Next”.
  9. On the “Peripheral Simulation Support” page, click “Next” without ticking the option to generate.
  10. After the “Peripheral Implementation Support” page, tick “Generate ISE and XST project files” and “Generate template driver files”. Click “Next”.
  11. Click “Finish”. Now our templates are created.

Modify the Oscillator Peripheral

Now we will add code in our peripheral template to instantiate a RocketIO primitive called GT_CUSTOM and set it up as an oscillator.

  1. Select from the menu “File->Open” and from the project folder, browse to “pcores\oscillator_v1_00_a\hdl\vhdl”.
  2. Open the file “oscillator.vhd”.
  3. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK   : in std_logic;
  USER_CLK       : in std_logic;
  RXP            : in std_logic;
  RXN            : in std_logic;
  TXP            : out std_logic;
  TXN            : 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.
  TOP_BREF_CLK => TOP_BREF_CLK,
  USER_CLK => USER_CLK,
  RXP => RXP,
  RXN => RXN,
  TXP => TXP,
  TXN => TXN,
  1. Save and close the file.
  2. Select from the menu “File->Open” and browse from the project folder to “pcores\oscillator_v1_00_a\hdl\vhdl”.
  3. Open the file “user_logic.vhd”. We will need to modify this source code to instantiate the GT_CUSTOM and connect it as an oscillator.
  4. Find the line of code that says “– ADD USER PORTS BELOW THIS LINE” and add the following lines of code just below.
  TOP_BREF_CLK   : in std_logic;
  USER_CLK       : in std_logic;
  RXP            : in std_logic;
  RXN            : in std_logic;
  TXP            : out std_logic;
  TXN            : 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.
signal mgt_txdata : std_logic_vector(19 downto 0);
signal count      : std_logic_vector(3 downto 0);

component GT_CUSTOM
   generic(
     REF_CLK_V_SEL : integer);
   port(
     CHBONDDONE     : out std_logic;
     CHBONDO        : out std_logic_vector(3 downto 0);
     CONFIGOUT      : out std_logic;
     RXBUFSTATUS    : out std_logic_vector(1 downto 0);
     RXCHARISCOMMA  : out std_logic_vector(3 downto 0);
     RXCHARISK      : out std_logic_vector(3 downto 0);
     RXCHECKINGCRC  : out std_logic;
     RXCLKCORCNT    : out std_logic_vector(2 downto 0);
     RXCOMMADET     : out std_logic;
     RXCRCERR       : out std_logic;
     RXDATA         : out std_logic_vector(31 downto 0);
     RXDISPERR      : out std_logic_vector(3 downto 0);
     RXLOSSOFSYNC   : out std_logic_vector(1 downto 0);
     RXNOTINTABLE   : out std_logic_vector(3 downto 0);
     RXREALIGN      : out std_logic;
     RXRECCLK       : out std_logic;
     RXRUNDISP      : out std_logic_vector(3 downto 0);
     TXBUFERR       : out std_logic;
     TXKERR         : out std_logic_vector(3 downto 0);
     TXN            : out std_logic;
     TXP            : out std_logic;
     TXRUNDISP      : out std_logic_vector(3 downto 0);
     BREFCLK        : in std_logic;
     BREFCLK2       : in std_logic;
     CHBONDI        : in std_logic_vector(3 downto 0);
     CONFIGENABLE   : in std_logic;
     CONFIGIN       : in std_logic;
     ENCHANSYNC     : in std_logic;
     ENMCOMMAALIGN  : in std_logic;
     ENPCOMMAALIGN  : in std_logic;
     LOOPBACK       : in std_logic_vector(1 downto 0);
     POWERDOWN      : in std_logic;
     REFCLK         : in std_logic;
     REFCLK2        : in std_logic;
     REFCLKSEL      : in std_logic;
     RXN            : in std_logic;
     RXP            : in std_logic;
     RXPOLARITY     : in std_logic;
     RXRESET        : in std_logic;
     RXUSRCLK       : in std_logic;
     RXUSRCLK2      : in std_logic;
     TXBYPASS8B10B  : in std_logic_vector(3 downto 0);
     TXCHARDISPMODE : in std_logic_vector(3 downto 0);
     TXCHARDISPVAL  : in std_logic_vector(3 downto 0);
     TXCHARISK      : in std_logic_vector(3 downto 0);
     TXDATA         : in std_logic_vector(31 downto 0);
     TXFORCECRCERR  : in std_logic;
     TXINHIBIT      : in std_logic;
     TXPOLARITY     : in std_logic;
     TXRESET        : in std_logic;
     TXUSRCLK       : in std_logic;
     TXUSRCLK2      : in std_logic);
end component;
  1. Find the line of code that says “–USER logic implementation added here” and add the following lines of code just below.
rock0 : GT_CUSTOM
  generic map(
    REF_CLK_V_SEL              => 1)
  port map(
    CHBONDDONE                 => open,
    CHBONDI                    => "0000",
    CHBONDO                    => open,
    CONFIGENABLE               => '0',
    CONFIGIN                   => '0',
    CONFIGOUT                  => open,
    ENCHANSYNC                 => '0',
    ENMCOMMAALIGN              => '0',
    ENPCOMMAALIGN              => '0',
    LOOPBACK                   => "00",
    POWERDOWN                  => '0',
    BREFCLK                    => TOP_BREF_CLK,
    BREFCLK2                   => '0',
    REFCLK                     => '0',
    REFCLK2                    => '0',
    REFCLKSEL                  => '0',
    RXBUFSTATUS                => open,
    RXCHARISCOMMA              => open,
    RXCHARISK                  => open,
    RXCHECKINGCRC              => open,
    RXCLKCORCNT                => open,
    RXCOMMADET                 => open,
    RXCRCERR                   => open,
    RXDATA                     => open,
    RXDISPERR                  => open,
    RXLOSSOFSYNC               => open,
    RXN                        => RXN,
    RXNOTINTABLE               => open,
    RXP                        => RXP,
    RXPOLARITY                 => '0',
    RXREALIGN                  => open,
    RXRECCLK                   => open,
    RXRESET                    => '0',
    RXRUNDISP                  => open,
    RXUSRCLK                   => '0',
    RXUSRCLK2                  => '0',
    TXBUFERR                   => open,
    TXBYPASS8B10B              => "1111",
    TXCHARDISPMODE(3 downto 2) => "00",
    TXCHARDISPMODE(1)          => mgt_txdata(19),
    TXCHARDISPMODE(0)          => mgt_txdata(9),
    TXCHARDISPVAL(3 downto 2)  => "00",
    TXCHARDISPVAL(1)           => mgt_txdata(18),
    TXCHARDISPVAL(0)           => mgt_txdata(8),
    TXCHARISK(3 downto 2)      => "00",
    TXCHARISK(1 downto 0)      => "00",
    TXDATA(31 downto 16)       => "0000000000000000",
    TXDATA(15 downto 8)        => mgt_txdata(17 downto 10),
    TXDATA(7 downto 0)         => mgt_txdata(7 downto 0),
    TXFORCECRCERR              => '0',
    TXINHIBIT                  => '0',
    TXKERR                     => open,
    TXN                        => TXN,
    TXP                        => TXP,
    TXPOLARITY                 => '0',
    TXRESET                    => Bus2IP_Reset,
    TXRUNDISP                  => open,
    TXUSRCLK                   => USER_CLK,
    TXUSRCLK2                  => USER_CLK);

-- This process manages a counter and feeds the MGT
-- with data from the slave registers  
process (USER_CLK, Bus2IP_Reset)
begin
  if Bus2IP_Reset = '1' then
    mgt_txdata <= (others => '0');
    count <= (others => '0');
  elsif USER_CLK'event and USER_CLK = '1' then
    if count = "0011" then
      count <= (others => '0');
    else
      count <= count + 1;     end if;     case count is        when "0000" => mgt_txdata <= slv_reg0(12 to 31);       when "0001" => mgt_txdata <= slv_reg1(12 to 31);       when "0010" => mgt_txdata <= slv_reg2(12 to 31);       when others => mgt_txdata <= slv_reg3(12 to 31);
    end case;
  end if;
end process;
  1. Save and close the file.

Import the Oscillator Peripheral

Now we will use the Peripheral Wizard in Import mode.

  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 “oscillator”. 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\oscillator_v1_00_a\data” and select the “oscillator_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 “OPB Slave” and click “Next”.
  9. On the SOPB: Port page, click “Next”.
  10. On the SOPB: Parameter page, click “Next”.
  11. On the “Identify Interrupt Signals” page, un-tick “Select and configure interrupt(s)” and click “Next”.
  12. On the “Parameter Attributes” page, click “Next”.
  13. On the “Port Attributes” page, click “Next”.
  14. Click “Finish”.

The oscillator peripheral should now be accessible through the “IP Catalog->Project Repository” in the XPS interface.

Create an Instance of the Oscillator Peripheral

Follow these steps to create an instance of the peripheral in the project.

  1. From the “IP Catalog” find the “oscillator” IP core in the “Project Repository” group. Right click on the core and select “Add IP”.
  2. From the “System Assembly View” using the “Bus Interface” filter, connect the “oscillator_0″ to the OPB bus.
  3. Click on the “Ports” filter. Click on the “+” for “oscillator_0″ to view its ports.
  4. Click on the “Net” field for the “TOP_BREF_CLK” port. Type “TOP_BREF_CLK” in this field and press “Enter”.
  5. Click on the “Net” field for the “USER_CLK” port. Type “USER_CLK” in this field and press “Enter”. The ports should look as shown in the screen shot below.
  6. Click on the “Addresses” filter. Change the “Size” for “oscillator_0″ to 64K. Then click “Generate Addresses”.

We have now made an instantiation of the oscillator peripheral in our design.

Modify the UCF Constraints File

Now we must add some lines to the project’s .ucf file to tell XPS: (1) which physical RocketIO MGT to use, (2) where the external reference clock pins are, and (3) the frequency or period of the reference clock.

  1. Click on the “Project” tab and double-click on “UCF File: data/system.ucf” from within the “Project Files” tree. The .ucf file should open.
  2. Insert the following code at the end of the .ucf file.
#Clock constraints
NET USER_CLK PERIOD = 75 MHz;
NET TOP_BREF_CLK PERIOD = 75 MHz;

#Reference clock pin locations
NET TOP_BREF_CLK_P_pin LOC = F16;
NET TOP_BREF_CLK_N_pin LOC = G16;
NET TOP_BREF_CLK_P_pin IOSTANDARD = LVDS_25;
NET TOP_BREF_CLK_N_pin IOSTANDARD = LVDS_25;

# SATA0 HOST - GT_X0Y1
# SATA1 TARGET - GT_X1Y1
# SATA2 HOST - GT_X2Y1
# SMA connectors - GT_X3Y1

# Place oscillator at SMA (REFCLK)
INST oscillator_0/oscillator_0/USER_LOGIC_I/rock0 LOC=GT_X3Y1;
  1. Save and close the file.

Modify the Software Application

Now all we need to do is modify the software application to test our oscillator 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 "oscillator.h"

// Pointer to the peripheral
Xuint32 *oscillator_0_baseaddr_p =
                     (Xuint32 *) XPAR_OSCILLATOR_0_BASEADDR;

// Base address of the peripheral
Xuint32 oscillator_0_baseaddr;

int main (void)
{
  // Check that the oscillator exists
  XASSERT_NONVOID(oscillator_0_baseaddr_p != XNULL);
  oscillator_0_baseaddr = (Xuint32) oscillator_0_baseaddr_p;

  // Write the data pattern to the slave registers
  OSCILLATOR_mWriteSlaveReg0(oscillator_0_baseaddr,0xAAAAA);
  OSCILLATOR_mWriteSlaveReg1(oscillator_0_baseaddr,0xAAAAA);
  OSCILLATOR_mWriteSlaveReg2(oscillator_0_baseaddr,0xAAAAA);
  OSCILLATOR_mWriteSlaveReg3(oscillator_0_baseaddr,0xAAAAA);

  xil_printf("\n\rOscillator running\n\r");

  while(1){}

  return(0);
}
  1. From the menu select “Device Configuration->Download Bitstream”.

The data rate of our MGT in this example is 1.5Gbps because we are using a reference clock of 75MHz which gets multiplied by 20. The code in this example loads the slave registers with a “10101010101010101010″ (0xAAAAA) data pattern. This will produce an oscillator output of 750MHz with a 50% duty cycle. If we changed the pattern to “11001100110011001100″ (0xCCCCC) then we would have an oscillator output of 375MHz with a 50% duty cycle.

Before the FPGA is programmed, make sure you have a Hyperterminal window opened so that you don’t miss the debug output. When the project runs, it sends the message “Oscillator running” to Hyperterminal so that you know that the slave registers have been loaded. You can then check the oscillator output at J19 and J20 on the XUPV2P board by connecting them to an oscilloscope by coaxial cables.

Please note that although this connection will not do any harm to your board, it does not provide the correct termination required by the CML outputs of the RocketIO MGTs. CML outputs require a 50 ohm termination to VCC whereas a typical oscilloscope provides a termination of 50 ohms to ground. This would not matter if the SMA connectors were AC-coupled to the MGT pins, but on the XUPV2P board they are in fact DC-coupled.

The project folder for this tutorial can be downloaded in a compressed ZIP file MGTOscillator.zip
. Right-click on the link and select “Save Link As”.

In the next tutorial, Create an Aurora Transceiver, we show how to use the RocketIO MGTs to create a high speed serial communications link between two FPGAs.

Tagged with:  

RocketIO FAQ

On February 13, 2008, in General FPGA, by Jeff

RocketIO Tutorials

Here is a list of our tutorials related to RocketIO multi-gigabit transceivers:

RocketIO Frequently Asked Questions

Here is a list of common questions about RocketIO:

What is the best way to get started developing with the RocketIOs?

The RocketIOs are very sophisticated devices and require a lot of time to understand and integrate into your designs. Fortunately, Xilinx provides many tools and examples to help you get developing faster. Here are our suggestions:

  • Download the Aurora IP core from the Xilinx website. When you generate the Aurora IP core using CORE Generator, a working example with documentation is also generated.
  • If you want to implement your own protocol, generate the GTP wrapper using CORE Generator. The GTP wrapper provides a working example and documentation.

You might also find our tutorials helpful.

Are the RocketIO MGTs on the Virtex-II Pro compatible with the SATA standard? Can the SATA protocol be implemented on the RocketIOs?

According to Xilinx technical support, the answer is NO. The RocketIO MGTs do not fully comply with the SATA standard. This however has not stopped people from trying it anyway. Here are some references: