Showing results for 
Show  only  | Search instead for 
Did you mean: 
Registered: ‎01-03-2014

using tcl hook scripts





I would very much appreciate your help with tcl hook scripts!


I am using the Vivado 2013.3 64bit IDE interface.

I created a TCL hook script which executes automatcially after I click on 'generate bitstream'.

(The purpose of this was to run 'promgen' to automatically generate a *.mcs file)


Here is a portion of the script:


puts "pwd is                         : [pwd]"

puts "current project is             : [current_project]"

puts "current run is                 : [current_run]"

puts ""


set curr_prj_dir [get_property DIRECTORY [current_project]]

puts "current project dir            : $curr_prj_dir"

set norm_curr_prj_dir [file normalize $curr_prj_dir]

puts "normalized current project dir : $norm_curr_prj_dir"


set curr_run_dir [get_property DIRECTORY [current_run]]

puts "current run dir                : $curr_run_dir"

set norm_curr_run_dir [file normalize $curr_run_dir]

puts "normalized current run dir     : $norm_curr_run_dir"


This script works fine (or at least as anticipated!) when I run it from the console.

source e:/P3000/Firmware/Xilinx/write_mcs.tcl -notrace

pwd is                         : C:/Users/synthesis/AppData/Roaming/Xilinx/Vivado:

current project is             : fpga_dvbs2x_ext_xc7k325t_2_fbg676

current run is                 : impl_1

current project dir            : E:/P3000/Firmware_Series2/FPGA_DVBS2X/FPGA_DVBS2X_EXT/implement/fpga_dvbs2x_ext_xc7k325t_2_fbg676

normalized current project dir : E:/P3000/Firmware_Series2/FPGA_DVBS2X/FPGA_DVBS2X_EXT/implement/fpga_dvbs2x_ext_xc7k325t_2_fbg676

current run dir                : E:/P3000/Firmware_Series2/FPGA_DVBS2X/FPGA_DVBS2X_EXT/implement/fpga_dvbs2x_ext_xc7k325t_2_fbg676/fpga_dvbs2x_ext_xc7k325t_2_fbg676.runs/impl_1

normalized current run dir     : E:/P3000/Firmware_Series2/FPGA_DVBS2X/FPGA_DVBS2X_EXT/implement/fpga_dvbs2x_ext_xc7k325t_2_fbg676/fpga_dvbs2x_ext_xc7k325t_2_fbg676.runs/impl_1


However when run as a 'hook' script then the script does not provide the same results.

source E:/P3000/Firmware/Xilinx/write_mcs.tcl

pwd is                         : E:/P3000/Firmware_Series2/FPGA_DVBS2X/FPGA_DVBS2X_EXT/implement/fpga_dvbs2x_ext_xc7k325t_2_fbg676/fpga_dvbs2x_ext_xc7k325t_2_fbg676.runs/impl_1: current project is             : project_fpga_dvbs2x_ext_xc7k325t_2_fbg676_routed

current run is                 : impl_1

current project dir            : .

normalized current project dir : E:/P3000/Firmware_Series2/FPGA_DVBS2X/FPGA_DVBS2X_EXT/implement/fpga_dvbs2x_ext_xc7k325t_2_fbg676/fpga_dvbs2x_ext_xc7k325t_2_fbg676.runs/impl_1 current run dir                : ./.runs/impl_1

normalized current run dir     : E:/P3000/Firmware_Series2/FPGA_DVBS2X/FPGA_DVBS2X_EXT/implement/fpga_dvbs2x_ext_xc7k325t_2_fbg676/fpga_dvbs2x_ext_xc7k325t_2_fbg676.runs/impl_1/.runs/impl_1



1) how do i make this script provide the same results regardless of whether i run form the console, or as a hook script

2) why does [current_project] insert the extra text project_xxxxx_routed

3) why doesnt [get_property DIRECTORY [current_project]] return the same value regardless of how i execute the script

4) why does [get_property DIRECTORY [current_run]] return a path that doesnt exist!

5) why doesnt [get_property DIRECTORY [current_run]] return the same value regardless of how i execute the script

6) how do i access the 'project name' within my script AND ensure that it will work regardless of the method of execution

7) are their any predefined/gloabl/project variables I can access


many thanks


0 Kudos
5 Replies
Registered: ‎01-23-2009

So you have wandered into complex territory...

Vivado has two modes - Project mode and non-project batch mode.

The "native" mode is really non-project batch mode. In this mode, all operations are done on the "design currently in memory". The netlist is initially created by the synth_design process, and is modifed by processes that can be run later - opt_design, place_design, phys_opt_design, route_design. All analysis, reporting, checkpointing and writing operations can also be done on the "design in memory".

Project mode is really a sort of wrapper around non-project batch mode. In project mode, Vivado generates the concept of a project, which determines where all the project files lives, and abstracts the actual processes with the concepts of "runs". Runs (synth_1 and impl_1 by default) are created, configured and then launched.

