Using Embedded TCL Rewriting on XPS Designs

  1. Using Embedded TCL Rewriting on XPS Designs
    1. Introduction
    2. Overview of Embedded TCL Rewriting
    3. Embedded TCL Rewriting Example
      1. Download the Source
      2. TCLized Files
      3. Example External Parameters
      4. Example TCLized Code
      5. The Rewriter Script
    4. Building the Example (using rewriting)
    5. Using Embedded TCL Rewriting in Other Projects
    6. Frequently Asked Questions


For many Xilinx Platform Studio (XPS) designs and hardware cores it is often desirable to be able to change some aspect of the design based on external parameters. For the design of hardware cores with an HDL the majority of parametrization can be done through the use of generics (or parameters) and generate statements. However, for changes to the interface of an HDL design or changes to XPS base system files, there is no standard way to automate design changes.

For example, a XPS design with multiple soft core processors may wish to easily vary the number of cores and other parameters such as connectivity or features without having to cut and paste or muck around with a GUI. Another example is a hardware core that operates as a multiport switch and would like to be able to vary the number of ports.

To address this problem at BWRC, we currently use a simple process we call "embedded TCL rewriting." Other users may have other methods to address the same problem, however several of the cores and reference designs included as part of the board support package use this scheme, so it is useful to explain how it works.

Overview of Embedded TCL Rewriting

Here is a quick, step by step explaination of how TCL rewriting works:

  1. Source code (HDL, MPD files, MHS files, etc) are written as normal except they are given the suffix .tcl For example the MHS file for a XPS project would go from system.mhs to system.mhs.tcl .

    1. Embedded anywhere in the source code the author can place arbitrary TCL variables in the form  ${VAR_NAME} . TCL variables are all strings and the variable will be expanded by preprocessing into a string representation of its value. For example a source line  PORT FSL_Rd_Control_${i}  with a value for  ${i}  of 1 at the time of preprocessing would expand to  PORT FSL_Rd_Control_1 .

    2. Arbitrary TCL code can also be embedded in the source by starting the line with the statement  !TCL! . Any statements after that line prefix will be treated as TCL code. This allows conditional, loop, and other statements to be generated.

  2. Any external parameters are placed in a .ini file which is pulled in by preprocessing code to set TCL variables.

  3. All code with .tcl suffix is preprocessed to generate a TCL rewriter script.

    1. Preprocessing is done by turning each file into an actual TCL script with the new suffix .tcl.tcl . b. Lines with !TCL! prefix are copied directly into new script. c. Lines without prefix are encapsulated in TCL "puts" statements which cause them to be printed by script and expand any embedded variables.

  4. The rewriter script is executed creating the actual source to be used by the tools. For example a file orginally called system.mhs.tcl will generate system.mhs .

Embedded TCL Rewriting Example

The best way to understand how TCL rewriting works, and how to use it yourself, is to examine an existing example. Several examples are available in the BEE2 board support package, so we will examine one that has the most extensive use of TCL rewriting.

Download the Source

First, download the "repository" and "reference" source code packages (see the Bee2Cvs page for instructions on downloading). Unzip both of the source packages and enter the reference/MPI_demo/XPS_Userfpga directory. Next, prepare the design by running

./ /PATH/TO/repository

which will setup symlinks from the IP core repository to the pcores directory in the design.

TCLized Files

If you poke around in the XPS_Userfpga directory you will notice several files with .tcl and .ini suffixes.

Example External Parameters

In the mb.ini file you will see what looks like TCL variable instantiations, which is exactly what the file does. For example:

# Use XAUI
set USE_XAUI    1
set NUM_XAUIS   4

This code creates two variables $USE_XAUI and $NUM_XAUIS and sets their values. These variables will be availble to the TCLized code that is rewritten. This is the main mechanism for the user to change parameters that will be used to generate the code. Any valid TCL code is permissible in this file because it is simply sourced by the rewriting script.

Example TCLized Code

In the system.mhs.tcl file you will notice the following snippet of code:

