RapidSmith

A Library for Low-level Manipulation of Partially Placed-and-Routed FPGA Designs

Technical Report and Documentation

Christopher Lavin, Marc Padilla, Jaren Lamprecht, Philip Lundrigan,
Brent Nelson, Brad Hutchings, and Michael Wirthlin

NSF Center for High Performance Reconfigurable Computing (CHREC)
Department of Electrical and Computer Engineering
Brigham Young University
Provo, UT 84602

 

Revised: 24 Jan 2014

 

 

 

 

This work was supported by the I/UCRC program of the National Science Foundation under grant number 0801876.

Table of Contents

Table of Figures. 5

Introduction. 6

What is RapidSmith?. 6

Who Should Use RapidSmith?. 6

Why RapidSmith?. 6

Which Xilinx Parts does RapidSmith Support?. 6

How is This Different than VPR?. 7

Why Java?. 7

Legal and Dependencies. 9

RapidSmith Legal Text 9

Included Dependency Projects. 9

Getting Started. 11

Installation. 11

Getting RapidSmith. 11

Requirements for Installation. 11

Steps for Installation. 11

Additional Notes for Mac OS X Installation. 12

Overview.. 13

bitstreamTools.* Package. 14

design Package. 14

design.explorer Package. 16

design.parser Package. 18

device Package. 18

device.browser Package. 19

device.helper Package. 20

examples Package. 20

placer Package. 20

primitiveDefs Package. 20

router Package. 21

tests Package. 21

timing Package. 21

util Package. 21

Examples. 21

Hello World. 21

Hand Router 23

Part Tile Browser 23

Understanding XDL.. 25

What is XDL?. 25

Basic Syntax of XDL Files. 26

Design Statement 26

Module Statement 26

Instance Statement 27

Net Statement 27

Basic Syntax of XDLRC Files. 28

Tiles. 28

Primitive Sites. 28

Wire. 29

PIP. 29

Primitive Definitions. 30

RapidSmith Structure. 31

A RapidSmith Design. 31

Loading Designs. 31

Saving Designs. 32

A RapidSmith Device. 32

Device. 32

Wire Enumerator 32

Memory and Performance. 33

Device Performance and Memory Usage. 33

Wire Enumerator Size and Performance. 33

Placement in RapidSmith. 34

Primitive Resources in RapidSmith. 34

Primitive Site. 34

Primitive Definitions and Types. 35

Primitive Instances. 35

Placement 36

Placement Techniques. 36

Routing in RapidSmith. 37

Wire Resources in RapidSmith. 37

Wire Representation. 37

Basic Routing. 39

Router Structure. 39

Routing Static Sources (VCC/GND) 40

Routing Clocks. 40

Internal Pin Names and External Pin Names. 40

Bitstreams in RapidSmith. 43

Bitstream Composition. 43

Bitstream Header 44

Dummy and Synchronization Data. 45

Packet List 45

Bitstream Configuration Data. 45

FPGA.. 45

Xilinx Configuration Specification. 45

Frame Address Register 46

Frame. 46

Configuration Block. 47

Appendix. 49

Appendix A: Modifying LUT Content 49

LUT Equation Syntax. 49

XDL LUT Equation Syntax. 49

Appendix B: Hard Macros in XDL and RapidSmith. 50

Xilinx NMC files. 50

Xilinx Hard Macros. 50

RapidSmith Hard Macro Generator 50

Appendix C: Xilinx Family Names and Part Names. 51

Xilinx Part Names in RapidSmith. 51

Xilinx Family Names in RapidSmith. 51

Appendix D: XDLRC Compatible Families. 52

Appendix E: Memory and Performance of RapidSmith. 52

Wire Enumerator Files. 53

Primitive Definitions Files. 53

Device Files. 53

 

Table of Figures

Figure 1 - Design and Attribute classes. 15

Figure 2 - Instance class. 15

Figure 3 - Net, Pin and PIP Classes. 16

Figure 4 - Hyperlinks in Design Explorer 17

Figure 5 - Timing report loaded in Design Explorer 18

Figure 6 - Device Browser screenshot 19

Figure 7 - Device browser screenshot showing wire connections. 20

Figure 8: Screenshot of Part Tile Browser 24

Figure 9: Block diagram of where XDL fits in CAD flow. 25

Figure 10: (a) The classes involved in defining a design in RapidSmith, (b) The major classes involved representing a device. 31

Figure 11 – Device Browser screenshot showing site SLICE_X1Y121 in tile CLB_X1Y60. 35

Figure 12 - A DOUBLE line in an FPGA illustrating how each part of the wire has a different name depending on the tile it is located in. 37

 

Introduction

What is RapidSmith?

The BYU RapidSmith project is a set of tools and APIs written in Java that aim to provide academics with an easy-to-use platform to try out experimental ideas and algorithms on modern Xilinx FPGAs.  RapidSmith is based on the Xilinx Design Language (XDL) which provides a human-readable file format equivalent to the Xilinx proprietary Netlist Circuit Description (NCD).  With RapidSmith, researchers are able to import XDL/NCD, manipulate, place, route and export designs among a variety of design transformations.  The RapidSmith project makes an excellent test bed to try out new ideas and algorithms for FPGA CAD research as code can quickly be written to take advantage of the APIs available. 

 

RapidSmith also contains packages which can parse/export bitstreams (at the packet level) and represent the frames and configuration blocks in the provided data structures.  It can parse, manipulate and export bitstreams according to Xilinx documented methods.

RapidSmith does not include any proprietary information about Xilinx FPGAs that is not publicly available.

Who Should Use RapidSmith?

RapidSmith is aimed at use by academics in all fields of FPGA CAD research.  It is written in Java; therefore those using it will need to have a basic knowledge of programming and using Java.  It also depends on some understanding of Xilinx FPGAs and XDL, however, this documentation hopes to bring people unfamiliar with these topics up to speed.

 

RapidSmith by no means is a Xilinx ISE replacement and cannot be used without a valid and current license to a Xilinx tools installation.  RapidSmith should not be used for designs bound for commercial products and is offered mainly as a research tool.

Why RapidSmith?

The Xilinx ISE tools provide an xdl executable that allows conversion of NCD files to and from XDL which can then be parsed, manipulated and exported using RapidSmith.  The xdl executable also creates special device files which are huge in size but contain useful detailed device data.   

 

RapidSmith takes care of all of the parsing and detailed FPGA part information that can be cumbersome to use—alleviating the need to build such parsing tools by the researcher.  RapidSmith creates special part files from these device files created by the ISE tools which can then be used by RapidSmith for design manipulation.  This project provides researchers the ability to leverage all of the XDL work previously done and avoid duplicate work.  This will enable researchers to have more time to focus on what matters most: their research of new ideas and algorithms.

Which Xilinx Parts does RapidSmith Support?

Virtex 4 and 5 families have been tested the most and are currently supported in all forms and applications.  However, the XDLRC reports which can be extracted from the xdl executable are very regular and so RapidSmith can create device files for all modern Xilinx FPGA families.  Therefore, RapidSmith supports (to a lesser extent than Virtex 4 and Virtex 5) the following families: Artix 7, Kintex 7, Spartan 2, Spartan 2E, Spartan 3, Spartan 3A, Spartan 3ADSP, Spartan 3E, Spartan 6, Virtex, Virtex E, Virtex 2, Virtex 2 Pro, Virtex 6, Virtex 7 and Zynq.  To create the device files for the legacy devices, Xilinx ISE 10.1.03 or earlier will be needed. The table below provides a complete set of compatible features for each Xilinx FPGA family. See the Appendix for more family compatibilities (Spartan 6L, Virtex 6L, etc.).

 

Xilinx FPGA Family

Device Database, XDL Parsing, Manipulation & Export

Placement Capabilities

Router Capabilities

Bitstream Parsing, Manipulation & Export

Artix 7

X

X

 

 

Kintex 7

X

X

 

 

Spartan 2

X

X

 

 

Spartan 2E

X

X

 

 

Spartan 3

X

X

 

 

Spartan 3A

X

X

 

 

Spartan 3ADSP

X

X

 

 

Spartan 3E

X

X

 

 

Spartan 6

X

X

 

 

Virtex

X

X

 

 

Virtex E

X

X

 

 

Virtex 2

X

X

 

 

Virtex 2 Pro

X

X

 

 

Virtex 4

X

X

X

X

Virtex 5

X

X

X

X

Virtex 6

X

X

 

X

Virtex 7

X

X

 

 

Zynq

X

X

 

 

How is This Different than VPR?

VPR (Versatile Place and Route) has been an FPGA research tool for several years and has led to hundreds of publications on new FPGA CAD research.  It has been a significant contribution to the FPGA research community and has grown to be a complete FPGA CAD flow for research-based FPGAs.

 

The main difference between RapidSmith and VPR is that RapidSmith aims to provide the ability to target commercial Xilinx FPGAs. All features of these FPGAs which are accessible via XDL are available in RapidSmith.  Our understanding is that VPR currently is limited to FPGA features which can be described using VPR's architectural description facilities.

