Can a VHDL configuration have generics of it's own? - tcl

What I want to do:
I want to pass the current date and time to a VHDL testbench so I can create nicer report file names.
The Problem:
The Top level VHDL file that is being called from my simulation TCL scripts is a configuration and I don't know how to pass the genericto it. The interesing part of the TCL script is the following:
set reportfilename "report_$testcase_id"
append reportfilename [clock format [clock seconds] -format _%Y-%m-%d_%H:%M]
vsim -t 10fs -gG_TC_REPORTFILE=$reportfilename -novopt work.CFG_TB_TOP_tc0027 - wlf result_$testcase_id.wlf
The resulting VSIM call looks like this:
# vsim -t 10fs -wlf result_tc0027.wlf -novopt -gG_TC_REPORTFILE=report_tc0027_2014-03-05_13:22 work.CFG_TB_TOP_tc0027
The problem is that G_TC_REPORTFILE is not a generic of CFG_TB_TOP_tc0027.vhd, but of one of the modules configured IN CFG_TB_TOP_tc0027.vhd
The relevant part of CFG_TB_TOP_tc0027.vhd:
configuration CFG_TB_TOP_tc0027 of TB_TOP_CFG is
for testcaseexecution
for TB_TOP_E_INST : TB_TOP_E
-------------------------------------------------------------
-- Testbench configuration
-------------------------------------------------------------
use entity work.TB_TOP_E(TB_TOP_sim)
generic map (
G_TC_STIMULUSFILE => "./testcases/tc0027.txt", --
G_TC_REPORTFILE => "./results/report_tc0027.txt",
G_TB_VNR => "V_03.10",
G_TC_NR => 27); --
for TB_TOP_A_sim
How would I pass the value from the TCL file to the generic G_TC_REPORTFILE of the TB_TOP_E entity? Can I somehow add a generic to the CFG file, or can I somehow specify for which entity the generic in the TCL file is meant? Best-case-scenario would be if I would not have to edit the vhdl files, only the TCL scripts.
The simulator is ModelSim SE 10.0b, I'm using VHDL 2008.

I have just found the answer myself:
You can indeed specify a path to the generic you want to overwrite. I changed the TCL file like this:
set reportfilename "./results/report_$testcase_id"
append reportfilename [clock format [clock seconds] -format _%Y-%m-%d_%H-%M.txt]
vsim -t 10fs -GTB_TOP_CFG/TB_TOP_E_INST/G_TC_REPORTFILE=$reportfilename -novopt work.CFG_TB_TOP_tc0027 -wlf result_$testcase_id.wlf
Which produces the following VSIM call:
# vsim -t 10fs -wlf result_tc0027.wlf -novopt -GTB_TOP_CFG/TB_TOP_E_INST/G_TC_REPORTFILE=./results/report_tc0027_2014-03-05_14-06.txt work.CFG_TB_TOP_tc0027
In addition to adding the path TB_TOP_CFG/TP_TOP_E_INST/ I also had to remove the : from the timestamp, as modelsim/vhdl did not handle it.

Related

Reading cmd arguments in TCL file

I am trying to run a tcl script through .bat file. I want to read some cmd arguments in the tcl script. Below is my code:
Command to run:
D:\Cadence\Sigrity2021.1\tools\bin\PowerSI.exe -tcl abcd.tcl %new_var%.spd %new_file_name%
Below is how I am trying to read the variable in the tcl file:
sigrity::open document [lindex $argv 0] {!}
It open up the Cadence Sigrity, but I see the below error:
How do I read cmd argument in tcl?
If you have no other way to do it that you can find (and it sounds like that might be the case) then you can fake it by writing a helper file with content like this, filling in the real arguments in the appropriate places:
# Name of script to call
set ::argv0 "abcd.tcl"
# Arguments to pass
set ::argv {}
lappend ::argv "%new_var%.spd"
lappend ::argv "%new_file_name%"
# Number of arguments (rarely used)
set ::argc [llength $::argv]
# Do the call
source $::argv0
Then you can pass that file to PowerSI and it will set things up and chain to the real file. It's messy, but practical.
If you're writing this from Tcl, use the list command to do the quoting of the strings (instead of putting them in double quotes) as it will do exactly the right thing for you. If you're writing the file from another language, you'll want to make sure you put backslashes in before \, ", $ and [ characters. The fiddlyness of doing that depends on your language.

How to print full path of a file being sourced?

let say there is a file a/b/c/d.tcl and it should print its full path when being sourced.
source d.tcl
And the output should be
a/b/c/d.tcl
How to do this? Is there any tcl variable which stores the full path info of the file being sourced?
The info script command returns the file that is currently evaluated. Combine that with file normalize to get the full path:
puts [file normalize [info script]]
Beware that info script is only valid while the file is evaluated. Calling info script from procs that are defined by the script, but are evaluated later in response to an event will not produce the name of the file that defined the proc.
You sometimes see the claim that info script cannot be used in a proc. That is incorrect. It can be used in a proc, but it only produces a useful result if that proc is called directly while evaluating the script.
Example:
proc foo {} {
puts [file normalize [info script]]
}
# This works fine:
foo
# This should not be trusted to produce the expected result:
after 5000 foo
To make that last command work, you would have to store the result of info script in a variable, and use that in your proc.

How do I perform a command substitution in tclsh?

