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:
- 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.
- 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:
- Open XPS and from the dialog box, select “Base System Builder wizard” and OK.
- 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”.
- Tick “I would like to create a new design” and click “Next”.
- 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”. - Tick “PowerPC” and click “Next”.
- Select all clock frequencies to be 100MHz. Select “No debug”. Click “Next”.
- In selecting the Additional IO Interfaces, tick
onewire_0
andRS232_Uart_1
. Untick everything else. We will not actually use theonewire_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. - When Adding Internal Peripherals, select 64KB for the
plb_bram_if_cntlr_1
and click “Next”. - Select
RS232_Uart_1
for both STDIN and STDOUT. Un-tick “Memory Test” and leave “Peripheral Test” ticked. Click “Next”. - On the “Configure Peripheral Test Application” page, select
plb_bram_if_cntlr_1
for the Instruction, Data, Stack and Heap memories. Click “Next”. - Click “Generate”.
- Click “Finish”.
- Tick “Start using Platform Studio” and click “OK”.
Create the DCM Peripheral
Follow these steps to create the DCM peripheral:
- Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
- Select “Create templates for a new peripheral” and click “Next”.
- Select “To an XPS project” and click “Next”.
- Type
mgt_dcm
for the peripheral name. Click “Next”. - Select “On-chip Peripheral Bus” (OPB) and click “Next”.
- The DCM peripheral is very simple and doesn’t need interrupts, registers or FIFOs. Un-tick everything and click “Next”.
- On the “IP Interconnect” page, leave everything as is. Click “Next”.
- On the “Peripheral Simulation Support” page, click “Next” without ticking the option to generate.
- 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”.
- 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”.
- Select from the menu “File->Open” and from the project folder, browse to
pcores\mgt_dcm_v1_00_a\hdl\vhdl
. - Open the file
mgt_dcm.vhd
. - 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;
- 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,
- Save and close the file.
- Select from the menu “File->Open” and from the project folder, browse to
pcores\mgt_dcm_v1_00_a\hdl\vhdl
. - Open the file
user_logic.vhd
. - 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;
- 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;
- 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;
- Save and close the file.
Import the DCM Peripheral
Now we will use the Peripheral Wizard to import the DCM peripheral.
- Select from the menu “Hardware->Create or Import Peripheral” and click “Next”.
- Select “Import existing peripheral” and click “Next”.
- Select “To an XPS project”, ensure that the folder chosen is the project folder, and click “Next”.
- 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”. - Tick “HDL source files” and click “Next”.
- 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 themgt_dcm_v2_1_0.pao
file. Click “Next”. - On the HDL analysis information page, click “Next”. The wizard will mention if any errors are found in the design.
- On the Bus Interfaces page, tick “OPB Slave” and click “Next”.
- On the SOPB: Port page, click “Next”.
- On the SOPB: Parameter page, click “Next”.
- On the “Identify Interrupt Signals” page, un-tick “Select and configure interrupt(s)” and click “Next”.
- On the “Parameter Attributes” page, click “Next”.
- On the “Port Attributes” page, click “Next”.
- 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.
- From the “IP Catalog” find the
mgt_dcm
IP core in the “Project Repository” group. Right click on the core and select “Add IP”. - From the “System Assembly View” using the “Bus Interface” filter, connect the
mgt_dcm_0
to the OPB bus. - Click on the “Ports” filter. Click on the “+” for
mgt_dcm_0
to view its ports. - Click on the “Net” field for the
TOP_BREF_CLK_P
port. TypeTOP_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”. - Click on the “Net” field for the
TOP_BREF_CLK_N
port. TypeTOP_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”. - Click on the “Net” field for the
TOP_BREF_CLK
port. TypeTOP_BREF_CLK
in this field and press “Enter”. - Click on the “Net” field for the
USER_CLK
port. TypeUSER_CLK
in this field and press “Enter”. The result should look like the image below. - Now if you click the “+” for “External Ports”, you should be able to find the two ports
TOP_BREF_CLK_P_pin
andTOP_BREF_CLK_N_pin
, with nets calledTOP_BREF_CLK_P
andTOP_BREF_CLK_N
respectively. - 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.
- Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
- Select “Create templates for a new peripheral” and click “Next”.
- Select “To an XPS project” and click “Next”.
- Type “oscillator” for the peripheral name. Click “Next”.
- Select “On-chip Peripheral Bus” (OPB) and click “Next”.
- Tick “User logic S/W register support”, un-tick everything else and click “Next”.
- Choose “4” for the number of software accessible registers. Choose 32-bits for the size of the registers.
- On the “IP Interconnect” page leave everything as is. Click “Next”.
- On the “Peripheral Simulation Support” page, click “Next” without ticking the option to generate.
- After the “Peripheral Implementation Support” page, tick “Generate ISE and XST project files” and “Generate template driver files”. Click “Next”.
- 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.
- Select from the menu “File->Open” and from the project folder, browse to
pcores\oscillator_v1_00_a\hdl\vhdl
. - Open the file
oscillator.vhd
. - 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;
- 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,
- Save and close the file.
- Select from the menu “File->Open” and browse from the project folder to
pcores\oscillator_v1_00_a\hdl\vhdl
. - 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. - 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;
- 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;
- 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;
- Save and close the file.
Import the Oscillator Peripheral
Now we will use the Peripheral Wizard in Import mode.
- Select from the menu “Hardware->Create or Import Peripheral” and click “Next”.
- Select “Import existing peripheral” and click “Next”.
- Select “To an XPS project”, ensure that the folder chosen is the project folder, and click “Next”.
- 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”.
- Tick “HDL source files” and click “Next”.
- 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 theoscillator_v2_1_0.pao
file. Click “Next”. - On the HDL analysis information page, click “Next”. The wizard will mention if any errors are found in the design.
- On the Bus Interfaces page, tick “OPB Slave” and click “Next”.
- On the SOPB: Port page, click “Next”.
- On the SOPB: Parameter page, click “Next”.
- On the “Identify Interrupt Signals” page, un-tick “Select and configure interrupt(s)” and click “Next”.
- On the “Parameter Attributes” page, click “Next”.
- On the “Port Attributes” page, click “Next”.
- 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.
- From the “IP Catalog” find the “oscillator” IP core in the “Project Repository” group. Right click on the core and select “Add IP”.
- From the “System Assembly View” using the “Bus Interface” filter, connect the
oscillator_0
to the OPB bus. - Click on the “Ports” filter. Click on the “+” for
oscillator_0
to view its ports. - Click on the “Net” field for the
TOP_BREF_CLK
port. TypeTOP_BREF_CLK
in this field and press “Enter”. - Click on the “Net” field for the
USER_CLK
port. TypeUSER_CLK
in this field and press “Enter”. The ports should look as shown in the screen shot below. - 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.
- 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. - 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;
- 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.
- From the “Applications” tab, open “Sources” within the “Project: TestApp_Peripheral” tree. Open the
TestApp_Peripheral.c
source file. - 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);
}
- 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.