Why Java?

We have found Java to be a rapid prototyping platform for FPGA CAD tools.  The Java libraries are rich with data structures useful for such applications and Java eliminates the need to clean up objects in memory.  This eliminates the time needed to debug such things in other development platforms, leaving more time for the researcher to focus on the real research at hand.

 

Some may argue that Java is a poor platform for FPGA CAD tool design as it has a reputation of being a memory hog and slow.  We believe that these claims are overstated and that both speed and memory can be controlled to the point where this is not an issue.

Legal and Dependencies

RapidSmith Legal Text

 

   BYU RapidSmith Tools

 

   Copyright (c) 2010-2011 Brigham Young University

  

   BYU RapidSmith Tools is free software: you may redistribute it

   and/or modify it under the terms of the GNU General Public License

   as published by the Free Software Foundation, either version 2 of

   the License, or (at your option) any later version.

  

   BYU RapidSmith Tools is distributed in the hope that it will be

   useful, but WITHOUT ANY WARRANTY; without even the implied warranty

   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU

   General Public License for more details.

  

   A copy of the GNU General Public License is included with the BYU

   RapidSmith Tools. It can be found at doc/gpl2.txt. You may also get

   a copy of the license at <http://www.gnu.org/licenses/>.

 

Included Dependency Projects

RapidSmith includes the Caucho Technology Hessian implementation which is distributed under the Apache License. A copy of this license is included in the doc directory in the file APACHE2-LICENSE.txt. This license is also available for download at:

 

   http://www.apache.org/licenses/LICENSE-2.0

 

The source for the Caucho Technology Hessian implementation is available at:

 

   http://hessian.caucho.com

 

RapidSmith also includes the Qt Jambi project jars for Windows, Linux and Mac OS X.  Qt Jambi is distributed under the LGPL GPL3 license and copies of this license and exception are also available in the /doc directory in files LICENSE.GPL3.TXT and LICENSE.LGPL.TXT respectively. These licenses can also be downloaded at:

 

   http://www.gnu.org/licenses/licenses.html

  

Source for the Qt Jambi project is available at:

 

   http://qt.nokia.com/downloads

 

and more recent versions are available at:

 

   http:/qt.gitorious.org/qt-jambi

 

RapidSmith also includes the JOpt Simple option parser which is released under

the open source MIT License which can be found in this directory in the file

MIT_LICENSE.TXT.  A copy of this license can also be found at:

 

   http://www.opensource.org/licenses/mit-license.php

  

A copy of the source for JOpt Simple can also be downloaded at:

 

   http://jopt-simple.sourceforge.net/download.html

 

The user is responsible for providing copies of these licenses and making available the source code of these projects when redistributing these jars.

Getting Started

Installation

Getting RapidSmith

You can download the latest release of RapidSmith from the sourceforge page here:

 

http://sourceforge.net/projects/rapidsmith/files/

 

You can also checkout the repository from SVN.  We recommend using Eclipse, however, any IDE will work fine.  To check out the RapidSmith project, the SVN repository URL is:

 

svn://svn.code.sf.net/p/rapidsmith/code/trunk

 

The SVN command to check it out is:

 

svn checkout svn://svn.code.sf.net/p/rapidsmith/code/trunk rapidsmith-code

 

This repository contains all the files you need (including supporting JAR files).  If you are using Eclipse as your IDE, it contains project files to get the project up and running with minimal effort. If you downloaded the distribution, just extract the files into your workspace (eg: ~/workspace/rapidSmith).  Then, in Eclipse, you can import the project by going to File->Import, then choose "General/Existing Projects into Workspace".  On the next screen, choose "Select root directory" and choose the newly created folder "rapidSmith". Then click finish.  This should load up the project in your workspace.  Then follow the steps below to complete the installation.  You may have to restart Eclipse after setting the environment variables to get things to work.

Requirements for Installation

·         400 MB free disk space

·         Windows XP/Vista/7 or Linux (Mac OS X will work (see notes below), but Xilinx tools do not run on Mac OS X)

·         Xilinx ISE 11.1 or higher (10.1.03 or earlier for legacy devices).

·         JDK 1.6 (earlier versions may work, but have not been tested). NOTE: If you plan on using the Qt Jambi framework in a Windows environment, you will need the 32-bit JRE (Qt Jambi 4.6.3 has yet to be compiled in 64-bit Windows).

·         Supporting JARs

o   INCLUDED: Caucho Hessian Implementation JAR v.4.0.6 (Used for compressing database device files)

o   INCLUDED: Qt Jambi (Qt for Java) for the Part Tile Browser example.  Just adding the jars to the CLASSPATH variable is adequate.

o   INCLUDED: JOpt Simple for use by some examples in the bitstream tools packages.

o   OPTIONAL: JavaCC if the user wants to change the XDL design parser. There is also a good plugin for Eclipse for JavaCC which makes it easier to modify and compile .jj files.

Steps for Installation

1.      Make sure the Xilinx tools and JDK are on your PATH.

2.      Add all the jar files in the jars folder (hessian-4.0.6.jar, qtjambi-4.6.3.jar, qtjambi-<your_platform>-4.6.3.jar, jopt-simple-3.2.jar) to your CLASSPATH environment variable.

3.      Add the RapidSmith Java project to your CLASSPATH environment variable.

4.      Create an environment variable called RAPIDSMITH_PATH and set its value to the path where you have the Java project located on your computer.

5.      (Skip this step if you are not using legacy devices) When using RapidSmith with legacy Xilinx devices (Spartan 2/2E, Virtex, Virtex E/2/2Pro), ISE 10.1 or earlier will be needed.  In order to point RapidSmith to the appropriate installation of tools, we use an environment variable: XILINX_LEGACY_PATH which you must add and set its value to the ‘bin’ path of the 10.1 or earlier tools.  For example, setting XILINX_LEGACY_PATH=/opt/xilinx/10.1/ISE/bin/lin64 would use the 64-bit tools of ISE 10.1 of a Linux installation.

6.      Compile all of the Java classes (this can be done automatically if the project is imported into an IDE such as Eclipse).

7.      Test your installation by running any of the programs, for example, run:

java edu.byu.ece.rapidSmith.util.BrowseDevice xc5vlx20tff323

 

 

OBSOLETE: Device files are now included with RapidSmith, so the Installer class no longer needs to be run. The following instructions are simply included for legacy users (versions of RapidSmith older than 0.5.0, and using older device versions).  Generate the supporting device and enumeration files needed to run the various parts of RapidSmith. Please note that if you are generating both families of Virtex 4 and Virtex 5 parts, it will take several hours and is best left to run overnight because of the time requirement.  This only needs to be done once, however. To generate the part files, follow these steps:

a.       Choose which parts you plan to use, or you can choose to do all parts in the Virtex 4 and Virtex 5 families (in the future, more parts will be compatible).

b.      Run the installer for RapidSmith by executing the main method in the class edu.byu.ece.rapidSmith.util.Installer. This is accomplished by running the following at the command line:

Java –Xmx1600M edu.byu.ece.rapidSmith.util.Installer virtex4 virtex5

c.       The previous command will take several hours.  Some of the larger parts will also require a lot of heap memory to generate the part file (sometimes 1600M is too large for some computers, if it fails, try 1200M). 

d.      You can test if the file generation worked by looking in the appropriate folders (devices/virtex4 and devices/virtex5).  You can also run the BrowseDevice class as a test to see if you are able to browse any of the parts that have just been created.  You can run this with the following command:

Additional Notes for Mac OS X Installation

·         The Xilinx tools do not run under Mac OS X and therefore, the installer would have to generate the files on Linux or Windows.  However, once the files are created, they could be moved to a Mac OS X installation.

·         To add/modify global environment variables in Mac OS X, one preferred way would be to edit the environment.plist file in the ~/.MacOSX directory.  Here is an example of a proper setup for RapidSmith:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

      <key>RAPIDSMITH_PATH</key>

      <string>/Users/[user name]/Documents/workspace/rapidSmith</string>

      <key>CLASSPATH</key>

      <string>$CLASSPATH:/Users/[user name]/Documents/workspace/rapidSmith:/Users/[user name]/Documents/workspace/rapidSmith:/Users/[user name]/Documents/workspace/rapidSmith/jars/hessian-4.0.6.jar:/Users/[user name]/Documents/workspace/rapidSmith/jars/qtjambi-4.6.3.jar:/Users/[user name]/Documents/workspace/rapidSmith/jars/qtjambi-macosx-gcc-4.6.3.jar</string>

</dict>

</plist>

 

·         Another difference is that when running programs that use Qt in Java under Mac OS X, the user will need to supply an extra JVM switch, “-XstartOnFirstThread”

Overview

RapidSmith is organized into several packages (all packages are prefixed with “edu.byu.ece.rapidSmith”):

Package Name

Description

bitstreamTools.bitstream

Represents the packet view of a Xilinx bitstream.  It contains classes to represent the header, packets, types, configuration registers and bitstream parsing and export facilities.

