Sometimes we end up with two versions of the same design, where one works and one doesn’t work. If the code is the same, typically the problem is in placement of your primitives. In this case we would like to compare the two designs at a to find out what exactly has changed in the placements.
This is where reading the NCD file (the Native Circuit Description file) can be useful. The NCD file is the product of PAR and the file used by bitgen to generate the bitstream.
My preferred method for checking out the NCD file is using FPGA Editor, but you can also read the file directly if for example you wanted a script to do the work. The NCD file is not a readable file, but Xilinx has provided a tool for converting it into a readable file: XDL.
If you run a command prompt and type “xdl” you get the following message:
Release 12.1 - xdl M.53d (nt) Copyright (c) 1995-2010 Xilinx, Inc. All rights reserved.Xdl is a single tool with 3 fundamental modes:* Report Device Resource Information * Convert NCD to XDL (ncd2xdl) * Convert XDL to NCD (xdl2ncd)Report generates a report of the physical resources available for a specific part.Ncd2xdl reads in an NCD file and generates an ASCII XDL file.Xdl2ncd reads in an XDL file and generates an NCD file.XDL is also a fully featured Physical Design language that provides direct read and write access to Xilinx's proprietary Native Circuit Description (NCD). This access enables all users to write tools to address their individual FPGA design needs.To find out the switches available for each mode, enter the mode switch and the -h switch as shown in the examples below:% xdl -h -report % xdl -h -ncd2xdl % xdl -h -xdl2ncdTo find out which parts are available, run partgen as follows:% partgen -i % partgen -i -arch virtex
As you get from the message, to convert an NCD file to readable ASCII (XDL) file, you should type:
xdl -ncd2xdl filename.ncd
where “filename.ncd” is the filename of your NCD file. The resulting XDL file will have the same filename but with .xdl as the extension. It can be a hundred or more megabytes so don’t expect just any editor to be able to open it.
Another useful option of the XDL tool is conversion from XDL file back to NCD, which you could then use to generate a bitstream with bitgen. The reason you would do this is if you had some small modifications to make to the design and you didn’t want to go through building the entire project from scratch again.
Here is the help message for the NCD2XDL option:
Release 12.1 - xdl M.53d (nt) Copyright (c) 1995-2010 Xilinx, Inc. All rights reserved.Usage: xdl.exe [-ncd2xdl] [-nopips] [-noformat] [-nw] [-force_cfg] <ncdfile> [<x dlfile>] Parameters: <ncdfile> The input NCD file. If the .ncd extension is not specified, it is appended automatically.<xdlfile> The output XDL file. If the <xdlfile> is not specified, the file name is created from the <ncdfile> name by replacing the .ncd extension with a .xdl extension.Switches: -ncd2xdl Mode specifier. -noformat Don't format the report for readability. -nopips Don't report pips. -nw Don't allow overwriting of an existing XDL file. -force_cfg Force the display of config strings. The config strings have removed the equations and RAM initialization data. Depending on the level of core security associated with the design and the individual blocks the results could vary. You cannot recreate a valid ncd from this xdl.Sample Usage: % xdl -ncd2xdl design % xdl -ncd2xdl design.ncd % xdl -ncd2xdl design.ncd design.xdl % xdl -ncd2xdl -noformat design.ncd design.xdl % xdl -ncd2xdl -nopips design.ncd design.xdl
Here is the help message for the XDL2NCD option:
Release 12.1 - xdl M.53d (nt) Copyright (c) 1995-2010 Xilinx, Inc. All rights reserved.Usage: xdl.exe [-xdl2ncd] [-force] [-nopips] <xdlfile> [<ncdfile>] Parameters: <xdlfile> The input XDL file. If the .xdl extension is not specified, it is appended automatically.<ncdfile> The output NCD file. If the <ncdfile> is not specified, the file name is created from the <xdlfile> name by replacing the .xdl extension with a .ncd extension.Switches: -force Force NCD creation in spite of DRC errors. -nopips Omit PIP routing information. -xdl2ncd Mode specifier.Sample Usage: % xdl -xdl2ncd foo.ncd % xdl -xdl2ncd foo.ncd bar.xdl % xdl -xdl2ncd foo bar % xdl -xdl2ncd -force foo bar % xdl -xdl2ncd -nopips foo bar
Most companies involved in code design manage their sources using SVN. If you’re not doing it, you should be. There are a multitude of websites explaining the benefits of using SVN so I wont go there. This post is about the best way to use SVN
for HDL designs.
HDL designs typically involve source files, netlist files and bitstreams. As in software design, the best way to use SVN is to commit source files only. That means, don’t commit netlist files or bitstream files. Our challenge is to ensure that someone who loads our sources from SVN to a clean slate (let’s call him Jack) will be able to re-generate the netlists and bitstream files without a problem.
To give you an example, a Xilinx IP core can contain all of these file types:
- .MPD file (Description of the IP core)
- .PAO file (List of source files used by the core)
- .UCF file (Constraints specific to the core)
- .BBD file (List of netlists used by the core)
- .NGC file(s) (Netlists used by the core)
- .VHD file(s) (VHDL source files)
- .V file(s) (Verilog source files)
In this example, all the files are necessary so we should commit them all except the netlist files. Obviously, Jack will need the netlist files, so we must also commit all the source files necessary to re-build the netlist file.
If the netlist file was originally built by Core Generator, for example, a FIFO, then you will need to commit the two files that are necessary to re-build the netlist with Coregen:
- .CGP file – The coregen project file which contains details about the target FPGA.
- .XCO file – The core description file (one for each netlist).
You can commit these files in a unique sub-folder of the IP core (let’s say “ngc_src”). Now, Jack will have all the sources for the IP core and all the sources needed to build the netlists of the IP core.
But there is still a problem: Jack doesn’t want to open Coregen, build the netlist and copy it to the right location for all of your IP cores. Unless you want to make it hard for Jack, you should automate the process of generating the netlists. This can be done through a TCL script file. By adding a TCL script file to your IP core, you can have the netlist generated when the core is synthesized (in EDK for example).
I’ll talk about using TCL scripts for this in the next post. For now, here is a list of the critical source files that you need to commit to SVN for the different types of projects in the Xilinx ISE Design Suite 13.1.
Xilinx Platform Studio (XPS or EDK) Project Critical Sources
- \system.xmp file – The project file.
- \system.mhs file – The hardware description file.
- \data\system.ucf – The constraints file.
- \etc\bitgen.ut – The bit gen file.
- \etc\download.cmd – The download options file.
- \etc\fast_runtime.opt – The XFLOW options file.
- \etc\xmd_microblaze_0.opt – Script to run XMD.
ISE Project Critical Sources
The product of an ISE project can be a netlist, a bitstream or both. Either way, you obviously need to commit the source files (VHDL or Verilog) and for projects that produce bitstreams, you need to commit the constraints file (.ucf). That leaves the project file:
- \projectname.xise – The ISE project file.
Core Generator IP core Critical Sources
The product of a Core generator project is typically a netlist (.NGC file). These are the source files you should commit to be able to re-generate a netlist file from coregen.
- \corename.cgp – The coregen project file contains details about the target FPGA.
- \corename.xco – The core description file.
In the previous tutorial titled Creating a project using Base System Builder, we used the Embedded Development Kit (EDK) to create a hardware design composed of IP cores and a Microblaze soft processor. In this tutorial, we will complete the design by writing a software application to run on the Microblaze processor. In version 13.1, this is done using the Software Development Kit (SDK) and it is no longer “doable” in the EDK. To keep things simple, we’ll start off with a “hello world” application and then move onto one that will communicate with our peripherals. Specifically, we will read the DIP switch settings and display them on the terminal screen using printfs.
Requirements
To perform this tutorial, you will need:
- Xilinx ISE Design Suite 13.1
- ML50x or XUPV5 development board
- Serial to USB converter
If you didn’t do the previous tutorial about creating an EDK hardware project, you will at least need to download the project files for your specific board and build the project in EDK. Find the project files at the end of the tutorial here.
Export the EDK project to SDK
- If it is not already the case, you will need to copy the EDK project files into the “C:\ML509\Projects\base-system-v13-1\edk” folder and build the bitstream as done in the tutorial. Note, it doesn’t have to be in C-drive and it doesn’t have to be in the ML509/Projects folder, but above this, try to use the same folder structure as we do here.
- Open EDK by selecting “Xilinx ISE Design Suite 13.1->EDK->Xilinx Platform Studio”.
- Open the base-system-v13-1 project.
- From the EDK menu, select “Project->Export hardware design to SDK”.
- In the dialog box that appears, make sure that “Include Bitstream and BMM file” is ticked and click “Export Only”.

