Global training solutions for engineers creating the world's electronics

Scripting Xilinx® ISE™ using Tcl

A Tutorial based on a simple implementation

Doulos, July 2008


Xilinx ISE is one of the many EDA tools that can be controlled using Tcl. Why would you want to do that? Well, on our courses we often see delegates make an edit to their source code, then re-implement it only to find that the synthesis/layout doesn't do the same as it did before.

This is a constant danger if repeatability depends on remembering to click on the correct boxes and menus in the user interface. If you create a command file you can run that same file many times, thus guaranteeing that you are issuing the same commands to the tool each time.

There are two ways of running the script:

  1. Within the GUI there is a Tcl command window, in which you can source (i.e. call/run) a script.
  2. You can issue the command "xtclsh scriptname" in your DOS command window or *nix shell and avoid the overhead of a graphical interface completely.


With all this in mind, we are now going to explore some of the ways in which we can drive ISE from a Tcl script. We will synthesise a small design using XST and implement it in a Spartan3e device (chosen to match the boards used on our course VHDL for FPGA Design).

Input files

The first thing we need to do is to tell the tool which source files will be used. We want to do this in a maintainable way, and to this end all filenames are given at the top of the script.

We set some Tcl variables to contain the filenames we require:

# where all output will be created
set compile_directory     spartan3e
# the top-level of our HDL source:
set top_name              spartan3e_top
# input source files:
set hdl_files [ list \
  ../constants_spartan.vhd \
  ../components.vhd \
  ...Other files... \
# constraints with pin placements.
set constraints_file      ../spartan3e_fsm.ucf

A # denotes a comment; the comment is terminated by a newline and is ignored by the parser. Care is required, as other Tcl behaviour means a hash character will not always be interpreted as the beginning of a comment. Until you know this behaviour it's best to follow these rules about comments:


  • Each comment appears on a separate line where # is the first character on that line
  • In a comment, don't include mismatched round or square brackets and don't use curly brackets at all

The set command is used to apply a value to a variable:

set variable_name value

In the setting of the variable "hdl_files" we used the list command to create a Tcl list from the text strings that follow it. As a simpler alternative, we could have used braces to enclose a set of strings:

set hdl_files {
  ...Other files...

This approach has some drawbacks, especially when the list items have spaces or special characters. It's generally best to construct the list using the list command. This also allows you to use lappend and lindex commands to manipulate the list.

Setting a Compilation Directory


We now need somewhere to process our files. We can use the file command and its sub-command mkdir to create a directory:

if {![file isdirectory $compile_directory]} {
  file mkdir $compile_directory

This code asks if the directory exists; if not, it is created. You may also find file exists useful. Using $ in front of a variable name gives you the content of that variable.

Project Creation and Settings

So, now we have a directory and we can do something there. Assuming no project exists in this directory we can go ahead and make one. Xilinx provide the project command, which includes sub-commands for the project settings and other related tasks. Let's try some:

project new $proj.ise
project set family Spartan3E
project set device xc3s500e
project set package fg320
project set speed -4

This is one of the strengths of Tcl; it is easy to add new commands by writing your own procedures. Doing that is outside the scope of this discussion but is covered fully in Essential Tcl/Tk.

Now we need to add some files to the project. Again, Xilinx provide a Tcl command for this: the xfile command is used to add or remove files and to get information on any source files in the current ISE project. We need to add some files, but we don't really want to type filenames again (maintainability, remember?) and we already have a list of source files. The solution is to loop through the list adding each file to the project:

foreach filename $hdl_files {
  xfile add $filename
  puts "Adding file $filename to the project."

The puts command is a simple way to write to STDOUT (which is usually the console/shell). Note: don't forget to add the constraints file; NGDBuild does not automatically detect .ucf files when run from Tcl. Use xfile add in the same way.

Running Processes

Before we run any processes, we can set process options using project set as above; see the provided script for examples and the Xilinx Development System Reference Guide for exhaustive detail.

Now we can run something. Just as with the ISE graphical interface, running any given process will run any required prior processes. In our example, I can issue this command:

process run "Generate Programming File"

and the design will be synthesised and implemented first before the bitfile is created. Again, just as in the graphical interface, source and intermediate file dependencies are checked and processes are run only if required. For example, to force a rerun:

process run "Implement Design" -force rerun_all

Programming the Device


Here we have to change our approach as Impact does not have a Tcl interface. However, this does allow us to explore another way of controlling applications. Impact has the ability to run a script file that consists of a series of commands. These are not Tcl commands, but we can use Tcl to construct this file. We can then run Impact from with the Tcl script. Let's see how.

First we need to open a file that will become the Impact script. We do this with the open command:

if {[catch {set f_id [open $impact_script_filename w]} msg]} {
  puts "Can't create $impact_script_filename"
  puts $msg

What's going on here? The open command returns a handle to the file which we put in the variable "f_id". If open fails it would stop the script; this is probably the best thing to do here, but in general you may want to trap errors and continue with other things. That's what catch can do; it will return a non-zero error code if the command it runs (in this case the open) fails, and it places any error message from that command in the variable that here we have called "msg". Hence, if the open fails $msg will contain the reason why.

How do we write text to the file? With the puts command. Earlier we used it to write text to the console, but here we see an addition:

puts $f_id "addDevice -position 1 -file $bit_filename"

Well, it's not really an addition: the default destination of a puts command is the standard output, so if we leave off the second argument then STOUT is where the output goes. The line above uses a second argument, so the text is written to the file given by $f_id instead. After we have written the required command to the Impact script we should close the file.

Now we have to start Impact. There are several ways of calling external programs from Tcl; the easiest is to use the exec command, which runs the external program, waits for it to finish and returns all its output. This is acceptable for quick programs but not for anything more complicated, as you cannot direct any input to the program or control it while it is running. More flexibility is provided by using open, but this time as a pipe from the program:

set impact_p [open "|impact -batch $impact_script_filename" r]

This line starts Impact with the script, and returns its output to the variable "impact_p". The benefit of using the pipe is that we can now watch the STDOUT of the tool from within our Tcl script:

while {![eof $impact_p]} { gets $impact_p line ; puts $line }

This code writes each line of Impact's output to the Tcl script's own standard output. The command eof returns true when the external program finishes. This approach will not work if the external program requires some interaction because that program will not tell you when it requires some input. In our case, however, this is fine, because we want the Impact script to run until completion. We explore ways of interacting with programs in Essential Tcl/Tk.

Assuming all this runs successfully you should have a working device. Congratulations!

Click here to download the source files for this example and this page as a PDF file. In exchange, we will ask you to enter some personal details. To read about how we use your details, click here. On the registration form, you will be asked whether you want us to send you further information concerning other Doulos products and services in the subject area concerned.

Great training!! Excellent Instructor, Excellent facility ...Met all my expectations.
Henry Hastings
Lockheed Martin

View more references