bitstreamTools.bitstream.test

Contains classes and scripts to test the bitstream package.

bitstreamTools.configuration

Provides an FPGA-level view of the configuration data in a bitstream using frames and contains an implementation of the frame address register.

bitstreamTools.configurationSpecification

This package contains specifications (column layouts) of all supported devices.  It also defines different constructs such as block types, block sub types and part library functions.

bitstreamTools.examples

This package provides some examples on how to use the bitstream functionality in RapidSmith.

bitstreamTools.examples.support

Some support classes for the examples in the previous package.

design

Represents all of the constructs in XDL design files (Instances, Nets, PIPs, Modules, and Designs).

design.explorer

This is a GUI interactive explorer that allows the user to navigate through the various constructs in the design (Nets, Instances, Modules and Module Instances).  It also has a tile map which allows the user to view the locations of various objects on the FPGA fabric. It also contains an experimental timing report parser to correlate timing information with a design.

design.parser

A JavaCC-based parser for XDL files which populate an instance of the Design class in the design package.

device

This package encompasses all the details of an FPGA device (part name, tiles, primitive sites, routing resources).  All information about Xilinx parts is populated in device from the XDLRC files generated by the xdl executable.

device.browser

This program is an extension of the part tile browser found in the examples package.  It allows the user to browse all of the installed parts and also navigate primitive sites as well as routing resources.

device.helper

Some classes to help in the creation of the device files.

examples

Some user examples of how to use RapidSmith.

gui

This package is used to help build graphical programs in Qt for RapidSmith.  It contains useful and common widgets that can be put together easily using the Qt framework.

placer

This contains classes to place designs.

primitiveDefs

This is also populated from the XDLRC file. It is specific to a Xilinx family of parts (such as Virtex 4 or Virtex 5).  It defines all primitives which are part of a Xilinx family of parts (SLICEL, SLICEM, RAMB16, …).

router

This contains classes to route designs and has a framework to help users of RapidSmith create new routers.

tests

This package contains test classes that will exercise various portions of RapidSmith.

timing

Currently, this is an experimental TWR parser that will parse timing reports output from Xilinx Trace (trce).

util

This contains miscellaneous support classes and utilities, including the installer.

bitstreamTools.* Package

Please see the chapter on Bitstreams in RapidSmith for details on the bitstream functionality in RapidSmith.

design Package

The design package has all the essential classes necessary to represent all kinds of XDL designs with classes to represent each type of XDL construct.   Below in Figures 1, 2, and 3 are some basic illustrations of how the most common XDL constructs map into RapidSmith design classes:

Figure 1 - Design and Attribute classes

Figure 2 - Instance class

Figure 3 - Net, Pin and PIP Classes


There are other classes such as Module and ModuleInstance classes that abstract the macro-like property of XDL which will be explained later.  There are also enumeration classes such as InstanceType which are an exhaustive list of all primitive types found in XDL and NetType which determines if a net is a WIRE, GND, or VCC.

design.explorer Package

The design explorer loads XDL design files and allows the user a GUI interface to the design members (Instances, Nets, Modules and Module Instances) with hyperlinks to the various other sites, tiles, modules and instances.  Currently the design explorer is read only although there is potential for it to be able to modify designs.  Below is a screenshot from the design explorer. 

 

 

 

 

 

 

Figure 4 - Hyperlinks in Design Explorer


Recently, a timing report parser has been added which allows the timing information for a particular design to be loaded at the same time as a design.  This can be done through the file menu or through the tool bar with a folder/clock icon.  This timing report parser is still experimental and so mixed results may result depending on the type of timing report and the device used.

 

Figure 5 - Timing report loaded in Design Explorer

design.parser Package

The XDL parser parses xdl design or hard macro files and populates the Design class accordingly.  The parser is a custom parser (previously a JavaCC parser was used but was ultimately abandoned) written exclusively for RapidSmith.

device Package

This package works closely with the design package in that the specific Device class is loaded when a design is loaded.  The Xilinx XDLRC part descriptions partition the FPGA into a 2D grid of tiles.  Each tile contains some mixture of primitive sites, wires and PIPs (Programmable Interconnect Points).  Primitive sites are resource locations where XDL “inst” or instances of primitives are allowed to reside.  Wires and PIPs provide wiring and routing resources information to connect the primitive instances together to form a complete design.  With this information provided by Xilinx and leveraged by RapidSmith a number of different placement and routing algorithms can be constructed by leveraging the APIs in this package.

 

The device package also contains a class called WireEnumerator.  All of the wires in a family are enumerated to an integer so they do not need to be stored as Strings.  The WireEnumerator class helps translates wires from integers to Strings and vice versa.  It also keeps track of important information about wires such as the type of wire (DOUBLE, HEX, PENT, …) and wire direction (NORTH, SOUTH, EAST, …) among other attributes.

device.browser Package

The device browser application allows the user to see a color coded tile array that allows them to browse any installed device.  The primitive and wire lists are populated by double clicking a tile.  The user can zoom in and out using the mouse wheel and can also pan by holding down the right mouse button while moving the mouse.  See below for a screenshot of the application.

 

Figure 6 - Device Browser screenshot

 

The device browser also allows the user to follow the various connections found in the FPGA.  By double clicking a wire in the wire list, the application will draw the connection on the tile array (as shown in the screenshot below).  By hovering the mouse pointer over the connection, the wire becomes red and a tooltip will appear describing the connection made by declaring the source tile and wire followed by an arrow (->) and the destination tile and wire.  By clicking on the wire, the application will redraw all the connections that can be made from the currently selected wire.  By repeating this action, the user can follow connections and discover how the FPGA interconnect is laid out. 

Figure 7 - Device browser screenshot showing wire connections

device.helper Package

This package contains special classes to help pack the device files smaller.  They are generally used only during installation.

examples Package

This package contains some examples of how to get started with RapidSmith and some different ways of using the various APIs available.

placer Package

This package still has yet to be completed but will have an example of a placer.

primitiveDefs Package

In the XDLRC descriptions produced by the Xilinx ‘xdl’ executable, each copy has a section at the end called primitive_defs which has a list of primitive definitions for all types of primitives found in the part. The primitiveDefs packages makes that information available in a convenient data structure to access the attributes and various parameters the primitives can be configured with.

router Package

This package has an example of a basic router that routes Virtex 4 and Virtex 5 designs.  It also contains an abstract class for which routers can be built upon.

tests Package

In order to help ensure correct functionality in RapidSmith as it grows, a tests package has been added to hold all of the different tests that can be performed to check for correct functionality with each new update.  Currently, this package contains a class for testing the device, primitive defs and wire enumerator files (it is the class used to create the statistical information on RapidSmith files found in the Appendix).

timing Package

A new experimental package that contains a timing report parser (TWR files output from Xilinx Trace) has been added.  This can parse a TWR file into a basic data structure contained in the timing package.  This parser has been integrated into the design explorer application in RapidSmith.

util Package

This has miscellaneous classes used for support of all other packages.  It is suggested to have the user browse the JavaDoc API descriptions to get a better feel for what is contained in the util package.

Examples

Hello World

To get started programming with RapidSmith, here is an example of a very simple program. 

/*

 * Copyright (c) 2010 Brigham Young University

 *

 * This file is part of the BYU RapidSmith Tools.

 *

 * BYU RapidSmith Tools is free software: you may redistribute it

 * and/or modify it under the terms of the GNU General Public License

 * as published by the Free Software Foundation, either version 2 of

 * the License, or (at your option) any later version.

 *

 * BYU RapidSmith Tools is distributed in the hope that it will be

 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty

 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU

 * General Public License for more details.

 *

 * A copy of the GNU General Public License is included with the BYU

 * RapidSmith Tools. It can be found at doc/gpl2.txt. You may also

 * get a copy of the license at <http://www.gnu.org/licenses/>.

 *

 */

package edu.byu.ece.rapidSmith.examples;

 

import java.util.HashMap;

import edu.byu.ece.rapidSmith.design.*;

import edu.byu.ece.rapidSmith.device.*;

 

/**

 * A simple class to illustrate how to use some of the basic methods in RapidSmith.

 * @author Chris Lavin

 */

public class HelloWorld{