- If you didn’t build the EDK project earlier, it will begin to build the bitstream which may take some time (maybe half an hour depending on your machine). After that, the project will have been exported to SDK and you can continue.
Start SDK
- Open SDK by selecting “Xilinx ISE Design Suite 13.1->EDK->Xilinx Software Development Kit”.
- The first thing you will be asked by SDK is what workspace to open.
What are SDK Workspaces?
Think of the SDK workspace as a folder where you will manage the software application(s) for one particular EDK hardware design. You can place the workspace anywhere on your machine, but I personally like to organize my projects in a folder structure as follows:
- base-system-v13-1: The high-level folder that uses the name of my project.
- edk: The sub-folder with my EDK project files.
- sdk: The sub-folder with my SDK project files.
In the example above, my project name is “base-system-v13-1″ which tells me its the base system project that I made using version 13.1 of the Xilinx suite.
- Select “C:\ML509\Projects\base-system-v13-1\sdk” for your SDK workspace and click OK.

- SDK opens up with a welcome screen. Select “File->New->Xilinx C project”.
- You will then be asked to specify a hardware platform. Click “Specify”.

- In the dialog box that appears, type the name of the project as “base-system-v13-1″ and use the browse button to navigate to the “base-system-v13-1/edk/SDK/SDK_Export/hw/system.xml” file. This file was created by EDK when we exported the project to SDK. If you cannot find this file, close SDK, open EDK and re-perform the “Export to SDK” step.

- Click Finish.
- The wizard that follows will allow us to create a template software application for our project. The default is the “hello world” example and we want to start with this one. Click Next to accept the defaults as shown in the image below.

- Click Finish to accept the defaults of the second page.

- If you did everything correctly, you should have the SDK window looking like the image below.

Load the FPGA with the bitstream
- Turn on your hardware platform (ML50x or XUPV5 or whatever you have).
- Connect the Serial to USB device to your board’s RS232 port and your computer’s USB port.
- Open your terminal program (eg. Hyperterminal or Putty) and connect to the COM port that corresponds to your Serial to USB device.
- From the SDK menu, select “Xilinx Tools->Program FPGA”.

- In the “Program FPGA” dialog box, the defaults should already specify the correct bitstream for the hardware project. Make sure they correspond to the image above and click Program.
Run the Software Application
- From the SDK menu, select “Run->Run”.
- In the “Run As” dialog box, select “Launch on Hardware”.