When you launch a run, Vivado actually spawns a background copy of Vivado, which

  • reads in the inputs of the process to be run (puts the design "in memory")
  • executes the command to be run, using the options that were configured for that run
  • writes out any results and log files necessary
  • and terminates

The hook scripts are specifically a mechanism of executing operations in this background process, before and after the process is run. In this case, the process is "write_bitstream". In the context in which these hook scripts run, there is no project - the background process is running in non-project batch mode. Since this is an entirely new context, running fundamentally in a different mode, the commands that you can run and the results that you should expect to get are different.

So, the short answer is "there is nothing you can do that is going to make these scripts run the same way from the console and from the hook script". They are in a fundamentally different context and they will not behave the same. I am suprised that things like [current_project] are even valid in the background context - it is in non-project batch mode.

If you really want to record all of this project status stuff, you will have to run it in the foreground process. As you have started to see, the project stuff simply isn't valid in the background context.

I know you want this automatically done when you click on the "generate bitstream" button, but its not going to work the way you want. So, what you could do instead is to add the

launch_runs impl_1 -to_step write_bitstream

to the end of your script. Now the script will invoke the equivalent of "generate bitstream" automatically with the running of the script. You can invoke the script using the "source" command, or you can execute it by "tools -> run Tcl script..."


0 Kudos
Registered: ‎01-03-2014

Hi Avrum


thanks for the reply. I appreciate the suggestion, and will give it a go;


however i think that what I am trying to do should work.

After all UG894 (v2012.4) December 18, 2012 pages 32-34 states


1)"In a non-project flow you have the ability to source a Tcl script at any point in the flow, such

as before or after running the synth_design command. You can also do this in a project-based flow, using the Vivado IDE"


2) For an implementation run you can define Tcl scripts before and after each step of the

implementation process: Opt Design, Power Opt Design, Place Design, Post-Place Power

Opt Design, Phys Opt Design, Route Design and Bitstream generation.


3)Relative paths within the tcl.pre and scripts are relative to the appropriate

run directory of the project they are applied to:


<project>/<project.runs>/<run_name>. You

can use the DIRECTORY property of the current project or current run to define the relative paths in

your Tcl hook scripts:

get_property DIRECTORY [current_project]

get_property DIRECTORY [current_run]


what do you think ?




0 Kudos
Registered: ‎01-03-2014

would anyone from xilinx like to comment ? 

0 Kudos
Xilinx Employee
Xilinx Employee
Registered: ‎03-24-2008

Justin, I'm sorry I didn't see this thread earlier.  I hope it is not tool late to offer some useful guidance.


What Avrum suggests is mostly true.  However, there IS a way to make these flows work identically.  Avrum explained that when you launch a run - it launches another session of vivado in anther process - and any Tcl global variable you have defined in your IDE session - or in another step (synth and impl are separate "runs") will not be inherited from the other.


So if you expect any global variables to be shared - you need to separate them into their own hook script - and add that into each pre-stage - either as a separate hook or at the top of the hook script you are implementing.  Another alternative is setting them up as an init.tcl script which is sourced at every invocation by a user.

Greg Daughtry
Vivado Product Marketing Director, Xilinx, Inc.
Xilinx Employee
Xilinx Employee
Registered: ‎03-24-2008

Let’s say you want to create a Tcl variable to specify an output directory where you want to write some custom reports to.  So in your IDE session you might try to do this:


set outputDir “[pwd]/out”


And you write a nifty custom report script that expects to have that variable defined ($outputDir).  Lets call that script myReport.tcl Great – if you source myReport.tcl in your IDE session with a design open – the script runs and it sees the global Tcl variable $outputDir.  Perfect!


But now suppose you try to set the myReport.tcl as a hook script which executes at the end of implementation.  Wait, it no longer works.  It will error out because $outputDir is not defined.  Wait, why?  I set it in my IDE session that launched the run?  Vivado is launching another version of itself – to make use of parallelism and multiprocessing – and Tcl variables do not inherit from one session to another.  It’s not just Vivado – every Tcl tools is this way. If you want access to global variables the solution is to make a separate (or add it to your current one) hook script which expects these variables.  There are many ways to do this.  You can set it as an init.tcl script or hard code it in every script , but probably the best way to do it is to create another Tcl script in the same directory as the hook script.  There are some useful tricks to make this very easy.


# this is a great trick for getting the directory of the location of the current script being executed:

set scriptDir [file dirname [info script]]

if {![info exists outputDir]} {

   source $scriptDir/myGlobalVars.tcl



So if you put your commands to set your global variables in the same directory as your hook script – this little snippet of code checks to see if the variables are set – if not – source the script to set them – then you can access them in any hook script – provided the myGlobalVars.tcl script is located in the same directory as the hook script which is running.  You can set this up in other ways if you like – but this is a pretty elegant solution.

Greg Daughtry
Vivado Product Marketing Director, Xilinx, Inc.
Tags (1)