       public static void main(String[] args){

              // Create a new Design from scratch rather than load an existing design

              Design design = new Design();

             

              // Set its name

              design.setName("helloWorld");

             

              // When we set the part name, it loads the corresponding Device and

             // WireEnumerator. Always include package and speed grade with the part name.

              design.setPartName("xc4vfx12ff668-10");

             

              // Create a new instance

              Instance myInstance = new Instance();

              myInstance.setName("Bob");

              myInstance.setType(PrimitiveType.SLICEL);

              // We need to add the instance to the design so it knows about it

              design.addInstance(myInstance);

              // Make the F LUT an Inverter Gate

              myInstance.addAttribute(new Attribute("F","LUT_of_Bob","#LUT:D=~A1"));

             

              // Add the instance to the design

              design.addInstance(myInstance);

             

              // This is how we can get the reference to the instance from the design,

              // by name

              Instance bob = design.getInstance("Bob");

             

              // Let's find a primitive site for our instance Bob

              HashMap<String, PrimitiveSite> primitiveSites =

                                           design.getDevice().getPrimitiveSites();

              for(PrimitiveSite site : primitiveSites.values()){

                     // Some primitive sites can have more than one type reside at the site, such as  

                    // SLICEM sites which can also have SLICELs placed there.  Checking if the site

                    // is compatible makes sure you get the best possible chance of finding a place

                    // for bob to live.

                     if(site.isCompatiblePrimitiveType(bob.getType())){

                           // Let's also make sure we don't place bob on a site that is already used

                           if(!design.isPrimitiveSiteUsed(site)){

                                  bob.place(site);

                                  System.out.println("We placed bob on tile: " + bob.getTile() +

                                                " and site: " + bob.getPrimitiveSiteName());

                                  break;

                           }

                     }

              }

             

              // Another way to find valid primitive sites if we want to use an exclusive site type

              PrimitiveSite[] allSitesOfTypeSLICEL =

                              design.getDevice().getAllSitesOfType(bob.getType());

              for(PrimitiveSite site : allSitesOfTypeSLICEL){

                     // Let's also make sure we don't place bob on a site that is already used

                     if(!design.isPrimitiveSiteUsed(site)){

                           bob.place(site);

                           System.out.println("We placed bob on tile: " + bob.getTile() +

                                         " and site: " + bob.getPrimitiveSiteName());

                           break;

                     }

              }

             

              // Let's create an IOB to drive our Inverter gate in Bob's LUT

              Instance myIOB = new Instance();

              myIOB.setName("input");

              myIOB.setType(PrimitiveType.IOB);

              design.addInstance(myIOB);

              // These are typical attributes that need to be set to configure the IOB

              // the way you like it

              myIOB.addAttribute(new Attribute("INBUFUSED","","0"));

              myIOB.addAttribute(new Attribute("IOATTRBOX","","LVCMOS25"));

              // Another way to find a primitive site is by name, this is the pin name

              // that you might find in a UCF file

              myIOB.place(design.getDevice().getPrimitiveSite("C17"));

             

              // Let's also create a new net to connect the two pins

              Net fred = new Net();

              // Be sure to add fred to the design

              design.addNet(fred);

              fred.setName("fred");

              // All nets are normally of type WIRE, however, some are also GND and VCC

              fred.setType(NetType.WIRE);

              // Add the IOB pin as an output pin or the source of the net

              fred.addPin(new Pin(true,"I",myIOB));

              // Add Bob as the input pin or sink, which is the input to the inverter

              fred.addPin(new Pin(false, "F1", bob));

             

              // Now let's write out our new design

              // We'll print the standard XDL comments out

              String fileName = design.getName() +".xdl";

              design.saveXDLFile(fileName, true);

             

              // We can load XDL files the same way.

              Design inputFromFile = new Design();

              inputFromFile.loadXDLFile(fileName);

             

              // Hello World

              System.out.println(inputFromFile.getName());

       }

}

Hand Router

This is a command-line-based router than allows a user to route one net at a time and write out the design changes afterwards.  Although not particularly useful as a router, it illustrates how RapidSmith could be used to build a router.    

Part Tile Browser

This GUI will let you browse Virtex 4 and 5 parts at the tile level.  On the left, the user may choose the desired part by navigating the tree menu and double-clicking on the desired part name.  This will load the part in the viewer pane on the right (the first available part is loaded at startup).  The status bar in the bottom left displays which part is currently loaded.  Also displayed is the name of the current tile which the mouse is over, highlighted by a yellow outline in the viewer pane. The user may navigate inside the viewer pane by using the mouse.  By right-clicking and dragging the cursor, the user may pan.  By using the scroll-wheel on the mouse, the user may zoom.  If a scroll-wheel is unavailable, the user may zoom by clicking inside the viewer pane and pressing the minus(-) key to zoom out or the equals(=) key to zoom in. See below for a screenshot.

 

Figure 8: Screenshot of Part Tile Browser

Understanding XDL

What is XDL?

XDL (or Xilinx Design Language, see ISE 6.1 documentation in help/data/xdl folder) is a human-readable ASCII format compatible with the more widely used Xilinx format NCD (or Netlist Circuit Description).   XDL has most if not all the same capabilities of the NCD format and Xilinx provides an executable called xdl which can convert NCD designs to XDL and vice versa (run “xdl –h for details).  XDL and NCD are both native Xilinx netlist formats for describing and representing Xilinx FPGA designs.  XDL is the interface used by RapidSmith to insert and extract design information at different points in the Xilinx design flow.

 

XDL can represent designs that are:

·         Mapped (unplaced and unrouted)

·         Partially placed and unrouted

·         Partially placed and partially routed

·         Fully placed and unrouted

·         Fully placed and partially routed

·         Fully placed and fully routed

·         Contain hard macros and instances of hard macros

·         A hard macro definition (equivalent to Xilinx NMC files)

 

Figure 9: Block diagram of where XDL fits in CAD flow.

 

RapidSmith provides some Java methods that can perform the XDL/NCD conversion (by calling the xdl executable) from within Java in the util.FileConverter class.  It also has methods for calling a number of Xilinx programs from within the RapidSmith environment.

 

The Xilinx xdl executable also contains options for generating report files (with extension .XDLRC) which contain descriptive information about a particular Xilinx part.  XDLRC report files have a different format to that of XDL (as they describe an FPGA rather than a design) and depending on the options given can create enormous files (several gigabytes) of text but are quite complete in describing the primitive sites, routing resources and tile layout of a Xilinx FPGA.  RapidSmith makes uses of these XDLRC files by generating them and parsing them into much smaller device files that can them be used with the rest of the RapidSmith API.

 

DISCLAIMER: The user must be aware that XDL is an externally unsupported format by Xilinx.  All questions about XDL and any problems associated with XDL or this tool should NOT be addressed to Xilinx, but through the RapidSmith website and forum.  The RapidSmith project is merely a tool to make use of the XDL software technical interface and cannot be used without a valid and current license for the Xilinx ISE tools.  The RapidSmith project is at the mercy of Xilinx in the availability of XDL and will attempt to accommodate updates and changes to the interface as they arise.

Basic Syntax of XDL Files

XDL is a self-documenting file format in that each type of statement is generally preceded by comments that explain the syntax.  Comments in XDL are denoted by using a ‘#’ character at the beginning of a line.  The ‘#’ is also used in other constructs that are part of the language that do not fall on the beginning character of the line.  In XDL there are four basic statements that make up the entire content of the file and description of the circuit.

Design Statement

The design statement (represented as the design.Design class) is included in every XDL file (even hard macros) and there is only one design statement in a file.  It includes global information such as the design name and part name of the targeted FPGA.  It can also contain a list of attributes in a ‘cfg’ string.  Below is an example of a design statement.

# =======================================================

# The syntax for the design statement is:               

# design <design_name> <part> <ncd version>;            

# or                                                    

# design <design_name> <device> <package> <speed> <ncd_version>

# =======================================================

design "designName" xc4vfx12ff668-10 v3.2 ,

  cfg "

       _DESIGN_PROP::BUS_INFO:4:OUTPUT:gpio<3:0>

       _DESIGN_PROP::PIN_INFO:gpio<0>:/top/PACKED/top/gpio<0>/PAD:OUTPUT:3:gpio<3\:0>

       _DESIGN_PROP::PIN_INFO:gpio<1>:/top/PACKED/top/gpio<1>/PAD:OUTPUT:2:gpio<3\:0>

       _DESIGN_PROP::PIN_INFO:gpio<2>:/top/PACKED/top/gpio<2>/PAD:OUTPUT:1:gpio<3\:0>

       _DESIGN_PROP::PIN_INFO:gpio<3>:/top/PACKED/top/gpio<3>/PAD:OUTPUT:0:gpio<3\:0>

       _DESIGN_PROP::PK_NGMTIMESTAMP:1231972339";

 

 

Module Statement

Modules (represented as the design.Module class) are collections of instances and nets which can be described as hard macros if the instances are placed and nets are routed.  A module will have a list of ports that determine the interface of the hard macro or module and each module will have its own list of instances and nets to describe the logic inside. An abbreviated module statement is shown below.

# =======================================================

# The syntax for modules is:

#     module <name> <inst_name> ;

#     port <name> <inst_name> <inst_pin> ;

#     .

#     instance ... ;

#     .

#     net ... ;

#     .

#     endmodule <name> ;

# =======================================================

module "moduleName" "anchorInstanceName" , cfg "_SYSTEM_MACRO::FALSE" ;

  port "portName1" "anchorInstanceName" "F2";

  port "portName2" "anotherInstanceInTheModule" "F4";

...

  inst "anchorInstanceName" "SLICEL", placed CLB_X14Y4 SLICE_X23Y8 , …

...

  net "aNetInsideTheModule" , …

...

endmodule "moduleName";

 

Instance Statement

The instance statement (represented as the design.Instance class), which begins with the keyword ‘inst’, is an instance of an FPGA primitive which can be placed or unplaced depending if a tile and primitive site location are specified.  The instance also has a primitive type (such as SLICEL, SLICEM, DCM_ADV, …).  Instance names should be unique in a design to avoid problems in RapidSmith.  Instances are configured with a ‘cfg’ string which is a list of attributes that define LUT content, and other functionality. An example of an instance statement is shown below.

inst "instanceName" "SLICEL",placed CLB_X14Y4 SLICE_X23Y8 ,

  cfg " BXINV::#OFF BYINV::#OFF CEINV::#OFF CLKINV::#OFF COUTUSED::#OFF CY0F::#OFF CY0G::#OFF CYINIT::#OFF DXMUX::#OFF DYMUX::#OFF F::#OFF F5USED::#OFF FFX::#OFF FFX_INIT_ATTR::#OFF FFX_SR_ATTR::#OFF FFY::#OFF FFY_INIT_ATTR::#OFF FFY_SR_ATTR::#OFF FXMUX::#OFF FXUSED::#OFF G:DCM_AUTOCALIBRATION_DCM_clock/DCM_clock/md/RSTOUT1:#LUT:D=A1 _BEL_PROP::G:LIT_NON_USER_LOGIC:DCM_STANDBY GYMUX::#OFF REVUSED::#OFF SRINV::#OFF SYNC_ATTR::#OFF XBUSED::#OFF XMUXUSED::#OFF XUSED::#OFF YBUSED::#OFF YMUXUSED::#OFF YUSED::0 "

   ;

 

Net Statement

The net statement (represented as the design.Net class) are the nets that describe inputs/outputs and routing of nets in a design.  Nets can be of 3 different types: GND, VCC, or WIRE.  The GND and VCC keyword must be present to mark a net as being sourced by ground or power, the keyword WIRE is not required as it is the default type.  Nets also must have a unique name when compared with all other nets.  Nets have two sub components to describe them: pins and PIPs.  An example of a net statement is shown below.

Pins (represented as the design.Pin class) define the source and one or more sinks within the net.  A pin is uniquely identified by the name of the instance where the pin resides as well as the internal name of the pin on this instance.  It also has a direction of being an ‘outpin’ (source) or an ‘inpin’ (sink).  A net can only have one source or ‘outpin’ in the net. It should also be noted that Xilinx added a ‘inout’ pin type specifically for the Zynq parts.  These are a special case and should be treated as such.

net "netName" ,

  outpin "instanceNameOfSourcePin" Y ,

  inpin "instanceNameOfSinkPin" RST ,

  pip CLB_X14Y4 Y_PINWIRE1 -> BEST_LOGIC_OUTS5_INT ,

  pip DCM_BOT_X15Y4 SR_B0_INT3 -> DCM_ADV_RST ,

  pip INT_X14Y4 BEST_LOGIC_OUTS5 -> OMUX8 ,

  pip INT_X15Y5 OMUX_EN8 -> N2BEG0 ,

  pip INT_X15Y7 N2END0 -> SR_B0 ,

  ;

PIPs (programmable interconnect points, represented by the design.PIP class) define routing resources used within the net to complete routing connections between the source and sinks.  A PIP is uniquely described as existing in a tile (ex: INT_X2Y3) and two wires with a connection between them.  Almost all PIPs are unidirectional (‘->’) in that they can only go in one direction.  Long lines are the one exception to that rule as they are bidirectional and are denoted by using a ‘-=’ symbol, however RapidSmith uses the ‘->’ symbol for all PIPs as this does not cause the xdl converter any problems. 

Basic Syntax of XDLRC Files

XDLRC files are report files generated by the Xilinx xdl executable.  During installation, RapidSmith will create XDLRC files and parse them for their pertinent information and then pack it into small device files that can be used later with the tool.  Each construct found in XDLRC files and the corresponding RapidSmith representation is described in the remainder of this subsection.

Tiles

# Example of an XDLRC tile declaration

     (tile 1 14 CLB_X6Y63 CLB 4

          (tile_summary CLB_X6Y63 CLB 122 403 148)

     )

