Skip to content
Snippets Groups Projects
Commit e5458f5f authored by Eric Kooistra's avatar Eric Kooistra
Browse files

Commit to recover from SVN issue with commands.do

parent 95acae9a
No related branches found
No related tags found
No related merge requests found
###############################################################################
#
# Copyright (C) 2009
# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
# Purpose: Provide useful commands for simulating Modelsim projects
# Desription:
#
# * The user commands are typically used at the Modelsim prompt are:
#
# . lp <name> : load UniBoard <name>.mpf project
# . mk <name> : make one or range of UniBoard mpf projects
# . as # : add signals for # levels of hierarchy to the wave window
# . ds : delete all signals from the wave window
#
# * The other procedures in this commands.do are internal command procedures
# that are typically not used at the Modelsim prompt. However they can be
# used to create user commands for other projects (i.e. another arg_env then
# UNB with other arg_dir for the libraries).
#
# * The general lp and mk commands assume that the Modelsim project file is
# located at:
#
# "$env($arg_env)/Firmware/$sdir/$arg_lib/build/sim/modelsim"
#
# or for designs with an SOPC system at:
#
# "$env($arg_env)/Firmware/$sdir/$arg_lib/build/synth/quartus/*_sim/"
#
# * The recommended project directory structure is:
#
# $arg_lib/build/sim/modelsim : Modelsim project file
# /synth/quartus : Quartus project file
# /src/vhdl : VHDL source code that gets synthesized
# /tb/vhdl : VHDL source code for test bench
#
#-------------------------------------------------------------------------------
# UniBoard settings
#-------------------------------------------------------------------------------
puts "Loading general UniBoard commands..."
# UniBoard environment variable
proc unb_env {} {
return "UNB"
}
# UniBoard project directories
proc unb_dir {} {
return {"designs" "modules" "modules/Altera" "modules/MegaWizard" "modules/Lofar" "dsp" "systems"}
}
#-------------------------------------------------------------------------------
# LP = Load project
#-------------------------------------------------------------------------------
# Default load UniBoard project
proc lp {{arg_lib ""}} {
lpu $arg_lib
}
# UniBoard load project
proc lpu {{arg_lib ""}} {
set arg_env [unb_env]
set arg_dir [unb_dir]
lp_gen $arg_env $arg_dir $arg_lib
}
# General load project
proc lp_gen {arg_env arg_dir arg_lib} {
set mpf [eval project env]
set cur_lib [string range $mpf [expr [string last / $mpf]+1] [expr [string last . $mpf]-1]]
if {[string equal $arg_lib ""] || [string equal $arg_lib $cur_lib]} {
# find out current module name
return $cur_lib
} elseif [file exists $arg_lib] {
set mpf $arg_lib
} else {
set sim [simdir $arg_env $arg_dir $arg_lib]
set mpf $sim/$arg_lib.mpf
}
if [file exists $mpf] then {
# if {[this_os]=="Windows"} {
# if [file attributes $mpf -readonly] then {
# file attributes $mpf -readonly 0
# }
# } else {
# set mpf_readonly [file attributes $mpf -permissions] ;# 5 char string: 0,0,u(rwx),g(rwx),a(rwx)
# set mpf_readonly [expr !([string index $mpf_readonly 2] & 0x2)] ;# filter out user write status
# if {$mpf_readonly==1} then {
# file attributes $mpf -permissions u+w
# }
# }
if {! [string equal $cur_lib ""]} then {
project close
}
project open $mpf
} else {
error "Project file $arg_lib not found"
}
return $arg_lib
}
#-------------------------------------------------------------------------------
# MK = Make project
#-------------------------------------------------------------------------------
# Default make UniBoard project
# . The args is a special TCL argument because it allows more than one formal.
# However when args is subsequently passed on to proc mku, then all arguments
# in args will be treated as a signal argument in mku. Therefore duplicate
# the content of proc mku in proc mk, because simply calling mku $args in mk
# does not work.
# . However using an alias also works and is a nicer solution:
# One can also define a command as an alias to a sequence of one or more
# words, which will be substituted for it before execution. (The funny {}
# arguments are names of the source and target interpreter, which typically
# is the current one, named by the empty string {} or "").
interp alias {} mk {} mku
# UniBoard make project
proc mku args {
set arg_env [unb_env]
set arg_dir [unb_dir]
set arg_cmd [parse_for_cmds $args]
set arg_lib [parse_for_libs $args]
set arg_lib [extract_unb_libs $arg_lib]
mk_gen $arg_env $arg_dir $arg_cmd $arg_lib
}
# Extract groups of UniBoard libs from arg_lib
proc extract_unb_libs arg_lib {
# Check arg_lib for make groups of UniBoard modules and designs
# Remarks:
# . order of groups is important
# . for the designs that have an SOPC system that needs to be generated first with SOPC Builder (to avoid pop up windows if these files are missing)
# . e.g. group of designs for which the node component is reused in other designs
# . e.g. group of reference designs that are still maintained
set m_unb_common {fmf easics tst common mm dp uth}
set m_unb_lofar {async_logic diag util i2c rcuh sens mdio eth ado pfs pft2 ss st}
set m_unb_dsp {bf rTwoSDF fft filter wpfb}
set m_unb_modules {diagnostics ppsh tse aduh tr_nonbonded ddr3 udp_packetizer remu epcs unb_common}
set m_unb_designs {unb_tr_nonbonded unb_ddr3 unb_tr_xaui bn_terminal_bg fn_terminal_db}
set m_old_designs {unb_sens unb_tse unb_heater fn_mdio unb_base bn_base fn_base}
set m_apertif_designs {bn_capture fn_bf bn_filterbank fn_beamformer}
if [ string equal $arg_lib "all_mod" ] { set arg_lib "$m_unb_common $m_unb_lofar $m_unb_modules $m_unb_dsp"
} elseif [ string equal $arg_lib "unb_designs" ] { set arg_lib "$m_unb_designs"
} elseif [ string equal $arg_lib "all_unb" ] { set arg_lib "$m_unb_common $m_unb_lofar $m_unb_modules $m_unb_dsp $m_unb_designs"
} elseif [ string equal $arg_lib "all_apertif" ] { set arg_lib "$m_unb_common $m_unb_lofar $m_unb_modules $m_unb_dsp $m_unb_designs $m_apertif_designs"
} elseif [ string equal $arg_lib "old_designs" ] { set arg_lib "$m_old_designs"
} elseif [ string equal $arg_lib "all" ] { set arg_lib "$m_unb_common $m_unb_lofar $m_unb_modules $m_unb_dsp $m_unb_designs $m_apertif_designs $m_old_designs"
}
return $arg_lib
}
# Get commands from the mk args
proc parse_for_cmds arg_list {
set cmds {}
if [ string equal $arg_list "help" ] then {
puts "mk \[commands\] \[projects\]"
puts " possible commands are:"
puts " check: check for absolute paths in project sources"
puts " clean: removes the library files"
puts " compile: runs project compileall"
puts " delete: delete Modelsim project file"
puts " files: list files in compile order"
puts " help: displays this help"
puts " make: runs makefile"
puts " test: runs test cases"
puts " vmake: creates makefile"
puts ""
puts "commands are executed for the projects indicated"
puts "- when no command is specified, 'make' is used as default"
puts "- when no projects are specified, the current project is used"
puts "- the keyword 'all_mod' is expanded to a subset of all uniboard reuseable modules"
puts "- the keyword 'all_unb' is expanded to a subset of all uniboard reuseable designs and reference designs"
puts ""
return
} else {
# search for commands in arg_list
foreach cmd {check clean compile delete files make test vmake} {
if {[lsearch $arg_list $cmd] >= 0} then {
lappend cmds $cmd
}
}
if {[llength $cmds] == 0} then {
# no commands found, use default commands
set cmds {make}
}
}
return $cmds
}
# Get libraries (modules, designs) from the mk args
proc parse_for_libs arg_list {
# strip the commands from arg_list to keep only the modules
set libs $arg_list
foreach cmd {check clean compile delete files make test vmake} {
set i [lsearch $libs $cmd]
if {$i >= 0} then {
set libs [lreplace $libs $i $i]
}
}
return $libs
}
# General make project
proc mk_gen {arg_env arg_dir arg_cmd arg_lib} {
if {[llength $arg_cmd] > 0} then {
set cur_lib [lp_gen $arg_env $arg_dir ""]
# without arguments mk current lib
if { [llength $arg_lib] == 0 } {
set arg_lib $cur_lib
}
# perform the commands on the specified libs
foreach cmd $arg_cmd {
foreach lib $arg_lib {
if { [ catch { eval ["mk_$cmd" $arg_env $arg_dir $lib] } msg ] } {
puts stderr $msg
}
}
}
# back to original lib
lp_gen $arg_env $arg_dir $cur_lib
}
}
proc mk_check {arg_env arg_dir arg_lib} {
lp_gen $arg_env $arg_dir $arg_lib
puts "\[mk check $arg_lib\]"
foreach file [project compileorder] {
if {[string first "../" $file] != 0 &&
[string first "\$" $file] != 0} {
puts stderr "Warning: $file is an absolute path"
}
}
}
# Issue mk delete all to delete all Modelsim project files to ensure that SVN
# update refreshes them all from the repository. This is necessary because
# Modelsim edits the mpf files even when they have no significant modification
# and then the edited mpf files will not get SVN updated.
proc mk_delete {arg_env arg_dir arg_lib} {
puts "\[mk delete $arg_lib\]"
set sim [simdir $arg_env $arg_dir $arg_lib]
if {[file exists "$sim/$arg_lib.mpf"]} then {
file delete $sim/$arg_lib.mpf
}
}
proc mk_clean {arg_env arg_dir arg_lib} {
puts "\[mk clean $arg_lib\]"
set sim [simdir $arg_env $arg_dir $arg_lib]
if {[file exists "$sim/work"]} then {
vdel -lib $sim/work -all
}
if {[file exists "$sim/makefile"]} then {
file delete $sim/makefile
}
if {[file exists "$sim/vsim.wlf"]} then {
file delete $sim/vsim.wlf
}
if {[file exists "$sim/$arg_lib.cr.mti"]} then {
file delete $sim/$arg_lib.cr.mti
}
}
proc mk_compile {arg_env arg_dir arg_lib} {
if {[string compare [env] "<No Context>"] != 0} {
puts "A project cannot be closed while a simulation is in progress.\nUse the \"quit -sim\" command to unload the design first."
return
}
puts "\[mk compile $arg_lib\]"
lp_gen $arg_env $arg_dir $arg_lib
if {![file exists work"]} then {
vlib work;
}
project compileall
}
proc mk_files {arg_env arg_dir arg_lib} {
lp_gen $arg_env $arg_dir $arg_lib
foreach file [project compileorder] {
puts $file
}
}
proc mk_vmake {arg_env arg_dir arg_lib} {
set sim [simdir $arg_env $arg_dir $arg_lib]
if {![file exists "$sim/work/_info"]} then {
mk_compile $arg_env $arg_dir $arg_lib
}
puts "\[mk vmake $arg_lib\]"
if {![file exists "$sim/makefile"] ||
([file mtime "$sim/makefile"] < [file mtime "$sim/work/_info"]) } then {
# Both the specific library name $(arg_lib)_lib and the work library map to the same local work library,
# so to be compatible for both names always use work to generate the makefile
puts [exec vmake -fullsrcpath work > $sim/makefile]
adapt_makefile "$sim/makefile"
}
if {[file exists "$sim/work"]} then {
vdel -lib $sim/work -all
vlib work
}
}
proc mk_make {arg_env arg_dir arg_lib} {
global env
set sim [simdir $arg_env $arg_dir $arg_lib]
if {! [file exists "$sim/makefile"] } then {
mk_vmake $arg_env $arg_dir $arg_lib
}
puts "\[mk make $arg_lib\]"
if {[this_os]=="Windows"} {
puts [exec $env(UNB)/Firmware/sim/bin/make.exe -C $sim -s -k -f makefile]
} else {
puts [exec /usr/bin/make -C $sim -s -k -f makefile]
}
}
proc mk_test {arg_env arg_dir arg_lib} {
# only for directory /modules, so arg_dir is not used but kept to match the other proc mk_*
puts "\[mk test $arg_lib\]"
radix -decimal
vsim -quiet tst_lib.tb_$arg_lib
set tb [tbdir $arg_env $arg_lib]
foreach tc [glob -directory $tb/data -type d -nocomplain tc*] {
puts "testcase $tc"
foreach fileName [glob -directory $tc -type f -nocomplain *.in *.out *.ref] {
file copy -force $fileName .
}
restart -force
run 1 ms
foreach fileName [glob -dir . -type f -nocomplain *.in *.out *.ref] {
file delete -force $fileName
}
}
quit -sim
}
#-------------------------------------------------------------------------------
# Auxiliary procedures
#-------------------------------------------------------------------------------
# compute simulation directory
proc simdir {arg_env arg_dir arg_lib {return_code -1}} {
global env
# The order of arg_dir is important when modules with the same name exist,
# the first one where the mpf is found will be used
foreach sdir $arg_dir {
# First look in the project default Modelsim project directory
if {[file exists "$env($arg_env)/Firmware/$sdir/$arg_lib/build/sim/modelsim"]} {
return $env($arg_env)/Firmware/$sdir/$arg_lib/build/sim/modelsim
} else {
# then also support the <sopc design name>_sim directory generated by SOPC Builder
# note that for this path to be found the modelsim/ directory in sim/ must be deleted
if {[catch {glob -directory $env($arg_env)/Firmware/$sdir/$arg_lib/build/synth/quartus *_sim/}] == 0} {
# If there exists more then one dir ending at '_sim' then return only the first
return [lindex [glob -directory $env($arg_env)/Firmware/$sdir/$arg_lib/build/synth/quartus *_sim/] 0]
}
}
}
if {$return_code==-1} {
# Default raise error to abort script
error "Project directory $arg_lib not found"
} else {
# Optionally return with return_code to continue script
return $return_code
}
}
# compute tb directory
proc tbdir {arg_env arg_lib} {
global env
return $arg_env/Firmware/modules/$arg_lib/tb
}
# find out which environment operating system we are on
proc this_os {} {
if {$::tcl_platform(platform)=="windows"} {
return "Windows"
} else {
return "Not Windows" ;# Linux, Unix, ...
}
}
# adapt makefile to allow (arch_name) in filenames by changing them into \\(arch_name\\)
proc adapt_makefile arg {
if {[this_os]=="Windows"} {
# Nothing to do, works OK
} else {
set arch_names {"pkg" "rtl" "str" "wrap" "recursive" "beh" "empty" "stratix4"}
set fh [open $arg r]
set txt [read $fh]
close $fh
foreach an $arch_names {
set ai [string first "($an)" $txt]
while {$ai != -1} {
set txt [string replace $txt $ai [expr $ai + [string length $an] + 1] "\\($an\\)"]
incr ai 2
set ai [string first "($an)" $txt $ai]
}
}
set fh [open $arg w]
puts $fh $txt
close $fh
}
}
#-------------------------------------------------------------------------------
# DS = Delete Signals : deletes all signals in the waveform window.
#-------------------------------------------------------------------------------
proc ds {} {
delete wave *
}
#-------------------------------------------------------------------------------
# AS = Add signals : adds all signals up to hierarchy depth to the wave window
#-------------------------------------------------------------------------------
proc as {depth {inst ""}} {
#asf $depth
asg $depth $inst
}
#-------------------------------------------------------------------------------
# ASF = add signals flat : flat adds all signals up to hierarchy depth to the wave window
# It will automatically add dividers between the blocks, and it will discard all
# nxt_ and i_ signals. Altera alt_ blocks will also be ignored.
#-------------------------------------------------------------------------------
proc asf depth {
global env
# Start with all signals in the model.
add wave -noupdate -divider {as}
add wave -noupdate -depth $depth -r "/*"
# Allow users to set environment variable if they don't want the signals to be deleted
if { ![info exists ::env(MODELSIM_WAVE_NO_DEL) ] } {
delete wave */nxt_*
delete wave */i_*
}
#delete wave */alt*
configure wave -signalnamewidth 0
echo "Done."
}
#-------------------------------------------------------------------------------
# ASG = add signals in groups : recursively scans the hierarchy and adds signals
# groupwise to the wave window.
# Normal use:
# . asg [depth]
# => Adds all signals down to a depth of [depth].
# Advanced/debugging use:
# . asg [depth] [instance_name]
# => Adds all signals in [instance_name] down to to a level of [depth]
# NOTE: instance_name = NOT the entity name!
#-------------------------------------------------------------------------------
proc asg {depth {inst ""}} {
add_wave_grouped_recursive "" "" $depth $inst 0
wave refresh
# The grouping already displays the hierarchy, so use short signal names.
config wave -signalnamewidth 1
# With our short signal names, the name column can be narrower than default.
config wave -namecolwidth 300
}
# called by ASG:
proc add_wave_grouped_recursive {current_level prev_group_option depth target_inst target_inst_det} {
# Find all instances (=next hierarchy levels) in the ecurrent hierarchy level
set found_instances [find instances "$current_level/*"]
# Find all blocks (=GENERATE statement labels that are also hierarchy levels to be explored)
set found_blocks [find blocks "$current_level/*"]
# Concatenate the instance list with the block list, sort them alphabetically
set objects [lsort -dictionary [concat $found_instances $found_blocks]]
foreach object $objects {
# Separate "/object_path" from "(entity_name)"
set object_path [lindex [split $object " "] 0]
# Get the word after last "/"
set gname [lrange [split $object_path "/"] end end]
if {[path_depth $object_path]<$depth} {
if { $gname == $target_inst || $target_inst_det==1} {
# Found an instance that matches user input - or we're already inside that instance.
add_wave_grouped_recursive "$object_path" "$prev_group_option -group $gname" $depth $target_inst 1
} else {
add_wave_grouped_recursive "$object_path" "$prev_group_option -group $gname" $depth $target_inst 0
}
}
}
if { $current_level != "" } {
# First check if what we're about to add is an instance, not merely a GENERATE level
if {[context isInst $current_level]==1} {
set CMD "add wave -noupdate -radix unsigned $prev_group_option $current_level/*"
if {$target_inst!=""} {
# User passed a target inst. Check if we inside of it.
if {$target_inst_det==0} {
# We're not in in instance. Only add a group and move on.
set CMD "add wave -noupdate -radix unsigned $prev_group_option"
}
}
# Use catch so e.g. empty entities don't cause script to fail
catch {eval $CMD}
}
return
}
}
# Count the number of occurences in a string:
proc scount {subs string} {
regsub -all $subs $string $subs string
}
# Return the depth of a given path; e.g. /some/path/to/some/thing = 5.
proc path_depth path {
scount "/" $path
}
#-------------------------------------------------------------------------------
# NOWARN default disables the library warnings for subsequent simulation runs.
# Use argument 0 to enable the warnings again.
#-------------------------------------------------------------------------------
proc nowarn {{off 1}} {
set ::StdArithNoWarnings $off
set ::NumericStdNoWarnings $off
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment