1 #------------------------------------------------------------------------
2 # Synopsys symbol library file parser for XCircuit
3 #------------------------------------------------------------------------
4 # Written by Tim Edwards, Open Circuit Design
5 #------------------------------------------------------------------------
7 # Revision 0: October 23, 2018 by Tim Edwards
8 # copied from edif.tcl and modified.
9 #------------------------------------------------------------------------
11 set XCOps
(module
,synopsys
) 1
13 # "Standard" scaling: Factor of 32 is typical.
18 #------------------------------------------------------------------------
19 # Reverse an xcircuit rotation.
20 #------------------------------------------------------------------------
22 proc rotinvert
{value
} {
23 set newvalue
[expr {360 - $value}]
24 if {$newvalue == 360} {set newvalue
0}
28 #------------------------------------------------------------------------
29 # Scale a value by factor (scalen) / (scaled)
30 #------------------------------------------------------------------------
32 proc scaleval
{value
} {
34 return [expr {int
(0.5 + $value * $Opts(scalen
) / $Opts(scaled
))}]
37 #------------------------------------------------------------------------
38 # Convert arc from center-endpoint-endpoint to center-radius-endpoint
40 #------------------------------------------------------------------------
42 proc convert_arc
{x1 y1 x2 y2 cx cy
} {
44 set r
[expr {sqrt
(($cx - $x1) * ($cx - $x1) + ($cy - $y1) * ($cy - $y1))}]
46 set a1
[expr {atan2
($y1 - $cy, $x1 - $cx)}]
47 set a2
[expr {atan2
($y2 - $cy, $x2 - $cx)}]
49 set a1
[expr {$a1 * 180 / 3.1415927}]
50 set a2
[expr {$a2 * 180 / 3.1415927}]
52 return [list $cx $cy $r $a1 $a2]
55 #------------------------------------------------------------------------
57 #------------------------------------------------------------------------
59 proc quiet_deselect
{} {
60 set handle
[select get
]
61 if {$handle != {}} {deselect
}
64 #------------------------------------------------------------------------
65 # Evaluate the argument as an expression, using name/value pairs from the
67 #------------------------------------------------------------------------
69 proc eval_arg
{argument libdict
} {
70 dict
for {key value
} $libdict {
71 set argument
[eval [subst {string map
{$key $value} \$argument}]]
73 set value
[expr $argument]
77 #------------------------------------------------------------------------
78 # Trim space from either end of the argument and return it.
79 #------------------------------------------------------------------------
81 proc parse_arg
{argument
} {
82 set argument
[string trimright
$argument]
83 set argument
[string trimleft
$argument]
87 #------------------------------------------------------------------------
88 # Parse a set statement
93 # Add the name/value pair to the dictionary "libdict". Note that the
94 # value may be an expression using values from other dictionary keys.
95 # The expression is assumed to be parseable by "eval" (probably true).
96 #------------------------------------------------------------------------
98 proc parse_set_statement
{keyword libdict statement
} {
99 set statement
[parse_arg
$statement]
100 set statement
[string trimright
$statement ";"]
101 set statement
[string trimleft
$statement =]
102 dict
for {key value
} $libdict {
103 set statement
[eval [subst {string map
{$key $value} \$statement}]]
105 dict
set libdict
$keyword [expr $statement]
109 #------------------------------------------------------------------------
110 # Like the parse_set_statement routine, but values are names and
111 # do not involve calculations. The dictionary is separate.
112 #------------------------------------------------------------------------
114 proc parse_assign_statement
{keyword namedict statement
} {
115 set statement
[parse_arg
$statement]
116 set statement
[string trimleft
$statement :]
117 set statement
[string trimleft
$statement]
118 dict
set namedict
$keyword $statement
122 #------------------------------------------------------------------------
123 # Parse a function, which has arguments in parentheses. Parse arguments
124 # according to the function name.
125 #------------------------------------------------------------------------
127 proc parse_function
{funcname libdict argstring
} {
128 set argstring
[parse_arg
$argstring]
129 set argstring
[string trimright
$argstring ";"]
130 set argstring
[string trimright
$argstring]
131 set argstring
[string trimright
$argstring )]
132 set argstring
[string trimleft
$argstring (]
133 set arguments
[split $argstring ,]
140 set_minimum_boundary
{
141 set x1
[scaleval
[eval_arg
[lindex $arguments 0] $libdict]]
142 set y1
[scaleval
[eval_arg
[lindex $arguments 1] $libdict]]
143 set x2
[scaleval
[eval_arg
[lindex $arguments 2] $libdict]]
144 set y2
[scaleval
[eval_arg
[lindex $arguments 3] $libdict]]
145 set handle
[polygon make box
[list $x1 $y1] [list $x2 $y2]]
146 polygon
$handle border bbox
150 set pinname
[parse_arg
[lindex $arguments 0]]
151 set pinx
[scaleval
[eval_arg
[lindex $arguments 1] $libdict]]
152 set piny
[scaleval
[eval_arg
[lindex $arguments 2] $libdict]]
153 set rotation
[parse_arg
[lindex $arguments 3]]
154 # puts stdout "Make pin $pinname"
155 set handle
[label make pin
$pinname [list $pinx $piny]]
158 set x1
[scaleval
[eval_arg
[lindex $arguments 0] $libdict]]
159 set y1
[scaleval
[eval_arg
[lindex $arguments 1] $libdict]]
160 set x2
[scaleval
[eval_arg
[lindex $arguments 2] $libdict]]
161 set y2
[scaleval
[eval_arg
[lindex $arguments 3] $libdict]]
162 # puts stdout "Make line $x1 $y1 $x2 $y2"
163 set handle
[polygon make
2 [list $x1 $y1] [list $x2 $y2]]
166 set x1
[eval_arg
[lindex $arguments 0] $libdict]
167 set y1
[eval_arg
[lindex $arguments 1] $libdict]
168 set x2
[eval_arg
[lindex $arguments 2] $libdict]
169 set y2
[eval_arg
[lindex $arguments 3] $libdict]
170 set cx
[eval_arg
[lindex $arguments 4] $libdict]
171 set cy
[eval_arg
[lindex $arguments 5] $libdict]
172 # puts stdout "Convert arc $x1 $y1 $x2 $y2 $cx $cy"
173 if {![catch {set xca
[convert_arc
$x1 $y1 $x2 $y2 $cx $cy]}]} {
174 set x
[scaleval
[lindex $xca 0]]
175 set y
[scaleval
[lindex $xca 1]]
176 set r
[scaleval
[lindex $xca 2]]
177 set a1
[lindex $xca 3]
178 set a2
[lindex $xca 4]
179 # puts stdout "Make arc $x $y $r $a1 $a2"
180 set handle
[arc make
[list $x $y] $r $a1 $a2]
184 set x1
[scaleval
[eval_arg
[lindex $arguments 0] $libdict]]
185 set y1
[scaleval
[eval_arg
[lindex $arguments 1] $libdict]]
186 set r
[scaleval
[eval_arg
[lindex $arguments 2] $libdict]]
187 # puts stdout "Make circle $x1 $y1 $r"
188 set handle
[arc make
[list $x1 $y1] $r]
193 #------------------------------------------------------------------------
194 # Main file reader routine. Read the file into a list.
195 #------------------------------------------------------------------------
197 proc read_synopsys
{filename} {
199 if [catch {open $filename r
} fileIn
] {
200 puts stderr
"Cannot find file $filename"
204 # Parse the file line-by-line, removing C-style /* ... */ comments
205 # and removing line-continuation backslashes. After reading scale
206 # and snap values from the header, generate symbols as they are
209 set everything
[read $fileIn]
210 # Remove C-style comments
211 regsub -all {[/][*].
*?
[*][/]} $everything "" everything
212 # Remove line-continuation backslashes.
213 set masterlist
[string map
{"\\\n" " "} $everything]
215 set linedata
[split $masterlist \n]
219 # Set up xcircuit for processing
226 # Now parse the file. . .
229 set libdict
[dict create
]
230 set namedict
[dict create
]
233 foreach line
$linedata {
235 if {![regexp {[ \t]*([^
\t\n"\(=]+)(.*)} $line lmatch keyword rest]} {continue}
239 regexp {\([ \t]*["]?
[ \t]*([^
\t"]+)[ \t]*["]?
[ \t]*\)} $rest lmatch libname
240 # If 'libname' is a filename w/extension, then remove the extension
241 set libname
[file root
$libname]
245 puts "Unsupported keyword $keyword"
248 } elseif
{!$in_symbol} {
251 regexp {\([ \t]*["]?[ \t]*([^ \t"]+)[ \t]*["]?[ \t]*\)} $rest lmatch symbolname
254 catch {object [object handle $symbolname] name "_
$symbolname"}
255 set handle [object make ${libname}::${symbolname} -force]
257 puts "Error
: Couldn't create new object
!"
262 symbol type fundamental
269 set namedict [parse_assign_statement $keyword $namedict $rest]
277 set libdict [parse_set_statement $keyword $libdict $rest]
281 parse_function $keyword $libdict $rest
287 puts "Unsupported keyword
$keyword in library definition
"
292 set_minimum_boundary -
297 parse_function $keyword $libdict $rest
302 if [catch {delete $handle}] {
304 if [catch {delete $handle}] {
305 puts "Error
: Element handle
$handle does not exist?
"
306 puts "Page objects
: [object parts
]"
311 puts "Unsupported keyword
$keyword in symbol definition
"
318 # Recompute bounding box on all library objects
319 puts stdout "Computing symbol bounding boxes
"
320 library "User Library
" goto
321 set liblist [library "User Library
" handle]
322 foreach handle $liblist {
323 if {[element $handle type] == "Object Instance
"} {
324 instance $handle bbox recompute
328 # Regenerate the library
329 puts stdout "Composing library page
"
330 library "User Library
" compose
332 # Return to (and redraw) original page
338 #------------------------------------------------------------------------
339 # Procedure that creates the dialog to find a Synopsys symbol library
340 # file to parse and calls procedure read_synopsys.
341 #---------------------------------------------------------------------------
343 proc xcircuit::promptreadsynopsys {} {
345 .filelist.bbar.okay configure -command \
346 {read_synopsys [.filelist.textent.txt get] ; \
347 wm withdraw .filelist}
348 .filelist.listwin.win configure -data "slib synopsys
"
349 .filelist.textent.title.field configure -text \
350 "Select Synopsys symbol library
file to parse
:"
351 .filelist.textent.txt delete 0 end
352 xcircuit::popupfilelist
353 xcircuit::removelists .filelist