litex/sim/hdl_common/hdl_common.tcl

407 lines
11 KiB
Tcl

##############################################################################
# Define some global variables
##############################################################################
if {![info exists HDL_LIBRARIES]} {
set HDL_LIBRARIES ()
}
set HDL_TARGET "default_target"
set HDL_PATH [pwd]
set HDL_WORK "work"
# Uncomment the following line to generate a log file for debug
#set HDL_LOG [open "hdl_common.log" "w"]
##############################################################################
# Some utilities
##############################################################################
# Extract first element from a list (for argument processing)
proc extract_first {list_name {option ""}} {
upvar $list_name mylist
if {[string length $option]>0 && [llength $mylist]==0} {
error "Missing argument for option $option"
}
set first [lindex $mylist 0]
if {[string length $option]>0 && [string match "-*" $first]} {
error "Missing argument for option $option"
}
set mylist [lrange $mylist 1 end]
return $first
}
# Clean-up file path
proc clean_path {f} {
# Add trailing /
set f "$f/"
# Remove double / (excepted leading)
while {[regsub {(.)//} $f "\1/" f]} {}
# Remove .
while {[regsub {/\./} $f "/" f]} {}
# Remove ..
while {[regsub {/[^/.]+/\.\./} $f "/" f]} {}
# Remove trailing /
regsub {/$} $f "" f
return $f
}
# Translate relative paths to absolute paths
proc get_full_path {files} {
global HDL_PATH
set r {}
# For DOS paths, replace \ by /
regsub -all {\\} $files "/" files
foreach f $files {
hdl_debug " $f"
# Append file path
if {[string match "/*" $f] || [string match "?:/*" $f]} {
# Path is an absolute path
hdl_warning "Using absolute path $f"
} else {
# Path is a relative path
set f [clean_path $HDL_PATH/$f]
}
hdl_debug " => $f"
lappend r $f
# Check access to file
if {![file readable $f]} {
error "Cannot read file $f"
}
}
return $r
}
# Check if value match any pattern in the list
proc match_list {mlist value} {
set match 0
foreach m $mlist {
if [string match $m $value] {
set match 1
}
}
return $match
}
proc get_lib_path {} {
if [file isdirectory "/cad/trash"] {
set libs "/cad/trash[pwd]/libs"
} elseif [file isdirectory "e:/trash"] {
set libs [pwd]
# Replace D:/ by D/ for local drive
regsub ":" $libs "" libs
# Remove leading // for network drive
regsub "//" $libs "" libs
set libs "e:/trash/$libs"
} else {
# No "trash" directory on this machine => work locally
set libs "./libs"
}
file mkdir $libs
return $libs
}
##############################################################################
# Procedures to display messages
##############################################################################
# Write message to log file if logging enabled
proc hdl_log { msg } {
global HDL_LOG
if [info exists HDL_LOG] {
puts $HDL_LOG $msg
flush $HDL_LOG
}
return
}
# Debug messages are sent only to log file
proc hdl_debug { msg } {
hdl_log "hdl_common - Debug: $msg"
return
}
# According to the tool, "puts" or "echo" should be used
# HDL_PUTS variable is used for this purpose
# All message are also sent to log file
proc hdl_puts { msg } {
global HDL_PUTS
$HDL_PUTS $msg
hdl_log $msg
return
}
proc hdl_note { msg } {
hdl_puts "hdl_common - Note: $msg"
return
}
proc hdl_warning { msg } {
hdl_puts "hdl_common - Warning: $msg"
return
}
proc hdl_message { args } {
global HDL_MSG_FORMAT
hdl_puts [format $HDL_MSG_FORMAT [join $args " "]]
return
}
##############################################################################
# Procedures for compilation scripts
##############################################################################
# Compile source files
proc hdl_compile { args } {
global HDL_TOOLTYPE HDL_TOOLNAME HDL_TARGET HDL_LIBRARIES HDL_WORK
# Default values
set format ""
set version "93"
set files {}
set incdirs {}
set only_for {}
set not_for {}
set toolname {}
set tooltype "*"
set library $HDL_WORK
set define {}
set behavioral 0
# Decode arguments
while {[llength $args]} {
set arg [extract_first args]
switch -glob -- $arg {
"-f" {
set format [extract_first args "-f"]
}
"-v" {
set version [extract_first args "-version"]
}
"-only_for" {
set only_for [concat $only_for [extract_first args "-only_for"]]
}
"-not_for" {
set not_for [concat $not_for [extract_first args "-not_for"]]
}
"-sim" {
set tooltype "SIMULATION"
set behavioral 1
}
"-syn" {
set tooltype "SYNTHESIS"
set behavioral 0
}
"-tool" {
set toolname [concat $toolname [extract_first args "-tool"]]
}
"-incdir" {
set incdirs [concat $incdirs [extract_first args "-incdir"]]
}
"-lib" {
set library [extract_first args "-lib"]
if {[string match "work" $library]} {
hdl_warning "Specifying '-lib work' is useless"
}
}
"-define" {
set define [concat $define [extract_first args "-define"]]
}
"-*" {
error "Unsupported argument $arg"
}
default {
set files [concat $files $arg]
}
}
}
# Check arguments
if {![llength $files]} {
error "No file to compile"
}
# If no "-only_for" option given, use file for any target
if {[llength $only_for]==0} {
set only_for {*}
}
# If no "-tool" option given, use file for any tool
if {[llength $toolname]==0} {
set toolname {*}
}
# Check if compilation is required
if {[match_list $only_for $HDL_TARGET] && ![match_list $not_for $HDL_TARGET] &&
[string match $tooltype $HDL_TOOLTYPE] && [match_list $toolname $HDL_TOOLNAME]} {
# Create library if needed
if {[lsearch -exact $HDL_LIBRARIES $library]<0} {
hdl_note "Creating library $library"
lappend HDL_LIBRARIES $library
hdl_tool_library $library
}
# Compile files
foreach f $files {
# Warning if dummy file is used
if {[string match "*dummy*" [string tolower $f]]} {
hdl_note "Using [file tail $f]"
}
# Determine format
if {![llength $format]} {
if {[string match "*.vh?*" $f]} {
set format "vhdl"
} elseif {[string match "*.v*" $f]} {
set format "verilog"
set version "sv"
} elseif {[string match "*.sv" $f]} {
set format "verilog"
set version "sv"
}
}
}
hdl_tool_compile $format $version [get_full_path $incdirs] $library $define [get_full_path $files] $behavioral
}
return
}
# Change directory
proc hdl_cd { path } {
global HDL_PATH
set HDL_PATH [get_full_path $path]
hdl_debug "New path is $HDL_PATH"
return
}
# Execute script
proc hdl_source { args } {
global HDL_PATH HDL_TARGET HDL_WORK HDL_TOOLTYPE HDL_TOOLNAME
# Save original values
set save_path $HDL_PATH
set save_target $HDL_TARGET
set save_work $HDL_WORK
# Default value
set files {}
set toolname {}
set tooltype "*"
set only_for {}
set not_for {}
# Process options
while {[llength $args]} {
set arg [extract_first args]
switch -glob -- $arg {
"-lib" {
set HDL_WORK [extract_first args "-lib"]
if {[string match "work" $HDL_WORK]} {
hdl_warning "Specifying '-lib work' is useless"
}
}
"-target" {
set HDL_TARGET [extract_first args "-target"]
}
"-sim" {
set tooltype "SIMULATION"
set behavioral 1
}
"-syn" {
set tooltype "SYNTHESIS"
set behavioral 0
}
"-tool" {
set toolname [concat $toolname [extract_first args "-tool"]]
}
"-only_for" {
set only_for [concat $only_for [extract_first args "-only_for"]]
}
"-not_for" {
set not_for [concat $not_for [extract_first args "-not_for"]]
}
"-*" {
error "Unsupported argument $arg"
}
default {
set files [concat $files $arg]
}
}
}
# Check arguments
if {![llength $files]} {
error "No script specified"
}
# If no "-only_for" option given, use file for any target
if {[llength $only_for]==0} {
set only_for {*}
}
# If no "-tool" option given, use file for any tool
if {[llength $toolname]==0} {
set toolname {*}
}
# Check if compilation is required
if {[match_list $only_for $HDL_TARGET] && ![match_list $not_for $HDL_TARGET] &&
[string match $tooltype $HDL_TOOLTYPE] && [match_list $toolname $HDL_TOOLNAME]} {
# Source scripts
foreach script $files {
# Change directory to script location
hdl_cd [file dirname $script]
# Execute script
set script [get_full_path [file tail $script]]
hdl_note "Source $script ($HDL_TARGET)"
uplevel source $script
# Restore original path
set HDL_PATH $save_path
hdl_debug "Back to directory $HDL_PATH"
}
}
# Restore original values
set HDL_TARGET $save_target
set HDL_WORK $save_work
#puts "Back to $HDL_PATH"
return
}
# Specify target
proc hdl_set_target { args } {
global HDL_TARGET env
# Default values
set use_env 0
set default ""
set target ""
# Decode arguments
while {[llength $args]} {
set arg [extract_first args]
switch -glob -- $arg {
"-env" {
set use_env 1
}
"-default" {
set default [extract_first args "-default"]
}
"-*" {
error "Unsupported argument $arg"
}
default {
set target $arg
}
}
}
# Check arguments
if {[llength $target]} {
set HDL_TARGET $target
hdl_note "Using target $HDL_TARGET"
} elseif {$use_env} {
if {[info exists env(HDL_TARGET)]} {
set HDL_TARGET $env(HDL_TARGET)
hdl_note "Using target $HDL_TARGET (from environment variable HDL_TARGET)"
} elseif {[llength $default]} {
set HDL_TARGET $default
hdl_note "Using default target $HDL_TARGET (environment variable HDL_TARGET not defined)"
} else {
error "No environment variable defined and no default target"
}
} else {
error "Missing argument"
}
return
}
##############################################################################
# clock is an invalid command name for Synplify at least until version 2010.09
# hdl_debug [clock format [clock seconds]]