!TCL! if {$USE_XAUI == 1} {
!TCL!   for {set i 0} {$i < $NUM_XAUIS} {incr i} {
# XAUI port ${i}
 PORT mgt${i}_tx_l0_p          = mgt${i}_tx_l0_p, DIR = O
 PORT mgt${i}_tx_l0_n          = mgt${i}_tx_l0_n, DIR = O
 PORT mgt${i}_tx_l1_p          = mgt${i}_tx_l1_p, DIR = O
 PORT mgt${i}_tx_l1_n          = mgt${i}_tx_l1_n, DIR = O
 PORT mgt${i}_tx_l2_p          = mgt${i}_tx_l2_p, DIR = O
 PORT mgt${i}_tx_l2_n          = mgt${i}_tx_l2_n, DIR = O
 PORT mgt${i}_tx_l3_p          = mgt${i}_tx_l3_p, DIR = O
 PORT mgt${i}_tx_l3_n          = mgt${i}_tx_l3_n, DIR = O
 PORT mgt${i}_rx_l0_p          = mgt${i}_rx_l0_p, DIR = I
 PORT mgt${i}_rx_l0_n          = mgt${i}_rx_l0_n, DIR = I
 PORT mgt${i}_rx_l1_p          = mgt${i}_rx_l1_p, DIR = I
 PORT mgt${i}_rx_l1_n          = mgt${i}_rx_l1_n, DIR = I
 PORT mgt${i}_rx_l2_p          = mgt${i}_rx_l2_p, DIR = I
 PORT mgt${i}_rx_l2_n          = mgt${i}_rx_l2_n, DIR = I
 PORT mgt${i}_rx_l3_p          = mgt${i}_rx_l3_p, DIR = I
 PORT mgt${i}_rx_l3_n          = mgt${i}_rx_l3_n, DIR = I

!TCL!   }
!TCL! }

This code shows an example of how to use conditionals and loops to generate code based on external parameters. In the example there are two external variables ($USE_XAUI and $NUM_XAUIS) which are set via the parameter file. The variables are used to generate an IF statement and FOR loop around some MHS external port declarations. After preprocessing this translates into the following TCL code in the system.tcl.tcl file:

set line_num 77;  if {$USE_XAUI == 1} {
set line_num 78;    for {set i 0} {$i < $NUM_XAUIS} {incr i} {
set line_num 79; puts $output_file "##"
set line_num 80; puts $output_file "# XAUI port ${i}"
set line_num 81; puts $output_file "##"
set line_num 82; puts $output_file " PORT mgt${i}_tx_l0_p          = mgt${i}_tx_l0_p, DIR = O"
set line_num 83; puts $output_file " PORT mgt${i}_tx_l0_n          = mgt${i}_tx_l0_n, DIR = O"
set line_num 84; puts $output_file " PORT mgt${i}_tx_l1_p          = mgt${i}_tx_l1_p, DIR = O"
set line_num 85; puts $output_file " PORT mgt${i}_tx_l1_n          = mgt${i}_tx_l1_n, DIR = O"
set line_num 86; puts $output_file " PORT mgt${i}_tx_l2_p          = mgt${i}_tx_l2_p, DIR = O"
set line_num 87; puts $output_file " PORT mgt${i}_tx_l2_n          = mgt${i}_tx_l2_n, DIR = O"
set line_num 88; puts $output_file " PORT mgt${i}_tx_l3_p          = mgt${i}_tx_l3_p, DIR = O"
set line_num 89; puts $output_file " PORT mgt${i}_tx_l3_n          = mgt${i}_tx_l3_n, DIR = O"
set line_num 90; puts $output_file " PORT mgt${i}_rx_l0_p          = mgt${i}_rx_l0_p, DIR = I"
set line_num 91; puts $output_file " PORT mgt${i}_rx_l0_n          = mgt${i}_rx_l0_n, DIR = I"
set line_num 92; puts $output_file " PORT mgt${i}_rx_l1_p          = mgt${i}_rx_l1_p, DIR = I"
set line_num 93; puts $output_file " PORT mgt${i}_rx_l1_n          = mgt${i}_rx_l1_n, DIR = I"
set line_num 94; puts $output_file " PORT mgt${i}_rx_l2_p          = mgt${i}_rx_l2_p, DIR = I"
set line_num 95; puts $output_file " PORT mgt${i}_rx_l2_n          = mgt${i}_rx_l2_n, DIR = I"
set line_num 96; puts $output_file " PORT mgt${i}_rx_l3_p          = mgt${i}_rx_l3_p, DIR = I"
set line_num 97; puts $output_file " PORT mgt${i}_rx_l3_n          = mgt${i}_rx_l3_n, DIR = I"
set line_num 98; puts $output_file ""
set line_num 99;    }
set line_num 100;  }