- SDK will build the software application, load it into the memory on the FPGA and trigger the Microblaze to run the code. You should see the words “Hello World” written in your terminal window.

In the following tutorial, we will modify the template software application so that it reads from the DIP switch IP core to obtain the switch values and display them in the terminal window using printfs.
Why can’t I find my signals in Chipscope inserter?
Often you want to assign a constraint to a particular signal in your design, or you want be able to find a particular signal in Chipscope inserter. In both cases, the signal must be in the physical design database (ie. in the .NCD file – Native Circuit Description) which is generated by the mapper. Not all signal names in your HDL code will end up in the NCD, some of them will be absorbed into logic blocks and grouped into a different signal name. To ensure that a particular signal name ends up in the NCD, it’s important to use the “keep” signal constraint.
When a design is mapped, some nets may be absorbed into logic blocks. The mapping tool does this because as a signal passes from one logic block to another, it can change name in your HDL code (eg. from data_in to data_out). As it is the same signal, the mapping tool gives it ONE name and it chooses among the names you have given it in your code.
When a net is absorbed into a block, it can no longer be seen in the physical design database. What this means in a practical sense is that you will no longer be able to refer to it in your UCF, and you will not find it in Chipscope inserter.
The “keep” constraint is a constraint that you put in your HDL code that prevents the signals you specify from being absorbed away.
In VHDL, before the “begin” statement, you must define “keep” as a string attribute and then assign the keep attributes as “true” for all the signals you want to keep.
attribute keep : string; attribute keep of MyRefClk : signal is "true"; attribute keep of MyData : signal is "true";
In Verilog, you would use the following lines:
// synthesis attribute keep [of] MyRefClk [is] "true"; // synthesis attribute keep [of] MyData [is] "true";
Both examples will keep the signal names “MyRefClk” and “MyData” in the physical design database and you will be able to refer to them in your UCF file and find them in Chipscope inserter.
The diagram below shows the EDK window with an open project. The important areas are labelled with numbers 1 to 6.
1. Project Information
This area contains information about the project and contains two tabs: Project and IP Catalog.
- The Project tab lists the project files and also some of the project settings such as target FPGA.
- The IP catalog contains a list of the peripherals or IP cores that your project has access to. You will use this tab when you want to instantiate IP cores into your design. Get information about cores by right clicking on them and clicking “View PDF datasheet”.
2. Bus connectivity
This area shows the interconnections between your IP cores, your memory and the Microblaze processor(s). You’ll notice two types of bus: the Processor Local Bus (PLB) and the Local Memory Bus (LMB).
The filled circles and squares you see on the bus lines indicate connections. For example, the filled circle to the left of IIC_EEPROM indicates that it is connected to the PLB. If you click on the circle, you can disconnect it from the PLB and the circle becomes hollow.
3. View Buttons
Although this looks like one button, it is actually two buttons. Click on the top of this little icon and you can change between hierarchical view and flat view. Try it yourself to see the difference however I personally never use the flat view.
4. Console Window
The console window displays all the textual information, warnings and errors that occur as you make changes to the project, generate netlists, bitstreams, etc.
5. System Assembly View
This is where all your project’s IP cores and processors are listed. Anything you use in your design will be listed here and you typically place things here from the IP catalog or by modifying your MHS file.
The Bus Interface tab shows the following information for each core:
- Instance name – this name is what you will use to reference the core in your UCF constraints file.
- Bus name – the bus to which the core is connected (eg. PLB).
- IP type – the name of the IP core as in the IP catalog. This column also shows an icon that indicates whether this IP core is in development or if it is a final revision (green star). The cores in development will always be checked for code changes every time you try to build the project.
- IP version – the version of the IP core.
The Ports tab shows the user accessible ports of the IP cores and the nets to which they connect. The first item in the Ports tab is the external ports which is the list of ports that will be connected to external pins of the FPGA. You create external ports by using the “Make External” option in the net drop-down menus, or by modifying your MHS file.
The Addresses tab shows how the IP cores are mapped to the PLBs in your design (usually you only have one PLB). The mapping is important to the Microblaze processor(s) because it uses these addresses to communicate with the cores, by reading and writing to registers inside the cores. The “Generate addresses” button allows you to create new addresses for cores that you manually added to the design (ie. for cores that Base System Builder did not include for you).
6. Filters Pane
The filters pane allows you to filter what is shown in the System Assembly View, for the case that you have many IP cores in your design or you want a simplified view of your design. I personally never find myself using this.
If you’re a hardware developer, you know the problem:
- My product integrates the FPGA and ADC on the one compact PCB, but now my customers want a higher-speed ADC, or a DAC, or both. Now I have to take on the risk of designing a whole new board to satisfy that demand.
- I’m getting killed on repairs because the cost of my field-replacable-unit is too high. Having too many high-cost devices on the same board is just not economical.
If you’re an FPGA developer, you know the problem:
- I want to interface a wide input stream to my FPGA, but my development board doesn’t offer that kind of connectivity.
- I need to pass multiple MGT connections from one board to another and I’d like to do it with one connector.
- And on and on and on…
The solution:
Expensive products need modular design to control the risk and create more adaptable products. FMC standard separates the FPGA from the IO (ADC/DAC/Ethernet/Optics/whatever) with a carrier to mezzanine card design.
The FPGA Mezzanine Card (FMC) standard solves these problems with a single 400-pin surface-mount connector and a standard for FMC carriers and daughter cards. The standard specifies the envelope of the FMCs and also their connections to the FMC connector in terms of which FMC pins connect to which pins of the FPGA. There are pins dedicated for MGTs, clocks and others for general IO.
Here’s what a standard FMC looks like. This is an 8-channel 250MSps analog-to-digital converter:

