1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
|
#---------------------------------------------------------------------------
# symbol.tcl ---
#
# xcircuit Tcl script for generating
# a canonical circuit symbol
#
# Tim Edwards 12/1/05 for MultiGiG
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
# Get the info label line declaring the text subcircuit, if one exists.
#---------------------------------------------------------------------------
proc xcircuit::getsubckttext {name} {
global XCOps
set curhandle [object handle]
set handle [page handle $name]
if {$curhandle != $handle} {schematic goto}
set pageparts [object $handle parts]
set itext {}
foreach j $pageparts {
set etype [element $j type]
if {$etype == "Label"} {
set ltype [label $j type]
if {$ltype == "info"} {
set itext [label $j text]
if {[string first ".subckt" $itext] >= 0} {
if {$curhandle != $handle} {symbol goto}
return $itext
}
}
}
}
return ""
}
#---------------------------------------------------------------------------
# Create a matching symbol for a subcircuit page or SPICE file.
#
# This is a replacement for the procedure makesymbol in wrapper.tcl.
# We make a sub-widget to list, change, and reorder the symbol pins,
# similar to the "addliblist" procedure in wrapper.tcl
#
# Modified 1/5/06: If "filename" is non-null, then it points to a SPICE
# netlist containing a subcircuit. A symbol is made to correspond to the
# subcircuit definition, with a link to include the file.
#
# Modified 1/7/06: If "orderedpins" is non-null, then it contains the
# list of pins in proper order.
#---------------------------------------------------------------------------
proc xcircuit::makesymbol {{filename ""} {orderedpins ""}} {
global XCOps
config suspend true ;# suspend graphics and change count
set techname [.dialog.techself.techselect cget -text]
set symbolname [.dialog.textent.txt get]
if {[string length $symbolname] == 0} {
set symbolname [page label]
if {[string length $symbolname] == 0 || [string first "Page " $symbolname] >= 0} {
puts stderr "Symbol/Schematic has no name!"
consoleup
return
}
}
if {[string first :: $symbolname] >= 0} { ;# symbolname has tech name embedded
set techname ""
} elseif {[string first ( $techname] >= 0} { ;# "(user)" specified
set techname "::"
} elseif {[string first :: $techname] < 0} {
set techname "${techname}::"
}
# If "filename" is specified then we have a netlist, not a schematic.
# Therefore, create an object but don't use xcircuit::symbol
if {$filename == ""} {
xcircuit::symbol make ${techname}${symbolname} $XCOps(library);
set schematicname [schematic get]
set noschem 0
} else {
set schematicname $symbolname
set noschem 1
}
set pinspace 64
set halfspace [expr $pinspace / 2]
set qtrspace [expr $pinspace / 4]
# remove the old pin labels
set oldpinlabels [object parts]
foreach j $oldpinlabels {
delete $j
}
set leftpins [.dialog.pinself.left.list index end]
set toppins [.dialog.pinself.top.list index end]
set rightpins [.dialog.pinself.right.list index end]
set botpins [.dialog.pinself.bottom.list index end]
set hpins $leftpins
if {$rightpins > $leftpins} {set hpins $rightpins}
set vpins $toppins
if {$botpins > $toppins} {set vpins $botpins}
set boxwidth [expr ($vpins + 1) * $pinspace]
set boxheight [expr ($hpins + 1) * $pinspace]
set hwidth [expr $boxwidth / 2]
if {$hwidth < 256} {set hwidth 256}
set hheight [expr $boxheight / 2]
if {$hheight < 256} {set hheight 256}
set sbox [polygon make box "-$hwidth -$hheight" "$hwidth $hheight"]
set pinlabels {}
# If we didn't make a symbol using xcircuit::symbol, now is the time
# to generate the object.
if {$noschem == 1} {
select $sbox
set handle [object make ${techname}${symbolname} $XCOps(library)]
push $handle
}
# Ordered right->left->bottom->top, on logical grounds.
set x [expr $hwidth + $qtrspace]
set y [expr -($rightpins - 1) * $halfspace]
for {set j 0} {$j < $rightpins} {incr j} {
set tabx [expr $x - $qtrspace]
polygon make 2 "$x $y" "$tabx $y"
set pintext [.dialog.pinself.right.list get $j]
lappend pinlabels $pintext
set tlab [label make pin "$pintext" "$x $y"]
label $tlab justify left
label $tlab justify middle
set nlab [element $tlab copy relative "-$halfspace 0"]
label $nlab type normal
label $nlab justify right
incr y $pinspace
deselect selected
}
set x [expr -$hwidth - $qtrspace]
set y [expr -($leftpins - 1) * $halfspace]
for {set j 0} {$j < $leftpins} {incr j} {
set tabx [expr $x + $qtrspace]
polygon make 2 "$x $y" "$tabx $y"
set pintext [.dialog.pinself.left.list get $j]
lappend pinlabels $pintext
set tlab [label make pin "$pintext" "$x $y"]
label $tlab justify right
label $tlab justify middle
set nlab [element $tlab copy relative "$halfspace 0"]
label $nlab type normal
label $nlab justify left
incr y $pinspace
deselect selected
}
set y [expr -$hheight -$qtrspace]
set x [expr -($botpins - 1) * $halfspace]
for {set j 0} {$j < $botpins} {incr j} {
set taby [expr $y + $qtrspace]
polygon make 2 "$x $y" "$x $taby"
set pintext [.dialog.pinself.bottom.list get $j]
lappend pinlabels $pintext
set tlab [label make pin "$pintext" "$x $y"]
rotate $tlab 270
label $tlab justify right
label $tlab justify middle
set nlab [element $tlab copy relative "0 $halfspace"]
label $nlab type normal
label $nlab justify left
incr x $pinspace
deselect selected
}
set y [expr $hheight + $qtrspace]
set x [expr -($toppins - 1) * $halfspace]
for {set j 0} {$j < $toppins} {incr j} {
set taby [expr $y - $qtrspace]
polygon make 2 "$x $y" "$x $taby"
set pintext [.dialog.pinself.top.list get $j]
lappend pinlabels $pintext
set tlab [label make pin "$pintext" "$x $y"]
rotate $tlab 90
label $tlab justify right
label $tlab justify middle
set nlab [element $tlab copy relative "0 -$halfspace"]
label $nlab type normal
label $nlab justify left
incr x $pinspace
deselect selected
}
deselect selected
set nlab [label make "$symbolname" {0 0}]
label $nlab justify middle
label $nlab justify center
element $nlab color set blue
deselect selected
parameter make substring index "?"
parameter make substring class "X"
if {$schematicname == $symbolname} {
parameter make substring link "%n"
} else {
parameter make substring link "$schematicname"
}
set nlab [label make "{Parameter class} {Parameter index}" "0 -$pinspace"]
label $nlab justify center
element $nlab color set blue
deselect selected
# Determine if the schematic already has a "subckt" line. If so,
# attempt to arrange the pin ordering from it. If not, create one.
if {$noschem == 1} {
set subckttext ""
set pinlabels $orderedpins
} else {
set subckttext [xcircuit::getsubckttext $schematicname]
}
if {$subckttext == ""} {
set subckttext [list {Text "spice1:.subckt %n"}]
set pstring ""
foreach j $pinlabels {
if {[string length $pstring] > 60} {
lappend subckttext [subst {Text "$pstring"}]
lappend subckttext {Return}
set pstring "+"
}
set pstring [join [list $pstring "$j"]] ;# preserves whitespace
}
lappend subckttext [subst {Text "$pstring"}]
if {$noschem == 0} {
schematic goto
set bbox [join [page bbox all]]
set x [expr ([lindex $bbox 2] + [lindex $bbox 0]) / 2]
set y [expr [lindex $bbox 1] - $pinspace]
set nlab [label make info "$subckttext" "$x $y"]
label $nlab justify center
deselect selected
set y [expr $y - $pinspace]
set nlab [label make info "spice-1:.ends" "$x $y"]
symbol goto
}
set itext [list {Text "spice:"} {Parameter class} {Parameter index}]
set pstring ""
foreach j $pinlabels {
if {[string length $pstring] > 60} {
lappend itext [subst {Text "$pstring"}]
lappend itext {Return}
set pstring "+"
}
set pstring [join [list $pstring "%p$j"]] ;# preserves whitespace
}
set pstring [join [list $pstring "%n"]] ;# preserves whitespace
lappend itext [subst {Text "$pstring"}]
} else {
set itext [list {Text "spice:"} {Parameter class} {Parameter index}]
set pstring ""
foreach j [lrange [lindex $subckttext 0] 2 end] {
if {[string length $pstring] > 60} {
lappend itext [subst {Text "$pstring"}]
lappend itext {Return}
set pstring "+"
}
set pstring [join [list $pstring "%p$j"]] ;# preserves whitespace
}
set pstring [join [list $pstring "%n"]] ;# preserves whitespace
lappend itext [subst {Text "$pstring"}]
}
set y [expr -$hheight - 3 * $pinspace]
deselect selected
set nlab [label make info "$itext" "0 $y"]
label $nlab justify center
if {$noschem == 1} {
deselect selected
if {[string index $filename 0] != "/"} {
set filename [join [concat [pwd] $filename] "/"]
}
set y [expr -$hheight - 4 * $pinspace]
set itext [list {Text "spice@1:%F"}]
lappend itext [subst {Text "$filename"}]
set nlab [label make info "$itext" "0 $y"]
label $nlab justify center
deselect selected
pop
} else {
library $XCOps(library) compose
deselect selected
symbol goto
zoom view
}
config suspend false ;# unlocked state
}
#---------------------------------------------------------------------------
# Get the list of pins for the object. If the schematic has a "subckt"
# line, then we use the pin names from it, in order. If not, then we
# compile a list of all unique pin labels and arrange them in dictionary
# alphabetical order.
#---------------------------------------------------------------------------
proc xcircuit::getpinlist {schematicname} {
global XCOps
set subckttext [xcircuit::getsubckttext $schematicname]
if {$subckttext == {}} {
set pinlist {}
deselect selected
set objlist [object parts]
foreach j $objlist {
set etype [element $j type]
if {$etype == "Label"} {
set ltype [label $j type]
if {$ltype == "local" || $ltype == "global"} {
# Avoid netlist-generated pins by rejecting labels that
# don't start with a font specifier.
set subtype [lindex [lindex [lindex [label $j list] 0] 0] 0]
if {$subtype == "Font"} {
lappend pinlist [label $j text]
}
}
}
}
set pinlist [lsort -unique -dictionary $pinlist]
} else {
set pinlist [lrange [lindex $subckttext 0] 2 end]
}
deselect selected
return $pinlist
}
#---------------------------------------------------------------------------
# Figure out which list has the selection
#---------------------------------------------------------------------------
proc xcircuit::getselectedpinwidget {} {
set w .dialog.pinself.left.list
set result [$w curselection]
if {$result != {}} {return $w}
set w .dialog.pinself.top.list
set result [$w curselection]
if {$result != {}} {return $w}
set w .dialog.pinself.right.list
set result [$w curselection]
if {$result != {}} {return $w}
set w .dialog.pinself.bottom.list
set result [$w curselection]
if {$result != {}} {return $w}
}
#---------------------------------------------------------------------------
# Remove a pin from the pin list
#---------------------------------------------------------------------------
proc xcircuit::removeselectedpin {} {
set w [xcircuit::getselectedpinwidget]
if {$w != {}} {
set idx [$w curselection]
$w delete $idx
}
}
#---------------------------------------------------------------------------
# Move a pin to the left side of the symbol
#---------------------------------------------------------------------------
proc xcircuit::movepinleft {} {
set w [xcircuit::getselectedpinwidget]
if {$w != {}} {
set idx [$w curselection]
set pinname [$w get $idx]
$w delete $idx
.dialog.pinself.left.list insert end $pinname
$w selection set $idx
}
}
#---------------------------------------------------------------------------
# Move a pin to the top side of the symbol
#---------------------------------------------------------------------------
proc xcircuit::movepintop {} {
set w [xcircuit::getselectedpinwidget]
if {$w != {}} {
set idx [$w curselection]
set pinname [$w get $idx]
$w delete $idx
.dialog.pinself.top.list insert end $pinname
$w selection set $idx
}
}
#---------------------------------------------------------------------------
# Move a pin to the right side of the symbol
#---------------------------------------------------------------------------
proc xcircuit::movepinright {} {
set w [xcircuit::getselectedpinwidget]
if {$w != {}} {
set idx [$w curselection]
set pinname [$w get $idx]
$w delete $idx
.dialog.pinself.right.list insert end $pinname
$w selection set $idx
}
}
#---------------------------------------------------------------------------
# Move a pin to the bottom side of the symbol
#---------------------------------------------------------------------------
proc xcircuit::movepinbottom {} {
set w [xcircuit::getselectedpinwidget]
if {$w != {}} {
set idx [$w curselection]
set pinname [$w get $idx]
$w delete $idx
.dialog.pinself.bottom.list insert end $pinname
$w selection set $idx
}
}
#---------------------------------------------------------------------------
# Create the pin arranger widget and add it to the dialog box.
#---------------------------------------------------------------------------
proc xcircuit::addpinarranger {w {pinlist {}}} {
frame ${w}.pinself
frame ${w}.pinself.left
frame ${w}.pinself.top
frame ${w}.pinself.right
frame ${w}.pinself.bottom
label ${w}.pinself.left.title -text "Left Pins"
label ${w}.pinself.top.title -text "Top Pins"
label ${w}.pinself.right.title -text "Right Pins"
label ${w}.pinself.bottom.title -text "Bottom Pins"
listbox ${w}.pinself.left.list
listbox ${w}.pinself.top.list
listbox ${w}.pinself.right.list
listbox ${w}.pinself.bottom.list
pack ${w}.pinself.left.title -side top
pack ${w}.pinself.left.list -side top -fill y -expand true
pack ${w}.pinself.top.title -side top
pack ${w}.pinself.top.list -side top -fill y -expand true
pack ${w}.pinself.right.title -side top
pack ${w}.pinself.right.list -side top -fill y -expand true
pack ${w}.pinself.bottom.title -side top
pack ${w}.pinself.bottom.list -side top -fill y -expand true
grid ${w}.pinself.left -row 0 -column 0 -sticky news -padx 1 -pady 1
grid ${w}.pinself.top -row 0 -column 1 -sticky news -padx 1 -pady 1
grid ${w}.pinself.right -row 0 -column 2 -sticky news -padx 1 -pady 1
grid ${w}.pinself.bottom -row 0 -column 3 -sticky news -padx 1 -pady 1
grid columnconfigure ${w}.pinself 0 -weight 1 -minsize 50
grid columnconfigure ${w}.pinself 1 -weight 1 -minsize 50
grid columnconfigure ${w}.pinself 2 -weight 1 -minsize 50
grid columnconfigure ${w}.pinself 3 -weight 1 -minsize 50
grid rowconfigure ${w}.pinself 0 -weight 1 -minsize 50
# Determine if the pinlist is fixed by either being taken from a "subckt"
# line in a schematic, or being taken from a "subckt" line in a SPICE deck.
# If so, we pass the ordered list to the symbol construction routine, and
# we also prevent symbol pins from being deleted.
if {$pinlist == {}} {
set pinlist [xcircuit::getpinlist [page label]]
if {[xcircuit::getsubckttext [page label]] != {}} {
set orderedpins 1
} else {
set orderedpins 0
}
} else {
set orderedpins 1
}
# Break the pinlist up into 4 parts
set rightpins [expr [llength $pinlist] / 2]
set bottompins [expr [llength $pinlist] - $rightpins]
set leftpins [expr $rightpins / 2]
set rightpins [expr $rightpins - $leftpins]
set toppins [expr $bottompins / 2]
set bottompins [expr $bottompins - $toppins]
incr leftpins $rightpins
incr bottompins $leftpins
incr toppins $bottompins
for {set k 0} {$k < $rightpins} {incr k} {
${w}.pinself.right.list insert end [lindex $pinlist $k]
}
for {} {$k < $leftpins} {incr k} {
${w}.pinself.left.list insert end [lindex $pinlist $k]
}
for {} {$k < $bottompins} {incr k} {
${w}.pinself.bottom.list insert end [lindex $pinlist $k]
}
for {} {$k < $toppins} {incr k} {
${w}.pinself.top.list insert end [lindex $pinlist $k]
}
pack ${w}.pinself -side top -anchor w -padx 20 -pady 5 -fill y -expand true
catch {
if {$orderedpins == 0} {
button ${w}.bbar.remove -text "Remove Pin" -bg beige -command \
{xcircuit::removeselectedpin}
}
button ${w}.bbar.moveleft -text "Move Left" -bg beige -command \
{xcircuit::movepinleft}
button ${w}.bbar.movetop -text "Move Top" -bg beige -command \
{xcircuit::movepintop}
button ${w}.bbar.moveright -text "Move Right" -bg beige -command \
{xcircuit::movepinright}
button ${w}.bbar.movebottom -text "Move Bottom" -bg beige -command \
{xcircuit::movepinbottom}
}
if {$orderedpins == 0} {
pack ${w}.bbar.remove -side left -ipadx 10
}
pack ${w}.bbar.moveleft -side left -ipadx 10
pack ${w}.bbar.movetop -side left -ipadx 10
pack ${w}.bbar.moveright -side left -ipadx 10
pack ${w}.bbar.movebottom -side left -ipadx 10
}
#---------------------------------------------------------------------------
# Remove the pin arranger widget from the dialog box.
#---------------------------------------------------------------------------
proc xcircuit::removepinarranger {w} {
catch {
pack forget ${w}.pinself
destroy ${w}.pinself
pack forget ${w}.bbar.movebottom
pack forget ${w}.bbar.moveright
pack forget ${w}.bbar.movetop
pack forget ${w}.bbar.moveleft
pack forget ${w}.bbar.remove
}
}
#---------------------------------------------------------------------------
# Redefine popupdialog to remove the pin arranger any time it is invoked.
#---------------------------------------------------------------------------
proc xcircuit::popupdialog {} {
xcircuit::removepinarranger .dialog
xcircuit::removelists .dialog
wm deiconify .dialog
focus .dialog.textent.txt
}
#---------------------------------------------------------------------------
# Redefine the procedure for the "Make Matching Symbol" menu button.
#---------------------------------------------------------------------------
proc xcircuit::promptmakesymbol {{name ""}} {
global XCOps
.dialog.bbar.okay configure -command \
{if {[string first "Page " [page label]] >= 0} { \
page label [.dialog.textent.txt get]}; \
xcircuit::makesymbol; \
wm withdraw .dialog}
.dialog.textent.title.field configure -text "Confirm symbol name:"
.dialog.textent.txt delete 0 end
if {[string length $name] == 0 && [string first "Page " [page label]] < 0} {
set name [page label]}
.dialog.textent.txt insert 0 $name
xcircuit::popupdialog
xcircuit::addtechlist .dialog "Technology: "
xcircuit::addliblist .dialog "Place in: "
xcircuit::addpinarranger .dialog
}
#---------------------------------------------------------------------------
# Routine which parses a spice file for the first .subckt line and
# generates a symbol to match, with a "%F" escape pointing to the
# spice file to include.
#---------------------------------------------------------------------------
proc xcircuit::spice2symbol {filename {subcktname ""}} {
global XCOps
set f [open $filename]
set infolabel ""
while {[gets $f line] >= 0} {
set dnline [string tolower $line]
if {[string first .subckt $dnline] == 0} {
while {[gets $f nextline] >= 0} {
if {[string first + $nextline] != 0} {break}
append line [string range $nextline 1 end]
}
set infolabel $line
if {$subcktname == ""} {break}
if {[string compare $subcktname [lindex $infolabel 1]] == 0} {break}
}
}
close $f
if {[string length $infolabel] == 0} {return}
set pinlabels [lrange $infolabel 2 end]
.dialog.bbar.okay configure -command \
"if {[string first {Page } [page label]] >= 0} { \
page label [.dialog.textent.txt get]}; \
xcircuit::makesymbol $filename [list $pinlabels]; \
wm withdraw .dialog"
.dialog.textent.title.field configure -text "Confirm symbol name:"
.dialog.textent.txt delete 0 end
.dialog.textent.txt insert 0 [lindex $infolabel 1]
xcircuit::popupdialog
xcircuit::addliblist .dialog "Place in: "
xcircuit::addpinarranger .dialog $pinlabels
}
#---------------------------------------------------------------------------
# Procedure that creates the dialog to find a spice file to parse and
# calls spice2symbol.
#---------------------------------------------------------------------------
proc xcircuit::promptspicesymbol {} {
global XCOps
.filelist.bbar.okay configure -command \
{xcircuit::spice2symbol [.filelist.textent.txt get] ; \
wm withdraw .filelist}
.filelist.listwin.win configure -data "cir"
.filelist.textent.title.field configure -text "Select spice file to parse:"
.filelist.textent.txt delete 0 end
xcircuit::popupfilelist
xcircuit::removelists .filelist
}
#---------------------------------------------------------------------------
# Add a menu item to invoke promptspicesymbol.
#---------------------------------------------------------------------------
set m .xcircuit.menubar.netlistbutton.netlistmenu
$m insert 7 command -label "SPICE to symbol" -command {xcircuit::promptspicesymbol}
unset m
#---------------------------------------------------------------------------
|