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