One more check on valid display which is known to be in the startup
[xcircuit.git] / lib / tcl / synopsys.tcl
blob878f6e17682eeb02811ca12b67c397cfd3eea81d
1 #------------------------------------------------------------------------
2 # Synopsys symbol library file parser for XCircuit
3 #------------------------------------------------------------------------
4 # Written by Tim Edwards, Open Circuit Design
5 #------------------------------------------------------------------------
6 # Revision history:
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.
15 set Opts(scalen) 32
16 set Opts(scaled) 1
18 #------------------------------------------------------------------------
19 # Reverse an xcircuit rotation.
20 #------------------------------------------------------------------------
22 proc rotinvert {value} {
23 set newvalue [expr {360 - $value}]
24 if {$newvalue == 360} {set newvalue 0}
25 return $newvalue
28 #------------------------------------------------------------------------
29 # Scale a value by factor (scalen) / (scaled)
30 #------------------------------------------------------------------------
32 proc scaleval {value} {
33 global Opts
34 return [expr {int(0.5 + $value * $Opts(scalen) / $Opts(scaled))}]
37 #------------------------------------------------------------------------
38 # Convert arc from center-endpoint-endpoint to center-radius-endpoint
39 # angles
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 #------------------------------------------------------------------------
56 # Quiet deselection
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
66 # dictionary libdict.
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]
74 return $value
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]
84 return $argument
87 #------------------------------------------------------------------------
88 # Parse a set statement
89 # name = value ;
90 # or
91 # name : value
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]
106 return $libdict
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
119 return $namedict
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 ,]
135 switch $funcname {
136 set_route_grid {
138 set_meter_scale {
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
147 deselect
149 pin {
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]]
157 line {
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]]
165 arc {
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]
183 circle {
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"
201 return;
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
207 # encountered.
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]
214 unset everything
215 set linedata [split $masterlist \n]
216 unset masterlist
217 close $fileIn
219 # Set up xcircuit for processing
221 set cpage [page]
222 config suspend true
223 set in_library false
224 set in_symbol false
226 # Now parse the file. . .
228 set libname ""
229 set libdict [dict create]
230 set namedict [dict create]
231 set lineno 0
232 set cpage 1
233 foreach line $linedata {
234 incr lineno
235 if {![regexp {[ \t]*([^ \t\n"\(=]+)(.*)} $line lmatch keyword rest]} {continue}
236 if {!$in_library} {
237 switch $keyword {
238 library {
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]
242 set in_library true
244 default {
245 puts "Unsupported keyword $keyword"
248 } elseif {!$in_symbol} {
249 switch $keyword {
250 symbol {
251 regexp {\([ \t]*["]?[ \t]*([^ \t"]+)[ \t]*["]?[ \t]*\)} $rest lmatch symbolname
252 set in_symbol true
254 catch {object [object handle $symbolname] name "_$symbolname"}
255 set handle [object make ${libname}::${symbolname} -force]
256 if {$handle == ""} {
257 puts "Error: Couldn't create new object!"
258 return
260 set cpage [page]
261 push $handle
262 symbol type fundamental
264 logic_1_symbol -
265 logic_0_symbol -
266 in_port_symbol -
267 out_port_symbol -
268 inout_port_symbol {
269 set namedict [parse_assign_statement $keyword $namedict $rest]
271 SYMBOLU_PER_UU -
272 METER_PER_UU -
273 ROUTE_GRID -
274 SNAP_SPACE -
275 SCALE -
276 METER_SCALE {
277 set libdict [parse_set_statement $keyword $libdict $rest]
279 set_route_grid -
280 set_meter_scale {
281 parse_function $keyword $libdict $rest
283 \} {
284 set in_library false
286 default {
287 puts "Unsupported keyword $keyword in library definition"
290 } else {
291 switch $keyword {
292 set_minimum_boundary -
293 pin -
294 line -
295 arc -
296 circle {
297 parse_function $keyword $libdict $rest
299 \} {
300 set in_symbol false
302 if [catch {delete $handle}] {
303 page $cpage
304 if [catch {delete $handle}] {
305 puts "Error: Element handle $handle does not exist?"
306 puts "Page objects: [object parts]"
310 default {
311 puts "Unsupported keyword $keyword in symbol definition"
316 unset linedata
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
333 page $cpage
334 zoom view
335 config suspend false
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 {} {
344 global XCOps
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