Xilinx has this to say about the benefits of FMC:
- Data throughput: Individual signaling speeds up to 10 Gb/s are supported, with a potential overall bandwidth of 40 Gb/s between mezzanine and carrier card
- Latency: Elimination of protocol overhead removes latency and ensures deterministic data delivery.
- Design simplicity: Expertise in protocol standards such as PCI, PCI Express®, or Serial RapidIO is not required.
- System overhead: Simplifying the system design reduces power consumption, IP core costs, engineering time, and material costs.
- Design reuse: Whether using a custom in-house board design or a commercial-off-the-shelf (COTS) mezzanine or carrier card, the FMC standard promotes the ability to retarget existing FPGA/carrier card designs to a new I/O. All that is required is swapping out the FMC module and slightly adjusting the FPGA design.
As an enabler of FPGA based technologies and a means to reduce development costs, Xilinx obviously has a lot to gain from FMC. I think we should be seeing more FPGA based designs showing up in the near future.
Here are some companies that design FMCs and carriers:
- Xilinx
- 4DSP
- Lyrtech (I work here)
- Hitech Global
- Delphi Engineering Group
- Faster Technology
- Alpha Data (carriers only)
Other groups and information:
- The VITA page for FMC
- FMC group on LinkedIn
- Open source FMC projects
- Open source FMC Analog-to-Digital converter 100MSps 14-bit 4-channel
How do I solder this thing?
I know a lot of you are DIY developers like me so I thought I’d mention a bit of the practical side of using these connectors. Unfortunately if you want to put together your own FMC, the connector itself is impossible to hand solder (I’d like to see someone prove me wrong though ;), so you will need a stencil, solder paste and an oven.
- Sparkfun has a great tutorial on solder paste stenciling that you can do at home and wont break your budget.
- A more adventurous guy has done it with toaster: What’s the easiest way to solder the FMC connector?
The other day I wasted hours trying to figure out why my peripheral wasn’t properly clocking Chipscope. Basically I had my peripheral generating a clock and data which I plugged directly into a Chipscope ILA peripheral. When I looked at the Chipscope data, it was sort of random but sort of looked right at the same time.
I eventually realized that in my MPD file for the peripheral, I had forgotten to specify that my clock output was in fact a “clock” output by using the SIGIS = CLK parameter.
Look at an example MPD file for a PLB peripheral. I highlighted all the SIGIS = CLK lines to show you what I mean:
BEGIN my_multiplier ## Peripheral Options OPTION IPTYPE = PERIPHERAL OPTION IMP_NETLIST = TRUE OPTION HDL = VHDL OPTION IP_GROUP = MICROBLAZE:PPC:USER ## Bus Interfaces BUS_INTERFACE BUS = SPLB, BUS_STD = PLBV46, BUS_TYPE = SLAVE ## Generics for VHDL or Parameters for Verilog PARAMETER C_BASEADDR = 0xffffffff, DT = std_logic_vector, PAIR = C_HIGHADDR, ADDRESS = BASE, BUS = SPLB PARAMETER C_HIGHADDR = 0x00000000, DT = std_logic_vector, PAIR = C_BASEADDR, ADDRESS = HIGH, BUS = SPLB PARAMETER C_SPLB_AWIDTH = 32, DT = INTEGER, BUS = SPLB PARAMETER C_SPLB_DWIDTH = 128, DT = INTEGER, BUS = SPLB PARAMETER C_SPLB_NUM_MASTERS = 8, DT = INTEGER, BUS = SPLB PARAMETER C_SPLB_MID_WIDTH = 3, DT = INTEGER, BUS = SPLB PARAMETER C_SPLB_NATIVE_DWIDTH = 32, DT = INTEGER, BUS = SPLB PARAMETER C_SPLB_P2P = 0, DT = INTEGER, BUS = SPLB PARAMETER C_SPLB_SUPPORT_BURSTS = 0, DT = INTEGER, BUS = SPLB PARAMETER C_SPLB_SMALLEST_MASTER = 32, DT = INTEGER, BUS = SPLB PARAMETER C_SPLB_CLK_PERIOD_PS = 10000, DT = INTEGER, BUS = SPLB PARAMETER C_INCLUDE_DPHASE_TIMER = 1, DT = INTEGER PARAMETER C_FAMILY = virtex5, DT = STRING ## Ports PORT SPLB_Clk = "", DIR = I, SIGIS = CLK, BUS = SPLB PORT SPLB_Rst = SPLB_Rst, DIR = I, SIGIS = RST, BUS = SPLB PORT PLB_ABus = PLB_ABus, DIR = I, VEC = [0:31], BUS = SPLB PORT PLB_UABus = PLB_UABus, DIR = I, VEC = [0:31], BUS = SPLB PORT PLB_PAValid = PLB_PAValid, DIR = I, BUS = SPLB PORT PLB_SAValid = PLB_SAValid, DIR = I, BUS = SPLB PORT PLB_rdPrim = PLB_rdPrim, DIR = I, BUS = SPLB PORT PLB_wrPrim = PLB_wrPrim, DIR = I, BUS = SPLB PORT PLB_masterID = PLB_masterID, DIR = I, VEC = [0:(C_SPLB_MID_WIDTH-1)], BUS = SPLB PORT PLB_abort = PLB_abort, DIR = I, BUS = SPLB PORT PLB_busLock = PLB_busLock, DIR = I, BUS = SPLB PORT PLB_RNW = PLB_RNW, DIR = I, BUS = SPLB PORT PLB_BE = PLB_BE, DIR = I, VEC = [0:((C_SPLB_DWIDTH/8)-1)], BUS = SPLB PORT PLB_MSize = PLB_MSize, DIR = I, VEC = [0:1], BUS = SPLB PORT PLB_size = PLB_size, DIR = I, VEC = [0:3], BUS = SPLB PORT PLB_type = PLB_type, DIR = I, VEC = [0:2], BUS = SPLB PORT PLB_lockErr = PLB_lockErr, DIR = I, BUS = SPLB PORT PLB_wrDBus = PLB_wrDBus, DIR = I, VEC = [0:(C_SPLB_DWIDTH-1)], BUS = SPLB PORT PLB_wrBurst = PLB_wrBurst, DIR = I, BUS = SPLB PORT PLB_rdBurst = PLB_rdBurst, DIR = I, BUS = SPLB PORT PLB_wrPendReq = PLB_wrPendReq, DIR = I, BUS = SPLB PORT PLB_rdPendReq = PLB_rdPendReq, DIR = I, BUS = SPLB PORT PLB_wrPendPri = PLB_wrPendPri, DIR = I, VEC = [0:1], BUS = SPLB PORT PLB_rdPendPri = PLB_rdPendPri, DIR = I, VEC = [0:1], BUS = SPLB PORT PLB_reqPri = PLB_reqPri, DIR = I, VEC = [0:1], BUS = SPLB PORT PLB_TAttribute = PLB_TAttribute, DIR = I, VEC = [0:15], BUS = SPLB PORT Sl_addrAck = Sl_addrAck, DIR = O, BUS = SPLB PORT Sl_SSize = Sl_SSize, DIR = O, VEC = [0:1], BUS = SPLB PORT Sl_wait = Sl_wait, DIR = O, BUS = SPLB PORT Sl_rearbitrate = Sl_rearbitrate, DIR = O, BUS = SPLB PORT Sl_wrDAck = Sl_wrDAck, DIR = O, BUS = SPLB PORT Sl_wrComp = Sl_wrComp, DIR = O, BUS = SPLB PORT Sl_wrBTerm = Sl_wrBTerm, DIR = O, BUS = SPLB PORT Sl_rdDBus = Sl_rdDBus, DIR = O, VEC = [0:(C_SPLB_DWIDTH-1)], BUS = SPLB PORT Sl_rdWdAddr = Sl_rdWdAddr, DIR = O, VEC = [0:3], BUS = SPLB PORT Sl_rdDAck = Sl_rdDAck, DIR = O, BUS = SPLB PORT Sl_rdComp = Sl_rdComp, DIR = O, BUS = SPLB PORT Sl_rdBTerm = Sl_rdBTerm, DIR = O, BUS = SPLB PORT Sl_MBusy = Sl_MBusy, DIR = O, VEC = [0:(C_SPLB_NUM_MASTERS-1)], BUS = SPLB PORT Sl_MWrErr = Sl_MWrErr, DIR = O, VEC = [0:(C_SPLB_NUM_MASTERS-1)], BUS = SPLB PORT Sl_MRdErr = Sl_MRdErr, DIR = O, VEC = [0:(C_SPLB_NUM_MASTERS-1)], BUS = SPLB PORT Sl_MIRQ = Sl_MIRQ, DIR = O, VEC = [0:(C_SPLB_NUM_MASTERS-1)], BUS = SPLB## My custom output ports PORT My_Clk = "", DIR = O, SIGIS = CLK PORT My_Rst = "", DIR = I, SIGIS = RST PORT My_Data = "", DIR = O, VEC = [7:0]END
My lesson:
When your peripheral generates a clock, make sure you specify that it’s a clock in your MPD file with SIGIS = CLK!
For some reason, the Base System Builder in EDK doesn’t support the XUPV5 board so when making an EDK project for the XUPV5 we have to select the ML505 board and modify the project settings later. If you have not yet created an EDK project, you should read the previous post Creating a project using the Base System Builder, and then continue from these instructions.
Change the target FPGA
The ML505 is based on the Virtex-5 XC5VLX50T whereas the XUPV5 is based on the Virtex-5 XC5VLX110T, so the first thing we must do is change the target FPGA of the project.
- Open XPS and open your base project which should have been setup for the ML505 board.
- Select “Project->Project Options”.

