| #------------------------------------------------------------------- |
| # 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 |
| } |
| } |
| } |
| } |
| } |
| |
| #---------------------------------------------------------------- |