1 #---------------------------------------------------------------------------
4 # xcircuit Tcl script for generating
5 # a canonical circuit symbol
7 # Tim Edwards 12/1/05 for MultiGiG
8 #---------------------------------------------------------------------------
10 #---------------------------------------------------------------------------
11 # Get the info label line declaring the text subcircuit, if one exists.
12 #---------------------------------------------------------------------------
14 proc xcircuit
::getsubckttext {name
} {
17 set curhandle
[object handle
]
18 set handle
[page handle
$name]
19 if {$curhandle != $handle} {schematic goto
}
21 set pageparts
[object
$handle parts
]
24 foreach j
$pageparts {
25 set etype
[element
$j type
]
26 if {$etype == "Label"} {
27 set ltype
[label $j type
]
28 if {$ltype == "info"} {
29 set itext
[label $j text]
30 if {[string first
".subckt" $itext] >= 0} {
31 if {$curhandle != $handle} {symbol goto
}
41 #---------------------------------------------------------------------------
42 # Create a matching symbol for a subcircuit page or SPICE file.
44 # This is a replacement for the procedure makesymbol in wrapper.tcl.
45 # We make a sub-widget to list, change, and reorder the symbol pins,
46 # similar to the "addliblist" procedure in wrapper.tcl
48 # Modified 1/5/06: If "filename" is non-null, then it points to a SPICE
49 # netlist containing a subcircuit. A symbol is made to correspond to the
50 # subcircuit definition, with a link to include the file.
52 # Modified 1/7/06: If "orderedpins" is non-null, then it contains the
53 # list of pins in proper order.
54 #---------------------------------------------------------------------------
56 proc xcircuit
::makesymbol {{filename ""} {orderedpins
""}} {
59 config suspend true
;# suspend graphics and change count
61 set techname
[.makesymbol.techself.techselect cget
-text]
62 set symbolname
[.makesymbol.textent.txt get
]
63 if {[string length
$symbolname] == 0} {
64 set symbolname
[page
label]
65 if {[string length
$symbolname] == 0 ||
[string first
"Page " $symbolname] >= 0} {
66 puts stderr
"Symbol/Schematic has no name!"
72 if {[string first
:: $symbolname] >= 0} { ;# symbolname has tech name embedded
74 } elseif
{[string first
( $techname] >= 0} { ;# "(user)" specified
76 } elseif
{[string first
:: $techname] < 0} {
77 set techname
"${techname}::"
80 # If "filename" is specified then we have a netlist, not a schematic.
81 # Therefore, create an object but don't use xcircuit::symbol
83 if {$filename == ""} {
85 xcircuit
::symbol make
${techname
}${symbolname
} $XCOps(library
);
86 set schematicname
[schematic get
]
89 set schematicname
$symbolname
94 set halfspace
[expr $pinspace / 2]
95 set qtrspace
[expr $pinspace / 4]
97 # remove the old pin labels
99 set oldpinlabels
[object parts
]
100 foreach j
$oldpinlabels {
103 set leftpins
[.makesymbol.pinself.left.
list index end
]
104 set toppins
[.makesymbol.pinself.top.
list index end
]
105 set rightpins
[.makesymbol.pinself.right.
list index end
]
106 set botpins
[.makesymbol.pinself.bottom.
list index end
]
109 if {$rightpins > $leftpins} {set hpins
$rightpins}
111 if {$botpins > $toppins} {set vpins
$botpins}
113 set boxwidth
[expr ($vpins + 1) * $pinspace]
114 set boxheight
[expr ($hpins + 1) * $pinspace]
116 set hwidth
[expr $boxwidth / 2]
117 if {$hwidth < 256} {set hwidth
256}
118 set hheight
[expr $boxheight / 2]
119 if {$hheight < 256} {set hheight
256}
121 set sbox
[polygon make box
"-$hwidth -$hheight" "$hwidth $hheight"]
124 # If we didn't make a symbol using xcircuit::symbol, now is the time
125 # to generate the object.
129 set handle
[object make
${techname
}${symbolname
} $XCOps(library
)]
133 # Ordered right->left->bottom->top, on logical grounds.
135 set x
[expr $hwidth + $qtrspace]
136 set y
[expr -($rightpins - 1) * $halfspace]
137 for {set j
0} {$j < $rightpins} {incr j
} {
138 set tabx
[expr $x - $qtrspace]
139 polygon make
2 "$x $y" "$tabx $y"
140 set pintext
[.makesymbol.pinself.right.
list get
$j]
141 lappend pinlabels
$pintext
142 set tlab
[label make pin
"$pintext" "$x $y"]
143 label $tlab anchor left
144 label $tlab anchor middle
145 set nlab
[element
$tlab copy relative
"-$halfspace 0"]
146 label $nlab type normal
147 label $nlab anchor right
151 set x
[expr -$hwidth - $qtrspace]
152 set y
[expr -($leftpins - 1) * $halfspace]
153 for {set j
0} {$j < $leftpins} {incr j
} {
154 set tabx
[expr $x + $qtrspace]
155 polygon make
2 "$x $y" "$tabx $y"
156 set pintext
[.makesymbol.pinself.left.
list get
$j]
157 lappend pinlabels
$pintext
158 set tlab
[label make pin
"$pintext" "$x $y"]
159 label $tlab anchor right
160 label $tlab anchor middle
161 set nlab
[element
$tlab copy relative
"$halfspace 0"]
162 label $nlab type normal
163 label $nlab anchor left
167 set y
[expr -$hheight -$qtrspace]
168 set x
[expr -($botpins - 1) * $halfspace]
169 for {set j
0} {$j < $botpins} {incr j
} {
170 set taby
[expr $y + $qtrspace]
171 polygon make
2 "$x $y" "$x $taby"
172 set pintext
[.makesymbol.pinself.bottom.
list get
$j]
173 lappend pinlabels
$pintext
174 set tlab
[label make pin
"$pintext" "$x $y"]
176 label $tlab anchor right
177 label $tlab anchor middle
178 set nlab
[element
$tlab copy relative
"0 $halfspace"]
179 label $nlab type normal
180 label $nlab anchor left
184 set y
[expr $hheight + $qtrspace]
185 set x
[expr -($toppins - 1) * $halfspace]
186 for {set j
0} {$j < $toppins} {incr j
} {
187 set taby
[expr $y - $qtrspace]
188 polygon make
2 "$x $y" "$x $taby"
189 set pintext
[.makesymbol.pinself.top.
list get
$j]
190 lappend pinlabels
$pintext
191 set tlab
[label make pin
"$pintext" "$x $y"]
193 label $tlab anchor right
194 label $tlab anchor middle
195 set nlab
[element
$tlab copy relative
"0 -$halfspace"]
196 label $nlab type normal
197 label $nlab anchor left
203 set nlab
[label make
"$symbolname" {0 0}]
204 label $nlab anchor middle
205 label $nlab anchor center
206 element
$nlab color
set blue
209 parameter make substring index
"?"
210 parameter make substring class
"X"
211 if {$schematicname == $symbolname} {
212 parameter make substring link
"%n"
214 parameter make substring link
"$schematicname"
217 set nlab
[label make
"{Parameter class} {Parameter index}" "0 -$pinspace"]
218 label $nlab anchor center
219 element
$nlab color
set blue
222 # Determine if the schematic already has a "subckt" line. If so,
223 # attempt to arrange the pin ordering from it. If not, create one.
226 set pinlabels
$orderedpins
228 set subckttext
[xcircuit
::getsubckttext $schematicname]
231 if {$subckttext == ""} {
232 set subckttext
[list {Text
"spice1:.subckt %n"}]
234 foreach j
$pinlabels {
235 if {[string length
$pstring] > 60} {
236 lappend subckttext
[subst {Text
"$pstring"}]
237 lappend subckttext
{Return
}
240 set pstring
[join [list $pstring "$j"]] ;# preserves whitespace
242 lappend subckttext
[subst {Text
"$pstring"}]
246 set bbox
[join [page bbox all
]]
247 set x
[expr ([lindex $bbox 2] + [lindex $bbox 0]) / 2]
248 set y
[expr [lindex $bbox 1] - $pinspace]
249 set nlab
[label make
info "$subckttext" "$x $y"]
250 label $nlab anchor center
252 set y
[expr $y - $pinspace]
253 set nlab
[label make
info "spice-1:.ends" "$x $y"]
257 set itext
[list {Text
"spice:"} {Parameter class
} {Parameter index
}]
259 foreach j
$pinlabels {
260 if {[string length
$pstring] > 60} {
261 lappend itext
[subst {Text
"$pstring"}]
262 lappend itext
{Return
}
265 set pstring
[join [list $pstring "%p$j"]] ;# preserves whitespace
267 set pstring
[join [list $pstring "%n"]] ;# preserves whitespace
268 lappend itext
[subst {Text
"$pstring"}]
270 set itext
[list {Text
"spice:"} {Parameter class
} {Parameter index
}]
272 foreach j
[lrange [lindex $subckttext 0] 2 end
] {
273 if {[string length
$pstring] > 60} {
274 lappend itext
[subst {Text
"$pstring"}]
275 lappend itext
{Return
}
278 set pstring
[join [list $pstring "%p$j"]] ;# preserves whitespace
280 set pstring
[join [list $pstring "%n"]] ;# preserves whitespace
281 lappend itext
[subst {Text
"$pstring"}]
284 set y
[expr -$hheight - 3 * $pinspace]
287 set nlab
[label make
info "$itext" "0 $y"]
288 label $nlab anchor center
292 if {[string index
$filename 0] != "/"} {
293 set filename [join [concat [pwd] $filename] "/"]
295 set y
[expr -$hheight - 4 * $pinspace]
296 set itext
[list {Text
"spice@1:%F"}]
297 lappend itext
[subst {Text
"$filename"}]
298 set nlab
[label make
info "$itext" "0 $y"]
299 label $nlab anchor center
303 library
$XCOps(library
) compose
309 config suspend false
;# unlocked state
312 #---------------------------------------------------------------------------
313 # Get the list of pins for the object. If the schematic has a "subckt"
314 # line, then we use the pin names from it, in order. If not, then we
315 # compile a list of all unique pin labels and arrange them in dictionary
316 # alphabetical order.
317 #---------------------------------------------------------------------------
319 proc xcircuit
::getpinlist {schematicname
} {
322 set subckttext
[xcircuit
::getsubckttext $schematicname]
324 if {$subckttext == {}} {
327 set objlist
[object parts
]
330 set etype
[element
$j type
]
331 if {$etype == "Label"} {
332 set ltype
[label $j type
]
333 if {$ltype == "local" ||
$ltype == "global"} {
335 # Avoid netlist-generated pins by rejecting labels that
336 # don't start with a font specifier.
338 set subtype
[lindex [lindex [lindex [label $j list] 0] 0] 0]
339 if {$subtype == "Font"} {
340 lappend pinlist
[label $j text]
345 set pinlist
[lsort -unique -dictionary $pinlist]
347 set pinlist
[lrange [lindex $subckttext 0] 2 end
]
353 #---------------------------------------------------------------------------
354 # Figure out which list has the selection
355 #---------------------------------------------------------------------------
357 proc xcircuit
::getselectedpinwidget {} {
358 set w .makesymbol.pinself.left.
list
359 set result
[$w curselection
]
360 if {$result != {}} {return $w}
362 set w .makesymbol.pinself.top.
list
363 set result
[$w curselection
]
364 if {$result != {}} {return $w}
366 set w .makesymbol.pinself.right.
list
367 set result
[$w curselection
]
368 if {$result != {}} {return $w}
370 set w .makesymbol.pinself.bottom.
list
371 set result
[$w curselection
]
372 if {$result != {}} {return $w}
375 #---------------------------------------------------------------------------
376 # Remove a pin from the pin list
377 #---------------------------------------------------------------------------
379 proc xcircuit
::removeselectedpin {} {
380 set w
[xcircuit
::getselectedpinwidget]
382 set idx
[$w curselection
]
387 #---------------------------------------------------------------------------
388 # Move a pin to the left side of the symbol
389 #---------------------------------------------------------------------------
391 proc xcircuit
::movepinleft {} {
392 set w
[xcircuit
::getselectedpinwidget]
394 set idx
[$w curselection
]
395 set pinname
[$w get
$idx]
397 .makesymbol.pinself.left.
list insert end
$pinname
398 $w selection set $idx
402 #---------------------------------------------------------------------------
403 # Move a pin to the top side of the symbol
404 #---------------------------------------------------------------------------
406 proc xcircuit
::movepintop {} {
407 set w
[xcircuit
::getselectedpinwidget]
409 set idx
[$w curselection
]
410 set pinname
[$w get
$idx]
412 .makesymbol.pinself.top.
list insert end
$pinname
413 $w selection set $idx
418 #---------------------------------------------------------------------------
419 # Move a pin to the right side of the symbol
420 #---------------------------------------------------------------------------
422 proc xcircuit
::movepinright {} {
423 set w
[xcircuit
::getselectedpinwidget]
425 set idx
[$w curselection
]
426 set pinname
[$w get
$idx]
428 .makesymbol.pinself.right.
list insert end
$pinname
429 $w selection set $idx
433 #---------------------------------------------------------------------------
434 # Move a pin to the bottom side of the symbol
435 #---------------------------------------------------------------------------
437 proc xcircuit
::movepinbottom {} {
438 set w
[xcircuit
::getselectedpinwidget]
440 set idx
[$w curselection
]
441 set pinname
[$w get
$idx]
443 .makesymbol.pinself.bottom.
list insert end
$pinname
444 $w selection set $idx
448 #---------------------------------------------------------------------------
449 # Create the pin arranger widget and add it to the dialog box.
450 #---------------------------------------------------------------------------
452 proc xcircuit
::addpinarranger {w
{pinlist
{}}} {
455 frame ${w
}.pinself.left
456 frame ${w
}.pinself.top
457 frame ${w
}.pinself.right
458 frame ${w
}.pinself.bottom
460 label ${w
}.pinself.left.title
-text "Left Pins"
461 label ${w
}.pinself.top.title
-text "Top Pins"
462 label ${w
}.pinself.right.title
-text "Right Pins"
463 label ${w
}.pinself.bottom.title
-text "Bottom Pins"
465 listbox ${w
}.pinself.left.
list
466 listbox ${w
}.pinself.top.
list
467 listbox ${w
}.pinself.right.
list
468 listbox ${w
}.pinself.bottom.
list
470 pack ${w
}.pinself.left.title
-side top
471 pack ${w
}.pinself.left.
list -side top
-fill y
-expand true
472 pack ${w
}.pinself.top.title
-side top
473 pack ${w
}.pinself.top.
list -side top
-fill y
-expand true
474 pack ${w
}.pinself.right.title
-side top
475 pack ${w
}.pinself.right.
list -side top
-fill y
-expand true
476 pack ${w
}.pinself.bottom.title
-side top
477 pack ${w
}.pinself.bottom.
list -side top
-fill y
-expand true
479 grid ${w
}.pinself.left
-row 0 -column 0 -sticky news
-padx 1 -pady 1
480 grid ${w
}.pinself.top
-row 0 -column 1 -sticky news
-padx 1 -pady 1
481 grid ${w
}.pinself.right
-row 0 -column 2 -sticky news
-padx 1 -pady 1
482 grid ${w
}.pinself.bottom
-row 0 -column 3 -sticky news
-padx 1 -pady 1
484 grid columnconfigure
${w
}.pinself
0 -weight 1 -minsize 50
485 grid columnconfigure
${w
}.pinself
1 -weight 1 -minsize 50
486 grid columnconfigure
${w
}.pinself
2 -weight 1 -minsize 50
487 grid columnconfigure
${w
}.pinself
3 -weight 1 -minsize 50
489 grid rowconfigure
${w
}.pinself
0 -weight 1 -minsize 50
491 # Determine if the pinlist is fixed by either being taken from a "subckt"
492 # line in a schematic, or being taken from a "subckt" line in a SPICE deck.
493 # If so, we pass the ordered list to the symbol construction routine, and
494 # we also prevent symbol pins from being deleted.
496 config suspend true
;# suspend graphics and change count
498 if {$pinlist == {}} {
499 set pinlist
[xcircuit
::getpinlist [page
label]]
500 if {[xcircuit
::getsubckttext [page
label]] != {}} {
509 # Break the pinlist up into 4 parts
511 set rightpins
[expr [llength $pinlist] / 2]
512 set bottompins
[expr [llength $pinlist] - $rightpins]
513 set leftpins
[expr $rightpins / 2]
514 set rightpins
[expr $rightpins - $leftpins]
515 set toppins
[expr $bottompins / 2]
516 set bottompins
[expr $bottompins - $toppins]
517 incr leftpins
$rightpins
518 incr bottompins
$leftpins
519 incr toppins
$bottompins
521 for {set k
0} {$k < $rightpins} {incr k
} {
522 ${w
}.pinself.right.
list insert end
[lindex $pinlist $k]
524 for {} {$k < $leftpins} {incr k
} {
525 ${w
}.pinself.left.
list insert end
[lindex $pinlist $k]
527 for {} {$k < $bottompins} {incr k
} {
528 ${w
}.pinself.bottom.
list insert end
[lindex $pinlist $k]
530 for {} {$k < $toppins} {incr k
} {
531 ${w
}.pinself.top.
list insert end
[lindex $pinlist $k]
534 pack ${w
}.pinself
-side top
-anchor w
-padx 20 -pady 5 -fill y
-expand true
537 if {$orderedpins == 0} {
538 button ${w
}.bbar.remove
-text "Remove Pin" -bg beige
-command \
539 {xcircuit
::removeselectedpin}
541 button ${w
}.bbar.moveleft
-text "Move Left" -bg beige
-command \
542 {xcircuit
::movepinleft}
543 button ${w
}.bbar.movetop
-text "Move Top" -bg beige
-command \
544 {xcircuit
::movepintop}
545 button ${w
}.bbar.moveright
-text "Move Right" -bg beige
-command \
546 {xcircuit
::movepinright}
547 button ${w
}.bbar.movebottom
-text "Move Bottom" -bg beige
-command \
548 {xcircuit
::movepinbottom}
552 if {$orderedpins == 0} {
553 pack ${w
}.bbar.remove
-side left
-ipadx 10
555 pack ${w
}.bbar.moveleft
-side left
-ipadx 10
556 pack ${w
}.bbar.movetop
-side left
-ipadx 10
557 pack ${w
}.bbar.moveright
-side left
-ipadx 10
558 pack ${w
}.bbar.movebottom
-side left
-ipadx 10
561 #---------------------------------------------------------------------------
562 # Remove the pin arranger widget from the dialog box.
563 #---------------------------------------------------------------------------
565 proc xcircuit
::removepinarranger {w
} {
567 pack forget
${w
}.pinself
569 pack forget
${w
}.bbar.movebottom
570 pack forget
${w
}.bbar.moveright
571 pack forget
${w
}.bbar.movetop
572 pack forget
${w
}.bbar.moveleft
573 pack forget
${w
}.bbar.remove
577 #---------------------------------------------------------------------------
578 # Redefine the procedure for the "Make Matching Symbol" menu button.
579 #---------------------------------------------------------------------------
581 proc xcircuit
::promptmakesymbol {{name
""}} {
583 .makesymbol.bbar.okay configure
-command \
584 {if {[string first
"Page " [page
label]] >= 0} { \
585 page
label [.makesymbol.textent.txt get
]}; \
586 xcircuit
::makesymbol; \
587 wm withdraw .makesymbol
}
588 .makesymbol.textent.title.field configure
-text "Confirm symbol name:"
589 .makesymbol.textent.txt delete
0 end
590 if {[string length
$name] == 0 && [string first
"Page " [page
label]] < 0} {
591 set name
[page
label]}
592 .makesymbol.textent.txt insert
0 $name
594 xcircuit
::popupdialog .makesymbol
595 xcircuit
::addtechlist .makesymbol
"Technology: "
596 xcircuit
::addliblist .makesymbol
"Place in: "
597 xcircuit
::addpinarranger .makesymbol
600 #---------------------------------------------------------------------------
601 # Routine which parses a spice file for the first .subckt line and
602 # generates a symbol to match, with a "%F" escape pointing to the
603 # spice file to include.
604 #---------------------------------------------------------------------------
606 proc xcircuit
::spice2symbol {filename {subcktname
""}} {
609 set f
[open $filename]
611 while {[gets $f line
] >= 0} {
612 set dnline
[string tolower
$line]
613 if {[string first .subckt
$dnline] == 0} {
614 while {[gets $f nextline
] >= 0} {
615 if {[string first
+ $nextline] != 0} {break}
616 append line
[string range
$nextline 1 end
]
619 if {$subcktname == ""} {break}
620 if {[string compare
$subcktname [lindex $infolabel 1]] == 0} {break}
625 if {[string length
$infolabel] == 0} {return}
626 set pinlabels
[lrange $infolabel 2 end
]
628 .makesymbol.bbar.okay configure
-command \
629 "if {[string first {Page } [page label]] >= 0} { \
630 page label [.makesymbol.textent.txt get]}; \
631 xcircuit::makesymbol $filename [list $pinlabels]; \
632 wm withdraw .makesymbol"
633 .makesymbol.textent.title.field configure
-text "Confirm symbol name:"
634 .makesymbol.textent.txt delete
0 end
635 .makesymbol.textent.txt insert
0 [lindex $infolabel 1]
636 xcircuit
::popupdialog .makesymbol
637 xcircuit
::addliblist .makesymbol
"Place in: "
638 xcircuit
::addpinarranger .makesymbol
$pinlabels
641 #---------------------------------------------------------------------------
642 # Procedure that creates the dialog to find a spice file to parse and
643 # calls spice2symbol.
644 #---------------------------------------------------------------------------
646 proc xcircuit
::promptspicesymbol {} {
648 .filelist.bbar.okay configure
-command \
649 {xcircuit
::spice2symbol [.filelist.textent.txt get
] ; \
650 wm withdraw .filelist
}
651 .filelist.listwin.win configure
-data "cir"
652 .filelist.textent.title.field configure
-text "Select spice file to parse:"
653 .filelist.textent.txt delete
0 end
654 xcircuit
::popupfilelist
655 xcircuit
::removelists .filelist
658 #---------------------------------------------------------------------------
659 # Add a menu item to invoke promptspicesymbol.
660 #---------------------------------------------------------------------------
662 set m .xcircuit.menubar.netlistbutton.netlistmenu
663 $m insert
7 command
-label "SPICE to symbol" -command {xcircuit
::promptspicesymbol}
666 #---------------------------------------------------------------------------