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

Moved or copied files to RadioHDL.

parent 9b6dbaac
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
}
###############################################################################
#
# Copyright (C) 2014
# 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/>.
#
###############################################################################
"""Common class for accessing a Python dictionary in one or more files
The contents of the dictionary file consist of a series of key - value
pairs. These key - value pairs are read from the file and kept in a
single dictionary of keys and values.
The format of the dictionary file is similar to that of an ini file but
without the sections. For ini files Python has the ConfigParser package.
Effectively the dictionary file only contains one section. It is not
obvious how to deal with sections if only one dictionary needs to be
stored flat. Defining a single section, is misleading because it suggests
that more sections are supported. Alternatively prepending a dummy
section when the file is read is also a bit awkward. In fact the parsing
by read_dict_file() is relatively simple and the other methods would also
be needed if the ConfigParser would be used. Therefore the Python
ConfigParser package for ini files is not used.
The key and value string in the dictionary file are separated by '='. Hence
the '=' character can not be used in keys. The '=' can be used in values,
because subsequent '=' on the same line are part of the value.
Every key must start on a new line. The value string can extend over one
or multiple lines. Comment lines are supported by preceding it with a '#'
and will get stripped.
# This is a comment section
# a key starts on a new line and extends until the '='
# a key and its values are separated by '='
key=string
key =string
key = string
# a key with multiple values in its string
key = value value value
# how the values are separated depends on the dictionary user
key = value, value, value
key = value value
# a key with many values can have its string extend on multiple lines,
# the newline is replaced by a ' ' and any indent is removed
key =
value
value
value
# empty lines and spaces are allowed
key = value
Whether the key is a valid key depends on the dict user that interprets
the dictionary.
It can be useful to be able to refer to the dicts based on a certain key
value, e.g. a key value that gives the name of the dict. The methods
get_key_values() and get_dicts() provide a means to easily link a dict
to its name and its name to the dict. The argument and the return can be
a list or a single value. Default the init list of self.dicts is used as
argument.
'fileName' = the name of the dictionary file including extension
'filePath' = the full directory name where the dictionary file is
stored
'filePathName' = filePath/fileName
"""
import common as cm
import sys
import os
import os.path
import collections
class CommonDictFile:
def __init__(self, rootDir, fileName='dict.txt'):
"""Store the dictionaries from all fileName files in rootDir."""
self.CDF_COMMENT = '#'
self.CDF_SEPARATOR = '='
self.rootDir = rootDir
self.fileName = fileName # all dictionary files have the same fileName
self.filePaths = self.find_all_dict_file_paths() # list of all directory paths of dictionary files that are available in the rootDir tree
if len(self.filePaths)==0:
sys.exit('Error : No %s file found in %s directory tree.' % (fileName, rootDir))
self.filePathNames = [] # list of all directory paths + fileName of the available dictionary files
for path in self.filePaths:
self.filePathNames.append(os.path.join(path, self.fileName))
self.dicts = self.read_all_dict_files() # list of dictionaries that are read from the available dictionary files
self.nof_dicts = len(self.dicts) # number of dictionaries = number of dictorary files
def find_all_dict_file_paths(self, rootDir=None):
"""Recursively search the rootDir tree to find the paths to all fileName files."""
if rootDir==None: rootDir=self.rootDir
paths = []
for root, _, files in os.walk(rootDir):
if self.fileName in files:
paths.append(root)
return paths
def read_all_dict_files(self, filePathNames=None):
"""Read the dictionary information from all files that were found in the rootDir tree."""
if filePathNames==None: filePathNames=self.filePathNames
read_dicts = []
for fp in self.filePathNames:
read_dicts.append(self.read_dict_file(fp))
return read_dicts
def read_dict_file(self, filePathName=None, valueSeparator=' '):
"""Read the dictionary information the filePathName file."""
if filePathName==None: filePathName=self.filePathNames[0]
file_dict = collections.OrderedDict()
with open(filePathName, 'r') as fp:
lineNr=0
key = ''
value = ''
for line in fp:
if line.find(self.CDF_COMMENT)==-1: # strip lines with comment
key_end = line.find(self.CDF_SEPARATOR) # find key
if key_end>=0:
key = line[0:key_end].strip() # new key
value = line[key_end+1:].strip() # new value
else:
value += valueSeparator # replace newline by valueSeparator
value += line.strip() # append value
if key!='':
file_dict[key] = value.strip() # update key in dict
lineNr += 1
return file_dict
def write_dict_file(self, dicts, filePathNames, keySeparator=None):
if keySeparator==None: keySeparator=self.CDF_SEPARATOR
for fpn, the_dict in zip(cm.listify(filePathNames), cm.listify(dicts)):
with open(fpn, 'w') as fp:
for key in the_dict:
fp.write('%s%s%s\n' % (key, keySeparator, the_dict[key]))
def append_key_to_dict_file(self, filePathName, key, values):
with open(filePathName, 'a') as fp:
if len(cm.listify(values))==1:
fp.write('%s = %s' % (key, values))
else:
fp.write('%s = \n' % key)
for v in cm.listify(values):
fp.write('%s\n' % v)
def get_filePath(self, the_dict):
return self.filePaths[self.dicts.index(the_dict)]
def get_filePathName(self, the_dict):
return self.filePathNames[self.dicts.index(the_dict)]
def get_key_values(self, key, dicts=None):
"""Get the value of a key in the dicts or None in case the key does not exist."""
if dicts==None: dicts=self.dicts
key_values = []
for fd in cm.listify(dicts):
if key in fd:
key_values.append(fd[key])
else:
key_values.append(None)
return cm.unlistify(key_values)
def get_dicts(self, key, values, dicts=None):
"""Get all dictionaries in dicts that contain a key with a value specified in values."""
if dicts==None:
dicts=self.dicts
the_dicts = []
for fd in cm.listify(dicts):
if fd not in the_dicts:
if key in fd:
if fd[key] in cm.listify(values):
the_dicts.append(fd)
return cm.unlistify(the_dicts)
if __name__ == '__main__':
tmpFileName = 'tmp_dict.txt'
tmpDirName = 'tmp_dict'
# Create some example file
with open(tmpFileName, 'w') as f:
f.write('# Example dictionary file 0\n')
f.write('src=\n')
f.write('z.vhd\n')
f.write('\n')
f.write('u.vhd\n')
f.write('tb = \'c.vhd\n')
f.write('x.vhd\'\n')
f.write('abc.vhd\n')
f.write('syn=\n')
f.write(' = \n')
f.write(' \n')
f.write('sim= d, u\n')
f.write('test= d u\n')
f.write('src_files = \n')
f.write(' x.vhd \n')
f.write(' y.vhd \n')
f.write('equal= with = in value\n')
f.write('\n')
# and created another example file in a sub directory
os.mkdir(tmpDirName)
tmpFilePathName = os.path.join(tmpDirName, tmpFileName)
with open(tmpFilePathName, 'w') as f:
f.write('# Example dictionary file 1\n')
f.write(' # Strip indent comment\n')
f.write('skip = will get skipped due to # this indent comment\n')
f.write('src = x.vhd y.vhd\n')
# Read the dictionary from the example files
cdf = CommonDictFile(rootDir='./', fileName=tmpFileName)
print '#'
print '# Test for CommonDictFile.py'
print '#'
print 'rootDir = %s' % cdf.rootDir
print 'nof_dicts = %d' % cdf.nof_dicts
print 'fileName = %s' % cdf.fileName
print 'filePaths = %s' % cdf.filePaths
print 'filePathNames = %s' % cdf.filePathNames
print ''
for i, p in enumerate(cdf.filePaths):
print os.path.join(p, cdf.fileName)
d = cdf.dicts[i]
for k,v in d.iteritems():
print k, '=', v
print ''
# Write dict file
cdf.write_dict_file(cdf.dicts[0], 'tmp_dict.out')
# Remove the example files
os.remove(tmpFileName)
os.remove(tmpFilePathName)
os.rmdir(tmpDirName)
\ No newline at end of file
###############################################################################
#
# Copyright (C) 2014
# 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/>.
#
###############################################################################
"""HDL configuration for building simulation and synthesis targets.
There should be one hdltool.cfg file somewhere in the toolRootDir and at
least one hdllib.cfg file somewhere in the libRootDir. Every HDL library
that is in the libRootDir can be found if it has a hdllib.cfg file.
Together the hdltool.cfg and hdllib.cfg files contain all the keys and
values that are sufficient to be able to build the targets for the HDL
library. The possible targets are:
- compile to created the library binaries for simulation
- synthesize to created an image that can be loaded ion the FPGA
- verify VHDL test benches in simulation
- verify Python test cases via the MM control interface in simulation
- validate Python test cases on hardware via the MM control interface
The contents of the cfg files consist of a series of key - value pairs
that are read into a dictionary as defined in common_dict_file.py. Whether
the key is a valid key depends on the application that interprets the
dictionary.
The methods can have the library dictionary or the library name as
argument. The default arguments are the self.libs.dicts and the
corresponding self.lib_names. The argument can be a list or a single value.
Similar the return can be a list or a single value, because a list of one
element is unlistified.
"""
import common as cm
import common_dict_file
import sys
import os
import os.path
class HdlConfig:
def __init__(self, libRootDir, toolRootDir='', libFileName='hdllib.cfg', toolFileName='hdltool.cfg'):
"""Get tool dictionary info from toolRootDir and all HDL library dictionary info from libRootDir."""
# HDL tool config file
self.tool = common_dict_file.CommonDictFile(toolRootDir, toolFileName) # tool dict file
if self.tool.nof_dicts==0: sys.exit('Error : No HDL tool config file found')
if self.tool.nof_dicts >1: sys.exit('Error : Multiple HDL tool config files found')
# HDL library config files
self.libs = common_dict_file.CommonDictFile(libRootDir, libFileName) # library dict files
if self.libs.nof_dicts==0: sys.exit('Error : No HDL library config file found')
self.lib_names = self.libs.get_key_values('hdl_lib_name')
self.MODELSIM_MPF_NAME = 'hdllib.mpf'
def derive_all_use_libs(self, lib_name):
"""Derive a list of all HDL libraries that the specified HDL lib_name library depends on."""
if lib_name in self.lib_names:
all_use_libs = [lib_name]
lib_dict = self.libs.dicts[self.lib_names.index(lib_name)]
if 'hdl_lib_uses' in lib_dict:
use_libs = lib_dict['hdl_lib_uses'].split()
for use_lib in use_libs:
all_use_libs.append(use_lib)
all_use_libs += self.derive_all_use_libs(use_lib)
return cm.unique(all_use_libs)
else:
sys.exit('Error : Unknown HDL library name')
def derive_lib_order(self, lib_names=None):
"""Derive the dependency order for all HDL libraries in the specified list of lib_names."""
if lib_names==None: lib_names=self.lib_names
lib_dicts = self.libs.get_dicts('hdl_lib_name', lib_names)
lib_order = []
for lib_dict in lib_dicts:
lib_name = lib_dict['hdl_lib_name']
if not lib_name in lib_order:
lib_order.append(lib_name) # append this lib
if 'hdl_lib_uses' in lib_dict:
use_libs = lib_dict['hdl_lib_uses'].split()
for use_lib in use_libs:
if not use_lib in lib_order:
lib_order.insert(lib_order.index(lib_name), use_lib) # insert used lib just before this lib
else:
if lib_order.index(use_lib) > lib_order.index(lib_name):
lib_order.remove(use_lib)
lib_order.insert(lib_order.index(lib_name), use_lib) # move used lib to just before this lib
return lib_order
def get_lib_build_sim_dirs(self, lib_dicts=None):
"""Get the simulation build directory for all HDL libraries in the specified list of lib_dicts."""
if lib_dicts==None: lib_dicts=self.libs.dicts
sim_dirs = []
for lib_dict in cm.listify(lib_dicts):
lib_path = self.libs.get_filePath(lib_dict)
build_dir = self.libs.get_key_values('build_dir', lib_dict)
sim_tool = self.tool.get_key_values('sim_tool')
sim_dirs.append(os.path.join(lib_path, build_dir, sim_tool))
return cm.unlistify(sim_dirs)
if __name__ == '__main__':
# Read the dictionary info from all HDL tool and library configuration files in the current directory and the sub directories
libRootDir = 'RADIOHDL'
#libRootDir = 'UNB'
hdl = HdlConfig(libRootDir=os.environ[libRootDir], toolRootDir=os.environ['UNB'], libFileName='hdllib.cfg', toolFileName='hdltool.cfg')
print '#'
print '# HdlConfig:'
print '#'
for i, p in enumerate(hdl.libs.filePathNames):
print i, p
d = hdl.libs.dicts[i]
for k,v in d.iteritems():
print k, '=', v
print ''
print ''
print 'tool = ', hdl.tool.filePathNames[0]
print ''
print 'lib paths'
for p in hdl.libs.filePaths:
print ' ', p
print ''
print 'lib paths names'
for p in hdl.libs.filePathNames:
print ' ', p
print ''
print 'lib_names = ', hdl.lib_names
print 'derive_lib_order : ', hdl.derive_lib_order()
print ''
print 'get_lib_build_sim_dirs:'
for sim_dir in hdl.get_lib_build_sim_dirs():
print ' ', sim_dir
print ''
if libRootDir=='RADIOHDL':
print 'derive_all_use_libs = ', hdl.derive_lib_order(hdl.derive_all_use_libs('technology_memory'))
if libRootDir=='UNB':
print 'derive_all_use_libs = ', hdl.derive_lib_order(hdl.derive_all_use_libs('dp'))
print 'derive_all_use_libs = ', hdl.derive_lib_order(hdl.derive_all_use_libs('uth'))
print 'derive_all_use_libs = ', hdl.derive_lib_order(hdl.derive_all_use_libs('unb_common'))
print 'derive_all_use_libs = ', hdl.derive_lib_order(hdl.derive_all_use_libs('unb_minimal'))
###############################################################################
#
# Copyright (C) 2014
# 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/>.
#
###############################################################################
"""HDL configuration for building Modelsim simulation targets.
"""
import common as cm
import hdl_config
import sys
import os
import os.path
class ModelsimConfig(hdl_config.HdlConfig):
def __init__(self, libRootDir, toolRootDir='', libFileName='hdllib.cfg', toolFileName='hdltool.cfg'):
"""Get Modelsim tool info from toolRootDir and all HDL library info from libRootDir."""
hdl_config.HdlConfig.__init__(self, libRootDir, toolRootDir, libFileName, toolFileName)
# Modelsim
self.MODELSIM_MPF_NAME = 'hdllib.mpf'
def read_compile_order_from_mpf(self, mpfPathName):
"""Utility to read the compile order of the project files from an existing <mpfPathName>.mpf and save it into hdl_order.out."""
# read <mpfPathName>.mpf to find all project files
project_file_indices = []
project_file_names = []
with open(mpfPathName, 'r') as fp:
for line in fp:
words = line.split()
if len(words)>0:
key = words[0]
if key.find('Project_File_')>=0 and key.find('Project_File_P_')==-1:
project_file_indices.append(key[len('Project_File_'):])
project_file_names.append(words[2])
# read <mpfPathName>.mpf again to find compile order for the project files
compile_order = range(len(project_file_names))
with open(mpfPathName, 'r') as fp:
for line in fp:
words = line.split()
if len(words)>0:
key = words[0]
if key.find('Project_File_P_')>=0:
project_file_index = project_file_indices.index(key[len('Project_File_P_'):])
project_file_name = project_file_names[project_file_index]
k = words.index('compile_order')
k = int(words[k+1])
compile_order[k]=project_file_name
return compile_order
def create_modelsim_project_file(self, lib_names=None):
"""Create the Modelsim project file for all HDL libraries in the specified list of lib_names."""
if lib_names==None: lib_names=self.lib_names
lib_dicts = self.libs.get_dicts('hdl_lib_name', lib_names)
for lib_dict in cm.listify(lib_dicts):
# Open mpf
mpf_name = self.MODELSIM_MPF_NAME
mpf_path = self.get_lib_build_sim_dirs(lib_dict)
cm.mkdir(mpf_path)
mpfPathName = os.path.join(mpf_path, mpf_name)
with open(mpfPathName, 'w') as fp:
# Write [Library] section for afileNamell used libraries
fp.write('[Library]\n')
lib_name = lib_dict['hdl_lib_name']
use_lib_names = self.derive_all_use_libs(lib_name)
use_lib_dicts = self.libs.get_dicts('hdl_lib_name', use_lib_names)
use_lib_build_sim_dirs = self.get_lib_build_sim_dirs(use_lib_dicts)
use_lib_clause_names = self.libs.get_key_values('hdl_library_clause_name', use_lib_dicts)
for lib_clause, lib_dir in zip(cm.listify(use_lib_clause_names), cm.listify(use_lib_build_sim_dirs)):
lib_work = os.path.join(lib_dir, 'work')
fp.write('%s = %s\n' % (lib_clause, lib_work))
fp.write('work = work\n')
model_tech_dir = os.path.expandvars(self.tool.get_key_values('model_tech_dir'))
fp.write('others = %s\n' % os.path.join(model_tech_dir, 'modelsim.ini'))
# Write [Project] section for all used libraries
fp.write('[Project]\n')
fp.write('Project_Version = 6\n') # must be >= 6 to fit all
fp.write('Project_DefaultLib = work\n')
fp.write('Project_SortMethod = unused\n')
# - hdl files
synth_files = lib_dict['synth_files'].split()
test_bench_files = lib_dict['test_bench_files'].split()
sim_files = synth_files + test_bench_files
fp.write('Project_Files_Count = %d\n' % len(sim_files))
lib_path = self.libs.get_filePath(lib_dict)
for i, fn in enumerate(sim_files):
filePathName = os.path.join(lib_path, fn)
fp.write('Project_File_%d = %s\n' % (i, filePathName))
project_file_p_defaults = 'vhdl_novitalcheck 0 file_type vhdl group_id 0 cover_nofec 0 vhdl_nodebug 0 vhdl_1164 1 vhdl_noload 0 vhdl_synth 0 vhdl_enable0In 0 vlog_1995compat 0 last_compile 0 vhdl_disableopt 0 cover_excludedefault 0 vhdl_vital 0 vhdl_warn1 1 vhdl_warn2 1 vhdl_explicit 0 vhdl_showsource 0 cover_covercells 0 vhdl_0InOptions {} vhdl_warn3 1 vlog_vopt {} cover_optlevel 3 voptflow 1 vhdl_options {} vhdl_warn4 1 toggle - ood 0 vhdl_warn5 1 cover_noshort 0 compile_to work cover_nosub 0 dont_compile 0 vhdl_use93 2002 cover_stmt 1'
project_folders = []
if len(synth_files)>0:
project_folders.append('synth')
for i, fn in enumerate(synth_files):
filePathName = os.path.join(lib_path, fn)
fp.write('Project_File_P_%d = folder %s compile_order %d %s\n' % (i, project_folders[-1], i, project_file_p_defaults))
if len(test_bench_files)>0:
project_folders.append('test_bench')
for j, fn in enumerate(test_bench_files):
filePathName = os.path.join(lib_path, fn)
fp.write('Project_File_P_%d = folder %s compile_order %d %s\n' % (i+j+1, project_folders[-1], i+j+1, project_file_p_defaults))
fp.write('Project_Folder_Count = %d\n' % len(project_folders))
for i, fd in enumerate(project_folders):
fp.write('Project_Folder_%d = %s\n' % (i, fd))
fp.write('Project_Folder_P_%d = folder {Top Level}\n' % i)
# - simulation configurations
fp.write('Project_Sim_Count = %d\n' % len(test_bench_files))
project_sim_p_defaults = 'Generics {} timing default -std_output {} -nopsl 0 +notimingchecks 0 -L {} selected_du {} -hazards 0 -sdf {} ok 1 -0in 0 -nosva 0 +pulse_r {} -absentisempty 0 OtherArgs {} -multisource_delay {} +pulse_e {} vopt_env 1 -coverage 0 -sdfnoerror 0 +plusarg {} -vital2.2b 0 -t default -memprof 0 is_vopt_flow 0 -noglitch 0 -nofileshare 0 -wlf {} -assertdebug 0 +no_pulse_msg 0 -0in_options {} -assertfile {} -sdfnowarn 0 -Lf {} -std_input {}'
project_sim_p_optimization = 'is_vopt_opt_used 2' # = when 'Enable optimization' is not selected in GUI
project_sim_p_optimization = 'is_vopt_opt_used 1 voptargs {OtherVoptArgs {} timing default VoptOutFile {} -vopt_keep_delta 0 -0in 0 -fvopt {} VoptOptimize:method 1 -vopt_00 2 +vopt_notimingcheck 0 -Lfvopt {} VoptOptimize:list .vopt_opt.nb.canvas.notebook.cs.page1.cs.g.spec.listbox -Lvopt {} +vopt_acc {} VoptOptimize .vopt_opt.nb.canvas.notebook.cs.page1.cs -vopt_hazards 0 VoptOptimize:Buttons .vopt_opt.nb.canvas.notebook.cs.page1.cs.g.spec.bf 0InOptionsWgt .vopt_opt.nb.canvas.notebook.cs.page3.cs.zf.ze -0in_options {}}' # = when 'Enable optimization' is selected in GUI for full visibility
for i, fn in enumerate(test_bench_files):
fName = os.path.basename(fn)
tbName = os.path.splitext(fName)[0]
fp.write('Project_Sim_%d = %s\n' % (i, tbName))
for i, fn in enumerate(test_bench_files):
fName = os.path.basename(fn)
tbName = os.path.splitext(fName)[0]
fp.write('Project_Sim_P_%d = folder {Top Level} additional_dus work.%s %s %s\n' % (i, tbName, project_sim_p_defaults, project_sim_p_optimization))
# Write [vsim] section
fp.write('[vsim]\n')
fp.write('RunLength = 0 ps\n')
fp.write('resolution = 1ps\n')
fp.write('IterationLimit = 100\n')
fp.write('DefaultRadix = decimal\n')
def create_modelsim_project_files_file(self, fileNamePath='modelsim_project_files.txt', lib_names=None):
"""Create file with list of the Modelsim project files for all HDL libraries in the specified list of lib_names."""
if lib_names==None: lib_names=self.lib_names
with open(fileNamePath, 'w') as fp:
lib_dicts = self.libs.get_dicts('hdl_lib_name', lib_names)
mpf_paths = self.get_lib_build_sim_dirs(lib_dicts)
for lib, path in zip(cm.listify(lib_names),cm.listify(mpf_paths)):
fp.write('%s = %s\n' % (lib, path))
if __name__ == '__main__':
# Read the dictionary info from all HDL tool and library configuration files in the current directory and the sub directories
libRootDir = 'RADIOHDL'
#libRootDir = 'UNB'
msim = ModelsimConfig(libRootDir=os.environ[libRootDir], toolRootDir=os.environ['UNB'], libFileName='hdllib.cfg', toolFileName='hdltool.cfg')
print '#'
print '# ModelsimConfig:'
print '#'
print 'derive_lib_order = ', msim.derive_lib_order()
print ''
print 'Create modelsim projects list file.'
msim.create_modelsim_project_files_file()
print ''
print 'Create modelsim project files for all HDL libraries in $%s.' % libRootDir
msim.create_modelsim_project_file()
# Use save_compile_order_in_mpf = True to avoid having to manually edit the compile order in the hdllib.cfg, because
# the synth_files need to be in hierarchical order. The test_bench_files are typically independent so these may be
# put in alphabetical order. The hdllib.cfg still does need some manual editing to set the proper key and paths.
lib_name = 'mm'
save_compile_order_in_mpf = False
if libRootDir=='UNB' and save_compile_order_in_mpf:
# Read compile order from existing <lib_name>.mpf
mpfPathName = os.path.expandvars('$UNB/Firmware/designs/%s/build/synth/quartus/sopc_%s_sim/%s.mpf' % (lib_name, lib_name, lib_name))
mpfPathName = os.path.expandvars('$UNB/Firmware/modules/Lofar/%s/build/sim/modelsim/%s.mpf' % (lib_name, lib_name))
mpfPathName = os.path.expandvars('$UNB/Firmware/modules/%s/build/sim/modelsim/%s.mpf' % (lib_name, lib_name))
compile_order = msim.read_compile_order_from_mpf(mpfPathName)
# Append the compile_order list to the lib_name dictionary hdllib.cfg file
lib_dict = msim.libs.get_dicts('hdl_lib_name', lib_name)
lib_path = msim.libs.get_filePath(lib_dict)
filePathName = os.path.join(lib_path, 'hdllib.cfg')
print ''
print 'Save modelsim compile order for', lib_name, 'in HDL library config file', filePathName
msim.libs.append_key_to_dict_file(filePathName, 'files', compile_order)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment