Tim Edwards | 55f4d0e | 2020-07-05 15:41:02 -0400 | [diff] [blame] | 1 | #------------------------------------------------------------------- |
| 2 | # General-purpose routines for the PDK script in all technologies |
| 3 | #------------------------------------------------------------------- |
| 4 | # |
| 5 | #---------------------------------------- |
| 6 | # Number Conversion Functions |
| 7 | #---------------------------------------- |
| 8 | |
| 9 | #--------------------- |
| 10 | # Microns to Lambda |
| 11 | #--------------------- |
| 12 | proc magic::u2l {micron} { |
| 13 | set techlambda [magic::tech lambda] |
| 14 | set tech1 [lindex $techlambda 1] |
| 15 | set tech0 [lindex $techlambda 0] |
| 16 | set tscale [expr {$tech1 / $tech0}] |
Tim Edwards | 0ee0f18 | 2020-11-21 16:15:07 -0500 | [diff] [blame] | 17 | set lambdaout [expr {((round([magic::cif scale output] * 10000)) / 10000.0)}] |
Tim Edwards | 55f4d0e | 2020-07-05 15:41:02 -0400 | [diff] [blame] | 18 | return [expr $micron / ($lambdaout*$tscale) ] |
| 19 | } |
| 20 | |
| 21 | #--------------------- |
| 22 | # Lambda to Microns |
| 23 | #--------------------- |
| 24 | proc magic::l2u {lambda} { |
| 25 | set techlambda [magic::tech lambda] |
| 26 | set tech1 [lindex $techlambda 1] ; set tech0 [lindex $techlambda 0] |
| 27 | set tscale [expr {$tech1 / $tech0}] |
Tim Edwards | 0ee0f18 | 2020-11-21 16:15:07 -0500 | [diff] [blame] | 28 | set lambdaout [expr {((round([magic::cif scale output] * 10000)) / 10000.0)}] |
Tim Edwards | 55f4d0e | 2020-07-05 15:41:02 -0400 | [diff] [blame] | 29 | return [expr $lambda * $lambdaout * $tscale ] |
| 30 | } |
| 31 | |
| 32 | #--------------------- |
| 33 | # Internal to Microns |
| 34 | #--------------------- |
| 35 | proc magic::i2u { value } { |
Tim Edwards | 0ee0f18 | 2020-11-21 16:15:07 -0500 | [diff] [blame] | 36 | return [expr {((round([magic::cif scale output] * 10000)) / 10000.0) * $value}] |
Tim Edwards | 55f4d0e | 2020-07-05 15:41:02 -0400 | [diff] [blame] | 37 | } |
| 38 | |
| 39 | #--------------------- |
| 40 | # Microns to Internal |
| 41 | #--------------------- |
| 42 | proc magic::u2i {value} { |
Tim Edwards | 0ee0f18 | 2020-11-21 16:15:07 -0500 | [diff] [blame] | 43 | return [expr {$value / ((round([magic::cif scale output] * 10000)) / 10000.0)}] |
Tim Edwards | 55f4d0e | 2020-07-05 15:41:02 -0400 | [diff] [blame] | 44 | } |
| 45 | |
| 46 | #--------------------- |
| 47 | # Float to Spice |
| 48 | #--------------------- |
| 49 | proc magic::float2spice {value} { |
| 50 | if {$value >= 1.0e+6} { |
| 51 | set exponent 1e+6 |
| 52 | set unit "meg" |
| 53 | } elseif {$value >= 1.0e+3} { |
| 54 | set exponent 1e+3 |
| 55 | set unit "k" |
| 56 | } elseif { $value >= 1} { |
| 57 | set exponent 1 |
| 58 | set unit "" |
| 59 | } elseif {$value >= 1.0e-3} { |
| 60 | set exponent 1e-3 |
| 61 | set unit "m" |
| 62 | } elseif {$value >= 1.0e-6} { |
| 63 | set exponent 1e-6 |
| 64 | set unit "u" |
| 65 | } elseif {$value >= 1.0e-9} { |
| 66 | set exponent 1e-9 |
| 67 | set unit "n" |
| 68 | } elseif {$value >= 1.0e-12} { |
| 69 | set exponent 1e-12 |
| 70 | set unit "p" |
| 71 | } elseif {$value >= 1.0e-15} { |
| 72 | set exponent 1e-15 |
| 73 | set unit "f" |
| 74 | } else { |
| 75 | set exponent 1e-18 |
| 76 | set unit "a" |
| 77 | } |
| 78 | set val [expr $value / $exponent] |
| 79 | set val [expr int($val * 1000) / 1000.0] |
| 80 | if {$val == 0} {set unit ""} |
| 81 | return $val$unit |
| 82 | } |
| 83 | |
| 84 | #--------------------- |
| 85 | # Spice to Float |
| 86 | #--------------------- |
| 87 | proc magic::spice2float {value {faultval 0.0}} { |
| 88 | # Remove trailing units, at least for some common combinations |
| 89 | set value [string tolower $value] |
| 90 | set value [string map {um u nm n uF n nF n pF p aF a} $value] |
| 91 | set value [string map {meg "* 1.0e6" k "* 1.0e3" m "* 1.0e-3" u "* 1.0e-6" \ |
| 92 | n "* 1.0 e-9" p "* 1.0e-12" f "* 1.0e-15" a "* 1.0e-15"} $value] |
| 93 | if {[catch {set rval [expr $value]}]} { |
| 94 | puts stderr "Value is not numeric!" |
| 95 | set rval $faultval |
| 96 | } |
| 97 | return $rval |
| 98 | } |
| 99 | |
| 100 | #--------------------- |
| 101 | # Numeric Precision |
| 102 | #--------------------- |
| 103 | proc magic::3digitpastdecimal {value} { |
| 104 | set new [expr int([expr $value * 1000 + 0.5 ]) / 1000.0] |
| 105 | return $new |
| 106 | } |
| 107 | |
| 108 | #------------------------------------------------------------------- |
| 109 | # File Access Functions |
| 110 | #------------------------------------------------------------------- |
| 111 | |
| 112 | #------------------------------------------------------------------- |
| 113 | # Ensures that a cell name does not already exist, either in |
| 114 | # memory or on disk. Modifies the name until it does. |
| 115 | #------------------------------------------------------------------- |
| 116 | proc magic:cellnameunique {cellname} { |
| 117 | set i 0 |
| 118 | set newname $cellname |
| 119 | while {[cellname list exists $newname] != 0 || [magic::searchcellondisk $newname] != 0} { |
| 120 | incr i |
| 121 | set newname ${cellname}_$i |
| 122 | } |
| 123 | return $newname |
| 124 | } |
| 125 | |
| 126 | #------------------------------------------------------------------- |
| 127 | # Looks to see if a cell exists on disk |
| 128 | #------------------------------------------------------------------- |
| 129 | proc magic::searchcellondisk {name} { |
| 130 | set rlist {} |
| 131 | foreach dir [path search] { |
| 132 | set ftry [file join $dir ${name}.mag] |
| 133 | if [file exists $ftry] { |
| 134 | return 1 |
| 135 | } |
| 136 | } |
| 137 | return 0 |
| 138 | } |
| 139 | |
| 140 | #------------------------------------------------------------------- |
| 141 | # Checks to see if a cell already exists on disk or in memory |
| 142 | #------------------------------------------------------------------- |
| 143 | proc magic::iscellnameunique {cellname} { |
| 144 | if {[cellname list exists $cellname] == 0 && [magic::searchcellondisk $cellname] == 0} { |
| 145 | return 1 |
| 146 | } else { |
| 147 | return 0 |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | #-------------------------------------------------------------- |
| 152 | # Procedure that checks the user's "ip" subdirectory on startup |
| 153 | # and adds each one's maglef subdirectory to the path. |
| 154 | #-------------------------------------------------------------- |
| 155 | |
| 156 | proc magic::query_mylib_ip {} { |
| 157 | global TECHPATH |
| 158 | global env |
| 159 | if [catch {set home $env(SUDO_USER)}] { |
| 160 | set home $env(USER) |
| 161 | } |
| 162 | set homedir /home/${home} |
| 163 | set ip_dirs [glob -directory ${homedir}/design/ip *] |
| 164 | set proj_dir [pwd] |
| 165 | set config_dir .config |
| 166 | set info_dir ${proj_dir}/${config_dir} |
| 167 | if {![file exists ${info_dir}]} { |
| 168 | set config_dir .ef-config |
| 169 | set info_dir ${proj_dir}/${config_dir} |
| 170 | } |
| 171 | |
| 172 | set info_file ${info_dir}/info |
| 173 | set depends [dict create] |
| 174 | if {![catch {open $info_file r} ifd]} { |
| 175 | set depsec false |
| 176 | while {[gets $ifd line] >= 0} { |
| 177 | if {[string first dependencies: $line] >= 0} { |
| 178 | set depsec true |
| 179 | } |
| 180 | if {$depsec} { |
| 181 | if {[string first version: $line] >= 0} { |
| 182 | if {$ipname != ""} { |
| 183 | set ipvers [string trim [lindex [split $line] 1] '] |
| 184 | dict set depends $ipname $ipvers |
| 185 | set ipname "" |
| 186 | } else { |
| 187 | puts stderr "Badly formatted info file in ${config_dir}!" |
| 188 | } |
| 189 | } else { |
| 190 | set ipname [string trim $line :] |
| 191 | } |
| 192 | } |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | foreach dir $ip_dirs { |
| 197 | # Version handling: version dependencies are found in |
| 198 | # ${config_dir}/info. For all other IP, use the most recent |
| 199 | # version number. |
| 200 | set ipname [lindex [file split $dir] end] |
| 201 | if {![catch {set version [dict get $depends $ipname]}]} { |
| 202 | if {[file isdirectory ${dir}/${version}/maglef]} { |
| 203 | addpath ${dir}/${version}/maglef |
| 204 | continue |
| 205 | } else { |
| 206 | puts stderr "ERROR: Dependency ${ipname} version ${version} does not exist" |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | # Secondary directory is the version number. Use the highest |
| 211 | # version available. |
| 212 | |
| 213 | set sub_dirs {} |
| 214 | catch {set sub_dirs [glob -directory $dir *]} |
| 215 | set maxver 0.0 |
| 216 | foreach subdir $sub_dirs { |
| 217 | set vidx [string last / $subdir] |
| 218 | incr vidx |
| 219 | set version [string range $subdir $vidx end] |
| 220 | if {$version > $maxver} { |
| 221 | set maxver $version |
| 222 | } |
| 223 | } |
| 224 | if {[file exists ${dir}/${maxver}/maglef]} { |
| 225 | # Compatibility rule: foundry name must match. |
| 226 | # Get foundry name from ${config_dir}/techdir symbolic link reference |
| 227 | if {[file exists ${dir}/${maxver}/${config_dir}/techdir]} { |
| 228 | set technodedir [file link ${dir}/${maxver}/${config_dir}/techdir] |
| 229 | set nidx [string last / $technodedir] |
| 230 | set techdir [string range $technodedir 0 $nidx-1] |
| 231 | if {$techdir == $TECHPATH} { |
| 232 | addpath ${dir}/${maxver}/maglef |
| 233 | } |
| 234 | } |
| 235 | } |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | #-------------------------------------------------------------- |
| 240 | # Procedure that checks the user's design directory on startup |
| 241 | # and adds each one's mag subdirectory to the path. |
| 242 | #-------------------------------------------------------------- |
| 243 | |
| 244 | proc magic::query_my_projects {} { |
| 245 | global TECHPATH |
| 246 | global env |
| 247 | if [catch {set home $env(SUDO_USER)}] { |
| 248 | set home $env(USER) |
| 249 | } |
| 250 | set homedir /home/${home} |
| 251 | set proj_dirs [glob -directory ${homedir}/design *] |
| 252 | foreach dir $proj_dirs { |
| 253 | # Compatibility rule: foundry name must match. |
| 254 | # Get foundry name from ${config_dir}/techdir symbolic link reference |
| 255 | if {[file exists ${dir}/mag]} { |
| 256 | set config_dir .config |
| 257 | set tech_dir ${dir}/${config_dir} |
| 258 | if {![file exists ${tech_dir}]} { |
| 259 | set config_dir .ef-config |
| 260 | set tech_dir ${dir}/${config_dir} |
| 261 | } |
| 262 | if {[file exists ${dir}/${config_dir}/techdir]} { |
| 263 | set technodedir [file link ${dir}/${config_dir}/techdir] |
| 264 | set nidx [string last / $technodedir] |
| 265 | set techdir [string range $technodedir 0 $nidx-1] |
| 266 | if {$techdir == $TECHPATH} { |
| 267 | addpath ${dir}/mag |
| 268 | } |
| 269 | } |
| 270 | } |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | #---------------------------------------------------------------- |