- Change the target FPGA setting to “XC5VLX110T”, package “FFG1136″ and speed grade “-1″.
- Click “OK” to save the changes.
We’re not finished yet so don’t get too excited and try building the bitstream. If you were to try to build the bitstream, you would come up with this error:
ERROR: Place:713 - IOB component "fpga_0_DDR2_SDRAM_DDR2_DQ_pin<13>" and IODELAY component "DDR2_SDRAM/DDR2_SDRAM/mpmc_core_0/gen_v5_ddr2_phy.mpmc_phy_if_0/u_phy_io_0/g en_dq[13].u_iob_dq/u_idelay_dq" must be placed adjacent to each other into the same I/O tile in order to route net "DDR2_SDRAM/DDR2_SDRAM/mpmc_core_0/gen_v5_ddr2_phy.mpmc_phy_if_0/u_phy_io_0/g en_dq[13].u_iob_dq/dq_in". The following issue has been detected: Some of the logic associated with this structure is locked. This should cause the rest of the logic to be locked.A problem was found at site IODELAY_X0Y56 where we must place IODELAY DDR2_SDRAM/DDR2_SDRAM/mpmc_core_0/gen_v5_ddr2_phy.mpmc_phy_if_0/u_phy_io_0/ge n_dq[13].u_iob_dq/u_idelay_dq in order to satisfy the relative placement requirements of this logic. IODELAY DDR2_SDRAM/DDR2_SDRAM/mpmc_core_0/gen_v5_ddr2_phy.mpmc_phy_if_0/u_phy_io_0/ge n_dqs[0].u_iob_dqs/u_iodelay_dq_ce appears to already be placed there which makes this design unplaceable. ERROR: Pack:1654 - The timing-driven placement phase encountered an error. ERROR: Xflow - Program map returned error code 2. Aborting flow execution... make: *** [__xps/system_routed] Error 1
The reason for this error is that the design contains certain location constraints that are optimal for the Virtex-5 XC5VLX50T but not for the XC5VLX110T. We will have to modify the UCF file to use location constraints that are optimal for our FPGA.
Add the PCIe Bridge Constraints
The PCIe bridge peripheral that we included in the project has timing constraints in the project UCF file (system.ucf) but it also has some location constraints in its core specific UCF file (implementation/pcie_bridge_wrapper/pcie_bridge_wrapper.ucf). If you are curious, open this file and read the constraints inside.
The core specific UCF file is generated when you build the project and it is usually generated with constraints that are optimal for the target platform (ie. ML505 in our case). As the ML505 contains a smaller FPGA, the constraints are not optimal for the XUPV5 and we will have to override them by placing the same constraints (with different locations) into the project UCF file (system.ucf).
- Copy and paste the following lines to the bottom of your system.ucf file. Notice that they are the same constraints you would have found in the pcie_bridge_wrapper.ucf file, but I have changed the LOCs. All constraints placed in the system.ucf file will override the core specific constraints.
############################################################################### # PCIe Bridge Constraints for XUPV5 ############################################################################### # BlockRAM placement INST "pcie_bridge/*pcie_mim_wrapper_i/bram_tl_tx/generate_tdp2[1].ram_tdp2_inst" LOC = RAMB36_X3Y11; INST "pcie_bridge/*pcie_mim_wrapper_i/bram_tl_rx/generate_tdp2[1].ram_tdp2_inst" LOC = RAMB36_X3Y9; INST "pcie_bridge/*pcie_mim_wrapper_i/bram_tl_tx/generate_tdp2[0].ram_tdp2_inst" LOC = RAMB36_X3Y10; INST "pcie_bridge/*pcie_mim_wrapper_i/bram_tl_rx/generate_tdp2[0].ram_tdp2_inst" LOC = RAMB36_X3Y8; INST "pcie_bridge/*pcie_mim_wrapper_i/bram_retry/generate_sdp.ram_sdp_inst" LOC = RAMB36_X3Y7; # Timing critical placements INST "pcie_bridge/*tx_bridge/shift_pipe1" LOC = "SLICE_X59Y56"; INST "pcie_bridge/*arb_inst/completion_available" LOC = "SLICE_X58Y46"; INST "pcie_bridge/*management_interface/mgmt_rdata_d1_3" LOC = "SLICE_X59Y45";
Remove the DDR2 constraints
The DDR2 memory controller peripheral is the other device with some critical location constraints that we will have to optimize for the XUPV5.
- Find and remove the following lines in the system.ucf file.
############################################################################### # LOC placement of DQS-squelch related IDDR and IDELAY elements # Each circuit can be located at any of the following locations: # 1. Ununsed "N"-side of DQS diff pair I/O # 2. DM data mask (output only, input side is free for use) # 3. Any output-only site ############################################################################### INST "*/gen_dqs[0].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y56"; INST "*/gen_dqs[0].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y56"; INST "*/gen_dqs[1].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y18"; INST "*/gen_dqs[1].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y18"; INST "*/gen_dqs[2].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y22"; INST "*/gen_dqs[2].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y22"; INST "*/gen_dqs[3].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y60"; INST "*/gen_dqs[3].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y60"; INST "*/gen_dqs[4].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y62"; INST "*/gen_dqs[4].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y62"; INST "*/gen_dqs[5].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y216"; INST "*/gen_dqs[5].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y216"; INST "*/gen_dqs[6].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y220"; INST "*/gen_dqs[6].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y220"; INST "*/gen_dqs[7].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y222"; INST "*/gen_dqs[7].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y222"; ############################################################################### # LOC and timing constraints for flop driving DQS CE enable signal # from fabric logic. Even though the absolute delay on this path is # calibrated out (when synchronizing this output to DQS), the delay # should still be kept as low as possible to reduce post-calibration # voltage/temp variations - these are roughly proportional to the # absolute delay of the path ############################################################################### INST "*/u_phy_calib_0/gen_gate[0].u_en_dqs_ff" LOC = SLICE_X0Y28; INST "*/u_phy_calib_0/gen_gate[1].u_en_dqs_ff" LOC = SLICE_X0Y9; INST "*/u_phy_calib_0/gen_gate[2].u_en_dqs_ff" LOC = SLICE_X0Y11; INST "*/u_phy_calib_0/gen_gate[3].u_en_dqs_ff" LOC = SLICE_X0Y30; INST "*/u_phy_calib_0/gen_gate[4].u_en_dqs_ff" LOC = SLICE_X0Y31; INST "*/u_phy_calib_0/gen_gate[5].u_en_dqs_ff" LOC = SLICE_X0Y108; INST "*/u_phy_calib_0/gen_gate[6].u_en_dqs_ff" LOC = SLICE_X0Y110; INST "*/u_phy_calib_0/gen_gate[7].u_en_dqs_ff" LOC = SLICE_X0Y111;
Add the new DDR2 constraints
- Add the following constraints to the system.ucf file. You will notice that they are similar to the constraints that we just removed, yes we are replacing the old constraints with these ones!
############################################################################### # LOC placement of DQS-squelch related IDDR and IDELAY elements # Each circuit can be located at any of the following locations: # 1. Ununsed "N"-side of DQS diff pair I/O # 2. DM data mask (output only, input side is free for use) # 3. Any output-only site ############################################################################### INST "*/gen_dqs[0].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y96"; INST "*/gen_dqs[0].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y96"; INST "*/gen_dqs[1].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y58"; INST "*/gen_dqs[1].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y58"; INST "*/gen_dqs[2].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y62"; INST "*/gen_dqs[2].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y62"; INST "*/gen_dqs[3].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y100"; INST "*/gen_dqs[3].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y100"; INST "*/gen_dqs[4].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y102"; INST "*/gen_dqs[4].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y102"; INST "*/gen_dqs[5].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y256"; INST "*/gen_dqs[5].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y256"; INST "*/gen_dqs[6].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y260"; INST "*/gen_dqs[6].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y260"; INST "*/gen_dqs[7].u_iob_dqs/u_iddr_dq_ce" LOC = "ILOGIC_X0Y262"; INST "*/gen_dqs[7].u_iob_dqs/u_iodelay_dq_ce" LOC = "IODELAY_X0Y262"; INST "DDR2_SDRAM/DDR2_SDRAM/gen_no_iodelay_grp.gen_instantiate_idelayctrls[1].idelayctrl0" LOC = IDELAYCTRL_X0Y2; INST "DDR2_SDRAM/DDR2_SDRAM/gen_no_iodelay_grp.gen_instantiate_idelayctrls[0].idelayctrl0" LOC = IDELAYCTRL_X0Y6; INST "DDR2_SDRAM/DDR2_SDRAM/gen_no_iodelay_grp.gen_instantiate_idelayctrls[2].idelayctrl0" LOC = IDELAYCTRL_X0Y1; ############################################################################### # LOC and timing constraints for flop driving DQS CE enable signal # from fabric logic. Even though the absolute delay on this path is # calibrated out (when synchronizing this output to DQS), the delay # should still be kept as low as possible to reduce post-calibration # voltage/temp variations - these are roughly proportional to the # absolute delay of the path ############################################################################### INST "*/u_phy_calib_0/gen_gate[0].u_en_dqs_ff" LOC = SLICE_X0Y48; INST "*/u_phy_calib_0/gen_gate[1].u_en_dqs_ff" LOC = SLICE_X0Y29; INST "*/u_phy_calib_0/gen_gate[2].u_en_dqs_ff" LOC = SLICE_X0Y31; INST "*/u_phy_calib_0/gen_gate[3].u_en_dqs_ff" LOC = SLICE_X0Y50; INST "*/u_phy_calib_0/gen_gate[4].u_en_dqs_ff" LOC = SLICE_X0Y51; INST "*/u_phy_calib_0/gen_gate[5].u_en_dqs_ff" LOC = SLICE_X0Y128; INST "*/u_phy_calib_0/gen_gate[6].u_en_dqs_ff" LOC = SLICE_X0Y130; INST "*/u_phy_calib_0/gen_gate[7].u_en_dqs_ff" LOC = SLICE_X0Y131;
Build the project
Now you are ready to build the project and if you have done everything right, you should not have any errors.
- Select “Device Configuration->Update Bitstream”. It should take about a half an hour to build depending on your machine.
- You should see the message below if you are successful.
Checking platform address map ... Initializing Memory... Running Data2Mem with the following command: data2mem -bm "implementation/system_bd" -p xc5vlx110tff1136-1 -bt "implementation/system.bit" -bd "bootloops/microblaze_0.elf" tag microblaze_0 -o b implementation/download.bit Memory Initialization completed successfully. Done!
You can download the project files as a compressed zip file here: base-system-xupv5-edk13-1.zip
What am I learning here?
In this post we’ll look at using the Base System Builder in EDK version 13.1. Specifically you’ll learn:
- How to create an EDK project with the Base System Builder
- How to add a software application to an EDK project
- How to implement and test your design
Requirements
You will need the following :
- One ML505/ML506/ML507 or XUPV5 board (or actually any board supported by Xilinx).
- Xilinx ISE Design Suite 13.1 (including EDK)
Create the Basic Project
Follow these steps to create the basic project:
- Open XPS by selecting “Start->Xilinx ISE Design Suite 13.1->EDK->Xilinx Platform Studio”.
- From the dialog box, select “Base System Builder wizard” and OK.
- You will be asked to specify which folder to place the project. Click “Browse” and create a new folder for the project. Click “OK”.

