October 18, 200811 minutes
Tutorial 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. Click on the images to view a higher resolution.
Requirements
Before following this tutorial, you will need to do the following:
Create the Basic Project
Follow these steps to create the basic project:




RS232_Uart_1 ticked and un-tick everything else.


RS232_Uart_1 for both STDIN and STDOUT. Un-tick “Memory Test” and leave “Peripheral Test” ticked. Click “Next”.

Create the Multiplier Peripheral
Follow these steps to create the multiplier peripheral.


my_multiplier for the peripheral name. Click “Next”.





Create the Multiplier with CORE Generator
Follow these steps to generate the Multiplier.




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.
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.user_logic.vhd. We will need to modify this source code to instantiate the multiplier and connect it to the read and write FIFOs.--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;--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);IP2RFIFO_Data <= WFIFO2IP_Data; and comment it out (or delete it). Now, the read FIFO will be loaded with data from the multiplier.Import the Peripheral
Now we will use the Peripheral Wizard again, but this time using the import function.

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


pcores\my_multiplier_v1_00_a\data and select the my_multiplier_v2_1_0.pao file. Click “Next”.


multiplier.ngc. Select the file and click “Open”. The file should now be listed on the “Netlist Files” page. Click “Next”.

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:\ML505\Projects\MultiplierNGC\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.ngcFinally, 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 = TRUEThe multiplier peripheral should now be accessible through the “IP Catalog->Project Local pcores” in the XPS interface.
Create an Instance of the Peripheral
Follow these steps to create an instance of the peripheral in the project.
my_multiplier IP core in the “Project Repository” group. Right click on the core and select “Add IP”.

my_multiplier_0 to the PLB bus.

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.
TestApp_Peripheral.c source 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,0, temp);
}
// pop data out from read packet FIFO
for(i = 0; i < 4; i++){
temp = MY_MULTIPLIER_mReadFromFIFO(baseaddr,0);
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){
}
}Download and Test the Project
The Hyperterminal output should look as shown in the image below:
Remember, those numbers are in hexadecimal so 0x10 = 16!
The project folder for this tutorial can be downloaded in a compressed ZIP file MultiplierNGC-EDK10-1.zip . Right-click on the link and select “Save Link As”.
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.