When this TCL code is executed the loop will setup the value of $i and will generate $NUM_XAUIS copies of the port declaration block with $i expanded out to "0 1 2 ...". The resulting system.mhs file will contain the following:

# XAUI port 0
 PORT mgt0_tx_l0_p          = mgt0_tx_l0_p, DIR = O
 PORT mgt0_tx_l0_n          = mgt0_tx_l0_n, DIR = O
 PORT mgt0_tx_l1_p          = mgt0_tx_l1_p, DIR = O
 PORT mgt0_tx_l1_n          = mgt0_tx_l1_n, DIR = O
 PORT mgt0_tx_l2_p          = mgt0_tx_l2_p, DIR = O
 PORT mgt0_tx_l2_n          = mgt0_tx_l2_n, DIR = O
 PORT mgt0_tx_l3_p          = mgt0_tx_l3_p, DIR = O
 PORT mgt0_tx_l3_n          = mgt0_tx_l3_n, DIR = O
 PORT mgt0_rx_l0_p          = mgt0_rx_l0_p, DIR = I
 PORT mgt0_rx_l0_n          = mgt0_rx_l0_n, DIR = I
 PORT mgt0_rx_l1_p          = mgt0_rx_l1_p, DIR = I
 PORT mgt0_rx_l1_n          = mgt0_rx_l1_n, DIR = I
 PORT mgt0_rx_l2_p          = mgt0_rx_l2_p, DIR = I
 PORT mgt0_rx_l2_n          = mgt0_rx_l2_n, DIR = I
 PORT mgt0_rx_l3_p          = mgt0_rx_l3_p, DIR = I
 PORT mgt0_rx_l3_n          = mgt0_rx_l3_n, DIR = I


The Rewriter Script

The rewriter script gen_ip.tcl is customized to each particular project, so it requires some modification to work in different contexts. The heart of the script is the rewrite_file function. This function takes a TCLized source file and generates the TCL script that will output the rewritten file.

If you examine the gen_ip.tcl file you will see a section marked:

###### Main flow ######

The code following this marker is the customized code for the particular project. In this example the code does the following steps:

  1. Parse arguments and read in the INI file (common code)

  2. Rewrite the XPS project files (common code that needs to be slightly modified)

  3. Rewrite hardware cores that have variable interfaces (common code with heavier modifications)

  4. Rewrite the bootloader code (custom code)

Much of this code can be reused in other applications, and any specific steps you require for your particular project can be added as custom TCL code.

Building the Example (using rewriting)

The next step to understanding TCL rewriting is to actually build the example project. This will give you a feel for how the TCL rewriting process actually operates.

Thats it. Keep in mind that any time you make changes to the INI file, you need to rerun the gen_ip.tcl script and that it will change the timestamps on source code (which means the XPS tools will probably force a recompile).

Using Embedded TCL Rewriting in Other Projects

The general idea behind TCL rewriting will work with pretty much any text file. If you want to use TCL rewriting in your own core, project files, or other text source you mainly need to modify the gen_ip.tcl file to suit your particular needs.

If you are new to TCL, or if you just need a good reference, we suggest using the TCL Reference Manual. The whole process just involves normal TCL code, so no special syntax outside the use of the !TCL! prefix is required.

Frequently Asked Questions

None so far.

Bee2TclRewrite (last edited 2006-06-28 16:57:45 by alschult)