- The first page of the wizard will ask us to choose between using a Processor Local Bus (PLB) or an Advanced Extensible Interface (AXI). As we are using the Virtex-5, we have to select a PLB system, but if you are working with a Virtex-6 or a Spartan-6 you are better to go with the AXI system.

- We are given the choice to create a new project or to create one using the template of another project. Tick “I would like to create a new design” and click “Next”.

- On the “Select Board” page, select “Xilinx” as the board vendor. Then select the board you are using (eg. “Virtex 5 ML505 Evaluation Platform”). Select “1″ as the board revision. Click “Next”. (Note: If you are using the XUPV5 (ML509) board, select “Virtex 5 ML505 Evaluation Platform” instead.)

- Now we have the choice to build a single-processor or dual-processor system. The Virtex-5 doesn’t have any hard processors, so the Base System Builder will setup a Microblaze soft processor for us. Select “Single-Processor System” and click “Next”.

- On the “Configure Microblaze” page, we can specify the clock frequency of our processor and the amount of memory it will use. Select the clock frequency to 125MHz. Click “Next”.

- Now we can select the peripherals to put in the design. The peripherals will all be connected to the Microblaze processor via the PLB and they allow us to control and access features of the FPGA and external hardware such as the DDR2 memory and the Ethernet MAC. We will leave the default setting which is to include ALL the standard peripherals. You might ask “Why include all the peripherals?“, well most of the time you would only include the peripherals that you need so that you don’t waste time building peripherals you wont use. In this case, I want you to include all the peripherals because a lot of the following EDK tutorials will be based on this “base system”. This way, we wont have to go through the Base System Builder for every tutorial and we’ll save time. The fact is, in a professional environment, you would never go through the Base System Builder when starting a new project, instead you would take an existing project and develop from that.

