blob: 489c5f649e55ed8dcef6a11974eaa18fc99fafd8 [file] [log] [blame]
#-------------------------------------------------------------------
# General-purpose routines for the PDK script in all technologies
#-------------------------------------------------------------------
#
#----------------------------------------
# Number Conversion Functions
#----------------------------------------
#---------------------
# Microns to Lambda
#---------------------
proc magic::u2l {micron} {
set techlambda [magic::tech lambda]
set tech1 [lindex $techlambda 1]
set tech0 [lindex $techlambda 0]
set tscale [expr {$tech1 / $tech0}]
set lambdaout [expr {((round([magic::cif scale output] * 10000)) / 10000.0)}]
return [expr $micron / ($lambdaout*$tscale) ]
}
#---------------------
# Lambda to Microns
#---------------------
proc magic::l2u {lambda} {
set techlambda [magic::tech lambda]
set tech1 [lindex $techlambda 1] ; set tech0 [lindex $techlambda 0]
set tscale [expr {$tech1 / $tech0}]
set lambdaout [expr {((round([magic::cif scale output] * 10000)) / 10000.0)}]
return [expr $lambda * $lambdaout * $tscale ]
}
#---------------------
# Internal to Microns
#---------------------
proc magic::i2u { value } {
return [expr {((round([magic::cif scale output] * 10000)) / 10000.0) * $value}]
}
#---------------------
# Microns to Internal
#---------------------
proc magic::u2i {value} {
return [expr {$value / ((round([magic::cif scale output] * 10000)) / 10000.0)}]
}
#---------------------
# Float to Spice
#---------------------
proc magic::float2spice {value} {
if {$value >= 1.0e+6} {
set exponent 1e+6
set unit "meg"
} elseif {$value >= 1.0e+3} {
set exponent 1e+3
set unit "k"
} elseif { $value >= 1} {
set exponent 1
set unit ""
} elseif {$value >= 1.0e-3} {
set exponent 1e-3
set unit "m"
} elseif {$value >= 1.0e-6} {
set exponent 1e-6
set unit "u"
} elseif {$value >= 1.0e-9} {
set exponent 1e-9
set unit "n"
} elseif {$value >= 1.0e-12} {
set exponent 1e-12
set unit "p"
} elseif {$value >= 1.0e-15} {
set exponent 1e-15
set unit "f"
} else {
set exponent 1e-18
set unit "a"
}
set val [expr $value / $exponent]
set val [expr int($val * 1000) / 1000.0]
if {$val == 0} {set unit ""}
return $val$unit
}
#---------------------
# Spice to Float
#---------------------
proc magic::spice2float {value {faultval 0.0}} {
# Remove trailing units, at least for some common combinations
set value [string tolower $value]
set value [string map {um u nm n uF n nF n pF p aF a} $value]
set value [string map {meg "* 1.0e6" k "* 1.0e3" m "* 1.0e-3" u "* 1.0e-6" \
n "* 1.0 e-9" p "* 1.0e-12" f "* 1.0e-15" a "* 1.0e-15"} $value]
if {[catch {set rval [expr $value]}]} {
puts stderr "Value is not numeric!"
set rval $faultval
}
return $rval
}
#---------------------
# Numeric Precision
#---------------------
proc magic::3digitpastdecimal {value} {
set new [expr int([expr $value * 1000 + 0.5 ]) / 1000.0]
return $new
}
#-------------------------------------------------------------------
# File Access Functions
#-------------------------------------------------------------------
#-------------------------------------------------------------------
# Ensures that a cell name does not already exist, either in
# memory or on disk. Modifies the name until it does.
#-------------------------------------------------------------------
proc magic:cellnameunique {cellname} {
set i 0
set newname $cellname
while {[cellname list exists $newname] != 0 || [magic::searchcellondisk $newname] != 0} {
incr i
set newname ${cellname}_$i
}
return $newname
}
#-------------------------------------------------------------------
# Looks to see if a cell exists on disk
#-------------------------------------------------------------------
proc magic::searchcellondisk {name} {
set rlist {}
foreach dir [path search] {
set ftry [file join $dir ${name}.mag]
if [file exists $ftry] {
return 1
}
}
return 0
}
#-------------------------------------------------------------------
# Checks to see if a cell already exists on disk or in memory
#-------------------------------------------------------------------
proc magic::iscellnameunique {cellname} {
if {[cellname list exists $cellname] == 0 && [magic::searchcellondisk $cellname] == 0} {
return 1
} else {
return 0
}
}
#--------------------------------------------------------------
# Procedure that checks the user's "ip" subdirectory on startup
# and adds each one's maglef subdirectory to the path.
#--------------------------------------------------------------
proc magic::query_mylib_ip {} {
global TECHPATH
global env
if [catch {set home $env(SUDO_USER)}] {
set home $env(USER)
}
set homedir /home/${home}
set ip_dirs [glob -directory ${homedir}/design/ip *]
set proj_dir [pwd]
set config_dir .config
set info_dir ${proj_dir}/${config_dir}
if {![file exists ${info_dir}]} {
set config_dir .ef-config
set info_dir ${proj_dir}/${config_dir}
}
set info_file ${info_dir}/info
set depends [dict create]
if {![catch {open $info_file r} ifd]} {
set depsec false
while {[gets $ifd line] >= 0} {
if {[string first dependencies: $line] >= 0} {
set depsec true
}
if {$depsec} {
if {[string first version: $line] >= 0} {
if {$ipname != ""} {
set ipvers [string trim [lindex [split $line] 1] ']
dict set depends $ipname $ipvers
set ipname ""
} else {
puts stderr "Badly formatted info file in ${config_dir}!"
}
} else {
set ipname [string trim $line :]
}
}
}
}
foreach dir $ip_dirs {
# Version handling: version dependencies are found in
# ${config_dir}/info. For all other IP, use the most recent
# version number.
set ipname [lindex [file split $dir] end]
if {![catch {set version [dict get $depends $ipname]}]} {
if {[file isdirectory ${dir}/${version}/maglef]} {
addpath ${dir}/${version}/maglef
continue
} else {
puts stderr "ERROR: Dependency ${ipname} version ${version} does not exist"
}
}
# Secondary directory is the version number. Use the highest
# version available.
set sub_dirs {}
catch {set sub_dirs [glob -directory $dir *]}
set maxver 0.0
foreach subdir $sub_dirs {
set vidx [string last / $subdir]
incr vidx
set version [string range $subdir $vidx end]
if {$version > $maxver} {
set maxver $version
}
}
if {[file exists ${dir}/${maxver}/maglef]} {
# Compatibility rule: foundry name must match.
# Get foundry name from ${config_dir}/techdir symbolic link reference
if {[file exists ${dir}/${maxver}/${config_dir}/techdir]} {
set technodedir [file link ${dir}/${maxver}/${config_dir}/techdir]
set nidx [string last / $technodedir]
set techdir [string range $technodedir 0 $nidx-1]
if {$techdir == $TECHPATH} {
addpath ${dir}/${maxver}/maglef
}
}
}
}
}
#--------------------------------------------------------------
# Procedure that checks the user's design directory on startup
# and adds each one's mag subdirectory to the path.
#--------------------------------------------------------------
proc magic::query_my_projects {} {
global TECHPATH
global env
if [catch {set home $env(SUDO_USER)}] {
set home $env(USER)
}
set homedir /home/${home}
set proj_dirs [glob -directory ${homedir}/design *]
foreach dir $proj_dirs {
# Compatibility rule: foundry name must match.
# Get foundry name from ${config_dir}/techdir symbolic link reference
if {[file exists ${dir}/mag]} {
set config_dir .config
set tech_dir ${dir}/${config_dir}
if {![file exists ${tech_dir}]} {
set config_dir .ef-config
set tech_dir ${dir}/${config_dir}
}
if {[file exists ${dir}/${config_dir}/techdir]} {
set technodedir [file link ${dir}/${config_dir}/techdir]
set nidx [string last / $technodedir]
set techdir [string range $technodedir 0 $nidx-1]
if {$techdir == $TECHPATH} {
addpath ${dir}/mag
}
}
}
}
}
#----------------------------------------------------------------