1#------------------------------------------ 2# sue_xc.tcl 3#------------------------------------------ 4# This script should be sourced into 5# XCircuit and provides the capability to 6# translate .sue files into XCircuit 7# schematics. This script works properly 8# with XCircuit version 3.10.21 or newer. 9#------------------------------------------ 10# The primary routine is "make_all_sue", 11# which is a TCL procedure to be run from 12# the XCircuit command line in the directory 13# containing .sue format files. Without 14# options, it creates a single XCircuit 15# PostScript output file "sue_gates.ps", 16# containing all of the gate symbols and 17# associated schematics in a single file. 18#------------------------------------------ 19# Written by R. Timothy Edwards 20# 8/23/04 21# MultiGiG, Inc. 22# Scotts Valley, CA 23# Updated 4/17/2020: Stopped hard-coding the primitive 24# devices in favor of making a "sue.lps" library. 25#------------------------------------------------------------ 26 27global xscale 28global sscale 29# sue puts things on grids of 10, xcircuit on grids of 16. 30set xscale 16 31set sscale 10 32 33#------------------------------------------------------------ 34# scale an {x y} list value from SUE units to XCircuit units 35#------------------------------------------------------------ 36 37proc scale_coord {coord} { 38 global xscale 39 global sscale 40 set x [lindex $coord 0] 41 set y [lindex $coord 1] 42 set x2 [expr {int(($x * $xscale) / $sscale)}] 43 set y2 [expr {int((-$y * $xscale) / $sscale)}] 44 set newc [lreplace $coord 0 1 $x2 $y2] 45 return $newc 46} 47 48namespace eval sue { 49 namespace export make make_wire make_line make_text 50 51 #------------------------------------------------------------ 52 # make and make_wire: create the schematic elements 53 #------------------------------------------------------------ 54 55 proc make {type args} { 56 57 if {[llength $args] == 1} { 58 set args [lindex $args 0] 59 } 60 61 # Default values 62 # Note that the inverted Y axis reverses the meaning of Y in the 63 # orientations. 64 65 set flipped {} 66 set angle 0 67 set width 1 68 set length 1 69 set name bad_element 70 set origin {0 0} 71 set instance_params {} 72 73 foreach {key value} $args { 74 switch -- $key { 75 -orient { 76 switch -- $value { 77 RXY { 78 set angle 180 79 } 80 RX { 81 set flipped horizontal 82 } 83 RY { 84 set flipped vertical 85 set angle 180 86 } 87 R270 { 88 set angle 270 89 } 90 R90 { 91 set angle 90 92 } 93 R0 { 94 # defaults 95 set flipped {} 96 set angle 0 97 } 98 } 99 } 100 -origin { 101 set origin $value 102 } 103 -name { 104 set name $value 105 } 106 -text { 107 set name $value 108 } 109 default { 110 lappend instance_params [list [string range $key 1 end] $value] 111 } 112 } 113 } 114 115 set origin [scale_coord $origin] 116 117 switch -- $type { 118 input - 119 output - 120 inout - 121 name_net - 122 name_net_s { 123 set newtext [label make pin $name $origin] 124 rotate $newtext $angle $origin 125 if {$flipped != {}} { 126 flip $newtext $flipped $origin 127 } 128 } 129 130 global { 131 set newtext [label make global $name $origin] 132 rotate $newtext $angle $origin 133 if {$flipped != {}} { 134 flip $newtext $flipped $origin 135 } 136 } 137 138 text { 139 set newtext [list $name] 140 while {[set rp [string first \n $newtext]] >= 0} { 141 set newtext [string replace $newtext $rp $rp "\} \{return\} \{"] 142 set rp [string first \n $newtext] 143 } 144 set newtext [label make normal $newtext $origin] 145 rotate $newtext $angle $origin 146 if {$flipped != {}} { 147 flip $newtext $flipped $origin 148 } 149 } 150 151 # Default behavior is to generate an object instance of the 152 # given name. This assumes that these are only objects that 153 # have been defined in .sue files already. 154 155 default { 156 set newgate [instance make $type $origin] 157 select $newgate 158 rotate $angle $origin 159 if {$flipped != {}} { 160 select $newgate 161 flip $flipped $origin 162 } 163 if {$instance_params != {}} { 164 select $newgate 165 foreach pair $instance_params { 166 set key [lindex $pair 0] 167 set value [lindex $pair 1] 168 parameter set $key $value -forward 169 } 170 deselect selected 171 } 172 } 173 } 174 deselect selected 175 } 176 177 #------------------------------------------------------------ 178 # Draw text on the schematic 179 #------------------------------------------------------------ 180 181 proc make_text {args} { 182 make text $args 183 } 184 185 #------------------------------------------------------------ 186 # Draw a wire into the schematic 187 #------------------------------------------------------------ 188 189 proc make_wire {x1 y1 x2 y2} { 190 # Scale the origin from SUE units to XCircuit units 191 set s1 [scale_coord [list $x1 $y1]] 192 set s2 [scale_coord [list $x2 $y2]] 193 polygon make 2 $s1 $s2 194 } 195 196 proc make_line {args} { 197 eval "make_wire $args" 198 } 199} 200 201#------------------------------------------------------------ 202# icon_*: create the symbol 203#------------------------------------------------------------ 204 205#------------------------------------------------------------ 206# default parameters (deferred) 207#------------------------------------------------------------ 208 209proc icon_setup {icon_args params} { 210 puts stdout "icon_setup $icon_args $params" 211 212 foreach pair $params { 213 set key [lindex $pair 0] 214 set value [lindex $pair 1] 215 if {$value == {}} {set value ""} 216 switch -- $key { 217 origin - 218 orient { 219 # Do nothing for now. These are library instance values 220 # in xcircuit, and could be set as such. 221 } 222 default { 223 parameter make substring $key [list [list Text $value]] 224 } 225 } 226 } 227} 228 229#------------------------------------------------------------ 230# pins 231#------------------------------------------------------------ 232 233proc icon_term {args} { 234 puts stdout "icon_term $args" 235 set pintype "no_pin" 236 set origin {0 0} 237 set name "bad_pin_name" 238 239 foreach {key value} $args { 240 switch -- $key { 241 -type { 242 set pintype $value 243 } 244 -origin { 245 set origin $value 246 } 247 -name { 248 set name $value 249 } 250 } 251 } 252 set newtext [label make pin $name [scale_coord $origin]] 253 label $newtext anchor center 254 label $newtext anchor middle 255 deselect selected 256} 257 258#------------------------------------------------------------ 259# instance parameters and symbol text labels 260#------------------------------------------------------------ 261 262proc icon_property {args} { 263 264 puts stdout "icon_property $args" 265 266 set name {} 267 set origin {0 0} 268 set proptype {} 269 set lscale 0.7 270 271 foreach {key value} $args { 272 273 switch -- $key { 274 -origin { 275 set origin $value 276 } 277 -name { 278 set lhandle [label make normal [list [list Parameter $value]] [scale_coord $origin]] 279 label $lhandle anchor center 280 label $lhandle anchor middle 281 label $lhandle scale $lscale 282 deselect selected 283 } 284 -type { 285 set proptype $value 286 } 287 -size { 288 # label size. Ignore, for now. 289 switch -- $value { 290 -small { 291 set lscale 0.5 292 } 293 -large { 294 set lscale 0.9 295 } 296 default { 297 set lscale 0.7 298 } 299 } 300 } 301 -label { 302 set lhandle [label make normal "$value" [scale_coord $origin]] 303 label $lhandle anchor center 304 label $lhandle anchor middle 305 label $lhandle scale $lscale 306 deselect selected 307 } 308 } 309 } 310} 311 312#------------------------------------------------------------ 313# Line drawing on the symbol 314#------------------------------------------------------------ 315 316proc icon_line {args} { 317 puts stdout "icon_line $args" 318 set coords {} 319 set i 0 320 foreach {x y} $args { 321 set s [scale_coord [list $x $y]] 322 lappend coords $s 323 incr i 324 } 325 eval "polygon make $i $coords" 326} 327 328#------------------------------------------------------------ 329# Recast schematic commands in a namespace used for a 330# preliminary parsing to discover dependencies 331#------------------------------------------------------------ 332 333namespace eval parse { 334 namespace export make make_wire make_line make_text 335 336 proc make {type args} { 337 global deplist 338 339 switch -- $type { 340 input - 341 output - 342 inout - 343 name_net - 344 name_net_s - 345 global - 346 text { 347 } 348 default { 349 lappend deplist $type 350 } 351 } 352 } 353 354 proc make_line {args} { 355 } 356 357 proc make_wire {x1 y1 x2 y2} { 358 } 359 360 proc make_text {args} { 361 } 362} 363 364#------------------------------------------------------------ 365# Main routine: Load the .sue file for the indicated 366# gate. Draw the schematic and the (user library) symbol, 367# and associate them. 368#------------------------------------------------------------ 369 370proc make_sue_gate {filename libname} { 371 global deplist 372 373 set name [file tail [file root $filename]] 374 375 # Check if this gate exists and ignore if so (may have been 376 # handled already as a dependency to another gate) 377 if {![catch {object handle ${name}}]} {return} 378 379 # DIAGNOSTIC 380 puts stdout "Sourcing ${filename}" 381 source ${filename} 382 383 set deplist {} 384 385 # DIAGNOSTIC 386 puts stdout "Evaluating SCHEMATIC_${name} in namespace parse" 387 namespace import parse::* 388 eval "SCHEMATIC_${name}" 389 390 if {[llength $deplist] > 0} { 391 # DIAGNOSTIC 392 puts stdout "Handling dependency list." 393 foreach dep $deplist { 394 make_sue_gate ${dep}.sue $libname 395 } 396 } 397 398 # DIAGNOSTIC 399 puts stdout "Generating new page" 400 401 # Go to a new page unless the current one is empty 402 while {[llength [object parts]] > 0} { 403 set p [page] 404 incr p 405 while {[catch {page $p}]} { 406 page make 407 } 408 } 409 410 puts stdout "Evaluating ICON_${name}" 411 namespace forget parse::* 412 namespace import sue::* 413 414 # Evaluate the symbol. Generate the symbol in xcircuit. 415 # Then clear the page to make the schematic 416 eval "ICON_${name}" 417 set hlist [object parts] 418 object make $name $hlist 419 set hlist [object parts] 420 push $hlist 421 pop 422 delete $hlist 423 424 # DIAGNOSTIC 425 puts stdout "Evaluating SCHEMATIC_${name} in namespace sue" 426 427 eval "SCHEMATIC_${name}" 428 catch {wm withdraw .select} 429 schematic associate $name 430 zoom view 431 432 # DIAGNOSTIC 433 puts stdout "Done." 434 namespace forget sue::* 435} 436 437#------------------------------------------------------------ 438# Read a .sue file and source it, then format a page around 439# the schematic contents. 440#------------------------------------------------------------ 441 442proc read_sue_file {filename name} { 443 config suspend true 444 make_sue_gate $filename $name 445 page filename $name 446 page orientation 90 447 page encapsulation full 448 page fit true 449 if {[page scale] > 1.0} { 450 page fit false 451 page scale 1.0 452 } 453 config suspend false 454} 455 456#------------------------------------------------------------ 457# Top-level routine: Find all the .sue files in the 458# current directory and generate a library from them 459#------------------------------------------------------------ 460 461proc make_all_sue {{name sue_gates}} { 462 set files [glob \*.sue] 463 464 foreach filename $files { 465 read_sue_file $filename $name 466 } 467} 468 469#------------------------------------------------------------ 470# Make sure that the sue technology (.lps file) has been read 471# 472#------------------------------------------------------------ 473 474if {[lsearch [technology list] sue] < 0} { 475 library load sue 476 technology prefer sue 477} 478