Hardware Details
The Xilinx University Program Virtex-II Pro (XUPV2P) Development System from Digilent is a development board for the Virtex-II Pro FPGA. It contains many useful hardware features including:
- Xilinx Virtex-II Pro XC2VP30 FPGA
- 10/100Mbps Ethernet PHY
- USB port
- Compact Flash card slot
- XSGA Video port
- Audio Codec
- SATA connectors (2 hosts, 1 target)
- PS/2 and RS-232 ports
- High and Low Speed expansion connectors
Virtex-II Pro FPGA Details
The XUPV2P is loaded with a Virtex-II Pro FPGA:
| Board | Virtex-II Pro Version | Package | Speed Grade |
| XUPV2P | XC2VP30 | FF896 | -7C |
For more information, please refer to the Xilinx University Program Virtex-II Pro Development System Hardware Reference Manual.
How to buy it
- The XUPV2P can be purchased through the Xilinx University Program from Digilent at only US$299. Click the Digilent link for more information.
Overview
In this tutorial we will improve on the Timer peripheral developed in Create a Simple Timer Peripheral. The improvement is achieved by enabling the peripheral to generate an interrupt when the timer expires. The PowerPC then processes the interrupt through an interrupt handler function which gets called whenever the interrupt occurs. In this example, the interrupt handler function will switch the state of the LEDs and reset the timer.
The timer will use two registers, one to store the delay period and the other for starting, stopping and checking if the timer has expired. We will call the first register the delay register and the second register the control register. The delay register will be set by the software application to determine how long of a delay it requires. This value will remain in the delay register unchanged and the software application will be able to read this value if for some reason it needs to. The control register will only use the first two bits, being bit 0 and bit 1. Bit 0 will be read-only and will be used by the timer peripheral to signal to the software application that the timer has expired. Bit 1 will be read and writeable, and it will be used by the software application to make the timer “run”. When a “1″ is written to this bit, the timer will start counting down from the delay value. When a “0″ is written to this bit, the timer will reset.
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.
Are you using EDK 10.1?
Try the updated version of this tutorial based on the Virtex-5 FPGA on the ML505 board: Timer with Interrupts
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 “RS232_Uart_1″ and “LEDs_4Bit”. Untick everything else.
- 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 Timer Peripheral
We now create our Timer peripheral using the Peripheral Wizard.
- Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
- Select “Create templates for a new peripheral” and click “Next”.
- 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”.
- Type “my_timer” for the peripheral name. Click “Next”.
- Select “On-chip Peripheral Bus” (OPB) and click “Next”.
- The Peripheral Wizard can generate our VHDL template to include many different features. Tick “User logic interrupt support” and “User logic S/W register support”. Un-tick everything else and click “Next”.
- On the “Interrupt Service” page, leave the defaults and click “Next”.
- Choose “2″ for the number of software accessible registers. Choose 32-bits for the size of the registers, as we will use a 32-bit timer.
- On the “IP Interconnect” page we can customize our connection to the OPB but we will leave everything as is for simplicity. Click “Next”.
- 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.
- 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 and we can modify them to include the code for the timer.
Modify the Timer Peripheral
Now we want to add a timer to this peripheral template and connect it up with the registers that the Peripheral Wizard created for us.
- Select from the menu “File->Open” and look in the project folder.
- Open the folders: “pcores\my_timer_v1_00_a\hdl\vhdl”. This folder contains two source files that describe our peripheral “my_timer.vhd” and “user_logic.vhd”. The first file is the main part of the peripheral and it implements the interface to the OPB. The second file is where we place our custom logic to make the peripheral do what we need it to do. This part is instantiated by the first file.
- Open the file “user_logic.vhd”. We will need to modify this source code to include our timer code.
- Find the line of code that says “–USER signal declarations added here” and add the following lines of code just below.
-- Timer signals and components signal timer_count : std_logic_vector(0 to C_DWIDTH-1); signal timer_expired : std_logic; signal timer_run : std_logic; |
- Find the line of code that says “–USER logic implementation added here” and add the following lines of code just below.
-- Timer connections
timer_run <= slv_reg1(1);
-- Timer process - times the delay between bursts
process (Bus2IP_Clk, Bus2IP_Reset)
begin
-- if the peripheral is told to reset, then reset the timer
if Bus2IP_Reset = '1' then
timer_count <= (others => '0');
timer_expired <= '1';
-- otherwise, if there is a clock event, run the timer
elsif Bus2IP_Clk'event and Bus2IP_Clk = '1' then
-- if the timer is not running, then reset the timer
if timer_run = '0' then
timer_count <= slv_reg0;
timer_expired <= '0';
-- if the timer count is not zero then decrease the count
elsif timer_count /= 0 then
timer_count <= timer_count - 1;
timer_expired <= '0';
-- otherwise, the timer has expired
else
timer_expired <= '1';
end if;
end if;
end process;
-- Interrupt connections
IP2Bus_IntrEvent(0) <= timer_expired;
|
- Find the line of code that says “when “01″ => slv_ip2bus_data <= slv_reg1″ and replace it with the three lines of code below. Now, when the timer control register is read from, bit 0 will represent the timer_expired signal.
when "01" => slv_ip2bus_data(1 to C_DWIDTH-1) <= slv_reg1(1 to C_DWIDTH-1); slv_ip2bus_data(0) <= timer_expired; |
- Now we need to remove the example code that generates interrupts. The peripheral wizard automatically generates some VHDL code to generate interrupts in our “user_logic.vhd” file. As we use the “timer_expired” signal to generate interrupts, we must delete the example code. Comment out or delete all the code between the line “– Example code to generate user logic interrupts” and the line “IP2Bus_IntrEvent <= interrupt;” inclusively.
- Save and close the file.
Import the Timer Peripheral
Now we will use the Peripheral Wizard again, but this time using the import function.
- 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 “my_timer”. 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\my_timer_v1_00_a\data” and select the “my_timer_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, leave the defaults and click “Next”.
- On the “Parameter Attributes” page, click “Next”.
- On the “Port Attributes” page, click “Next”.
- Click “Finish”.
The timer peripheral is now ready to use and it should be accessible through the “IP Catalog->Project Repository” 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 which can then be downloaded into the FPGA and tested by using simple code running on the PowerPC.
- From the “IP Catalog” find the “my_timer” 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 “my_timer_0″ to the OPB bus.
- Click on the “Ports” filter. Click on the “+” for “my_timer_0″ to view its ports.
Click on the “Net” field for the “IP2INTC_Irpt” port. Type “my_timer_irq” in this field and press “Enter”.
- Still within the “Ports” filter, click on the “+” for the “ppc405_0″ to view the PowerPC ports. Click on the “Net” field for the “EICC405EXTINPUTIRQ” port. Type “my_timer_irq” in this field and press “Enter”. This connects the timer interrupt request signal to the interrupt request input of the PowerPC.
- Click on the “Addresses” filter. Change the “Size” for “my_timer_0″ to 64K. Then click “Generate Addresses”.
Now we have created an instance of the Timer peripheral in our design and we have connected its interrupt request signal to the external interrupt request input of the PowerPC. This completes our hardware connections for interrupt capability.
Modify the Software Application
The software application will contain the main program and the interrupt handler function to be called when an interrupt occurs. It must create the interrupt vector table which tells the PowerPC what code to run when an interrupt is generated. It also must enable the Timer peripheral to generate interrupts, and the PowerPC to respond to interrupts.
- 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 "xgpio.h"
#include "xstatus.h"
#include "my_timer.h"
#include "xexception_l.h"
#define TIMER_RESET 0x00000000
#define TIMER_RUN 0x40000000
#define TIMER_EXPIRED 0x80000000
#define TIMER_HALFSEC 0x02FAF080
XGpio GpioOutput;
Xuint32 my_timer;
unsigned int *my_timer_p =
(unsigned int *) XPAR_MY_TIMER_0_BASEADDR;
//----------------------------------------------------
// INTERRUPT HANDLER FUNCTION
//----------------------------------------------------
void MY_TIMER_Intr_Handler(void * baseaddr_p)
{
static Xuint32 led_data;
Xuint32 baseaddr;
Xuint32 IpStatus;
baseaddr = (Xuint32) baseaddr_p;
// Get the timer interrupt status
IpStatus = MY_TIMER_mReadReg(baseaddr,
MY_TIMER_INTR_ISR_OFFSET);
// If timer caused the interrupt then switch LEDs
if (IpStatus){
// If LEDs are ON then turn OFF and vice versa
led_data = led_data ^ 0xF;
XGpio_DiscreteWrite(&GpioOutput, 1, led_data);
// Reset the timer and hence the interrupt
MY_TIMER_mWriteSlaveReg1(baseaddr, TIMER_RESET);
MY_TIMER_mWriteSlaveReg1(baseaddr, TIMER_RUN);
}
}
//----------------------------------------------------
// MAIN FUNCTION
//----------------------------------------------------
int main (void)
{
Xuint32 status;
// Clear screen
xil_printf("%c[2J",27);
xil_printf(" Timer Project from ");
xil_printf("http://www.fpgadeveloper.com\r\n");
xil_printf(" --------------------------------");
xil_printf("-----------------\r\n\r\n");
//----------------------------------------------------
// INITIALIZE INTERRUPT VECTOR TABLE
//----------------------------------------------------
xil_printf(" - Initializing interrupt vector table\r\n");
// Initialize exception handling
XExc_Init();
XExc_RegisterHandler(XEXC_ID_NON_CRITICAL_INT,
(XExceptionHandler)MY_TIMER_Intr_Handler,
(void *)XPAR_MY_TIMER_0_BASEADDR);
//----------------------------------------------------
// INITIALIZE THE TIMER PERIPHERAL
//----------------------------------------------------
xil_printf(" - Initializing the timer peripheral\r\n");
// Check that the my_timer peripheral exists
XASSERT_NONVOID(my_timer_p != XNULL);
my_timer = (Xuint32) my_timer_p;
// Load the delay register with the delay time of 0.5s
MY_TIMER_mWriteSlaveReg0(my_timer, TIMER_HALFSEC);
//----------------------------------------------------
// SETUP THE LEDs
//----------------------------------------------------
xil_printf(" - Setting up the LEDs\r\n");
// Initialize the GPIO driver
status = XGpio_Initialize(&GpioOutput,
XPAR_LEDS_4BIT_DEVICE_ID);
if (status != XST_SUCCESS)
return XST_FAILURE;
// Set the direction for all signals to be outputs
XGpio_SetDataDirection(&GpioOutput, 1, 0x0);
// Turn the LEDs ON
XGpio_DiscreteWrite(&GpioOutput, 1, 0x0);
//----------------------------------------------------
// ENABLE INTERRUPTS
//----------------------------------------------------
xil_printf(" - Enabling interrupts\r\n");
// Enable timer interrupts
MY_TIMER_EnableInterrupt(my_timer_p);
// Enable PowerPC non-critical interrupts
XExc_mEnableExceptions(XEXC_NON_CRITICAL);
// Start the timer
xil_printf(" - Starting the timer\r\n\r\n");
MY_TIMER_mWriteSlaveReg1(my_timer, TIMER_RUN);
xil_printf(" SUCCESS!\r\n");
while(1){
}
}
|
- Save and close the file.
Use the Default Linker Script
As mentioned earlier, the PowerPC requires an interrupt vector table to know what code to run when an interrupt occurs. The vector table resides in memory reserved by the linker script. The custom linker script for the “TestApp_Peripheral” application does not include a vector table, so we need to switch to the default linker script.
- From the “Applications” tab and within “Project: TestApp_Peripheral”, right-click on “Compiler Options” and select “Set Compiler Options”.
- Tick “Use default linker script” and click “OK”.
Download and Test the Project
- Open a Hyperterminal window with the required settings. For the correct settings, see Hyperterminal Settings.
- Turn on the XUPV2P board.
- From the XPS software, select “Device Configuration->Download Bitstream”.
The Hyperterminal output should look as shown in the image below:
The LEDs should be flashing once every second. The timer peripheral is set for a delay period of half a second. Each call to the interrupt handler changes the state of the LEDs and resets the timer for another half a second. The result is that the LEDs remain ON for half a second and OFF for half a second.
The PowerPC has only one input for non-critical interrupt requests and in this project, we used it for our Timer peripheral. In a more complex design with multiple interrupts sources, we need to use an interrupt controller to multiplex all the interrupt request signals into one. This is the topic of the next tutorial.
The project folder for this tutorial can be downloaded in a compressed ZIP file TimerInterrupts.zip
. Right-click on the link and select “Save Link As”.
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.
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:
- 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.
- 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:
- 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″ 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.
- 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 the “mgt_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. 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”.
- 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”.
- Click on the “Net” field for the “TOP_BREF_CLK” port. Type “TOP_BREF_CLK” in this field and press “Enter”.
- 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.
- 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.
- 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.
- 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 “aurora_plb” for the peripheral name. Click “Next”.
- Select “Processor Local Bus” (PLB) and click “Next”.
- On the “IPIF Services” page, tick “Burst transaction support”, “FIFO” and “DMA”. Un-tick everything else and click “Next”.
- 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.
- 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.
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.
- Run the Xilinx CORE Generator. Note that you do not have to close the XPS software.
- Select “File->New Project”.
- 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”.
- CORE Generator will ask you if you want to create the “coregen” folder. Click “OK”.
- 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”.
- 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.
- Open “Memories and Storage Elements->FIFOs” and double-click on “FIFO Generator 3.2″.
- 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”.
- 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”.
- 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.
- 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:
- Run the Xilinx CORE Generator if it is not already open.
- 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”.
- 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.
- 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”.
- 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”.
- The Aurora core will be generated and you will see it listed in the “Generated IP” tab.
- 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.
- 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.
- 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.
- 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.
- 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”.
- 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 |
- 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 |
- 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.
- Select from the menu “File->Open” and from the project folder, browse to “pcores\aurora_plb_v1_00_a\hdl\vhdl”.
- Open the file “aurora_plb.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; 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; |
- 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, |
- Save and close the file.
- Select from the menu “File->Open” and browse from the project folder to “pcores\aurora_plb_v1_00_a\hdl\vhdl”.
- Open the file “user_logic.vhd”. We will need to modify this source code to instantiate the Aurora core and TX/RX FIFOs.
- 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; |
- 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;
|
- 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;
|
- 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.
- 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.
- 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 “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”.
- 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”.
- 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”.
- 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 “PLB Master and Slave” and click “Next”.
- On the MSPLB: Port page, click “Next”.
- On the MSPLB: Parameter page, click “Next”.
- On the “Identify Interrupt Signals” page, leave the default settings and click “Next”.
- On the “Parameter Attributes” page, click “Next”.
- On the “Port Attributes” page, click “Next”.
- 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”.
- 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.
- 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.
- From the “System Assembly View” using the “Bus Interface” filter, connect the “aurora_plb_0″ and “aurora_plb_1″ to the PLB.
- Click on the “Ports” filter. Click on the “+” for “aurora_plb_0″ and “aurora_plb_1″ to view their ports.
- 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″.
- 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″.
- 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”.
- 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”.
- 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.
- 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.
- 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.
- 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.
##### 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; |
- 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.
- 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 "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){
}
}
|
- Save and close the file.
Download and Test the Project
- Open a Hyperterminal window with the required settings. For the correct settings, see Hyperterminal Settings.
- 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”.
- Turn on the XUPV2P board.
- 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.
Below we describe various problems with the XUPV2P board and/or XPS software, and the solution or work-around.
No Vista Support for 9.1 or Older
Presently, the EDK and ISE platforms versions 9.1 and older do not support Vista. You must upgrade to version 9.2 to operate under Vista.
The Onewire Problem
| Conditions | I am using the Digilent XUPV2P board with Xilinx Platform Studio v8.2i. I connect to my XUPV2P board via USB (i.e. not JTAG). |
| Problem | I have a working project but for some reason, it does not work if it is the first project to be downloaded to the XUPV2P after the power is turned ON. To make it work, I download another project to the XUPV2P after power-up, then I download the project I want to use. |
| Peculiarities | Not all my projects have this problem. It seems to be the more complex projects, such as those using the RocketIO MGTs. |
| Our Solution and Observations | When you create your more complex projects using the Base System Builder, be sure to always include the “Onewire_0″ interface, even if you don’t need it. Your projects will work even after the XUPV2P board is powered up. Strangely, for simple projects, including the “Onewire_0″ interface will actually make it fail to work after power-up. |
This problem can be reproduced by following through the tutorial: Create an Oscillator with a RocketIO MGT. Follow the tutorial and leave out the “Onewire_0″ interface. You will find that the project does not work if it is the first project to be downloaded after the XUPV2P board is powered up.
To reproduce the inverse problem for simple projects, try creating a project using Base System Builder and include the “Onewire_0″ and “RS232″ interfaces only. Include the default peripheral test application, then generate and download the bitstream. You will find that this project will not work if it is the first to be downloaded to the FPGA after power-up. Remove the “Onewire_0″ interface manually and you will find that the project will now work.
At present, we have not managed to trace the source of this problem, nor do we understand why our solution actually works. If you know why this problem exists or why the solution works, leave a comment please!
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.
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:
- 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.
- 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:
- 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″ 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.
- 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 the “mgt_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. 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”.
- 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”.
- Click on the “Net” field for the “TOP_BREF_CLK” port. Type “TOP_BREF_CLK” in this field and press “Enter”.
- 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.
- 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.
- 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.
- 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 “aurora_mgt” for the peripheral name. Click “Next”.
- Select “On-chip Peripheral Bus” (OPB) and click “Next”.
- Tick “FIFO”, un-tick everything else and click “Next”.
- 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.
- 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.
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.
- Run the Xilinx CORE Generator. Note that you do not have to close the XPS software.
- Select “File->New Project”.
- 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”.
- CORE Generator will ask you if you want to create the “coregen” folder. Click “OK”.
- 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”.
- 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.
- Open “Memories and Storage Elements->FIFOs” and double-click on “FIFO Generator 3.2″.
- 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”.
- 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”.
- 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.
- 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:
- Run the Xilinx CORE Generator if it is not already open.
- 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”.
- 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.
- 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”.
- 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”.
- The Aurora core will be generated and you will see it listed in the “Generated IP” tab.
- 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.
- 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.
- 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.
- 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.
- 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”.
- 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 |
- 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 |
- 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.
- Select from the menu “File->Open” and from the project folder, browse to “pcores\aurora_mgt_v1_00_a\hdl\vhdl”.
- Open the file “aurora_mgt.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; 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; |
- 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, |
- Save and close the file.
- Select from the menu “File->Open” and browse from the project folder to “pcores\aurora_mgt_v1_00_a\hdl\vhdl”.
- Open the file “user_logic.vhd”. We will need to modify this source code to instantiate the Aurora core and TX/RX FIFOs.
- 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; |
- 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;
|
- 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;
|
- 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.
- Save and close the file.
Import the Aurora 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 “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”.
- 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”.
- 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”.
- 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”.
- 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”.
- 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.
- 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.
- From the “System Assembly View” using the “Bus Interface” filter, connect the “aurora_mgt_0″ and “aurora_mgt_1″ to the OPB bus.
- Click on the “Ports” filter. Click on the “+” for “aurora_mgt_0″ and “aurora_mgt_1″ to view their ports.
- 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″.
- 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″.
- 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”.
- 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”.
- 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.
- 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”.
- 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.
- 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.
##### 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; |
- 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.
- 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 "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){
}
}
|
- Save and close the file.
Download and Test the Project
- Open a Hyperterminal window with the required settings. For the correct settings, see Hyperterminal Settings.
- 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”.
- Turn on the XUPV2P board.
- 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.
Here is a maintained list of our step-by-step online tutorials and examples for the Xilinx Virtex-II Pro FPGA based on the XUPV2P Development Board from Digilent. The following tutorials guide the user through various FPGA designs that combine the PowerPC with custom user logic peripherals.
Xilinx Platform Studio (XPS) Tutorials for XUPV2P
The following tutorials develop working embedded projects that employ the Microblaze soft processor. They are developed using EDK.
Version 13.1- Timer with Interrupts
Overview In this tutorial we will improve on the Timer peripheral developed in Create a Simple Timer Peripheral. The improvement is achieved by enabling the peripheral to generate an interrupt when the timer expires. The PowerPC then processes the i...
- Aurora Transceiver for the PLB
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 Auro...
- Known Issues
Below we describe various problems with the XUPV2P board and/or XPS software, and the solution or work-around. No Vista Support for 9.1 or Older Presently, the EDK and ISE platforms versions 9.1 and older do not support Vista. You must upgrade to v...
- Create an Aurora Transceiver
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 be...
- Other Tutorials and Examples
Here are links to some useful tutorials and examples hosted on other websites, including Xilinx: Xilinx EDK Concepts, Tools, and Techniques A Hands-on Guide to Effective Embedded System Design Xilinx Creating an OPB IPIF-based IP and Using it ...
- Integrating a VHDL Design into a Peripheral
Overview This tutorial is similar to the previous one titled: Integrating a Blackbox into a Peripheral however in this case, instead of integrating an .ngc file into a peripheral, we integrate one or more VHDL files. Sometimes we have a VHDL design ...
- Integrating a Blackbox into a Peripheral
Overview Sometimes we have an .ngc file from CORE Generator (or some other source) that we would like to bring into EDK as a peripheral. This project is a simple example of integrating a blackbox design into a peripheral generated by the Peripheral ...
- Create a Simple Timer Peripheral
Overview In this project, we will add code to a peripheral template generated by the Peripheral Wizard to create a simple timer. The timer peripheral will be used by the PowerPC to make the LEDs flash with a fixed period. Figure: The Timer pe...
- XUPV2P Library Files
To develop projects in XPS for the XUPV2P board it is necessary to copy the XUPV2P library files into a directory on the C drive of your computer. These files contain software libraries and hardware specific information for the XUPV2P board that are ne...
- Create a Peripheral using the Peripheral Wizard
Overview In this tutorial we will create a simple project that uses our own IP core (instead of using the General Purpose IO core provided by Xilinx) to read from the DIP switches and write to the LEDs. The software application will display the DIP ...
- Manually Add a Peripheral to a Project
Overview In the previous example, we created a project using the BSB and all of the work related to the hardware design was done by the BSB. In this example, we will create the same simple project, but this time we will add the GPIO for the LEDs man...
- Create a Project Using the Base System Builder
Tutorial Overview In this example, we will create a simple project using the Base System Builder that includes three peripherals: the RS232 UART and two GPIOs. One GPIO will be used for the DIP switches and the other for the LEDs. We will then use a...
Tutorials and Examples
The examples on this website are provided in a tutorial form. Each tutorial guides the user through the entire process of building a working project from “scratch”. The tutorials guide the user through all steps, with explanations, screen shots and source code. Each tutorial extends or builds on the concepts developed in the previous tutorials. It is recommended that beginners follow the tutorials in sequence.
Scope and Requirements
The projects on this website all involve use of the PowerPC microprocessors and interfacing them with peripherals developed in VHDL. It is assumed that the reader has a basic understanding of the C programming language and VHDL. All debugging is done through the RS232 port of the XUPV2P Development Board. It is therefore necessary that the user have a PC with an RS232 port (comport/serial port) or RS232-to-USB converter, and a copy of Hyperterminal or other terminal program. For the required Hyperterminal settings, click here.
RocketIO Tutorials
Here is a list of our tutorials related to RocketIO multi-gigabit transceivers:
- Aurora to Ethernet Bridge
- Tri-mode Ethernet MAC
- Aurora Transceiver for the PLB
- Create an Aurora Transceiver
- Create an Oscillator with a RocketIO MGT
- RocketIO FAQ
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:
Here are links to some useful tutorials and examples hosted on other websites, including Xilinx:
Xilinx
EDK Concepts, Tools, and Techniques
A Hands-on Guide to Effective Embedded System Design
Xilinx
Creating an OPB IPIF-based IP and Using it in EDK
Adding Custom Logic to an Embedded Design
Xilinx
Using the RocketIO Controller in Virtex-II Pro for Frequency Multiplication
An example design similar to the Oscillator example on this website
Digilent
Using the Base System Builder
A Quick Start Guide to the BSB
Overview
This tutorial is similar to the previous one titled: Integrating a Blackbox into a Peripheral however in this case, instead of integrating an .ngc file into a peripheral, we integrate one or more VHDL files. Sometimes we have a VHDL design that we developed in ISE, or some other program, and we would like to bring it into the EDK as a peripheral. In this tutorial, we will create the same multiplier peripheral as was created in the previous tutorial.
The multiplier will take in two 16 bit unsigned inputs and have a 32 bit unsigned output. A single 32 bit write to the peripheral will contain the two 16 bit inputs, separated by the lower and higher 16 bits. A single 32 bit read from the peripheral will contain the result from the multiplication of the two 16 bit inputs. Instead of registers, we will use a read and write FIFO for the interface with the software application. In this way, the peripheral write FIFO can be loaded with a number of multiplications to perform, and the results can be pushed into the read FIFO for the software application to retrieve at its convenience. Practically, this design does not serve much purpose, but it is a simple demonstration of integrating VHDL designs into peripherals.
For a more powerful example of integrating a VHDL design into a peripheral, see Creating an Aurora Transceiver, in which we create a peripheral from the Aurora core source files generated by CORE Generator.
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.
Are you using EDK 10.1?
Try the updated version of this tutorial based on the Virtex-5 FPGA on the ML505 board: Integrating a VHDL Design into a Peripheral
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, leave “RS232_Uart_1″ ticked and un-tick everything else.
- 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”.
- Click “Generate”.
- Click “Finish”.
- Tick “Start using Platform Studio” and click “OK”.
Create the Multiplier Peripheral
Follow these steps to create the multiplier peripheral.
- Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
- Select “Create templates for a new peripheral” and click “Next”.
- 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”.
- Type “my_multiplier” for the peripheral name. Click “Next”.
- Select “On-chip Peripheral Bus” (OPB) and click “Next”.
- The Peripheral Wizard can generate our VHDL template to include many different features. We will only need “FIFO”. Tick that option, un-tick everything else and click “Next”.
- 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.
- On the “IP Interconnect” page we can customize our connection to the OPB but we will leave everything as is for simplicity. Click “Next”.
- 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.
- 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.
Create the Multiplier core in VHDL
Follow these steps to create the Multiplier core:
- Select “File->New”. This will open a new text document that we will use for the multiplier VHDL source code.
- Copy and paste the following code into the new text document.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity multiplier is
port(
clk : in std_logic;
a : in std_logic_vector(15 downto 0);
b : in std_logic_vector(15 downto 0);
p : out std_logic_vector(31 downto 0)
);
end multiplier;
architecture IMP of multiplier is
begin
process (clk)
begin
if (clk'event and clk = '1') then
p <= unsigned(a) * unsigned(b);
end if;
end process;
end IMP;
|
- Save the file as “multiplier.vhd” in the “pcores\my_multiplier_v1_00_a\hdl\vhdl” folder.
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 another source file to the project (“multiplier.vhd”), we must include it in the .pao file.
- Select “File->Open” and browse to the “pcores\my_multiplier_v1_00_a\data” folder. Select the file “my_multiplier_v2_1_0.pao” and click “Open”.
- At the bottom of this file you will see these two lines:
lib my_multiplier_v1_00_a user_logic vhdl lib my_multiplier_v1_00_a my_multiplier vhdl |
- Add the line “lib my_multiplier_v1_00_a multiplier vhdl” just above those two lines.
- Save the file.
Now we can use this .pao file with the Peripheral Wizard and it will know to include the “multiplier.vhd” file in our design. Notice that the .pao file lists the source files in hierarchical order. Thus if you have a VHDL design consisting of multiple files, it is important to know the hierarchical order of your components. The components at the top of the chain are listed at the bottom of the file.
Modify the Peripheral
Now we will add code in our peripheral template to instantiate a multiplier core and we will connect it to the read and write FIFOs.
- Select from the menu “File->Open” and look in the project folder.
- Open the folders: “pcores\my_multiplier_v1_00_a\hdl\vhdl”. This folder contains two source files that describe our peripheral “my_multiplier.vhd” and “user_logic.vhd”. The first file is the main part of the peripheral and it implements the interface to the OPB. The second file is where we place our custom logic to make the peripheral do what we need it to do. This part is instantiated by the first file.
- Open the file “user_logic.vhd”. We will need to modify this source code to instantiate the multiplier and connect it to the read and write FIFOs.
- Find the line of code that says “–USER signal declarations added here” and add the following lines of code just below.
component multiplier
port (
clk: in std_logic;
a: in std_logic_VECTOR(15 downto 0);
b: in std_logic_VECTOR(15 downto 0);
p: out std_logic_VECTOR(31 downto 0));
end component;
|
- Find the line of code that says “–USER logic implementation added here” and add the following lines of code just below.
multiplier_0 : multiplier
port map (
clk => Bus2IP_Clk,
a => WFIFO2IP_Data(16 to 31),
b => WFIFO2IP_Data(0 to 15),
p => IP2RFIFO_Data);
|
- Find the line of code that says “IP2RFIFO_Data <= WFIFO2IP_Data;” and comment it out (or delete it). Now, the read FIFO will be loaded with data from the multiplier.
- Save and close the file.
Import the Multiplier 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 “my_multiplier”. 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\my_multiplier_v1_00_a\data” and select the “my_multiplier_v2_1_0.pao” file. Click “Next”.
- On the HDL analysis information page, if you scroll down, you will see the “multiplier.vhd” file listed third from the bottom. 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 “Parameter Attributes” page, click “Next”.
- On the “Port Attributes” page, click “Next”.
- Click “Finish”.
The multiplier peripheral should now be accessible through the “IP Catalog->Project Repository” in the XPS interface.
Create an Instance of the Peripheral
Follow these steps to create an instance of the peripheral in the project.
- From the “IP Catalog” find the “my_multiplier” 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 “my_multiplier_0″ to the OPB bus.
- Click on the “Addresses” filter. Change the “Size” for “my_multiplier_0″ to 64K. Then click “Generate Addresses”.
Now we have an instance of the multiplier peripheral in our project and our hardware design is complete.
Modify the Software Application
Now all we need to do is modify the software application to test our multiplier 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.
#include "xparameters.h"
#include "xbasic_types.h"
#include "xstatus.h"
#include "my_multiplier.h"
Xuint32 *baseaddr_p = (Xuint32 *)XPAR_MY_MULTIPLIER_0_BASEADDR;
int main (void) {
Xuint32 i;
Xuint32 temp;
Xuint32 baseaddr;
// Clear the screen
xil_printf("%c[2J",27);
// Check that the peripheral exists
XASSERT_NONVOID(baseaddr_p != XNULL);
baseaddr = (Xuint32) baseaddr_p;
xil_printf("Multiplier Test\n\r");
// Reset read and write packet FIFOs to initial state
MY_MULTIPLIER_mResetWriteFIFO(baseaddr);
MY_MULTIPLIER_mResetReadFIFO(baseaddr);
// Push data to write packet FIFO
for(i = 1; i <= 4; i++ ){
temp = (i << 16) + i;
xil_printf("Wrote: 0x%08x \n\r", temp);
MY_MULTIPLIER_mWriteToFIFO(baseaddr, temp);
}
// pop data out from read packet FIFO
for(i = 0; i < 4; i++){
temp = MY_MULTIPLIER_mReadFromFIFO(baseaddr);
xil_printf("Read: 0x%08x \n\r", temp);
}
// Reset the read and write FIFOs
MY_MULTIPLIER_mResetWriteFIFO(baseaddr);
MY_MULTIPLIER_mResetReadFIFO(baseaddr);
xil_printf("End of test\n\n\r");
// Stay in an infinite loop
while(1){
}
}
|
- Save and close the file.
Download and Test the Project
- Open a Hyperterminal window with the required settings. For the correct settings, see Hyperterminal Settings.
- Turn on the XUPV2P board.
- From the XPS software, select “Device Configuration->Download Bitstream”.
The Hyperterminal output should look as shown in the image below:
Remember, those numbers are in hexadecimal so 0×10 = 16!
The project folder for this tutorial can be downloaded in a compressed ZIP file MultiplierVHDL.zip
. Right-click on the link and select “Save Link As”.
For a more powerful example of integrating a VHDL design into a peripheral, see Creating an Aurora Transceiver. In this tutorial, we create a peripheral to allow serial communication at 1.5Gbps between two XUPV2P boards connected by a SATA cable.
In the next tutorial, Timer with Interrupts, we show how to create a peripheral that is capable of generating interrupts on the PowerPC.
Overview
Sometimes we have an .ngc file from CORE Generator (or some other source) that we would like to bring into EDK as a peripheral. This project is a simple example of integrating a blackbox design into a peripheral generated by the Peripheral Wizard. We will first create a blackbox multiplier using the Xilinx CORE Generator and then we will use the generated .ngc file in our peripheral.
The multiplier will take in two 16 bit unsigned inputs and have a 32 bit unsigned output. A single 32 bit write to the peripheral will contain the two 16 bit inputs, separated by the lower and higher 16 bits. A single 32 bit read from the peripheral will contain the result from the multiplication of the two 16 bit inputs. Instead of registers, we will use a read and write FIFO for the interface with the software application. In this way, the peripheral write FIFO can be loaded with a number of multiplications to perform, and the results can be pushed into the read FIFO for the software application to retrieve at its convenience. Practically, this design does not serve much purpose, but it is a simple demonstration of integrating blackbox designs into peripherals.
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.
Are you using EDK 10.1?
Try the updated version of this tutorial based on the Virtex-5 FPGA on the ML505 board: Integrating a Blackbox into a Peripheral
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, leave “RS232_Uart_1″ ticked and un-tick everything else.
- 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”.
- Click “Generate”.
- Click “Finish”.
- Tick “Start using Platform Studio” and click “OK”.
Create the Multiplier Peripheral
Follow these steps to create the multiplier peripheral.
- Select from the menu “Hardware->Create or Import Peripheral”. Click “Next”.
- Select “Create templates for a new peripheral” and click “Next”.
- 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”.
- Type “my_multiplier” for the peripheral name. Click “Next”.
- Select “On-chip Peripheral Bus” (OPB) and click “Next”.
- The Peripheral Wizard can generate our VHDL template to include many different features. We will only need “FIFO”. Tick that option, un-tick everything else and click “Next”.
- 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.
- On the “IP Interconnect” page we can customize our connection to the OPB but we will leave everything as is for simplicity. Click “Next”.
- 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.
- 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.
Create the Multiplier with CORE Generator
Follow these steps to generate the Multiplier.
- Leaving XPS running and your project open, from the “Start” menu, open Xilinx CORE Generator.
- Select “File->New Project”.
- 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, for example “C:\XUPV2P\Projects”. Click “OK”.
- CORE Generator will ask you if you want to create the “coregen” folder. Click “OK”.
- 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”.
- 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.
- Open “Math Functions->Multipliers” and double-click on “Multiplier”.
- A dialog box should open to allow you to select the features of the Multiplier you want. For “Multiplier Type” select “Parallel Multiplier”. Select “Unsigned” for both port inputs and give them a width of 16 bits.
- Click “Finish”. Your Multiplier core will be generated and CORE Generator will display a list of all the generated files. Close this window, and close CORE Generator.
Modify the Peripheral
When we create a peripheral with read and write FIFOs, the Peripheral Wizard generates code in the user_logic.vhd file that loops the data from the write FIFO to the read FIFO. This makes it easy to test for the first time because one can write data to the peripheral and verify that it was received by reading back the same data. In our case, the loop-back design reduces the number of modifications we need to make because we want to do the same thing, only we want to first pass the data through the multiplier before putting it through to the read FIFO. Now we will add code in our peripheral template to instantiate a multiplier core and connect it to the read and write FIFOs.
- Select from the menu “File->Open” and look in the project folder.
- Open the folders: “pcores\my_multiplier_v1_00_a\hdl\vhdl”. This folder contains two source files that describe our peripheral “my_multiplier.vhd” and “user_logic.vhd”. The first file is the main part of the peripheral and it implements the interface to the OPB. The second file is where we place our custom logic to make the peripheral do what we need it to do. This part is instantiated by the first file.
- Open the file “user_logic.vhd”. We will need to modify this source code to instantiate the multiplier and connect it to the read and write FIFOs.
- Find the line of code that says “–USER signal declarations added here” and add the following lines of code just below.
component multiplier_v9_0
port (
clk: IN std_logic;
a: IN std_logic_VECTOR(15 downto 0);
b: IN std_logic_VECTOR(15 downto 0);
p: OUT std_logic_VECTOR(31 downto 0));
end component;
|
- Find the line of code that says “–USER logic implementation added here” and add the following lines of code just below.
multiplier_0 : multiplier_v9_0
port map (
clk => Bus2IP_Clk,
a => WFIFO2IP_Data(16 to 31),
b => WFIFO2IP_Data(0 to 15),
p => IP2RFIFO_Data);
|
- Find the line of code that says “IP2RFIFO_Data <= WFIFO2IP_Data;” and comment it out (or delete it). Now, the read FIFO will be loaded with data from the multiplier.
- Save and close the file.
Import the Peripheral
Now we will use the Peripheral Wizard again, but this time using the import function.
- 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 “my_multiplier”. 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”.
- Now we are asked about the files that make up our peripheral. As usual we tick “HDL source files” and in this case, to include our .ngc file, we will also tick “Netlist files”. Now click “Next”.
- Select “Use existing Peripheral Analysis Order file (*.pao)” and click “Browse”. From the project folder, go to “pcores\my_multiplier_v1_00_a\data” and select the “my_multiplier_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 “Parameter Attributes” page, click “Next”.
- On the “Port Attributes” page, click “Next”.
- Now we should arrive at the “Netlist Files” page where we are asked to locate any netlist files or black-box components that are instantiated in our peripheral. Click “Select Files” and navigate your way to the Coregen project folder “coregen” that you created using CORE Generator earlier. You will find a file called “multiplier_v9_0_mult_gen_v9_0_xst_1.ngc”. Rename this file to “multiplier_v9_0.ngc”, then select the file and click “Open”. The file should now be listed on the “Netlist Files” page. Click “Next”.
- Click “Finish”.
When you include .ngc files in a peripheral design as we just did, the Peripheral Wizard does some things behind-the-scenes that are important to know. Firstly, it makes a copy of the .ngc file and places it in the “pcores\my_multiplier_v1_00_a\netlist” folder (if that folder doesn’t exist, it creates one). Secondly, it creates a file called “my_multiplier_v2_1_0.bbd” in the “pcores\my_multiplier_v1_00_a\data” folder with the following contents:
############################################################ ## Filename: C:\XUPV2P\Projects\Multiplier5\pcores- /my_multiplier_v1_00_a/data/my_multiplier_v2_1_0.bbd ## Description: Black Box Definition ## Date: Mon Feb 11 16:53:42 2008 (by Create a- nd Import Peripheral Wizard) ############################################################ Files ############################################################ multiplier_v9_0.ngc |
Finally, the Peripheral Wizard adds these two lines to the “my_multiplier_v2_1_0.mpd” file in the “pcores\my_multiplier_v1_00_a\data” folder:
OPTION STYLE = MIX OPTION RUN_NGCBUILD = TRUE |
The multiplier peripheral should now be accessible through the “IP Catalog->Project Repository” in the XPS interface.
Create an Instance of the Peripheral
Follow these steps to create an instance of the peripheral in the project.
- From the “IP Catalog” find the “my_multiplier” 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 “my_multiplier_0″ to the OPB bus.
- Click on the “Addresses” filter. Change the “Size” for “my_multiplier_0″ to 64K. Then click “Generate Addresses”.
Now we have an instance of the multiplier peripheral in our project and our hardware design is complete.
Modify the Software Application
Now all we need to do is modify the software application to test our multiplier 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 "xstatus.h"
#include "my_multiplier.h"
Xuint32 *baseaddr_p = (Xuint32 *)XPAR_MY_MULTIPLIER_0_BASEADDR;
int main (void) {
Xuint32 i;
Xuint32 temp;
Xuint32 baseaddr;
// Clear the screen
xil_printf("%c[2J",27);
// Check that the peripheral exists
XASSERT_NONVOID(baseaddr_p != XNULL);
baseaddr = (Xuint32) baseaddr_p;
xil_printf("Multiplier Test\n\r");
// Reset read and write packet FIFOs to initial state
MY_MULTIPLIER_mResetWriteFIFO(baseaddr);
MY_MULTIPLIER_mResetReadFIFO(baseaddr);
// Push data to write packet FIFO
for(i = 1; i <= 4; i++ ){
temp = (i << 16) + i;
xil_printf("Wrote: 0x%08x \n\r", temp);
MY_MULTIPLIER_mWriteToFIFO(baseaddr, temp);
}
// pop data out from read packet FIFO
for(i = 0; i < 4; i++){
temp = MY_MULTIPLIER_mReadFromFIFO(baseaddr);
xil_printf("Read: 0x%08x \n\r", temp);
}
// Reset the read and write FIFOs
MY_MULTIPLIER_mResetWriteFIFO(baseaddr);
MY_MULTIPLIER_mResetReadFIFO(baseaddr);
xil_printf("End of test\n\n\r");
// Stay in an infinite loop
while(1){
}
}
|
- Save and close the file.
Download and Test the Project
- Open a Hyperterminal window with the required settings. For the correct settings, see Hyperterminal Settings.
- Turn on the XUPV2P board.
- From the XPS software, select “Device Configuration->Download Bitstream”.
The Hyperterminal output should look as shown in the image below:
Remember, those numbers are in hexadecimal so 0×10 = 16!
The project folder for this tutorial can be downloaded in a compressed ZIP file MultiplierNGC.zip
. Right-click on the link and select “Save Link As”.
For an example of integrating a black-box FIFO into a peripheral, see Creating an Aurora Transceiver. In this tutorial, we create an Aurora peripheral to allow serial communication at 1.5Gbps between two XUPV2P boards connected by a SATA cable.
In the next tutorial, Integrating a VHDL Design into a Peripheral, we show how to integrate a custom VHDL design into the Peripheral Wizard templates.




Recent Comments