- In the next page we can configure cache memory for the Microblaze. In our case we wont use cache memory so leave the default and click “Next”.

- The Base System Builder then gives us a summary of the design that it will create for us, showing the PLB memory map, the peripherals and the files that it will create.

- Click “Finish”.
If you are using the XUPV5 (ML509) board
If you are using the XUPV5 (ML509) board and you selected “Virtex 5 ML505 Evaluation Platform” in step 6 above, you will have to change the target FPGA setting to “XC5VLX110T”, package “FFG1136″ and speed grade “-1″ in the “Project->Project Options” menu. There are more changes to make that will be discussed in the next post: Convert an ML505 project for the XUPV5. If you don’t make these changes, you’ll find this error message when you try to build the bitstream:
ERROR:Place:713 - IOB component "fpga_0_DDR2_SDRAM_DDR2_DQ_pin<13>" and IODELAY component "DDR2_SDRAM/DDR2_SDRAM/mpmc_core_0/gen_v5_ddr2_phy.mpmc_phy_if_0/u_phy_io_0/g en_dq[13].u_iob_dq/u_idelay_dq" must be placed adjacent to each other into the same I/O tile in order to route net "DDR2_SDRAM/DDR2_SDRAM/mpmc_core_0/gen_v5_ddr2_phy.mpmc_phy_if_0/u_phy_io_0/g en_dq[13].u_iob_dq/dq_in". The following issue has been detected: Some of the logic associated with this structure is locked. This should cause the rest of the logic to be locked.A problem was found at site IODELAY_X0Y56 where we must place IODELAY DDR2_SDRAM/DDR2_SDRAM/mpmc_core_0/gen_v5_ddr2_phy.mpmc_phy_if_0/u_phy_io_0/ge n_dq[13].u_iob_dq/u_idelay_dq in order to satisfy the relative placement requirements of this logic. IODELAY DDR2_SDRAM/DDR2_SDRAM/mpmc_core_0/gen_v5_ddr2_phy.mpmc_phy_if_0/u_phy_io_0/ge n_dqs[0].u_iob_dqs/u_iodelay_dq_ce appears to already be placed there which makes this design unplaceable. ERROR:Pack:1654 - The timing-driven placement phase encountered an error. ERROR:Xflow - Program map returned error code 2. Aborting flow execution... make: *** [__xps/system_routed] Error 1
Build the bitstream
The project is now ready to build.
- To build the bitstream of the project, select “Device Configuration->Update Bitstream”. This will take some time (around half an hour) depending on your machine.
You should end up seeing this message when the build is complete:
Checking platform address map ... Initializing Memory... Running Data2Mem with the following command: data2mem -bm "implementation/system_bd" -p xc5vlx110tff1136-1 -bt "implementation/system.bit" -bd "bootloops/microblaze_0.elf" tag microblaze_0 -o b implementation/download.bit Memory Initialization completed successfully. Done!
What about the software application?
If you’re used to older versions of EDK, you would notice that we didn’t put any software into the project – software to run on the Microblaze processor. The reason for this is that Xilinx has removed this functionality from EDK in version 13.1. They gave us plenty of notice actually, but now all the software development for your FPGA projects must be done in SDK (Software Development Kit), logical isn’t it?
The project folder for this tutorial can be downloaded in a compressed ZIP file. Remember that if you want to understand the modifications made to the project for the XUPV5, you should read the next post.
| Board | Virtex-5 Version | Project files |
| ML505 | XC5VLX50T | base-system-ml505-edk13-1.zip |
| ML506 | XC5VSX50T | base-system-ml506-edk13-1.zip |
| ML507 | XC5VFX70T | base-system-ml507-edk13-1.zip |
| XUPV5 | XC5VLX110T | base-system-xupv5-edk13-1.zip |
Some of you will know that I ran some polls on the site over the last couple of months. Well I checked out the results and accordingly there will be some big changes on the site, the first of which is that I’ve moved to WordPress and given the site a “fresh” new look.
Thanks to all the people who responded to the polls, your input was very very appreciated! Here are the changes:
- Comments will be enabled so now if you have something to say, you can let everyone know!
- I’m going to write up tutorials for version 13.1 so if you’re not there yet, you should get updated.
- More tutorials for EDK (which will be known as XPS from now on).
- Tutorials for ISE.
- Tutorials for Core generator.
- Tutorials for Chipscope.
- Tutorials for FPGA editor.
- Tutorials for PlanAhead.
I don’t get paid to write these tutorials and I’m totally against filling this site with ads, so I’ve decided to offer my professional services to any companies who come across the site, so please support me by linking to the site and telling your friends about the great tutorials we have here! ![]()




Recent Comments