I want to capture the stdout of a command in a variable, similarly to command substitution in Bash:
#!/bin/bash
x="$(date)"
echo $x
I tried doing the same in tclsh but it doesn't do what I want:
#!/bin/tclsh
set x [date]
echo $x
If I execute the script withtclsh myscript.tclsh it gives an error:
invalid command name "date"
while executing
"date "
invoked from within
"set x [ date ]"
On the other hand, if I open a TCL interactive shell with tclsh, it does not give an error and the echo line prints an empty string.
Why is my program giving different results when I execute the script with or without the REPL? And it there a way to capture the output of a shell command and store it in a variable, similarly to command substitution in Bash?
When not using Tcl interactively, you need to explicitly use the exec command to run a subprocess.
set x [exec date]
# Tcl uses puts instead of echo
puts $x
In interactive use, the unknown command handler guesses that that's what you wanted. In some cases. Be explicit in your scripts, please!
You should probably replace running a date subprocess with the appropriate calls to the built-in clock command:
# Get the timestamp in seconds-from-the-epoch
set now [clock seconds]
# Convert it to human-readable form
set x [clock format $now -format "%a %d %b %Y %H:%M:%S %Z"]
(That almost exactly matches the output of date on this system. The spacing isn't quite the same, but that doesn't matter for a lot of uses.)

Command to return library (not work) name of a path in modelsim

I want to find a way to return the name of a library of a certain path in a VHDL Design in Modelsim.
Given a VHDL Design with a path like "/mega_tb/D0". This is compiled in a library that is NOT 'work', say "libnwork".
I can of course take a look in my 'do' file to get the correct lib name. Or I can search in ModelSim's Library tab. But I want to have or create a modelsim command which I can later use in a Tcl script, to get the correct library name.
One of the easiest ways to find something in a Tcl script file – which is all a Modelsim “do” file is — is to evaluate it. Tcl's very good at that. Of course, you don't want to have the commands do all the conventional things. Instead, we'll evaluate in a context where we can make everything do nothing except for the command that produces the information we want:
# Set up our evaluation context, 'worker'
interp create worker -safe
interp eval worker {proc unknown args {}}; # Our do-nothing handler
interp alias worker theInterestingCommand {} ourHandler
proc ourHandler args {
puts "We were called with: $args"
}
# Parse the file!
set f [open /the/file.tcl]
interp eval worker [read $f]
# Clean up
close $f
interp delete worker
Now you just have to make theInterestingCommand have the right name and extract the interesting information from the arguments. Which should be relatively easy…
Te only way I've found is to use the command
write report -tcl
This prints a long list where I have search for the lib names with regexps.
Something like
set data [ write report -tcl]
foreach_regexp { _ type lib entity} $data{
if {$type == "Entity" && $entity == [entity_of_path /mega_tb/D0] } {
....
}
}
Where I of course had to define my "foreach_regexp" procedure and my "entity_of_path" procedure. I then can use something like regsub to extract the library name.
I am still looking for a better and easier way.

How to run tcl script inside other tcl script?

I have two tcl scripts. I want to run the second script when the first finished. How can I do it?
Depends on what do you really mean.
One way is to write a third ("master") script which would do
source /the/path/to/the/first.tcl
source /the/path/to/the/second.tcl
Another way is to just add the second call to source from the above example to the bottom of the first script.
Amendment to the first approach: if the scripts to be executed are located in the same directory as the master script, an idiomatic way to source them is
set where [file dirname [info script]]
source [file join $where first.tcl]
source [file join $where second.tcl]
This way sourcing will work no matter what the current process's directory is and where the project directory is located.
While this is generally a correct answer, because the question was not precisely formulated there are tons of ways to achieve the goal of running Tcl code from within Tcl.
I want to get into this in detail because understanding the execution of code is one major point in understanding Tcl itself.
There is source
The source command should not be confound with executing scripts in a classical way, what I think the thread starter has asked.
The source command is like the "include" command in c/perl/php.
Languages like java or python on the other hand only have "import" mechanisms.
The difference is that those languages create a internal database of available packages, who are linked to the corresponding source/binary/bytecode files. By writing a import statement, linked source or bytecode or binary files are loaded. This allows more in-depth dependency management without writing additional code.
In Tcl this can be achieved with namespaces and the package require command.
Example:
Suppose you have this source.tcl:
proc foo {bar} {puts "baz"}
set BAM "BOO"
Now, you have your "master" script like you call it. I call it "main". It has the content:
set BAM {my important data}
source source.tcl
#also the function foo can now be used because the source reads the whole script
foo {wuz}
set BAM
#will output "BOO"
The exec command
If you can live with additional overhead of starting a whole new interpreter instance you could also do:
set BAM {my important data}
exec tclsh source.tcl
#The variable BAM will not be modified. You can not use the function foo.
The eval command
The command eval can evaluate a string or a list (in Tcl everything is a string) like it would be programmed code.
You would have to load the complete source file to a string. And then use eval, to evaluate the code within a separate scope, to not overwrite stuff in your main source file.
set fp [open "somefile" r]
set code_string [read $fp]
close $fp
eval $code_string
You just need to use source to run the 2nd script.
source "/tmp/whatever.tcl"
Simplest possible working example I could find:
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$ tclsh main.tcl
hello world
7
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$ cat main.tcl
lappend auto_path /home/thufir/NetBeansProjects/spawnTelnet/telnet/api
package require weather 1.0
tutstack::hello
set A 3
set B 4
puts [tutstack::sum $A $B]
#puts [tutstack::hello "fred"]
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$ cat api/weather.tcl
package provide weather 1.0
package require Tcl 8.5
namespace eval ::tutstack {
}
proc ::tutstack::hello {} {
puts "hello world"
}
proc ::tutstack::sum {arg1 arg2} {
set x [expr {$arg1 + $arg2}];
return $x
}
proc ::tutstack::helloWorld {arg1} {
return "hello plus arg"
}
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$ cat api/pkgIndex.tcl
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script. It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands. When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.
package ifneeded weather 1.0 [list source [file join $dir weather.tcl]]
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$