Tiles (represented in the device.Tile class) are the building blocks of Xilinx FPGAs.  Every FPGA is described as 2D array or grid of tiles laid out like a checker board (this can be seen also in the Part Tile Browser example).  Each tile is declared with a “(tile” directive as shown above followed by the unique row and column index of where the tile fits into the grid of tiles found on the FPGA.  The tile declaration also contains a name followed by a type with the final number being the number of primitive sites found within the tile.  The tile ends with a “tile_summary” statement repeating the name and type with some other numbered statistics.  Tiles can contain three different sub components, primitive sites, wires, and PIPs.

Primitive Sites

# Example of an XDLRC primitive site declaration

          (primitive_site SLICE_X9Y127 SLICEL internal 27

              (pinwire BX input BX_PINWIRE3)

              (pinwire BY input BY_PINWIRE3)

              (pinwire CE input CE_PINWIRE3)

             

              (pinwire XMUX output XMUX_PINWIRE3)

          )

 

 

Primitive sites (represented in the device.PrimitiveSite class) are declared in tiles.  A primitive site is a location on the FPGA that allows for an instance of that primitive type (primitive types are enumerated in the device.PrimitiveType enum) to reside.  For example, in the declaration of a SLICEL primitive site above, any SLICEL instance can be placed at that site.  A primitive site has a unique name (SLICE_X9Y127) and type (SLICEL).  However, in some cases, more than one primitive type is compatible with a given primitive site.  One example of this is the primitive type SLICEM (Virtex 4 slices that contain RAM functionality in the LUT among other enhancements to the SLICEL type) is a superset of SLICEL functionality.  Therefore, a SLICEL primitive instance can be placed in a SLICEM primitive site.  RapidSmith allows the developer to determine if a given site is compatible in the device.PrimtiveSite class using the method isCompatiblePrimitiveType(PrimitiveType otherType).

 

Primitive site declarations in XDLRC also contain a list of pinwires which describe the name and direction of pins on the primitive site.  The first pinwire declared in the example above is the BX input pin which is the internal name to the SLICEL primitive site. Pinwires have an external name as well to differentiate the multiple primitive sites that may be present in the same tile.  In this case, BX of SLICE_X9Y127 has the external name BX_PINWIRE3.  RapidSmith provides mechanisms to translate between these two names in the device.PrimitiveSite class with the method getExternalPinName(String internalName).

Wire

# Example of an XDLRC wire declaration

          (wire E2BEG0 5

              (conn CLB_X7Y63 CLB_E2BEG0)

              (conn INT_X8Y63 E2MID0)

              (conn CLB_X8Y63 CLB_E2MID0)

              (conn INT_X9Y63 E2END0)

              (conn INT_X9Y62 E2END_S0)

          )

A wire as declared in XDLRC is a routing resource that exists in the tile that may have zero or more connections leaving the tile.  In the example above, the wire E2BEG0 connected to 5 other neighboring tiles.  These connections (denoted by ‘conn’) are described using the unique tile name and wire name of that tile to denote connectivity.  These connections are not programmable, but hard wired into the FPGA.  Inter-tile connections are not programmable, however, intra-tile connections (PIPs, see below) are.  RapidSmith must represent the routing resources of Xilinx FPGAs very carefully as a significant fraction of the FPGA description is routing.  Therefore, the wire names (such as E2BEG0, …) are enumerated into integers or Java primitive int data types using the device.WireEnumerator class.  The WireEnumerator class keeps track of what integer value goes with each wire name and allows for significant compaction of the FPGA routing description.

 

The wire connections are described using a relative tile offset to reuse data structure elements.  The class used to represent these wires and corresponding connections is in the device.WireConnection class.

PIP

# Example of an XDLRC PIP declaration

          (pip INT_X7Y63 BEST_LOGIC_OUTS0 -> BYP_INT_B5)

A PIP (programmable interconnect point) is a possible connection that can be made between two wires.  In the example above the PIP is declared in the tile and repeats the tile name for reference.  It specifies two wires by name that both exist in that same tile (BEST_LOGIC_OUTS0 and BYP_INT_B5)  and declares that the wire BEST_LOGIC_OUTS0 can drive the wire BYP_INT_B5 if the PIP exists in a net’s PIP list in a given design. A collection of these PIPs in a net define how a net is routed and is consistent with saying that those PIPs are “turned on.”  The connections are also represented in the device.WireConnection class as connections with a special flag denoting the connection as a PIP.

Primitive Definitions

At the end of every XDLRC file (regardless of verboseness) is a list of all primitive definitions for the Xilinx part.  Primitive definitions are used mainly for reference and are reflected in the primitiveDefs.* package. In more recent Xilinx parts, some of the primitive definitions have been found to lack some information which may require special handling in RapidSmith.  Currently, the primitive definitions are not widely used in RapidSmith.

RapidSmith Structure

This section details much of the complexity and theory behind the structure of RapidSmith.  There are two main abstractions that developers need to be aware of; that of the device and design.  A hierarchy of classes within RapidSmith can be seen in Figure 6 below.

 

Figure 10: (a) The classes involved in defining a design in RapidSmith, (b) The major classes involved representing a device.

A RapidSmith Design

Designs in RapidSmith are represented and stored in the data structures found in the design package.  The classes found in this package closely follow the constructs found in XDL design files to make the classes easier to follow and make the abstraction understandable to those who are familiar with XDL.  For those who have less experience with XDL, see the previous section on understanding XDL.

Loading Designs

There is typically only one way to load a design with RapidSmith and that is to create a new design and call the method loadXDLDesign(String fileName) on that instance of the design.  An NCD file can also be loaded indirectly by using methods in the util.FileConverter class which enables the conversion of an existing NCD file to XDL by calling the Xilinx xdl executable.  Example code of how this could be done is shown below:

      // Loading an XDL design

      Design myDesign = new Design();

      myDesign.loadXDLFile("myDesign.xdl");

           

      // Loading an existing NCD file by converting it to XDL

      String ncdFileName = "myOtherDesign.ncd";

      String xdlFileName = FileConverter.convertNCD2XDL(ncdFileName);

      if(xdlFileName == null){

            MessageGenerator.briefErrorAndExit("ERROR: Conversion of " +

                        ncdFileName + " to XDL failed.");

      }

      Design otherDesign = new Design();

      otherDesign.loadXDLFile(xdlFileName);

 

When loading a design, one must be conscious of everything that gets loaded.  In RapidSmith, a JavaCC-based XDL parser (found in the design.parser package) reads and parses the given XDL file and populates the instance of the Design class respectively.  When the parser populates the design with the design part name, it causes the corresponding device file of the Xilinx part as well as the wire enumerator to be loaded and populates the design.  This is done be default because the primitive sites and wires in the design reference those same resources in the device class.

Saving Designs

RapidSmith also has a method to save designs in the XDL format similar to the method for loading them.  In a similar manner, the saved XDL file can be converted to NCD using the FileConverter class.  Very little error checking is made when loading and saving XDL designs, but a good test would be the conversion to NCD as Xilinx runs several DRCs when the design is converted.

A RapidSmith Device

A device is defined in RapidSmith as a unique Xilinx FPGA part that includes package information but not speed grade (such as xc4vfx12ff668).  Each device contains specific information concerning its primitive sites, tiles, wires, IOBs, and PIPs that are available to realize designs.  This information is made available through the Xilinx executable xdl in -report mode. See the previous section on XDLRC for more details on these device resources.

Device

During the initial setup of RapidSmith, the Installer creates fully verbose XDLRC files ($xdl –report –pips –all_conns <partName>) for each device specified as command line parameters.  After the creation of each XDLRC file, they are parsed, compacted by the Installer, and a device file is generated for later use.  These device files are placed in $(RAPIDSMITH_PATH)/devices/familyName/partName_db.dat and then the corresponding XDLRC file is deleted as they can be several gigabytes in size.  These device files make accessing device information about a specific FPGA part much more convenient than a gigantic text file.  Most of the device files are just a few megabytes or less and can be loaded in a few seconds or less.  RapidSmith uses a custom form of serialization as well as a compression library to make sure the device files are small and load quickly. 

Wire Enumerator

In order to make the device files small, each uniquely named wire is assigned to an integer as enumeration.  This avoids moving strings around in memory which would be costly in terms of space and comparison times.  RapidSmith has a class called WireEnumerator which enumerates all uniquely named wires in an FPGA family and has methods to convert to and from the wire name and enumeration or enum for short.  It also stores information about each wire such as a direction or type which can be useful in building a router.  Note that wires with the same name can occur several times within a device and they are uniquely identified not only by their name, but also by the tile in which they are present.

 

In order to create the wire enumeration files, a subset of XDLRC files must be parsed so that a complete set of wires can be enumerated.  This is automatically done by the installer and the files are placed in $(RAPIDSMITH_PATH)/devices/familyName/wireEnumerator.dat.  Only one wire enumerator is needed per FPGA family.

Memory and Performance

Although Java typically has a reputation for being slow and a memory hog, RapidSmith has been able to create a very good device representation that is compact and fast loading, even for some of the largest parts offered by Xilinx.  A summary of some performance and memory footprint figures are shown in the tables below for selected parts.   These results were taken a Windows 7 Enterprise 64-bit OS with an Intel Core i7 860 running at 2.8GHz.  The test machine had 8 GB of DDR3 memory, a conventional 1 TB SATA hard drive and was using version 0.5.0 of RapidSmith and the 32-bit Oracle JVM version 1.6.0_22. Note that the Device and WireEnumerator classes are both required before loading any design in RapidSmith.  For a more extensive list of performance figures of all RapidSmith-compatible devices, see the Appendix.

Device Performance and Memory Usage

Family Name

Part Name

XDLRC Report Size

File Size

Java Heap Size

Load Time from Disk

VIRTEX 4

SX55

3.5GB

539KB

34MB

0.299s

VIRTEX 4

FX140

8.0GB

1546KB

70MB

0.616s

VIRTEX 4

LX200

10.0GB

1010KB

61MB

0.602s

VIRTEX 5

FX200T

9.4GB

1227KB

60MB

0.585s

VIRTEX 5

TX240T

10.0GB

1111KB

56MB

0.620s

VIRTEX 5

SX240T

11.9GB

1135KB

61MB

0.630s

VIRTEX 5

LX330

12.5GB

1069KB

69MB

0.622s

VIRTEX 6

CX240T

8.5GB

937KB

35MB

0.460s

VIRTEX 6

SX475T

17.7GB

1506KB

61MB

0.814s

VIRTEX 6

LX760

22.8GB

1758KB

77MB

1.068s

VIRTEX 7

855T

32.0GB

2634KB

115MB

1.408s

VIRTEX 7

1500T

53.0GB

4985KB

263MB

2.653s

VIRTEX 7

2000T

73.6GB

5956KB

301MB

3.339s

Wire Enumerator Size and Performance

Family Name

Heap Memory Footprint

File Size on Disk

Load Time from Disk

VIRTEX4

233KB

8.1MB

0.100s

VIRTEX5

264KB

9.9MB

0.111s

VIRTEX6

171KB

6.3MB

0.079s

VIRTEX7

200KB

7.4MB

0.096s

 

Placement in RapidSmith

This chapter is intended to help users of RapidSmith understand how placement works in RapidSmith and in XDL. 

Primitive Resources in RapidSmith

RapidSmith uses the XDLRC primitive definitions and sites declared to help create a map of useable places where objects may be placed.  In order to understand placement in RapidSmith, let’s review the following: primitive sites, primitive definitions and types, and primitive instances.

Primitive Site

A primitive site is an actual physical location in an FPGA.  Let’s take a look at a typical primitive_site declaration found in an XDLRC report for a Virtex 4:

 

          (primitive_site SLICE_X1Y121 SLICEL internal 27

                  (pinwire BX input BX_PINWIRE1)

                  (pinwire BY input BY_PINWIRE1)

                  (pinwire CE input CE_PINWIRE1)

                  (pinwire CIN input CIN1)

                  (pinwire CLK input CLK_PINWIRE1)

                  (pinwire SR input SR_PINWIRE1)

                  (pinwire F1 input F1_PINWIRE1)

                  (pinwire F2 input F2_PINWIRE1)

                  (pinwire F3 input F3_PINWIRE1)

                  (pinwire F4 input F4_PINWIRE1)

                  (pinwire G1 input G1_PINWIRE1)

                  (pinwire G2 input G2_PINWIRE1)

                  (pinwire G3 input G3_PINWIRE1)

                  (pinwire G4 input G4_PINWIRE1)

                  (pinwire FXINA input FXINA1)

                  (pinwire FXINB input FXINB1)

                  (pinwire F5 output F51)

                  (pinwire FX output FX1)

                  (pinwire X output X_PINWIRE1)

                  (pinwire XB output XB_PINWIRE1)

                  (pinwire XQ output XQ_PINWIRE1)

                  (pinwire Y output Y_PINWIRE1)

                  (pinwire YB output YB_PINWIRE1)

                  (pinwire YQ output YQ_PINWIRE1)

                  (pinwire COUT output COUT1)

                  (pinwire YMUX output YMUX_PINWIRE1)

                  (pinwire XMUX output XMUX_PINWIRE1)

            )

 

This declaration is found inside of a tile declaration in XDLRC reports which denotes where the primitive site is located on the FPGA.  Every primitive site belongs to a tile.  If you open the Virtex 4 FX12 part in the Device Browser, you could find the primitive site SLICE_X1Y121 as shown in the screenshot below.  You would find that it belongs to the tile CLB_X1Y60.

 

 

 

 

Figure 11 – Device Browser screenshot showing site SLICE_X1Y121 in tile CLB_X1Y60

 

Primitive sites all have a unique name (SLICE_X1Y121 in this example) to uniquely identify each one.  Although the XY coordinates in the name help reference their location, they are not found in all primitive site names (IOBM/IOBS sites being a common example).  Each site also has a type associated with it.  RapidSmith enumerates all of the primitive types in the device.PrimitiveType enum. 

Primitive Definitions and Types

Each Xilinx FPGA family has a list of primitive definitions which appear at the end of every XDLRC report in the primitive_defs declaration.   A list of primitive_def declarations are contained in this declaration, each detailing the inputs, outputs, elements, and configurations of each primitive.  Theses definitions are stored in the primitiveDefs package found in RapidSmith and are easily accessible using the data structures created.  The names of each of the primitive definitions are called primitive types in RapidSmith.  The PrimitiveType enum found in the device package contains all of the primitive types found in every Xilinx FPGA family supported in RapidSmith (see Appendix C for a complete list).

Primitive Instances

A primitive instance (or instance for short) is an actual instantiation of a primitive definition and is the same instance as declared in XDL “inst” constructs.  These instances are represented in the design package using the Instance class. Each instance has a unique name and primitive type associated with it and can be placed or unplaced in an XDL design.  When an instance is unplaced, it will have the keyword “unplaced” in its declaration.  When an instance is placed, it will have the keyword placed followed by a tile name and a primitive site name (such as CLB_X1Y60 SLICE_X1Y121).  An example of the first part of an instance declaration is shown below:

 

inst "instanceName" "SLICEL",placed CLB_X1Y60 SLICE_X1Y121 ,

 

Placement

Placement occurs by assigning an instance to a specific primitive site on the FPGA.  Generally, an instance of type X can only be placed on a primitive site of type X.  However, there are some exceptions where type X can actually be placed onto more than just the primitive site of the same type.  A common example in modern devices is that a SLICEL instance can be placed on either a SLICEL primitive site or a SLICEM primitive site.  There are actually several scenarios where this exception occurs.  Sometimes, a primitive site of the same type never occurs on the FPGA fabric such as an IOB primitive type.  IOB primitives must be placed on either an IOBM or IOBS primitive site. 

 

In order to help avoid the special cases in placement with different primitive types, RapidSmith includes all of the legal placement types in the PrimitiveSite class and they can be accessed with the following methods:

 

/**

* This method will check if the PrimitiveType otherType can be placed

* at this primitive site.  Most often only if they are

* equal can this be true.  However there are a few special cases that require

* extra handling.  For example a SLICEL can reside in a SLICEM site but not

* vice versa. 

* @param otherType The primitive type to try to place on this site.

* @return True if otherType can be placed at this primitive site, false otherwise.

*/

public boolean isCompatiblePrimitiveType(PrimitiveType otherType);

 

/**

 * This method gets the type of otherSite and calls the other method

 * public boolean isCompatiblePrimitiveType(PrimitiveType otherType);

 * See that method for more information.

 * @param otherSite The other site to see if its type is compatible with this site.

 * @return True if compatible, false otherwise.

 */

public boolean isCompatiblePrimitiveType(PrimitiveSite otherSite);

 

Placement Techniques

Currently RapidSmith only has a very limited random placer which is found in the placer package. 

 

 

Routing in RapidSmith

This chapter is intended to help users and developers in understanding how routing resources are handled in RapidSmith.  It also illustrates how to build on the existing classes to create custom routers.

Wire Resources in RapidSmith

RapidSmith has a unique way of representing wires and connections for Xilinx devices.  This approach was developed mainly to minimize disk and memory usage while also maintaining some level of efficiency and speed. 

Wire Representation

The wire enumerator class keeps a list of all uniquely XDLRC-named wires that exist in a given Xilinx FPGA family.  Wires can span multiple tiles in the FPGA, however, the wire has a separate name for each tile in which it crosses.  An example of this concept is illustrated in the DOUBLE lines found in several family architectures.  A DOUBLE line is a wire that connects switch boxes either one or two hops away in a given direction.  An example of this layout is given in Figure 7.

 

Figure 12 - A DOUBLE line in an FPGA illustrating how each part of the wire has a different name depending on the tile it is located in.

In this example, we see a wire that can be driven by one point, E2BEG4, and can drive either E2MID4 in tile INT_X2Y1 and/or E2END4 in tile INT_X3Y1.  However, the wire is assigned a name as it travels through the CLB tiles (CLB_E2BEG4 and CLB_E2MID4).  For the purposes of RapidSmith, these wires have been removed from device files as they do not contribute to the overall possible connections a wire can make and simply add overhead to the device data structures.  This technique has actually dramatically reduced the size of the devices files and improved routing speed as dead-end connections do not need to be examined.

 

In RapidSmith, these uniquely-named wire segments are represented either as a String or as an int or Integer.  Often it is represented as an integer to save space and increase comparison speed with other wires.  To illustrate how this representation works, here is some example Java code that exposes the wire segments:

 

            // Load the appropriate Device and WireEnumerator

            // (this is done automatically when loading XDL designs)

            String partName = "xc4vfx12ff668";

            Device dev = FileTools.loadDevice(partName);

            WireEnumerator we = FileTools.loadWireEnumerator(partName);

            // Here we pick a wire name

            String wireName = "E2BEG4";

            // Here we get the integer enum value for that wire name

            int wire = we.getWireEnum(wireName);

            // The wire enumerator also keeps information about these wire segments

            // such as wire direction and type

            WireDirection direction = we.getWireDirection(wire);

            WireType type = we.getWireType(wire);

 

Now, there are actually several wires in an FPGA device with the same name.  The wire E2BEG4 exists in almost every switch box tile in the FPGA.  To uniquely identify routing resources in a device, a tile and its name or wire enumeration is required (that is, INT_X1Y1 E2BEG4 is its unique representation). 

 

In an effort to save space and ultimately reuse much of the routing connections, the WireConnection class is used to represent internal and external tile connections.  Each tile has a special hash map where the key is the integer enum value of the wire and the value is an array of WireConnection objects.  Each WireConnection object contains the following information to define a connection:

 

      /** The wire enumeration value of the wire to be connected to */

      private int wire;

      /** The tile row offset from the source wire's tile */

      private int rowOffset;

      /** The tile column offset from the source wire's tile */

      private int columnOffset;

      /** Does the source wire connected to this wire make a PIP? */

      private boolean isPIP;

 

The WireConnection objects can define the connecting wire by using the integer enumeration value of the wire name and a relative offset of the tile differences between the two wires (again, relative to save space and increase reuse of the object).  The WireConnection object also defines if the connection made is a programmable connection (or PIP).  When the row and column tile offsets are both 0, the connection exists within the same tile and is likely a PIP. 

 

To query the connections that can be made from INT_X1Y1 E2BEG4, here is some sample Java code to illustrate how this is done:

 

// Load the appropriate Device and WireEnumerator

// (this is done automatically when loading XDL designs)

String partName = "xc4vfx12ff668";

Device dev = FileTools.loadDevice(partName);

WireEnumerator we = FileTools.loadWireEnumerator(partName);

// Here we pick a wire name

String wireName = "E2BEG4";

// Here we get the integer enum value for that wire name

int wire = we.getWireEnum(wireName);

String tileName = "INT_X1Y1";

Tile tile = dev.getTile(tileName);

WireConnection[] wireConnections = tile.getWireConnections(wire);

for(WireConnection w : wireConnections){

      System.out.println(tileName + " " +

                         wireName + " connects to " +

                         dev.getTile(tile.getRow()-w.getRowOffset(),

                                     tile.getColumn()-w.getColumnOffset()) + " " +

                         we.getWireName(w.getWire()) + " (is" +

                         (w.isPIP()? " " : " not ") +

                         "a PIP connection)");

}

Console Output:

 

INT_X1Y1 E2BEG4 connects to INT_X1Y1 BOUNCE1 (is a PIP connection)

INT_X1Y1 E2BEG4 connects to INT_X1Y1 BOUNCE2 (is a PIP connection)

INT_X1Y1 E2BEG4 connects to INT_X3Y1 E2END4 (is not a PIP connection)

INT_X1Y1 E2BEG4 connects to INT_X2Y1 E2MID4 (is not a PIP connection)

Routes in XDL are specified only with PIPs.  Non-PIP connections (that is E2BEG4 to E2MID4, etc.) are not declared in an XDL Net since the connection is implied.  The two wire segments are part of the same piece of metal on the FPGA.  Thus, when declaring the routing resources used in a Net (the list of PIPs), these connections are not explicitly listed.  However, the PIP connections are, for example:

 

net "main_00/i_ila/i_dt0/1/data_dly1_20" ,

  outpin "main_00/i_ila/i_dt0/1/data_dly1_20" XQ ,

  inpin "main_00/i_ila/i_yes_d/u_ila/idata_70" BY ,

  pip CLB_X16Y48 XQ_PINWIRE2 -> SECONDARY_LOGIC_OUTS2_INT ,

  pip CLB_X18Y48 BYP_INT_B4_INT -> BY_PINWIRE0 ,

  pip INT_X16Y48 SECONDARY_LOGIC_OUTS2 -> OMUX7 ,

  pip INT_X17Y48 OMUX_E7 -> E2BEG4 ,

  pip INT_X18Y48 E2MID4 -> BYP_INT_B4 ,

  ;

 

The listing of PIPs in XDL is arbitrary, that is, they do not always follow from one connection to the next.

Basic Routing

RapidSmith has included an AbstractRouter class that allows for a common template so that routers can be constructed quite easily.  However, the user should not feel restricted in using this template as it may not meet everyone’s needs and/or requirements.

 

An example BasicRouter class has also been provided to illustrate how a router can be constructed easily.  The BasicRouter class is ~400 lines of code.  It is very simple and does not do any routing conflict resolution (it is a basic Maze router implementation) and it will commonly be unable to route certain connections in a design.  Also, because the timing information for Xilinx parts is not publicly available, the router must use other means to optimize the router rather than delay.  However, it does perform re-entrant routing, that is, it will attempt to route all nets that don’t have any PIPs while keeping the original routed nets intact.  If a net is impartially routed or improperly routed before given to the router, it does not resolve these problems.  The behavior and mechanics of this router are described in the remainder of this section.

Router Structure

The basic router provided in RapidSmith is based on a simple maze router algorithm.  It does not allow routing resources to be used more than once, and thus, routing resources come on a first-come-first-served basis.  This makes for a very simple implementation but does not resolve routing conflicts when they arise.  The router chooses a route by iterating through a growing set of nodes, represented by the Node class.  A node is a unique tile and wire combination to uniquely identify any routing wire available in the FPGA.  Nodes are given a cost based on their Manhattan distance from the sink of the current connection to be routed and then placed in a priority queue.  Those nodes with the smallest cost propagate to the bottom of the queue.

 

The least cost node of the queue is iteratively removed.  With each removal, the node is examined for its expanding connections and those new potential nodes are also placed on the queue.  Each time a node is removed, it is tested to see if it is the sink, if it is, the method traverses the path it has found and returns, otherwise it continues to expand more connections of the current node. 

 

The router uses the following basic algorithm:

1.      The central routing method, routeDesign() prepares the nets in the design for routing.

2.      For each net in the design, routeDesign() will call routeNet().

a.       routeNet() prepares each inpin or sink in the net for routing.

                                                              i.      If this is the first inpin of the net, it will only supply the outpin or source of the net as a starting point to the router.

                                                            ii.      If this is the second or later inpin routed in the net, all intermediate points along those routes are added as starting points.

b.      For each inpin, routeNet() will call routeConnection().

                                                              i.      routeConnection() initializes the priority queue of potential source nodes.

                                                            ii.      routeConnection() calls the main routing method route() for each connection to be routed.

1.      The route() method iterates over the nodes in the priority queue, expanding their connections and adding new ones to the queue and putting more connections on the queue.  The process continues until the sink is found.

3.      After a net has been routed, the routing resources used will be marked as used to avoid reusing the resources twice.

Routing Static Sources (VCC/GND)

One major preparation step in routing a full design is preparing where the static sources will be supplied from.  The basic primitive in all Xilinx FPGAs to supply VCC and GND signals to a design is the TIEOFF.  The TIEOFF accompanies every switch matrix and has several connections to all sink connections to its neighboring logic tile (CLB, BRAM, DSP, etc.).  It has 3 pins, HARD0 or GND, KEEP1 (VCC) and HARD1 (VCC).  By default, without any configuration, it seems that pins will default to KEEP1.  Some pins, however, require a HARD1 when specified to be driven with VCC.

 

The StaticSourceHandler class takes care of partitioning the various nets and sinks into their respective tiles and instancing the TIEOFF automatically.  It also will instance SLICEs when necessary.  It also “reserves” certain routing resources for certain nets that could potentially introduce routing conflicts later.  These reserved nodes are released just before the net is routed in the basic router. 

Routing Clocks

When routing clocks, it is quite important that they get routed to the appropriate clock tree routing resources.  The best current method to determine this is based on the WireDirection (the type CLK was placed in WireDirection because there are certain CLK wires that also fell into certain WireType categories).  The cost function for determining node position in the priority queue take into account clock wires and significantly reduces their cost when routing clock nets.

Internal Pin Names and External Pin Names

In RapidSmith, there is the notion of each pin on an instance having an internal name and an external name.  This can easily get confusing, especially where this can be a weak point for XDLRC report files which lack some of this information for some primitive types. 

 

Internal pin names occur commonly in two places (although, they do occur in other places):

1.      In XDL nets which contain “outpin” and “inpin” statements

2.      In XDLRC primitive_def declarations in the primitive_defs section of an XDLRC report.

 

First, let’s talk about pins found in nets in XDL designs.  In XDL, pins in a net are declared first with either the keyword “outpin” (to designate the source) or “inpin” (to designate a sink).  Following the keyword is the name of the instance the pin belongs to.  To illustrate this, let’s look at an example:

net "netName" ,

  outpin "fred" Y ,

  inpin "barney" RST ,

  pip CLB_X14Y4 Y_PINWIRE1 -> BEST_LOGIC_OUTS5_INT ,

  pip DCM_BOT_X15Y4 SR_B0_INT3 -> DCM_ADV_RST ,

  pip INT_X14Y4 BEST_LOGIC_OUTS5 -> OMUX8 ,

  pip INT_X15Y5 OMUX_EN8 -> N2BEG0 ,

  pip INT_X15Y7 N2END0 -> SR_B0 ,

  ;

 

In the example above, there are two pins, a source and a sink.  The source is found on the instance “fred” and the sink is found on the instance “barney.”  The source pin on “fred” is pin “Y” and the sink pin is “RST” on “barney.”    

 

However, a problem arises when trying to use pin names in routing.  For example if the pin name Y were used to specify routing to the instance it would be ambiguous because the Y pin belongs to a slice.  Since PIPs declare routing resources at the tile level, the pin Y would have to be unique to the tile, however, there are actually multiple slices in a CLB tile making the reference “Y” ambiguous.  To eliminate the ambiguity, Xilinx developed what we call an internal pin name and external pin name.  The internal pin name (Y and RST in the example) is used when talking about a pin on an instance, however, to route to/from that pin the external name is used.  In the PIP list of the example net above, the first PIP contains the external name “Y_PINWIRE1” of pin Y on “fred” and the second PIP contains that external name “DCM_ADV_RST” of the pin RST.  In the Virtex 4 architecture, there are 4 slices in each CLB, so the Y pin on each slice is named Y_PINWIRE0, Y_PINWIRE1, Y_PINWIRE2 and Y_PINWIRE3 respectively.  The mapping of an internal pin name to an external pin name is found in the primitive_site declaration in an XDLRC report.

 

Let’s look at an example of an XDLRC primitive_site:

 

          (primitive_site SLICE_X1Y126 SLICEL internal 27

                  (pinwire BX input BX_PINWIRE1)

                  (pinwire BY input BY_PINWIRE1)

                  (pinwire CE input CE_PINWIRE1)

                  (pinwire CIN input CIN1)

                  (pinwire CLK input CLK_PINWIRE1)

                  (pinwire SR input SR_PINWIRE1)

                  (pinwire F1 input F1_PINWIRE1)

                  (pinwire F2 input F2_PINWIRE1)

                  (pinwire F3 input F3_PINWIRE1)

                  (pinwire F4 input F4_PINWIRE1)

                  (pinwire G1 input G1_PINWIRE1)

                  (pinwire G2 input G2_PINWIRE1)

                  (pinwire G3 input G3_PINWIRE1)

                  (pinwire G4 input G4_PINWIRE1)

                  (pinwire FXINA input FXINA1)

                  (pinwire FXINB input FXINB1)

                  (pinwire F5 output F51)

                  (pinwire FX output FX1)

                  (pinwire X output X_PINWIRE1)

                  (pinwire XB output XB_PINWIRE1)

                  (pinwire XQ output XQ_PINWIRE1)

                  (pinwire Y output Y_PINWIRE1)

                  (pinwire YB output YB_PINWIRE1)

                  (pinwire YQ output YQ_PINWIRE1)

                  (pinwire COUT output COUT1)

                  (pinwire YMUX output YMUX_PINWIRE1)

                  (pinwire XMUX output XMUX_PINWIRE1)

            )

 

XDLRC report files show a mapping of internal pin name to external pin name on each line which starts with “(pinwire”.  The pattern is:

 

            “(pinwire <internal pin name> <direction of pin> <external pin name>)”

 

This is very straight forward and is the second common location to find internal and external pin names in XDL/XDLRC.  In RapidSmith, the mapping between internal and external pin names can be made using the following methods:

 

In the PrimitiveSite class:

      /**

       * Gets the external wire enumeration of the name of the wire corresponding to the

       * internal wire name.

       * @param internalName The inter