PCore Generation

Once a module has been compiled with ROCCC and translated into hardware, you can create a Xilinx PCore and run the hardware on an FPGA much like a function call in C.  Currently, ROCCC on supports generating PCores for XPS/EDK version 12 using the PLB interface.  For this example, we are going to be using the FIR filter module and generate a PCore for it.

To generate a PCore for a module, select “Generate->PCore” in the ROCCC menu.  If you have not yet compiled the module or it cannot be found in the database, the module will need to be recompiled first.

If your PCore has dependencies on other modules or IPCores, a window will pop up asking for the files needed to fill in those dependencies.  For example, the FFTOneStage example uses the FFT module and therefore needs the VHDL for the FFT module.  If one of your dependencies is an imported IPCore from a netlist, you will need to specify the ngc file as well as a wrapper file that interfaces with ROCCC.

Once the PCore is done generating, all the necessary files will be placed into a folder called “PCore” that will be found in the root folder of the module you are generating a PCore for.

Now that we have our PCore generated, let’s put into XPS/EDK to run.


Loading the PCore into XPS/EDK

Once you have your PCore generated, you can now insert this into an EDK project and run it on an FPGA.  First open up Xilinx Platform Studio (XPS) and create a new project and place it where you would like it to be located at on your computer.

Next select which FPGA board you are going to be running your PCore on.  For this example we are going to be running our FIR PCore on a Virtex 6 ML605 board. You may have a different board so select the one you will be using.

Go ahead and press “Next” through the rest of the project creation windows until you have focus back on XPS and you can see your System Assembly View as shown below.  You can remove some of the additional peripherals that are included by default since the ROCCC PCore only uses the UART peripheral, but this step is not necessary to get your PCore running.

Now that we have a project created, we can drop in our generated PCore files into our project. Navigate to the location where you created your XPS project.  Inside the project folder, find the directory named “pcores.”  Here is where we want to copy our PCore files.  Find the folder inside the generated PCore called “roccc_gen_pcore_v1_00_a” and copy that into the “pcores” folder in the XPS project directory.

Now that our PCore is in place, let’s tell XPS to rescan the project so that it can find the inserted PCore for us to use.  Click the “Rescan User Repositories” command under the “Project” menu in XPS.

Once that is done, click the “IP Catalog” tab on the left side of the screen.  Here you will see various IP’s listed.  Go down to the bottom of the list under “Project Local PCores” and expand the “USER” section.  Here you will see an IP called “ROCCC_GEN_PCORE.”  Right click this selection and select “Add IP.”

Now that our PCore IP has been added, go back to the System Assembly View and select the tab that says “Bus Interfaces” at the top.  In the list for this tab, find the entry named “roccc_gen_pcore_0″ and expand it.  Here you will see a drop down menu with the item selected being “No Connection.” Open up the drop down menu and select the option “mb_plb.”

Now that we have told EDK to hook up our PCore using the PLB, let’s set up the address space for our PCore.  Click the tab at the top named “Addresses.”  At the bottom of the list, expand the option “Unmapped Addresses.”  Here you will see our roccc_gen_pcore_0 with an address size listed as U.  Select a size for the address space for our PCore.  For this example we chose 16K which is more than enough address space needed.

Now that we have specified how much address space we are asking for our PCore, let’s generate the addresses for our PCore by pressing the “Generate Addresses” button on the top right.

This is everything needed to generate a bitstream for our FPGA.  Go to the menu at the top of the program and select “Generate Bitstream” under the Hardware menu.  The generation of the hardware bitstream will take a bit of time so we will work on writing our code that calls our hardware function while it is doing that.

Under the “Project” tab on the left side of XPS, right click the Headers category for the TestApp_Memory program and select “Add Existing Files.” If you are unsure which project to do this for, it should be the project that does not have a red X on its icon in the list.

So we are going to add the C headers that were generated by ROCCC that will allow us to call the hardware from C.  Navigate to the pcores folder of the XPS project and go into the “roccc_gen_pcore_v1_00_a” folder that you copied in there earlier.  Inside that folder navigate into the folder named “devl.”  In here you will find two .h files.  Select both of these and press ok.

Now that we have our hardware function call headers in place, we can now modify the main program of our project to call this hardware function.  Open up the file listed under “Sources” of the project we are working on in the list located on the left side of the program.

The main function will have pre-generated code from XPS, delete the entire contents of the main function and replace it with the code below.

Now all we have to do is set which values are passed into the hardware function and then read the output values out.  Since we are programming in C, there is no way to obtain multiple output values from a function.  Because of this, ROCCC generates a struct that has all the inputs and all the output variables that correspond to the hardware structure you wrote, which in this case was FIR.  Also, because we cannot have the struct name be the same name as the function call, ROCCC generates a random number that is appended to the struct name to make sure no conflict arises.

To see what the struct and hardware function call look like, open up the header file in your project that we added named PCORE_”MODULE_NAME”.h.  For this example, ours is named PCORE_FIR.h.

Here you see the struct with all the input and output values as well as the function call to run this on the hardware. The way we set these values and read them is to create the struct for our component, set all the inputs in that struct, then call the function passing in our struct and also setting our struct equal to the return value of that function.  This way, the function can set all the output values of our struct and give them back to us to read.  So let’s go back to our main file and do as we just explained which is shown below.

So here we create our struct, set the input values, call our hardware function, and read the outputs back out. One thing you will notice above is the set_FIR_baseaddr function being called.  This function header is located in the other .h we added and this function will be named set_”COMPONENT_NAME”_baseaddr.  Again, since we are using FIR in this example, ours was named set_FIR_baseaddr.

We need to call this function to make sure the PCore knows what memory locations to write and read values from to run our function on the FPGA.  To figure out what values to pass into this function, go back to the “System Assembly View” file and select the “Addresses” tab and find the base address value for our roccc_gen_pcore_0.  Place that base address value into the function that sets the base address of our PCore.  For our example, the base address was 0xA7000000.

Once we have all this data filled out and our main function is written, we can now run our hardware function on our FPGA.  Make sure to save your file and that XPS is done generating the bitstream we started earlier.  After that is done, let’s set up our console to view the output of our PCore.


Running the PCore

To be able to read the output from our program, open up a program like Tera Term or Hyper Terminal and connect to the port that is hooked up to your FPGA.  Ours is hooked up on COM3 so we are selecting that, yours may be on a different port.

We are now ready to run our hardware function and read the output. Go back into XPS and select “Download Bitstream” from the “Device Configuration” menu.  This will compile your C code and if no errors arise, it will run the main function and our PCore function.  If you need to make any changes, make them and save your file and select Download Bitstream again.

Assuming everything works out alright and your function runs properly after downloading the bitstream, you will see your output on the Tera Term console.

If for whatever reason your function is not giving the correct values or is hanging after the “Entering Main” part, make sure you have set your base address correctly.  Also, there have been times where it seems the C compiler optimizations have resulted in incorrect results inside XPS.  In that case, right click your project in XPS and select “Set Compiler Options.”  From there you will be able to set the compiler optimization level to zero and see if that fixes your problem.  Lastly, verify that the hardware circuit you generated in ROCCC is correct by using our automatic testbench generation.

If you are receiving timing errors when generating a bitstream for the hardware function, your function may require a slower bus speed or removing some of the unnecessary peripherals that are added by default.  You can try lowering the bus speed or removing some of the peripherals and regenerating the bitstream again.


<< Testbench Generation Tutorials Home Connecting To ROCCC Generated Code >>