1#----------------------------------------------------- 2# Magic/TCL general-purpose toolkit procedures 3#----------------------------------------------------- 4# Tim Edwards 5# February 11, 2007 6# Revision 0 7# December 15, 2016 8# Revision 1 9# October 29, 2020 10# Revision 2 (names are hashed from properties) 11# March 9, 2021 12# Added spice-to-layout procedure 13#-------------------------------------------------------------- 14# Sets up the environment for a toolkit. The toolkit must 15# supply a namespace that is the "library name". For each 16# parameter-defined device ("gencell") type, the toolkit must 17# supply five procedures: 18# 19# 1. ${library}::${gencell_type}_defaults {} 20# 2. ${library}::${gencell_type}_convert {parameters} 21# 3. ${library}::${gencell_type}_dialog {parameters} 22# 4. ${library}::${gencell_type}_check {parameters} 23# 5. ${library}::${gencell_type}_draw {parameters} 24# 25# The first defines the parameters used by the gencell, and 26# declares default parameters to use when first generating 27# the window that prompts for the device parameters prior to 28# creating the device. The second converts between parameters 29# in a SPICE netlist and parameters used by the dialog, 30# performing units conversion and parameter name conversion as 31# needed. The third builds the dialog window for entering 32# device parameters. The fourth checks the parameters for 33# legal values. The fifth draws the device. 34# 35# If "library" is not specified then it defaults to "toolkit". 36# Otherwise, where specified, the name "gencell_fullname" 37# is equivalent to "${library}::${gencell_type}" 38# 39# Each gencell is defined by cell properties as created by 40# the "cellname property" command. Specific properties used 41# by the toolkit are: 42# 43# library --- name of library (see above, default "toolkit") 44# gencell --- base name of gencell (gencell_type, above) 45# parameters --- list of gencell parameter-value pairs 46#-------------------------------------------------------------- 47 48# Initialize toolkit menus to the wrapper window 49 50global Opts 51 52#---------------------------------------------------------------- 53# Add a menu button to the Magic wrapper window for the toolkit 54#---------------------------------------------------------------- 55 56proc magic::add_toolkit_menu {framename button_text {library toolkit}} { 57 menubutton ${framename}.titlebar.mbuttons.${library} \ 58 -text $button_text \ 59 -relief raised \ 60 -menu ${framename}.titlebar.mbuttons.${library}.toolmenu \ 61 -borderwidth 2 62 63 menu ${framename}.titlebar.mbuttons.${library}.toolmenu -tearoff 0 64 pack ${framename}.titlebar.mbuttons.${library} -side left 65} 66 67#----------------------------------------------------------------- 68# Add a menu item to the toolkit menu calling the default function 69#----------------------------------------------------------------- 70 71proc magic::add_toolkit_button {framename button_text gencell_type \ 72 {library toolkit} args} { 73 set m ${framename}.titlebar.mbuttons.${library}.toolmenu 74 $m add command -label "$button_text" -command \ 75 "magic::gencell $library::$gencell_type {} $args" 76} 77 78#---------------------------------------------------------------- 79# Add a menu item to the toolkit menu that calls the provided 80# function 81#---------------------------------------------------------------- 82 83proc magic::add_toolkit_command {framename button_text \ 84 command {library toolkit} args} { 85 set m ${framename}.titlebar.mbuttons.${library}.toolmenu 86 $m add command -label "$button_text" -command "$command $args" 87} 88 89#---------------------------------------------------------------- 90# Add a separator to the toolkit menu 91#---------------------------------------------------------------- 92 93proc magic::add_toolkit_separator {framename {library toolkit}} { 94 set m ${framename}.titlebar.mbuttons.${library}.toolmenu 95 $m add separator 96} 97 98#----------------------------------------------------- 99# Add "Ctrl-P" key callback for device selection 100#----------------------------------------------------- 101 102magic::macro ^P "magic::gencell {} ; raise .params" 103 104#------------------------------------------------------------- 105# Add tag callback to select to update the gencell window 106#------------------------------------------------------------- 107 108magic::tag select "[magic::tag select]; magic::gencell_update %1" 109 110#-------------------------------------------------------------- 111# Supporting procedures for netlist_to_layout procedure 112#-------------------------------------------------------------- 113 114# move_forward_by_width -- 115# 116# Given an instance name, find the instance and position the 117# cursor box at the right side of the instance. 118 119proc magic::move_forward_by_width {instname} { 120 select cell $instname 121 set anum [lindex [array -list count] 1] 122 set xpitch [lindex [array -list pitch] 0] 123 set bbox [box values] 124 set posx [lindex $bbox 0] 125 set posy [lindex $bbox 1] 126 set width [expr [lindex $bbox 2] - $posx] 127 set posx [expr $posx + $width + $xpitch * $anum] 128 box position ${posx}i ${posy}i 129 return [lindex $bbox 3] 130} 131 132# get_and_move_inst -- 133# 134# Given a cell name, creat an instance of the cell named "instname" 135# at the current cursor box position. If option "anum" is given 136# and > 1, then array the cell. 137 138proc magic::get_and_move_inst {cellname instname {anum 1}} { 139 set newinst [getcell $cellname] 140 select cell $newinst 141 if {$newinst == ""} {return} 142 identify $instname 143 if {$anum > 1} {array 1 $anum} 144 set bbox [box values] 145 set posx [lindex $bbox 2] 146 set posy [lindex $bbox 1] 147 box position ${posx}i ${posy}i 148 return [lindex $bbox 3] 149} 150 151# create_new_pin -- 152# 153# Create a new pin of size 1um x 1um at the current cursor box 154# location. If "layer" is given, then create the pin on the 155# given layer. Otherwise, the pin is created on the m1 layer. 156 157proc magic::create_new_pin {pinname portnum {layer m1}} { 158 box size 1um 1um 159 paint $layer 160 label $pinname FreeSans 16 0 0 0 c $layer 161 port make $portnum 162 box move s 2um 163} 164 165# generate_layout_add -- 166# 167# Add a new subcircuit to a layout and seed it with components 168# as found in the list "complist", and add pins according to the 169# pin names in "subpins". Each entry in "complist" is a single 170# device line from a SPICE file. 171 172proc magic::generate_layout_add {subname subpins complist library} { 173 global PDKNAMESPACE 174 175 # Create a new subcircuit 176 load $subname -quiet 177 box 0 0 0 0 178 179 # Generate pins 180 if {[llength $subpins] > 0} { 181 set pinlist [split $subpins] 182 set i 0 183 foreach pin $pinlist { 184 # Escape [ and ] in pin name 185 set pin_esc [string map {\[ \\\[ \] \\\]} $pin] 186 magic::create_new_pin $pin_esc $i 187 incr i 188 } 189 } 190 191 # Set initial position for importing cells 192 box size 0 0 193 set posx 0 194 set posy [expr {round(3 / [cif scale out])}] 195 box position ${posx}i ${posy}i 196 197 # Seed layout with components 198 foreach comp $complist { 199 set pinlist {} 200 set paramlist {} 201 202 # NOTE: This routine deals with subcircuit calls and devices 203 # with models. It needs to determine when a device is instantiated 204 # without a model, and ignore such devices. 205 206 # Parse SPICE line into pins, device name, and parameters. Make 207 # sure parameters incorporate quoted expressions as {} or ''. 208 209 set rest $comp 210 while {$rest != ""} { 211 if {[regexp -nocase {^[ \t]*[^= \t]+=[^=]+} $rest]} { 212 break 213 } elseif {[regexp -nocase {^[ \t]*([^ \t]+)[ \t]*(.*)$} $rest \ 214 valid token rest]} { 215 lappend pinlist $token 216 } else { 217 set rest "" 218 } 219 } 220 221 while {$rest != ""} { 222 if {[regexp -nocase {^([^= \t]+)=\'([^\']+)\'[ \t]*(.*)} $rest \ 223 valid pname value rest]} { 224 lappend paramlist [list $pname "{$value}"] 225 } elseif {[regexp -nocase {^([^= \t]+)=\{([^\}]+)\}[ \t]*(.*)} $rest \ 226 valid pname value rest]} { 227 lappend paramlist [list $pname "{$value}"] 228 } elseif {[regexp -nocase {^([^= \t]+)=([^= \t]+)[ \t]*(.*)} $rest \ 229 valid pname value rest]} { 230 lappend paramlist [list $pname $value] 231 } else { 232 puts stderr "Error parsing line \"$comp\"" 233 puts stderr "at: \"$rest\"" 234 set rest "" 235 } 236 } 237 238 if {[llength $pinlist] < 2} { 239 puts stderr "Error: No device type found in line \"$comp\"" 240 puts stderr "Tokens found are: \"$pinlist\"" 241 continue 242 } 243 244 set instname [lindex $pinlist 0] 245 set devtype [lindex $pinlist end] 246 set pinlist [lrange $pinlist 0 end-1] 247 248 set mult 1 249 foreach param $paramlist { 250 set parmname [lindex $param 0] 251 set parmval [lindex $param 1] 252 if {[string toupper $parmname] == "M"} { 253 if {[catch {set mult [expr {int($parmval)}]}]} { 254 set mult [expr [string trim $parmval "'"]] 255 } 256 } 257 } 258 259 # devtype is assumed to be in library. If not, it will attempt to 260 # use 'getcell' on devtype. Note that this code depends on the 261 # PDK setting varible PDKNAMESPACE. 262 263 if {$library != ""} { 264 set libdev ${library}::${devtype} 265 } else { 266 set libdev ${PDKNAMESPACE}::${devtype} 267 } 268 269 set outparts {} 270 lappend outparts "magic::gencell $libdev $instname" 271 272 # Output all parameters. Parameters not used by the toolkit are 273 # ignored by the toolkit. 274 275 lappend outparts "-spice" 276 foreach param $paramlist { 277 lappend outparts [string tolower [lindex $param 0]] 278 lappend outparts [lindex $param 1] 279 } 280 281 if {[catch {eval [join $outparts]}]} { 282 # Assume this is not a gencell, and get an instance. 283 magic::get_and_move_inst $devtype $instname $mult 284 } else { 285 # Move forward for next gencell 286 magic::move_forward_by_width $instname 287 } 288 } 289 save $subname 290} 291 292#-------------------------------------------------------------- 293# Wrapper for generating an initial layout from a SPICE netlist 294# using the defined PDK toolkit procedures 295# 296# "netfile" is the name of a SPICE netlist 297# "library" is the name of the PDK library namespace 298#-------------------------------------------------------------- 299 300proc magic::netlist_to_layout {netfile library} { 301 302 if {![file exists $netfile]} { 303 puts stderr "No such file $netfile" 304 return 305 } 306 307 # Read data from file. Remove comment lines and concatenate 308 # continuation lines. 309 310 set topname [file rootname [file tail $netfile]] 311 puts stdout "Creating layout from [file tail $netfile]" 312 313 if {[file ext $netfile] == ".cdl"} { 314 set is_cdl true 315 } else { 316 set is_cdl false 317 } 318 319 if [catch {open $netfile r} fnet] { 320 puts stderr "Error: Cannot open file \"$netfile\" for reading." 321 return 322 } 323 324 set fdata {} 325 set lastline "" 326 while {[gets $fnet line] >= 0} { 327 # Handle CDL format *.PININFO (convert to .PININFO ...) 328 if {$is_cdl && ([string range $line 0 1] == "*.")} { 329 if {[string tolower [string range $line 2 8]] == "pininfo"} { 330 set line [string range $line 1 end] 331 } 332 } 333 if {[string index $line 0] != "*"} { 334 if {[string index $line 0] == "+"} { 335 if {[string range $line end end] != " "} { 336 append lastline " " 337 } 338 append lastline [string range $line 1 end] 339 } else { 340 lappend fdata $lastline 341 set lastline $line 342 } 343 } 344 } 345 lappend fdata $lastline 346 close $fnet 347 348 set insub false 349 set incmd false 350 set subname "" 351 set subpins "" 352 set complist {} 353 set toplist {} 354 355 # suspendall 356 357 set ignorekeys {.global .ic .option .end} 358 359 # Parse the file 360 foreach line $fdata { 361 if {$incmd} { 362 if {[regexp -nocase {^[ \t]*\.endc} $line]} { 363 set incmd false 364 } 365 } elseif {! $insub} { 366 set ftokens [split $line] 367 set keyword [string tolower [lindex $ftokens 0]] 368 369 if {[lsearch $ignorekeys $keyword] != -1} { 370 continue 371 } elseif {$keyword == ".command"} { 372 set incmd true 373 } elseif {$keyword == ".subckt"} { 374 set subname [lindex $ftokens 1] 375 set subpins [lrange $ftokens 2 end] 376 set insub true 377 } elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \ 378 valid instname rest]} { 379 lappend toplist $line 380 } elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \ 381 valid instname rest]} { 382 # These are testbench devices and should be ignored 383 continue 384 } 385 } else { 386 if {[regexp -nocase {^[ \t]*\.ends} $line]} { 387 set insub false 388 magic::generate_layout_add $subname $subpins $complist $library 389 set subname "" 390 set subpins "" 391 set complist {} 392 } elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \ 393 valid instname rest]} { 394 lappend complist $line 395 } elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \ 396 valid instname rest]} { 397 # These are testbench devices and should be ignored 398 continue 399 } 400 } 401 } 402 403 # Add in any top-level components (not in subcircuits) 404 if {[llength $toplist] > 0} { 405 magic::generate_layout_add $topname "" $toplist $library 406 } 407 408 # resumeall 409} 410 411#------------------------------------------------------------- 412# gencell 413# 414# Main routine to call a cell from either a menu button or 415# from a script or command line. The name of the device 416# is required, followed by the name of the instance, followed 417# by an optional list of parameters. Handling depends on 418# instname and args: 419# 420# gencell_name is either the name of an instance or the name 421# of the gencell in the form <library>::<device>. 422# 423# name args action 424#----------------------------------------------------------------- 425# none empty interactive, new device w/defaults 426# none specified interactive, new device w/parameters 427# instname empty interactive, edit device 428# instname specified non-interactive, change device 429# device empty non-interactive, new device w/defaults 430# device specified non-interactive, new device w/parameters 431# 432#------------------------------------------------------------- 433# Also, if instname is empty and gencell_name is not specified, 434# and if a device is selected in the layout, then gencell 435# behaves like line 3 above (instname exists, args is empty). 436# Note that macro Ctrl-P calls gencell this way. If gencell_name 437# is not specified and nothing is selected, then gencell{} 438# does nothing. 439# 440# "args" must be a list of the cell parameters in key:value pairs, 441# and an odd number is not legal; the exception is that if the 442# first argument is "-spice", then the list of parameters is 443# expected to be in the format used in a SPICE netlist, and the 444# parameter names and values will be treated accordingly. 445#------------------------------------------------------------- 446 447proc magic::gencell {gencell_name {instname {}} args} { 448 449 # Pull "-spice" out of args, if it is the first argument 450 if {[lindex $args 0] == "-spice"} { 451 set spicemode 1 452 set args [lrange $args 1 end] 453 } else { 454 set spicemode 0 455 } 456 set argpar [dict create {*}$args] 457 458 if {$gencell_name == {}} { 459 # Find selected item (to-do: handle multiple selections) 460 461 set wlist [what -list] 462 set clist [lindex $wlist 2] 463 set ccell [lindex $clist 0] 464 set ginst [lindex $ccell 0] 465 set gname [lindex $ccell 1] 466 set library [cellname list property $gname library] 467 if {$library == {}} { 468 set library toolkit 469 } 470 set gencell_type [cellname list property $gname gencell] 471 if {$gencell_type == {}} { 472 if {![regexp {^(.*)_[0-9]*$} $gname valid gencell_type]} { 473 # Error message 474 error "No gencell device is selected!" 475 } 476 } 477 # need to incorporate argpar? 478 set parameters [cellname list property $gname parameters] 479 set parameters [magic::gencell_defaults $gencell_type $library $parameters] 480 magic::gencell_dialog $ginst $gencell_type $library $parameters 481 } else { 482 # Parse out library name from gencell_name, otherwise default 483 # library is assumed to be "toolkit". 484 if {[regexp {^([^:]+)::([^:]+)$} $gencell_name valid library gencell_type] \ 485 == 0} { 486 set library "toolkit" 487 set gencell_type $gencell_name 488 } 489 490 # Check that the device exists as a gencell, or else return an error 491 if {[namespace eval ::${library} info commands ${gencell_type}_convert] == ""} { 492 error "No import routine for ${library} library cell ${gencell_type}!" 493 } 494 495 if {$instname == {}} { 496 # Case: Interactive, new device with parameters in args (if any) 497 if {$spicemode == 1} { 498 # Legal not to have a *_convert routine 499 if {[info commands ${library}::${gencell_type}_convert] != ""} { 500 set argpar [${library}::${gencell_type}_convert $argpar] 501 } 502 } 503 set parameters [magic::gencell_defaults $gencell_type $library $argpar] 504 magic::gencell_dialog {} $gencell_type $library $parameters 505 } else { 506 # Check if instance exists or not in the cell 507 set cellname [instance list celldef $instname] 508 509 if {$cellname != ""} { 510 # Case: Change existing instance, parameters in args (if any) 511 select cell $instname 512 set devparms [cellname list property $gencell_type parameters] 513 set parameters [magic::gencell_defaults $gencell_type $library $devparms] 514 if {[dict exists $parameters nocell]} { 515 set arcount [array -list count] 516 set arpitch [array -list pitch] 517 518 dict set parameters nx [lindex $arcount 1] 519 dict set parameters ny [lindex $arcount 3] 520 dict set parameters pitchx $delx 521 dict set parameters pitchy $dely 522 } 523 if {[dict size $argpar] == 0} { 524 # No changes entered on the command line, so start dialog 525 magic::gencell_dialog $instname $gencell_type $library $parameters 526 } else { 527 # Apply specified changes without invoking the dialog 528 if {$spicemode == 1} { 529 set argpar [${library}::${gencell_type}_convert $argpar] 530 } 531 set parameters [dict merge $parameters $argpar] 532 magic::gencell_change $instname $gencell_type $library $parameters 533 } 534 } else { 535 # Case: Non-interactive, create new device with parameters 536 # in args (if any) 537 if {$spicemode == 1} { 538 set argpar [${library}::${gencell_type}_convert $argpar] 539 } 540 set parameters [magic::gencell_defaults $gencell_type $library $argpar] 541 set inst_defaultname [magic::gencell_create \ 542 $gencell_type $library $parameters] 543 select cell $inst_defaultname 544 identify $instname 545 } 546 } 547 } 548 return 0 549} 550 551#------------------------------------------------------------- 552# gencell_makecell 553# 554# This is a variation of magic::gencell and is used to generate 555# a cell and return the cell name without creating or placing 556# an instance. 557#------------------------------------------------------------- 558 559proc magic::gencell_makecell {gencell_fullname args} { 560 561 set argpar [dict create {*}$args] 562 set gencell_basename [namespace tail $gencell_fullname] 563 set library [namespace qualifiers $gencell_fullname] 564 set parameters [magic::gencell_defaults $gencell_basename $library $argpar] 565 set gsuffix [magic::get_gencell_hash ${parameters}] 566 set gname ${gencell_basename}_${gsuffix} 567 suspendall 568 cellname create $gname 569 pushstack $gname 570 if {[catch {${library}::${gencell_basename}_draw $parameters} drawerr]} { 571 puts stderr $drawerr 572 } 573 property library $library 574 property gencell $gencell_basename 575 property parameters $parameters 576 popstack 577 resumeall 578 return $gname 579} 580 581#------------------------------------------------------------- 582# gencell_getparams 583# 584# Go through the parameter window and collect all of the 585# named parameters and their values. Return the result as 586# a dictionary. 587#------------------------------------------------------------- 588 589proc magic::gencell_getparams {} { 590 set parameters [dict create] 591 set slist [grid slaves .params.edits] 592 foreach s $slist { 593 if {[regexp {^.params.edits.(.*)_ent$} $s valid pname] != 0} { 594 set value [subst \$magic::${pname}_val] 595 } elseif {[regexp {^.params.edits.(.*)_chk$} $s valid pname] != 0} { 596 set value [subst \$magic::${pname}_val] 597 } elseif {[regexp {^.params.edits.(.*)_sel$} $s valid pname] != 0} { 598 set value [subst \$magic::${pname}_val] 599 } 600 dict set parameters $pname $value 601 } 602 return $parameters 603} 604 605#------------------------------------------------------------- 606# gencell_setparams 607# 608# Fill in values in the dialog from a set of parameters 609#------------------------------------------------------------- 610 611proc magic::gencell_setparams {parameters} { 612 if {[catch {set state [wm state .params]}]} {return} 613 set slist [grid slaves .params.edits] 614 foreach s $slist { 615 # ignore .params.edits.gencell_sel, as that does not exist in the 616 # parameters dictionary 617 if {$s == ".params.edits.gencell_sel"} {continue} 618 if {[regexp {^.params.edits.(.*)_ent$} $s valid pname] != 0} { 619 set value [dict get $parameters $pname] 620 set magic::${pname}_val $value 621 } elseif {[regexp {^.params.edits.(.*)_chk$} $s valid pname] != 0} { 622 set value [dict get $parameters $pname] 623 set magic::${pname}_val $value 624 } elseif {[regexp {^.params.edits.(.*)_sel$} $s valid pname] != 0} { 625 set value [dict get $parameters $pname] 626 set magic::${pname}_val $value 627 .params.edits.${pname}_sel configure -text $value 628 } elseif {[regexp {^.params.edits.(.*)_txt$} $s valid pname] != 0} { 629 if {[dict exists $parameters $pname]} { 630 set value [dict get $parameters $pname] 631 .params.edits.${pname}_txt configure -text $value 632 } 633 } 634 } 635} 636 637#------------------------------------------------------------- 638# gencell_change 639# 640# Recreate a gencell with new parameters. Note that because 641# each cellname is uniquely identified by the (hashed) set 642# of parameters, changing parameters effectively means 643# creating a new cell. If the original cell has parents 644# other than the parent of the instance being changed, then 645# it is retained; otherwise, it is deleted. The instance 646# being edited gets replaced by an instance of the new cell. 647# If the instance name was the cellname + suffix, then the 648# instance name is regenerated. Otherwise, the instance 649# name is retained. 650#------------------------------------------------------------- 651 652proc magic::gencell_change {instname gencell_type library parameters} { 653 global Opts 654 suspendall 655 656 set newinstname $instname 657 if {$parameters == {}} { 658 # Get device defaults 659 set pdefaults [${library}::${gencell_type}_defaults] 660 # Pull user-entered values from dialog 661 set parameters [dict merge $pdefaults [magic::gencell_getparams]] 662 set newinstname [.params.title.ient get] 663 if {$newinstname == "(default)"} {set newinstname $instname} 664 if {$newinstname == $instname} {set newinstname $instname} 665 if {[instance list exists $newinstname] != ""} {set newinstname $instname} 666 } 667 if {[dict exists $parameters gencell]} { 668 # Setting special parameter "gencell" forces the gencell to change type 669 set gencell_type [dict get $parameters gencell] 670 } 671 if {[catch {set parameters [${library}::${gencell_type}_check $parameters]} \ 672 checkerr]} { 673 puts stderr $checkerr 674 } 675 magic::gencell_setparams $parameters 676 if {[dict exists $parameters gencell]} { 677 set parameters [dict remove $parameters gencell] 678 } 679 680 set old_gname [instance list celldef $instname] 681 set gsuffix [magic::get_gencell_hash ${parameters}] 682 set gname ${gencell_type}_${gsuffix} 683 684 # Guard against instance having been deleted. Also, if parameters have not 685 # changed as evidenced by the cell suffix not changing, then nothing further 686 # needs to be done. 687 if {$gname == "" || $gname == $old_gname} { 688 resumeall 689 return 690 } 691 692 set snaptype [snap list] 693 snap internal 694 set savebox [box values] 695 696 catch {setpoint 0 0 $Opts(focus)} 697 if [dict exists $parameters nocell] { 698 select cell $instname 699 set abox [instance list abutment] 700 delete 701 if {$abox != ""} {box values {*}$abox} 702 if {[catch {set newinst [${library}::${gencell_type}_draw $parameters]} \ 703 drawerr]} { 704 puts stderr $drawerr 705 } 706 select cell $newinst 707 } elseif {[cellname list exists $gname] != 0} { 708 # If there is already a cell of this type then it is only required to 709 # remove the instance and replace it with an instance of the cell 710 select cell $instname 711 # check rotate/flip before replacing and replace with same 712 set orient [instance list orientation] 713 set abox [instance list abutment] 714 delete 715 716 if {$abox != ""} {box values {*}$abox} 717 set newinstname [getcell $gname $orient] 718 select cell $newinstname 719 expand 720 721 # If the old instance name was not formed from the old cell name, 722 # then keep the old instance name. 723 if {[string first $old_gname $instname] != 0} { 724 set newinstname $instname 725 } 726 727 if {[cellname list parents $old_gname] == []} { 728 # If the original cell has no intances left, delete it. It can 729 # be regenerated if and when necessary. 730 cellname delete $old_gname 731 } 732 733 } else { 734 select cell $instname 735 set orient [instance list orientation] 736 set abox [instance list abutment] 737 delete 738 739 # There is no cell of this name, so generate one and instantiate it. 740 if {$abox != ""} {box values {*}$abox} 741 set newinstname [magic::gencell_create $gencell_type $library $parameters $orient] 742 select cell $newinstname 743 744 # If the old instance name was not formed from the old cell name, 745 # then keep the old instance name. 746 if {[string first $old_gname $instname] != 0} { 747 set newinstname $instname 748 } else { 749 # The buttons "Apply" and "Okay" need to be changed for the new 750 # instance name 751 catch {.params.buttons.apply config -command \ 752 "magic::gencell_change $newinstname $gencell_type $library {}"} 753 catch {.params.buttons.okay config -command \ 754 "magic::gencell_change $newinstname $gencell_type $library {} ;\ 755 destroy .params"} 756 } 757 } 758 identify $newinstname 759 eval "box values $savebox" 760 snap $snaptype 761 762 # Update window 763 if {$gname != $old_gname} { 764 catch {.params.title.glab configure -text "$gname"} 765 } 766 if {$instname != $newinstname} { 767 catch {.params.title.ient delete 0 end} 768 catch {.params.title.ient insert 0 "$newinstname"} 769 } 770 771 resumeall 772 redraw 773} 774 775#------------------------------------------------------------- 776# gencell_change_orig 777# 778# Original version: Redraw a gencell with new parameters, 779# without changing the cell itself. 780#------------------------------------------------------------- 781 782proc magic::gencell_change_orig {instname gencell_type library parameters} { 783 global Opts 784 suspendall 785 786 set newinstname $instname 787 if {$parameters == {}} { 788 # Get device defaults 789 set pdefaults [${library}::${gencell_type}_defaults] 790 # Pull user-entered values from dialog 791 set parameters [dict merge $pdefaults [magic::gencell_getparams]] 792 set newinstname [.params.title.ient get] 793 if {$newinstname == "(default)"} {set newinstname $instname} 794 if {$newinstname == $instname} {set newinstname $instname} 795 if {[instance list exists $newinstname] != ""} {set newinstname $instname} 796 } 797 if {[dict exists $parameters gencell]} { 798 # Setting special parameter "gencell" forces the gencell to change type 799 set gencell_type [dict get $parameters gencell] 800 } 801 if {[catch {set parameters [${library}::${gencell_type}_check $parameters]} \ 802 checkerr]} { 803 puts stderr $checkerr 804 } 805 magic::gencell_setparams $parameters 806 if {[dict exists $parameters gencell]} { 807 set parameters [dict remove $parameters gencell] 808 } 809 810 set gname [instance list celldef $instname] 811 812 # Guard against instance having been deleted 813 if {$gname == ""} { 814 resumeall 815 return 816 } 817 818 set snaptype [snap list] 819 snap internal 820 set savebox [box values] 821 822 catch {setpoint 0 0 $Opts(focus)} 823 if [dict exists $parameters nocell] { 824 select cell $instname 825 delete 826 if {[catch {set newinst [${library}::${gencell_type}_draw $parameters]} \ 827 drawerr]} { 828 puts stderr $drawerr 829 } 830 select cell $newinst 831 } else { 832 pushstack $gname 833 select cell 834 tech unlock * 835 erase * 836 if {[catch {${library}::${gencell_type}_draw $parameters} drawerr]} { 837 puts stderr $drawerr 838 } 839 property parameters $parameters 840 property gencell ${gencell_type} 841 tech revert 842 popstack 843 select cell $instname 844 } 845 identify $newinstname 846 eval "box values $savebox" 847 snap $snaptype 848 resumeall 849 redraw 850} 851 852#------------------------------------------------------------- 853# Assign a unique name for a gencell 854# 855# Note: This depends on the unlikelihood of the name 856# existing in a cell on disk. Only cells in memory are 857# checked for name collisions. Since the names will go 858# into SPICE netlists, names must be unique when compared 859# in a case-insensitive manner. Using base-36 (alphabet and 860# numbers), each gencell name with 6 randomized characters 861# has a 1 in 4.6E-10 chance of reappearing. 862#------------------------------------------------------------- 863 864proc magic::get_gencell_name {gencell_type} { 865 while {true} { 866 set postfix "" 867 for {set i 0} {$i < 6} {incr i} { 868 set pint [expr 48 + int(rand() * 36)] 869 if {$pint > 57} {set pint [expr $pint + 39]} 870 append postfix [format %c $pint] 871 } 872 if {[cellname list exists ${gencell_type}_$postfix] == 0} {break} 873 } 874 return ${gencell_type}_$postfix 875} 876 877#---------------------------------------------------------------- 878# get_gencell_hash 879# 880# A better approach to the above. Take the parameter 881# dictionary, and run all the values through a hash function 882# to generate a 30-bit value, then convert to base32. This 883# gives a result that is repeatable for the same set of 884# parameter values with a very low probability of a collision. 885# 886# The hash function is similar to elfhash but reduced from 32 887# to 30 bits so that the result can form a 6-character value 888# in base32 with all characters being valid for a SPICE subcell 889# name (e.g., alphanumeric only and case-insensitive). 890#---------------------------------------------------------------- 891 892proc magic::get_gencell_hash {parameters} { 893 set hash 0 894 # Apply hash 895 dict for {key value} $parameters { 896 foreach s [split $value {}] { 897 set hash [expr {($hash << 4) + [scan $s %c]}] 898 set high [expr {$hash & 0x03c0000000}] 899 set hash [expr {$hash ^ ($high >> 30)}] 900 set hash [expr {$hash & (~$high)}] 901 } 902 } 903 # Divide hash up into 5 bit values and convert to base32 904 # using letters A-Z less I and O, and digits 2-9. 905 set cvals "" 906 for {set i 0} {$i < 6} {incr i} { 907 set oval [expr {($hash >> ($i * 5)) & 0x1f}] 908 if {$oval < 8} { 909 set bval [expr {$oval + 50}] 910 } elseif {$oval < 16} { 911 set bval [expr {$oval + 57}] 912 } elseif {$oval < 21} { 913 set bval [expr {$oval + 58}] 914 } else { 915 set bval [expr {$oval + 59}] 916 } 917 append cvals [binary format c* $bval] 918 } 919 return $cvals 920} 921 922#------------------------------------------------------------- 923# gencell_create 924# 925# Instantiate a new gencell called $gname. If $gname 926# does not already exist, create it by calling its 927# drawing routine. 928# 929# Don't rely on pushbox/popbox since we don't know what 930# the drawing routine is going to do to the stack! 931#------------------------------------------------------------- 932 933proc magic::gencell_create {gencell_type library parameters {orient 0}} { 934 global Opts 935 suspendall 936 937 set newinstname "" 938 939 # Get device defaults 940 if {$parameters == {}} { 941 # Pull user-entered values from dialog 942 set dialogparams [magic::gencell_getparams] 943 if {[dict exists $dialogparams gencell]} { 944 # Setting special parameter "gencell" forces the gencell to change type 945 set gencell_type [dict get $dialogparams gencell] 946 } 947 set pdefaults [${library}::${gencell_type}_defaults] 948 set parameters [dict merge $pdefaults $dialogparams] 949 set newinstname [.params.title.ient get] 950 if {$newinstname == "(default)"} {set newinstname ""} 951 if {[instance list exists $newinstname] != ""} {set newinstname ""} 952 } else { 953 if {[dict exists $parameters gencell]} { 954 # Setting special parameter "gencell" forces the gencell to change type 955 set gencell_type [dict get $parameters gencell] 956 } 957 set pdefaults [${library}::${gencell_type}_defaults] 958 set parameters [dict merge $pdefaults $parameters] 959 } 960 961 if {[catch {set parameters [${library}::${gencell_type}_check $parameters]} \ 962 checkerr]} { 963 puts stderr $checkerr 964 } 965 magic::gencell_setparams $parameters 966 if {[dict exists $parameters gencell]} { 967 set parameters [dict remove $parameters gencell] 968 } 969 970 set snaptype [snap list] 971 snap internal 972 set savebox [box values] 973 974 catch {setpoint 0 0 $Opts(focus)} 975 if [dict exists $parameters nocell] { 976 if {[catch {set instname [${library}::${gencell_type}_draw $parameters]} \ drawerr]} { 977 puts stderr $drawerr 978 } 979 set gname [instance list celldef $instname] 980 eval "box values $savebox" 981 } else { 982 set gsuffix [magic::get_gencell_hash ${parameters}] 983 set gname ${gencell_type}_${gsuffix} 984 cellname create $gname 985 pushstack $gname 986 if {[catch {${library}::${gencell_type}_draw $parameters} drawerr]} { 987 puts stderr $drawerr 988 } 989 property library $library 990 property gencell $gencell_type 991 property parameters $parameters 992 popstack 993 eval "box values $savebox" 994 set instname [getcell $gname $orient] 995 expand 996 } 997 if {$newinstname != ""} { 998 identify $newinstname 999 set instname $newinstname 1000 } 1001 snap $snaptype 1002 resumeall 1003 redraw 1004 return $instname 1005} 1006 1007#----------------------------------------------------- 1008# Add a standard entry parameter to the gencell window 1009#----------------------------------------------------- 1010 1011proc magic::add_entry {pname ptext parameters} { 1012 1013 if [dict exists $parameters $pname] { 1014 set value [dict get $parameters $pname] 1015 } else { 1016 set value "" 1017 } 1018 1019 set numrows [lindex [grid size .params.edits] 1] 1020 label .params.edits.${pname}_lab -text $ptext 1021 entry .params.edits.${pname}_ent -background white -textvariable magic::${pname}_val 1022 grid .params.edits.${pname}_lab -row $numrows -column 0 \ 1023 -sticky ens -ipadx 5 -ipady 2 1024 grid .params.edits.${pname}_ent -row $numrows -column 1 \ 1025 -sticky ewns -ipadx 5 -ipady 2 1026 .params.edits.${pname}_ent insert end $value 1027 set magic::${pname}_val $value 1028} 1029 1030#---------------------------------------------------------- 1031# Default entry callback, without any dependencies. Each 1032# parameter changed 1033#---------------------------------------------------------- 1034 1035proc magic::add_check_callbacks {gencell_type library} { 1036 set wlist [winfo children .params.edits] 1037 foreach w $wlist { 1038 if {[regexp {\.params\.edits\.(.+)_ent} $w valid pname]} { 1039 # Add callback on enter or focus out 1040 bind $w <Return> \ 1041 "magic::update_dialog {} $pname $gencell_type $library" 1042 bind $w <FocusOut> \ 1043 "magic::update_dialog {} $pname $gencell_type $library" 1044 } 1045 } 1046} 1047 1048#---------------------------------------------------------- 1049# Add a dependency between entries. When one updates, the 1050# others will be recomputed according to the callback 1051# function. 1052# 1053# The callback function is passed the value of all 1054# parameters for the device, overridden by the values 1055# in the dialog. The routine computes the dependent 1056# values and writes them back to the parameter dictionary. 1057# The callback function must return the modified parameters 1058# dictionary. 1059# 1060# Also handle dependencies on checkboxes and selection lists 1061#---------------------------------------------------------- 1062 1063proc magic::add_dependency {callback gencell_type library args} { 1064 if {[llength $args] == 0} { 1065 # If no arguments are given, do for all parameters 1066 set parameters ${library}::${gencell_type}_defaults 1067 magic::add_dependency $callback $gencell_type $library \ 1068 {*}[dict keys $parameters] 1069 return 1070 } 1071 set clist [winfo children .params.edits] 1072 foreach pname $args { 1073 if {[lsearch $clist .params.edits.${pname}_ent] >= 0} { 1074 # Add callback on enter or focus out 1075 bind .params.edits.${pname}_ent <Return> \ 1076 "magic::update_dialog $callback $pname $gencell_type $library" 1077 bind .params.edits.${pname}_ent <FocusOut> \ 1078 "magic::update_dialog $callback $pname $gencell_type $library" 1079 } elseif {[lsearch $clist .params.edits.${pname}_chk] >= 0} { 1080 # Add callback on checkbox change state 1081 .params.edits.${pname}_chk configure -command \ 1082 "magic::update_dialog $callback $pname $gencell_type $library" 1083 } elseif {[lsearch $clist .params.edits.${pname}_sel] >= 0} { 1084 set smenu .params.edits.${pname}_sel.menu 1085 set sitems [${smenu} index end] 1086 for {set idx 0} {$idx <= $sitems} {incr idx} { 1087 set curcommand [${smenu} entrycget $idx -command] 1088 ${smenu} entryconfigure $idx -command "$curcommand ; \ 1089 magic::update_dialog $callback $pname $gencell_type $library" 1090 } 1091 } 1092 } 1093} 1094 1095#---------------------------------------------------------- 1096# Execute callback procedure, then run bounds checks 1097#---------------------------------------------------------- 1098 1099proc magic::update_dialog {callback pname gencell_type library} { 1100 set pdefaults [${library}::${gencell_type}_defaults] 1101 set parameters [dict merge $pdefaults [magic::gencell_getparams]] 1102 1103 if {[dict exists $parameters gencell]} { 1104 # Setting special parameter "gencell" forces the gencell to change type 1105 set gencell_type [dict get $parameters gencell] 1106 set pdefaults [${library}::${gencell_type}_defaults] 1107 set parameters [dict merge $pdefaults [magic::gencell_getparams]] 1108 } 1109 1110 if {$callback != {}} { 1111 set parameters [$callback $pname $parameters] 1112 } 1113 if {[catch {set parameters [${library}::${gencell_type}_check $parameters]} \ 1114 checkerr]} { 1115 puts stderr $checkerr 1116 } 1117 magic::gencell_setparams $parameters 1118} 1119 1120#---------------------------------------------------------- 1121# Add a standard checkbox parameter to the gencell window 1122#---------------------------------------------------------- 1123 1124proc magic::add_checkbox {pname ptext parameters} { 1125 1126 if [dict exists $parameters $pname] { 1127 set value [dict get $parameters $pname] 1128 } else { 1129 set value "" 1130 } 1131 1132 set numrows [lindex [grid size .params.edits] 1] 1133 label .params.edits.${pname}_lab -text $ptext 1134 checkbutton .params.edits.${pname}_chk -variable magic::${pname}_val 1135 grid .params.edits.${pname}_lab -row $numrows -column 0 -sticky ens 1136 grid .params.edits.${pname}_chk -row $numrows -column 1 -sticky wns 1137 set magic::${pname}_val $value 1138} 1139 1140#---------------------------------------------------------- 1141# Add a message box (informational, not editable) to the 1142# gencell window. Note that the text does not have to be 1143# in the parameter list, as it can be upated through the 1144# textvariable name. 1145#---------------------------------------------------------- 1146 1147proc magic::add_message {pname ptext parameters {color blue}} { 1148 1149 if [dict exists $parameters $pname] { 1150 set value [dict get $parameters $pname] 1151 } else { 1152 set value "" 1153 } 1154 1155 set numrows [lindex [grid size .params.edits] 1] 1156 label .params.edits.${pname}_lab -text $ptext 1157 label .params.edits.${pname}_txt -text $value \ 1158 -foreground $color -textvariable magic::${pname}_val 1159 grid .params.edits.${pname}_lab -row $numrows -column 0 -sticky ens 1160 grid .params.edits.${pname}_txt -row $numrows -column 1 -sticky wns 1161} 1162 1163#---------------------------------------------------------- 1164# Add a selectable-list parameter to the gencell window 1165#---------------------------------------------------------- 1166 1167proc magic::add_selectlist {pname ptext all_values parameters {itext ""}} { 1168 1169 if [dict exists $parameters $pname] { 1170 set value [dict get $parameters $pname] 1171 } else { 1172 set value $itext 1173 } 1174 1175 set numrows [lindex [grid size .params.edits] 1] 1176 label .params.edits.${pname}_lab -text $ptext 1177 menubutton .params.edits.${pname}_sel -menu .params.edits.${pname}_sel.menu \ 1178 -relief groove -text ${value} 1179 grid .params.edits.${pname}_lab -row $numrows -column 0 -sticky ens 1180 grid .params.edits.${pname}_sel -row $numrows -column 1 -sticky wns 1181 menu .params.edits.${pname}_sel.menu -tearoff 0 1182 foreach item ${all_values} { 1183 .params.edits.${pname}_sel.menu add radio -label $item \ 1184 -variable magic::${pname}_val -value $item \ 1185 -command ".params.edits.${pname}_sel configure -text $item" 1186 } 1187 set magic::${pname}_val $value 1188} 1189 1190#---------------------------------------------------------- 1191# Add a selectable-list parameter to the gencell window 1192# Unlike the routine above, it returns the index of the 1193# selection, not the selection itself. This is useful for 1194# keying the selection to other parameter value lists. 1195#---------------------------------------------------------- 1196 1197proc magic::add_selectindex {pname ptext all_values parameters {ival 0}} { 1198 1199 if [dict exists $parameters $pname] { 1200 set value [dict get $parameters $pname] 1201 } else { 1202 set value $ival 1203 } 1204 1205 set numrows [lindex [grid size .params.edits] 1] 1206 label .params.edits.${pname}_lab -text $ptext 1207 menubutton .params.edits.${pname}_sel -menu .params.edits.${pname}_sel.menu \ 1208 -relief groove -text [lindex ${all_values} ${value}] 1209 grid .params.edits.${pname}_lab -row $numrows -column 0 -sticky ens 1210 grid .params.edits.${pname}_sel -row $numrows -column 1 -sticky wns 1211 menu .params.edits.${pname}_sel.menu -tearoff 0 1212 set idx 0 1213 foreach item ${all_values} { 1214 .params.edits.${pname}_sel.menu add radio -label $item \ 1215 -variable magic::${pname}_val -value $idx \ 1216 -command ".params.edits.${pname}_sel configure -text $item" 1217 incr idx 1218 } 1219 set magic::${pname}_val $value 1220} 1221 1222#------------------------------------------------------------- 1223# gencell_defaults --- 1224# 1225# Set all parameters for a device. Start by calling the base 1226# device's default value list to generate a dictionary. Then 1227# parse all values passed in 'parameters', overriding any 1228# defaults with the passed values. 1229#------------------------------------------------------------- 1230 1231proc magic::gencell_defaults {gencell_type library parameters} { 1232 set basedict [${library}::${gencell_type}_defaults] 1233 set newdict [dict merge $basedict $parameters] 1234 return $newdict 1235} 1236 1237#------------------------------------------------------------- 1238# Command tag callback on "select". "select cell" should 1239# cause the parameter dialog window to update to reflect the 1240# selected cell. If a cell is unselected, then revert to the 1241# default 'Create' window. 1242#------------------------------------------------------------- 1243 1244proc magic::gencell_update {{command {}}} { 1245 if {[info level] <= 1} { 1246 if {![catch {set state [wm state .params]}]} { 1247 if {[wm state .params] == "normal"} { 1248 if {$command == "cell"} { 1249 # If multiple devices are selected, choose the first in 1250 # the list returned by "what -list". 1251 set instname [lindex [lindex [lindex [what -list] 2] 0] 0] 1252 magic::gencell_dialog $instname {} {} {} 1253 } 1254 } 1255 } 1256 } 1257} 1258 1259#------------------------------------------------------------- 1260# gencell_dialog --- 1261# 1262# Create the dialog window for entering device parameters. The 1263# general procedure then calls the dialog setup for the specific 1264# device. 1265# 1266# 1) If gname is NULL and gencell_type is set, then we 1267# create a new cell of type gencell_type. 1268# 2) If gname is non-NULL, then we edit the existing 1269# cell of type $gname. 1270# 3) If gname is non-NULL and gencell_type or library 1271# is NULL or unspecified, then we derive the gencell_type 1272# and library from the existing cell's property strings 1273# 1274# The device setup should be built using the API that defines 1275# these procedures: 1276# 1277# magic::add_entry Single text entry window 1278# magic::add_checkbox Single checkbox 1279# magic::add_selectlist Pull-down menu with list of selections 1280# 1281#------------------------------------------------------------- 1282 1283proc magic::gencell_dialog {instname gencell_type library parameters} { 1284 if {$gencell_type == {}} { 1285 # Revert to default state for the device that was previously 1286 # shown in the parameter window. 1287 if {![catch {set state [wm state .params]}]} { 1288 if {$instname == {}} { 1289 set devstr [.params.title.lab1 cget -text] 1290 if {$devstr == "Edit device:"} { 1291 set gencell_type [.params.title.lab2 cget -text] 1292 set library [.params.title.lab4 cget -text] 1293 } else { 1294 return 1295 } 1296 } 1297 } 1298 } 1299 1300 if {$instname != {}} { 1301 # Remove any array component of the instance name 1302 set instname [string map {\\ ""} $instname] 1303 if {[regexp {^(.*)\[[0-9,]+\]$} $instname valid instroot]} { 1304 set instname $instroot 1305 } 1306 set gname [instance list celldef [subst $instname]] 1307 set gencell_type [cellname list property $gname gencell] 1308 if {$library == {}} { 1309 set library [cellname list property $gname library] 1310 } 1311 if {$parameters == {}} { 1312 set parameters [cellname list property $gname parameters] 1313 } 1314 if {$gencell_type == {} || $library == {}} {return} 1315 1316 if {$parameters == {}} { 1317 set parameters [${library}::${gencell_type}_defaults] 1318 } 1319 1320 # If the default parameters contain "nocell", then set the 1321 # standard parameters for fixed devices from the instance 1322 if {[dict exists $parameters nocell]} { 1323 select cell $instname 1324 set arcount [array -list count] 1325 set arpitch [array -list pitch] 1326 1327 dict set parameters nx [expr [lindex $arcount 1] - [lindex $arcount 0] + 1] 1328 dict set parameters ny [expr [lindex $arcount 3] - [lindex $arcount 2] + 1] 1329 dict set parameters pitchx [lindex $arpitch 0] 1330 dict set parameters pitchy [lindex $arpitch 1] 1331 } 1332 set ttext "Edit device" 1333 set itext $instname 1334 } else { 1335 set parameters [magic::gencell_defaults $gencell_type $library $parameters] 1336 set gname "(default)" 1337 set itext "(default)" 1338 set ttext "New device" 1339 } 1340 1341 # Destroy children, not the top-level window, or else window keeps 1342 # bouncing around every time something is changed. 1343 if {[catch {toplevel .params}]} { 1344 .params.title.lab1 configure -text "${ttext}:" 1345 .params.title.lab2 configure -text "$gencell_type" 1346 .params.title.lab4 configure -text "$library" 1347 .params.title.glab configure -foreground blue -text "$gname" 1348 .params.title.ient delete 0 end 1349 .params.title.ient insert 0 "$itext" 1350 foreach child [winfo children .params.edits] { 1351 destroy $child 1352 } 1353 foreach child [winfo children .params.buttons] { 1354 destroy $child 1355 } 1356 } else { 1357 frame .params.title 1358 label .params.title.lab1 -text "${ttext}:" 1359 label .params.title.lab2 -foreground blue -text "$gencell_type" 1360 label .params.title.lab3 -text "Library:" 1361 label .params.title.lab4 -foreground blue -text "$library" 1362 label .params.title.clab -text "Cellname:" 1363 label .params.title.glab -foreground blue -text "$gname" 1364 label .params.title.ilab -text "Instance:" 1365 entry .params.title.ient -foreground brown -background white 1366 .params.title.ient insert 0 "$itext" 1367 ttk::separator .params.sep 1368 frame .params.edits 1369 frame .params.buttons 1370 1371 grid .params.title.lab1 -padx 5 -row 0 -column 0 1372 grid .params.title.lab2 -padx 5 -row 0 -column 1 -sticky w 1373 grid .params.title.lab3 -padx 5 -row 0 -column 2 1374 grid .params.title.lab4 -padx 5 -row 0 -column 3 -sticky w 1375 1376 grid .params.title.clab -padx 5 -row 1 -column 0 1377 grid .params.title.glab -padx 5 -row 1 -column 1 -sticky w 1378 grid .params.title.ilab -padx 5 -row 1 -column 2 1379 grid .params.title.ient -padx 5 -row 1 -column 3 -sticky ew 1380 grid columnconfigure .params.title 3 -weight 1 1381 1382 pack .params.title -fill x -expand true 1383 pack .params.sep -fill x -expand true 1384 pack .params.edits -side top -fill both -expand true -ipadx 5 1385 pack .params.buttons -fill x 1386 1387 grid columnconfigure .params.edits 1 -weight 1 1388 } 1389 1390 if {$instname == {}} { 1391 button .params.buttons.apply -text "Create" -command \ 1392 [subst {set inst \[magic::gencell_create \ 1393 $gencell_type $library {}\] ; \ 1394 magic::gencell_dialog \$inst $gencell_type $library {} }] 1395 button .params.buttons.okay -text "Create and Close" -command \ 1396 [subst {set inst \[magic::gencell_create \ 1397 $gencell_type $library {}\] ; \ 1398 magic::gencell_dialog \$inst $gencell_type $library {} ; \ 1399 destroy .params}] 1400 } else { 1401 button .params.buttons.apply -text "Apply" -command \ 1402 "magic::gencell_change $instname $gencell_type $library {}" 1403 button .params.buttons.okay -text "Okay" -command \ 1404 "magic::gencell_change $instname $gencell_type $library {} ;\ 1405 destroy .params" 1406 } 1407 button .params.buttons.reset -text "Reset" -command \ 1408 "magic::gencell_dialog {} ${gencell_type} ${library} {}" 1409 button .params.buttons.close -text "Close" -command {destroy .params} 1410 1411 pack .params.buttons.apply -padx 5 -ipadx 5 -ipady 2 -side left 1412 pack .params.buttons.okay -padx 5 -ipadx 5 -ipady 2 -side left 1413 pack .params.buttons.close -padx 5 -ipadx 5 -ipady 2 -side right 1414 pack .params.buttons.reset -padx 5 -ipadx 5 -ipady 2 -side right 1415 1416 # Invoke the callback procedure that creates the parameter entries 1417 1418 ${library}::${gencell_type}_dialog $parameters 1419 1420 # Add standard callback to all entry fields to run parameter bounds checks 1421 magic::add_check_callbacks $gencell_type $library 1422 1423 # Make sure the window is raised 1424 raise .params 1425} 1426 1427#------------------------------------------------------------- 1428