1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: ioedifo.c
6 * Input/output tool: EDIF netlist generator
7 * Written by: Steven M. Rubin, Static Free Software
8 * Modifications and extensions by B G West and G. Lawson
9 *
10 * Copyright (c) 2000 Static Free Software.
11 *
12 * Electric(tm) is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * Electric(tm) is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with Electric(tm); see the file COPYING. If not, write to
24 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
25 * Boston, Mass 02111-1307, USA.
26 *
27 * Static Free Software
28 * 4119 Alpine Road
29 * Portola Valley, California 94028
30 * info@staticfreesoft.com
31 */
32
33 #include "config.h"
34 #include "global.h"
35 #include "efunction.h"
36 #include "eio.h"
37 #include "egraphics.h"
38 #include "tech.h"
39 #include "tecgen.h"
40 #include "tecschem.h"
41 #include "network.h"
42 #include "usr.h"
43 #include "edialogs.h"
44 #include <math.h>
45
46 #define WORD 256
47 #define MAXDEPTH 40
48 #define LINE 1024
49
50 #define GETBLANKS(C, M) (C ? x_("") : &io_edifo_blanks[sizeof(io_edifo_blanks)-(M)-1])
51 #define DOSPACE (stream->compress ? x_("") : x_(" "))
52 #define NOEO_STREAM ((struct _eo_stream *)0)
53
54 /* primary stream structure */
55 typedef enum { EO_OPENED, EO_CLOSED, EO_TCLOSED } EO_FSTATE;
56 typedef struct _eo_stream
57 {
58 CHAR *filename; /* the file name */
59 FILE *file; /* the opened stream */
60 EO_FSTATE state; /* the file state */
61 INTBIG fpos; /* the saved file position */
62 CHAR *blkstack[MAXDEPTH]; /* the stream keyword stack */
63 INTBIG blkstack_ptr; /* the current position */
64 struct _eo_stream *next; /* the next stream file */
65 INTBIG compress; /* the compress flag */
66 } EO_STREAM, *EO_STREAM_PTR;
67
68 static CHAR *io_edifoextlibname[WORD+1];
69 static INTBIG io_edifoextlibcount;
70 static INTBIG io_edifo_gateindex;
71 static CHAR io_edifo_blanks[] = {x_(" ")};
72
73 /* globals for SCHEMATIC View */
74 static INTBIG schematic_view = 0;
75 static double schematic_scale = 1.0;
76 typedef enum
77 {
78 EGUNKNOWN = 0,
79 EGART = 1,
80 EGTEXT = 2,
81 EGWIRE = 3,
82 EGBUS = 4
83 } _egraphic;
84 static _egraphic egraphic = EGUNKNOWN;
85 static _egraphic egraphic_override = EGUNKNOWN;
86 static CHAR *egraphic_text[5] = {x_("UNKNOWN"), x_("ARTWORK"), x_("TEXT"), x_("WIRE"), x_("BUS")};
87 static EO_STREAM_PTR edif_stream;
88
89 /* prototypes for local routines */
90 static INTBIG io_edif_scale(INTBIG val);
91 static INTBIG io_edifsearch(NODEPROTO *np);
92 static void io_edifextsearch(NODEPROTO *np);
93 static CHAR *io_ediffind_path(NODEPROTO *np);
94 static void io_edifwriteprim(NODEPROTO *np, INTBIG i, INTBIG fun);
95 static CHAR *io_edif_orientation(NODEINST *ni);
96 static CHAR *io_edifwritecompname(NODEINST *ni, INTBIG fun, INTBIG serindex);
97 static void io_edif_pt(INTBIG x, INTBIG y);
98 static BOOLEAN io_edifwritecell(NODEPROTO *np, INTBIG external);
99 static CHAR *io_edifdescribepriminst(NODEINST *ni, INTBIG fun);
100 static BOOLEAN io_edifisglobal(PORTPROTO *pp);
101 static INTBIG io_edifmarknetports(NODEPROTO *np);
102 static BOOLEAN io_edifwritelibext(NODEPROTO *np);
103 static CHAR *io_ediftoken(CHAR *str);
104 static CHAR io_edifnotwhitespace(CHAR ch);
105 static BOOLEAN io_edifvalid(CHAR ch);
106 static CHAR *io_edifvalidname(VARIABLE *var);
107 static BOOLEAN io_edifwritefootprint(NODEPROTO *np, CHAR *name, INTBIG routegrid);
108 static BOOLEAN io_edifwriteportpositions(PORTPROTO *pp, INTBIG cellx, INTBIG celly,
109 CHAR *accessrules, INTBIG routegrid);
110 static CHAR *io_ediflowerstring(CHAR *str);
111 static CHAR *io_edifupperstring(CHAR *str);
112 static void io_edifsymbol(NODEPROTO *np);
113 static void io_edifsymbol_cell(NODEINST *ni, XARRAY prevtrans);
114 static void io_edifsymbol_nodeinst(NODEINST *ni, XARRAY prevtrans);
115 static void io_edifsymbol_arcinst(ARCINST *ai, XARRAY trans);
116 static void io_edifsetgraphic(_egraphic type);
117 static INTBIG io_edifsymbol_showpoly(POLYGON *obj);
118 static EO_STREAM_PTR EO_open_stream(CHAR *, INTBIG);
119 static INTBIG EO_close_stream(EO_STREAM_PTR);
120 static INTBIG EO_open_block(EO_STREAM_PTR, CHAR *);
121 static INTBIG EO_put_block(EO_STREAM_PTR, CHAR *, CHAR *);
122 static INTBIG EO_put_identifier(EO_STREAM_PTR, CHAR *);
123 static INTBIG EO_put_string(EO_STREAM_PTR, CHAR *);
124 static INTBIG EO_put_integer(EO_STREAM_PTR, INTBIG);
125 static INTBIG EO_put_float(EO_STREAM_PTR, double);
126 static INTBIG EO_put_header(EO_STREAM_PTR, CHAR *, CHAR *, CHAR *);
127 static INTBIG EO_close_block(EO_STREAM_PTR, CHAR *);
128 static EO_STREAM_PTR EO_alloc_stream(void);
129 static INTBIG EO_free_stream(EO_STREAM_PTR);
130 static CHAR *EO_get_timestamp(void);
131 static CHAR *EO_make_string(CHAR *);
132 static CHAR *EO_get_exp(double);
133 static void io_edifoptionsdlog(void);
134
135 void io_compute_center(INTBIG xc, INTBIG yc, INTBIG x1, INTBIG y1,
136 INTBIG x2, INTBIG y2, INTBIG *cx, INTBIG *cy);
137
138 /*
139 * Routine to initialize EDIF I/O.
140 */
io_initedif(void)141 void io_initedif(void)
142 {
143 extern COMCOMP io_edifp;
144
145 DiaDeclareHook(x_("edifopt"), &io_edifp, io_edifoptionsdlog);
146 }
147
148 /*
149 * routine to write a ".edif" file (or a ".foot" file for layouts)
150 * describing the current cell from the library "lib"
151 */
io_writeediflibrary(LIBRARY * lib)152 BOOLEAN io_writeediflibrary(LIBRARY *lib)
153 {
154 CHAR name[100], fname[100];
155 REGISTER NODEPROTO *lnp, *np;
156 REGISTER BOOLEAN backannotate;
157 REGISTER INTBIG i, lambda, *curstate;
158 REGISTER LIBRARY *olib;
159 REGISTER TECHNOLOGY *tech;
160 INTBIG fun, rgrid;
161 VARIABLE *var;
162 double meters_to_lambda;
163
164 /* make sure network tool is on */
165 if ((net_tool->toolstate & TOOLON) == 0)
166 {
167 ttyputerr(_("Network tool must be running...turning it on"));
168 toolturnon(net_tool);
169 ttyputerr(_("...now reissue the EDIF I/O command"));
170 return(TRUE);
171 }
172
173 /* initialize counters for automatic name generation */
174 io_edifo_gateindex = 1;
175
176 /* first write the "edif" file */
177 np = lib->curnodeproto;
178 if (np == NONODEPROTO)
179 {
180 ttyputerr(_("Must be editing a cell to generate EDIF output"));
181 return(TRUE);
182 }
183
184 /* See if schematic view is requested */
185 lambda = lib->lambda[el_curtech->techindex];
186 curstate = io_getstatebits();
187 if ((curstate[0] & EDIFSCHEMATIC) != 0)
188 {
189 schematic_view = 1;
190 schematic_scale = 1.0 / ((double)lambda);
191 meters_to_lambda = scaletodispunit(lambda, DISPUNITCM) / 100;
192 } else
193 schematic_view = 0;
194
195 (void)estrcpy(name, io_ediftoken(np->protoname));
196
197 /* If this is a layout representation, then create the footprint */
198 if (np->cellview == el_layoutview)
199 {
200 /* default routing grid is 6.6u = 660 centimicrons */
201 var = getval((INTBIG) np, VNODEPROTO, VINTEGER, x_("EDIF_routegrid"));
202 if (var != NOVARIABLE) rgrid = var->addr; else
203 rgrid = 660;
204 return(io_edifwritefootprint(np, name, rgrid));
205 }
206
207 /* Not a layout view - create the netlist */
208 (void)esnprintf(fname, 100, x_("%s.edif"), name);
209 if ((edif_stream = EO_open_stream(fname, 0)) == NOEO_STREAM)
210 {
211 return(TRUE);
212 }
213
214 /* write the header */
215 if ((us_useroptions&NODATEORVERSION) == 0)
216 {
217 (void)esnprintf(name, 100, _("Electric VLSI Design System, version %s"), el_version);
218 } else
219 {
220 (void)esnprintf(name, 100, _("Electric VLSI Design System"));
221 }
222 (void)EO_put_header(edif_stream, name, _("EDIF Writer"), lib->libname);
223
224 /* write the external primitive reference library, if any */
225 if (io_edifwritelibext(np))
226 {
227 /* determine the primitives being used */
228 for (tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
229 for (lnp = tech->firstnodeproto; lnp != NONODEPROTO; lnp = lnp->nextnodeproto)
230 lnp->temp1 = 0;
231 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
232 for (lnp = olib->firstnodeproto; lnp != NONODEPROTO; lnp = lnp->nextnodeproto)
233 lnp->temp1 = 0;
234
235 /* search recursively for all primitives used */
236 if (io_edifsearch(np) != 0)
237 {
238 /* advise user that generic primitives are being used */
239 ttyputerr(_("WARNING: external primitive library undefined - using generic models"));
240
241 /* write out all primitives used in the library */
242 EO_open_block(edif_stream, x_("library"));
243 EO_put_identifier(edif_stream, x_("lib0"));
244 EO_put_block(edif_stream, x_("edifLevel"), x_("0"));
245 EO_open_block(edif_stream, x_("technology"));
246 EO_open_block(edif_stream, x_("numberDefinition"));
247 if (schematic_view)
248 {
249 EO_open_block(edif_stream, x_("scale"));
250 EO_put_integer(edif_stream, io_edif_scale(lambda));
251 EO_put_float(edif_stream, meters_to_lambda);
252 EO_put_block(edif_stream, x_("unit"), x_("DISTANCE"));
253 EO_close_block(edif_stream, x_("scale"));
254 }
255 EO_close_block(edif_stream, x_("technology"));
256 for (tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
257 for (lnp = tech->firstnodeproto; lnp != NONODEPROTO; lnp = lnp->nextnodeproto)
258 {
259 if (lnp->temp1 != 0)
260 {
261 /* write primitive "lnp" */
262 fun = (lnp->userbits & NFUNCTION) >> NFUNCTIONSH;
263 if (fun == NPUNKNOWN || fun == NPPIN || fun == NPCONTACT ||
264 fun == NPNODE || fun == NPCONNECT || fun == NPART) continue;
265 for (i = 0; i < lnp->temp1; i++)
266 io_edifwriteprim(lnp, i, fun);
267 }
268 }
269 EO_close_block(edif_stream, x_("library"));
270 }
271 }
272
273 /* search recursively for all external libraries required */
274 backannotate = FALSE;
275 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
276 for (lnp = olib->firstnodeproto; lnp != NONODEPROTO; lnp = lnp->nextnodeproto)
277 {
278 lnp->temp1 = 0;
279 lnp->temp2 = 0;
280 }
281 io_edifoextlibcount = 0;
282 io_edifextsearch(np);
283
284 /* mark all node prototypes for final netlisting */
285 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
286 for (lnp = olib->firstnodeproto; lnp != NONODEPROTO; lnp = lnp->nextnodeproto)
287 lnp->temp1 = 0;
288
289 /* write out all external references in the library */
290 if (io_edifoextlibcount > 0)
291 for (i = 1; i <= io_edifoextlibcount; i++)
292 {
293 EO_open_block(edif_stream, x_("external"));
294 (void)esnprintf(name, 100, x_("schem_lib_%ld"), i);
295 EO_put_identifier(edif_stream, name);
296 EO_put_block(edif_stream, x_("edifLevel"), x_("0"));
297 EO_open_block(edif_stream, x_("technology"));
298 EO_open_block(edif_stream, x_("numberDefinition"));
299 if (schematic_view)
300 {
301 EO_open_block(edif_stream, x_("scale"));
302 EO_put_integer(edif_stream, io_edif_scale(lambda));
303 EO_put_float(edif_stream, meters_to_lambda);
304 EO_put_block(edif_stream, x_("unit"), x_("DISTANCE"));
305 EO_close_block(edif_stream, x_("scale"));
306 }
307 EO_close_block(edif_stream, x_("technology"));
308 if (io_edifwritecell(np, i)) backannotate = TRUE;
309 EO_close_block(edif_stream, x_("external"));
310 }
311
312 /* now recursively write the cells expanded within the library */
313 EO_open_block(edif_stream, x_("library"));
314 EO_put_identifier(edif_stream, io_ediftoken(lib->libname));
315 EO_put_block(edif_stream, x_("edifLevel"), x_("0"));
316 EO_open_block(edif_stream, x_("technology"));
317 EO_open_block(edif_stream, x_("numberDefinition"));
318 if (schematic_view)
319 {
320 EO_open_block(edif_stream, x_("scale"));
321 EO_put_integer(edif_stream, io_edif_scale(lambda));
322 EO_put_float(edif_stream, meters_to_lambda);
323 EO_put_block(edif_stream, x_("unit"), x_("DISTANCE"));
324 EO_close_block(edif_stream, x_("scale"));
325 }
326 EO_close_block(edif_stream, x_("technology"));
327
328 if (io_edifwritecell(np, 0)) backannotate = TRUE;
329 EO_close_block(edif_stream, x_("library"));
330
331 /* post-identify the design and library */
332 EO_open_block(edif_stream, x_("design"));
333 EO_put_identifier(edif_stream, io_ediftoken(np->protoname));
334 EO_open_block(edif_stream, x_("cellRef"));
335 EO_put_identifier(edif_stream, io_ediftoken(np->protoname));
336 EO_put_block(edif_stream, x_("libraryRef"), io_ediftoken(lib->libname));
337
338 /* clean up */
339 ttyputmsg(_("%s written"), edif_stream->filename);
340 EO_close_stream(edif_stream);
341 if (backannotate)
342 ttyputmsg(_("Back-annotation information has been added (library must be saved)"));
343 return(FALSE);
344 }
345
346 /*
347 * routine to count the usage of primitives hierarchically below cell "np"
348 */
io_edifsearch(NODEPROTO * np)349 INTBIG io_edifsearch(NODEPROTO *np)
350 {
351 REGISTER NODEINST *ni;
352 REGISTER NODEPROTO *onp;
353 REGISTER PORTARCINST *pi;
354 REGISTER INTBIG i, fun, primcount;
355
356 /* do not search this cell if it is an icon */
357 if (np->cellview == el_iconview) return(0);
358
359 /* keep a count of the total number of primitives encountered */
360 primcount = 0;
361
362 for (ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
363 {
364 if (ni->proto->primindex != 0)
365 {
366 fun = nodefunction(ni);
367 i = 1;
368 if (fun == NPGATEAND || fun == NPGATEOR || fun == NPGATEXOR)
369 {
370 /* count the number of inputs */
371 for (pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
372 if (pi->proto == ni->proto->firstportproto) i++;
373 }
374 ni->proto->temp1 = maxi(ni->proto->temp1, i);
375
376 if (fun != NPUNKNOWN && fun != NPPIN && fun != NPCONTACT &&
377 fun != NPNODE && fun != NPCONNECT && fun != NPMETER &&
378 fun != NPCONPOWER && fun != NPCONGROUND && fun != NPSOURCE &&
379 fun != NPSUBSTRATE && fun != NPWELL && fun != NPART)
380 primcount++;
381 continue;
382 }
383
384 /* ignore recursive references (showing icon in contents) */
385 if (isiconof(ni->proto, np)) continue;
386
387 /* get actual subcell (including contents/body distinction) */
388 onp = contentsview(ni->proto);
389 if (onp == NONODEPROTO) onp = ni->proto;
390
391 /* search the subcell */
392 if (onp->temp1 == 0) primcount += io_edifsearch(onp);
393 }
394 np->temp1++;
395 return(primcount);
396 }
397
398 /*
399 * Routine to identify cells with external connection models hierarchically below
400 * cell "np" and locate the libraries that contain their models. Sets np->temp2
401 * to point to the location in the external library array containing the library
402 * name.
403 */
io_edifextsearch(NODEPROTO * np)404 void io_edifextsearch(NODEPROTO *np)
405 {
406 REGISTER NODEINST *ni;
407 REGISTER NODEPROTO *onp, *subnp;
408 REGISTER INTBIG i;
409 CHAR *libname;
410 REGISTER void *infstr;
411
412 /* return if primitive (handled separately) */
413 if (np->primindex != 0) return;
414
415 /* check if this is a previously unencountered icon with no contents */
416 onp = contentsview(np);
417 if (np->temp2 == 0 && np->cellview == el_iconview && onp == NONODEPROTO)
418 {
419 /* do not mention monitor_probes */
420 if (namesame(np->protoname, x_("monitor_probe")) == 0) return;
421
422 /* this cell is not expanded in this library */
423 libname = io_ediffind_path(np);
424
425 if (io_edifoextlibcount == 0) i = 1; else
426 for (i = 1; i <= io_edifoextlibcount; i++)
427 if (namesame(libname, io_edifoextlibname[i]) == 0) break;
428 if (i > io_edifoextlibcount)
429 {
430 io_edifoextlibcount = i;
431 infstr = initinfstr();
432 addstringtoinfstr(infstr, libname);
433 (void)allocstring(&io_edifoextlibname[i], returninfstr(infstr), io_tool->cluster);
434 ttyputmsg(_("External library %s, lib number %ld"), io_edifoextlibname[i], i);
435 }
436 np->temp2 = i;
437 np->temp1++;
438 return;
439 }
440 if (onp == NONODEPROTO) onp = np;
441 for (ni = onp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
442 {
443 subnp = ni->proto;
444 if (subnp->temp1 != 0) continue;
445
446 /* ignore recursive references (showing icon in contents) */
447 if (isiconof(subnp, onp)) continue;
448 io_edifextsearch(subnp);
449 }
450
451 np->temp1++;
452 }
453
454 /*
455 * Routine to find the path to the EDIF file in the standard library
456 * structure, as contained in /usr/local/electric/lib/edifpath.
457 */
io_ediffind_path(NODEPROTO * np)458 CHAR *io_ediffind_path(NODEPROTO *np)
459 {
460 CHAR *path, libpath[255], ch, *filename;
461 FILE *f, *etry;
462 INTBIG i;
463
464 /* initialize the local path name variable */
465 f = xopen(x_("edifpath"), io_filetypeedif, el_libdir, &filename);
466 if (f != NULL)
467 {
468 for(ch = (CHAR)xgetc(f), i = 0; ; ch = (CHAR)xgetc(f), i++)
469 {
470 if (ch == ' ' || ch == '\t') continue;
471 if (ch == '\n' || ch == EOF || ch == ';')
472 {
473 libpath[i] = DIRSEP;
474 libpath[i + 1] = 0;
475 estrcat(libpath, np->protoname);
476 estrcat(libpath, DIRSEPSTR);
477 estrcat(libpath, x_("edif"));
478 estrcat(libpath, DIRSEPSTR);
479 estrcat(libpath, x_("source"));
480 etry = xopen(libpath, io_filetypeedif, el_libdir, &filename);
481 if (etry != NULL)
482 {
483 libpath[i] = 0;
484 xclose(etry);
485 break;
486 }
487 i = -1; /* start another line after incrementing i */
488 } else libpath[i] = ch;
489 if (ch == EOF)
490 {
491 (void)estrcpy(libpath, x_("unknown"));
492 break;
493 }
494 }
495 xclose(f);
496 } else (void)estrcpy(libpath, x_("unknown"));
497
498 (void)allocstring(&path, libpath, io_tool->cluster);
499 return(path);
500 }
501
502 /*
503 * routine to dump the description of primitive "np" to the EDIF file
504 * If the primitive is a schematic gate, use "i" as the number of inputs
505 */
io_edifwriteprim(NODEPROTO * np,INTBIG i,INTBIG fun)506 void io_edifwriteprim(NODEPROTO *np, INTBIG i, INTBIG fun)
507 {
508 REGISTER INTBIG j;
509 REGISTER PORTPROTO *firstport, *pp;
510 REGISTER CHAR *direction;
511 CHAR name[100];
512
513 /* write primitive name */
514 if (fun == NPGATEAND || fun == NPGATEOR || fun == NPGATEXOR)
515 {
516 EO_open_block(edif_stream, x_("cell"));
517 (void)esnprintf(name, 100, x_("%s%ld"), io_ediftoken(np->protoname), i);
518 EO_put_identifier(edif_stream, name);
519 } else
520 {
521 EO_open_block(edif_stream, x_("cell"));
522 EO_put_identifier(edif_stream, io_ediftoken(np->protoname));
523 }
524
525 /* write primitive connections */
526 EO_put_block(edif_stream, x_("cellType"), x_("GENERIC"));
527 EO_open_block(edif_stream, x_("view"));
528 EO_put_identifier(edif_stream, x_("cell"));
529 EO_put_block(edif_stream, x_("viewType"), (CHAR *)(schematic_view ? x_("SCHEMATIC") : x_("NETLIST")));
530 EO_open_block(edif_stream, x_("interface"));
531
532 firstport = np->firstportproto;
533 if (fun == NPGATEAND || fun == NPGATEOR || fun == NPGATEXOR)
534 {
535 for (j = 0; j < i; j++)
536 {
537 EO_open_block(edif_stream, x_("port"));
538 (void)esnprintf(name, 100, x_("IN%ld"), j + 1);
539 EO_put_identifier(edif_stream, name);
540 EO_put_block(edif_stream, x_("direction"), x_("INPUT"));
541 EO_close_block(edif_stream, x_("port"));
542 }
543 firstport = np->firstportproto->nextportproto;
544 }
545 for (pp = firstport; pp != NOPORTPROTO; pp = pp->nextportproto)
546 {
547 switch (pp->userbits & STATEBITS)
548 {
549 case OUTPORT:
550 direction = x_("output");
551 break;
552 case BIDIRPORT:
553 direction = x_("inout");
554 break;
555 default:
556 direction = x_("input");
557 break;
558 }
559 EO_open_block(edif_stream, x_("port"));
560 EO_put_identifier(edif_stream, io_ediftoken(pp->protoname));
561 EO_put_block(edif_stream, x_("direction"), direction);
562 EO_close_block(edif_stream, x_("port"));
563 }
564 if (schematic_view)
565 {
566 /* EMPTY */
567 }
568 EO_close_block(edif_stream, x_("cell"));
569 }
570
571 /* module: io_edif_scale
572 * function: will scale the requested integer
573 * returns the scaled value
574 */
io_edif_scale(INTBIG val)575 INTBIG io_edif_scale(INTBIG val)
576 {
577 if (val < 0)
578 return((INTBIG)(((double) val - 0.5) * schematic_scale));
579 return((INTBIG)(((double) val + 0.5) * schematic_scale));
580 }
581
582 /*
583 * Routine to map Electric orientations to EDIF orientations
584 */
io_edif_orientation(NODEINST * ni)585 CHAR *io_edif_orientation(NODEINST *ni)
586 {
587 if (ni->transpose)
588 {
589 switch (ni->rotation)
590 {
591 case 0: return(x_("MYR90"));
592 case 900: return(x_("MY"));
593 case 1800: return(x_("MXR90"));
594 case 2700: return(x_("MX"));
595 }
596 } else
597 {
598 switch (ni->rotation)
599 {
600 case 0: return(x_("R0"));
601 case 900: return(x_("R90"));
602 case 1800: return(x_("R180"));
603 case 2700: return(x_("R270"));
604 }
605 }
606 return(x_("ERROR"));
607 }
608
609 /*
610 * Helper name builder
611 */
io_edifwritecompname(NODEINST * ni,INTBIG fun,INTBIG serindex)612 CHAR *io_edifwritecompname(NODEINST *ni, INTBIG fun, INTBIG serindex)
613 {
614 REGISTER VARIABLE *var;
615 REGISTER CHAR *okname;
616 static CHAR name[WORD+1];
617 static INTBIG EDIF_name_key = 0;
618 Q_UNUSED( fun );
619 Q_UNUSED( serindex );
620
621 if (EDIF_name_key == 0) EDIF_name_key = makekey(x_("EDIF_name"));
622
623 /* always use EDIF_name if required */
624 var = getvalkey((INTBIG) ni, VNODEINST, VSTRING, EDIF_name_key);
625 okname = io_edifvalidname(var);
626 if (okname == 0)
627 {
628 /* check for node name */
629 var = getvalkey((INTBIG) ni, VNODEINST, VSTRING, el_node_name_key);
630 okname = io_edifvalidname(var);
631 if (okname == 0)
632 {
633 /* create a new EDIF_name */
634 (void)esnprintf(name, WORD+1, x_("INSTANCE%ld"), io_edifo_gateindex++);
635 (void)setvalkey((INTBIG) ni, VNODEINST, EDIF_name_key, (INTBIG)name, VSTRING);
636 } else
637 {
638 (void)setvalkey((INTBIG) ni, VNODEINST, EDIF_name_key, (INTBIG)okname, VSTRING);
639 }
640 }
641
642 if (isdigit(*okname) || *okname == '_')
643 (void)esnprintf(name, WORD+1, x_("&%s"), okname); else
644 (void)estrcpy(name, okname);
645 return(name);
646 }
647
648 /* module: io_edif_pt
649 * function: will generate a pt symbol (pt x y)
650 * returns success or failure
651 */
io_edif_pt(INTBIG x,INTBIG y)652 void io_edif_pt(INTBIG x, INTBIG y)
653 {
654 EO_open_block(edif_stream, x_("pt"));
655 EO_put_integer(edif_stream, io_edif_scale(x));
656 EO_put_integer(edif_stream, io_edif_scale(y));
657 EO_close_block(edif_stream, x_("pt"));
658 }
659
660 /*
661 * Routine to recursively dump cell "np" to the EDIF file
662 * Recurses for contents if 'external' is zero, creates only
663 * interface models for external elements for library number
664 * 'external' if 'external' is non-zero.
665 * Returns true if back-annotation was added.
666 */
io_edifwritecell(NODEPROTO * np,INTBIG external)667 BOOLEAN io_edifwritecell(NODEPROTO *np, INTBIG external)
668 {
669 INTBIG i, netcount, displaytotal;
670 INTBIG fun;
671 BOOLEAN backannotate;
672 NETWORK *net, *cnet, *onet;
673 VARIABLE *var;
674 NODEINST *ni;
675 PORTARCINST *pi;
676 PORTEXPINST *pe;
677 PORTPROTO *pp, *cpp;
678 NODEPROTO *onp, *cnp, *lnp;
679 ARCINST *ai;
680 CHAR *pt, *iname, *oname, line[WORD+1], *direction;
681 BOOLEAN globalport;
682 BOOLEAN contents, schematic;
683 INTBIG netindex, pageindex, is_array, sx, mx, rx, sy, my, ry;
684 INTBIG diffcount;
685 XARRAY trans;
686 INTBIG bx, by, xpos, ypos;
687 CHAR name[WORD+1], page[10];
688 static POLYGON *poly = NOPOLYGON;
689 static INTBIG EDIF_name_key = 0;
690 static INTBIG EDIF_array_key = 0;
691
692 if (EDIF_name_key == 0) EDIF_name_key = makekey(x_("EDIF_name"));
693 if (EDIF_array_key == 0) EDIF_array_key = makekey(x_("EDIF_array"));
694
695 /* stop if requested */
696 if (el_pleasestop != 0)
697 {
698 stopping(STOPREASONEDIF);
699 return(FALSE);
700 }
701
702 /* get polygon */
703 if (schematic_view)
704 (void)needstaticpolygon(&poly, 4, io_tool->cluster);
705
706 /* recurse on sub-cells first */
707 backannotate = FALSE;
708 if (np->cellview != el_iconview)
709 {
710 for (ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
711 {
712 ni->temp1 = 0;
713 if (ni->proto->primindex != 0) continue;
714
715 /* ignore recursive references (showing icon in contents) */
716 if (isiconof(ni->proto, np)) continue;
717
718 /* do not expand "monitor_probe" construct (icon) */
719 if (namesame(ni->proto->protoname, x_("monitor_probe")) == 0) continue;
720
721 /* get actual subcell (including contents/body distinction) */
722 onp = contentsview(ni->proto);
723 if (onp == NONODEPROTO) onp = ni->proto;
724
725 /* write the subcell */
726 if (onp->temp1 == 0)
727 {
728 if (io_edifwritecell(onp, external) != 0) backannotate = TRUE;
729 }
730 }
731 }
732
733 /* check whether writing external or contents cells */
734 if (external > 0 && np->cellview != el_iconview) return(backannotate);
735
736 /* check whether this cell is in this external library */
737 if (external > 0 && np->temp2 != external) return(backannotate);
738
739 /* make sure that all nodes and networks have names on them */
740 if (asktool(net_tool, x_("name-nodes"), (INTBIG)np) != 0) backannotate++;
741 if (asktool(net_tool, x_("name-nets"), (INTBIG)np) != 0) backannotate++;
742
743 /* mark this cell as written */
744 np->temp1++;
745
746 /* assign bus names to unnamed bus wires connecting bus ports on objects */
747 netindex = 1;
748 /* sim_namebusnets(np, &netindex); */
749
750 /* clear unnamed net identifier field */
751 for (net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
752 net->temp1 = 0;
753
754 /* write out the cell header information */
755 EO_open_block(edif_stream, x_("cell"));
756 EO_put_identifier(edif_stream, io_ediftoken(np->protoname));
757 EO_put_block(edif_stream, x_("cellType"), x_("generic"));
758 EO_open_block(edif_stream, x_("view"));
759 EO_put_identifier(edif_stream, x_("cell"));
760 EO_put_block(edif_stream, x_("viewType"), (CHAR *)(schematic_view ? x_("SCHEMATIC") : x_("NETLIST")));
761
762 /* write out the interface description */
763 EO_open_block(edif_stream, x_("interface"));
764
765 /* list all ports in interface except global ports in network order */
766 (void)io_edifmarknetports(np);
767
768 /* count check on differentialGroup property */
769 diffcount = 0;
770 for (net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
771 {
772 if ((pp = (PORTPROTO *) net->temp2) != NOPORTPROTO && !io_edifisglobal(pp))
773 {
774 switch (pp->userbits & STATEBITS)
775 {
776 case OUTPORT:
777 direction = x_("OUTPUT");
778 break;
779 case BIDIRPORT:
780 direction = x_("INOUT");
781 break;
782 case REFOUTPORT:
783 direction = x_("OUTPUT");
784 break;
785 case INPORT:
786 case REFINPORT:
787 default:
788 direction = x_("INPUT");
789 break;
790 }
791 EO_open_block(edif_stream, x_("port"));
792 EO_put_identifier(edif_stream, io_ediftoken(networkname(net, 0)));
793 if (estrlen(direction) > 0)
794 EO_put_block(edif_stream, x_("direction"), direction);
795
796 /* list port properties if they exist on this schematic */
797 /* if (np->cellview != el_iconview) listPortProperties(pp, direction, net, diffcount); */
798
799 EO_close_block(edif_stream, x_("port"));
800 }
801 }
802 if (schematic_view && np->cellview == el_iconview)
803 {
804 /* output the icon */
805 io_edifsymbol(np);
806 }
807
808 EO_close_block(edif_stream, x_("interface"));
809
810 if (diffcount != 0)
811 ttyputmsg(_("** WARNING - unmatched constructed differentialGroup property in %s"),
812 describenodeproto(np));
813
814 /* list contents if expanding */
815 if (np->cellview != el_iconview)
816 {
817 /* write the components, if there are any */
818 contents = FALSE;
819
820 /* determine if this is a schematic view */
821 if (schematic_view && !estrncmp(np->cellview->viewname, x_("schematic-page-"), 15))
822 {
823 /* set beginning page */
824 pageindex = 1;
825 (void)esnprintf(page, 10, x_("P%ld"), pageindex);
826
827 /* locate the next like in cell */
828 FOR_CELLGROUP(lnp, np)
829 if (!namesame(lnp->cellview->sviewname, page))
830 {
831 /* list all ports in interface except global ports in network order */
832 (void)io_edifmarknetports(lnp);
833 break;
834 }
835 schematic = TRUE;
836 } else schematic = FALSE;
837
838 contents = FALSE;
839 while (np != NONODEPROTO)
840 {
841 if (np->firstnodeinst != NONODEINST)
842 {
843 contents = TRUE;
844 if (!contents) EO_open_block(edif_stream, x_("contents"));
845 if (schematic_view && schematic)
846 {
847 EO_open_block(edif_stream, x_("page"));
848 EO_put_identifier(edif_stream, np->cellview->sviewname);
849 }
850 for (ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
851 {
852 fun = nodefunction(ni);
853 if (ni->proto->primindex != 0)
854 {
855 if (fun == NPUNKNOWN || fun == NPPIN || fun == NPCONTACT ||
856 fun == NPNODE || fun == NPCONNECT || fun == NPART) continue;
857 } else if (namesame(ni->proto->protoname, x_("monitor_probe")) == 0)
858 continue;
859
860 /* ignore recursive references (showing icon in contents) */
861 if (isiconof(ni->proto, np)) continue;
862
863 EO_open_block(edif_stream, x_("instance"));
864 iname = io_edifwritecompname(ni, fun, 0);
865 if ((var = getvalkey((INTBIG) ni, VNODEINST, VSTRING, el_node_name_key)) != NOVARIABLE)
866 oname = (CHAR *)var->addr; else
867 oname = iname;
868
869 /* check for an array */
870 is_array = 0;
871 if ((var = getvalkey((INTBIG) ni, VNODEINST, VSTRING, EDIF_array_key)) != NOVARIABLE)
872 {
873 /* decode the array bounds min:max:range min:max:range */
874 (void)esscanf((CHAR *)var->addr, x_("%ld:%ld:%ld %ld:%ld:%ld"), &sx, &mx, &rx, &sy, &my, &ry);
875 if (sx != mx || sy != my)
876 {
877 is_array = 1;
878 EO_open_block(edif_stream, x_("array"));
879 }
880 }
881
882 if (namesame(oname, iname))
883 {
884 EO_open_block(edif_stream, x_("rename"));
885 EO_put_identifier(edif_stream, iname);
886 EO_put_string(edif_stream, oname);
887 EO_close_block(edif_stream, x_("rename"));
888 } else EO_put_identifier(edif_stream, iname);
889
890 if (is_array)
891 {
892 if (rx > 1) EO_put_integer(edif_stream, rx);
893 if (ry > 1) EO_put_integer(edif_stream, ry);
894 EO_close_block(edif_stream, x_("array"));
895 }
896
897 if (ni->proto->primindex != 0)
898 {
899 EO_open_block(edif_stream, x_("viewRef"));
900 EO_put_identifier(edif_stream, x_("cell"));
901 EO_open_block(edif_stream, x_("cellRef"));
902 if (fun == NPGATEAND || fun == NPGATEOR || fun == NPGATEXOR)
903 {
904 /* count the number of inputs */
905 i = 0;
906 for (pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
907 if (pi->proto == ni->proto->firstportproto) i++;
908 (void)esnprintf(name, WORD+1, x_("%s%ld"), io_ediftoken(ni->proto->protoname), i);
909 EO_put_identifier(edif_stream, name);
910 } else EO_put_identifier(edif_stream, io_edifdescribepriminst(ni, fun));
911 EO_put_block(edif_stream, x_("libraryRef"), x_("lib0"));
912 EO_close_block(edif_stream, x_("viewRef"));
913 } else if (ni->proto->cellview == el_iconview &&
914 contentsview(ni->proto) == NONODEPROTO)
915 {
916 /* this node came from an external schematic library */
917 EO_open_block(edif_stream, x_("viewRef"));
918 EO_put_identifier(edif_stream, x_("cell"));
919 EO_open_block(edif_stream, x_("cellRef"));
920 EO_put_identifier(edif_stream, io_ediftoken(ni->proto->protoname));
921 (void)esnprintf(name, WORD+1, x_("schem_lib_%ld"), ni->proto->temp2);
922 EO_put_block(edif_stream, x_("libraryRef"), name);
923 EO_close_block(edif_stream, x_("viewRef"));
924 } else
925 {
926 /* this node came from this library */
927 EO_open_block(edif_stream, x_("viewRef"));
928 EO_put_identifier(edif_stream, x_("cell"));
929 EO_open_block(edif_stream, x_("cellRef"));
930 EO_put_identifier(edif_stream, io_ediftoken(ni->proto->protoname));
931 EO_put_block(edif_stream, x_("libraryRef"), np->lib->libname);
932 EO_close_block(edif_stream, x_("viewRef"));
933 }
934
935 /* now graphical information */
936 if (schematic_view)
937 {
938 EO_open_block(edif_stream, x_("transform"));
939
940 /* get the orientation (note only support orthogonal) */
941 EO_put_block(edif_stream, x_("orientation"), io_edif_orientation(ni));
942
943 /* now the origin */
944 EO_open_block(edif_stream, x_("origin"));
945 var = getvalkey((INTBIG) ni->proto, VNODEPROTO, VINTEGER | VISARRAY,
946 el_prototype_center_key);
947 if (var != NOVARIABLE)
948 {
949 bx = ((INTBIG *) var->addr)[0] + (ni->lowx + ni->highx) / 2 -
950 (ni->proto->lowx + ni->proto->highx) / 2;
951 by = ((INTBIG *) var->addr)[1] + (ni->lowy + ni->highy) / 2 -
952 (ni->proto->lowy + ni->proto->highy) / 2;
953 } else
954 {
955 /* use center of node */
956 /* now origin, normal placement */
957 bx = (ni->lowx - ni->proto->lowx);
958 by = (ni->lowy - ni->proto->lowy);
959 }
960 makerot(ni, trans);
961 xform(bx, by, &xpos, &ypos, trans);
962 io_edif_pt(xpos, ypos);
963 EO_close_block(edif_stream, x_("transform"));
964 }
965
966
967 /* check for variables to write as properties */
968 if (schematic_view)
969 {
970 /* do all display variables first */
971 displaytotal = tech_displayablenvars(ni, NOWINDOWPART, &tech_oneprocpolyloop);
972 for (i = 0; i < displaytotal; i++)
973 {
974 var = tech_filldisplayablenvar(ni, poly, NOWINDOWPART, 0, &tech_oneprocpolyloop);
975 xformpoly(poly, trans);
976 /* check for name */
977 if (namesame((pt = makename(var->key)), x_("EDIF_annotate")))
978 {
979 /* open the property (all properties are strings at this time) */
980 EO_open_block(edif_stream, x_("property"));
981 EO_put_identifier(edif_stream, pt);
982 EO_open_block(edif_stream, x_("string"));
983 } else
984 {
985 EO_open_block(edif_stream, x_("annotate"));
986 pt = NULL;
987 }
988 io_edifsymbol_showpoly(poly);
989 if (pt != NULL) EO_close_block(edif_stream, x_("property")); else
990 EO_close_block(edif_stream, x_("annotate"));
991 }
992 }
993 EO_close_block(edif_stream, x_("instance"));
994 }
995
996 /* search for unconnected inputs */
997 for (ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
998 {
999 if (ni->proto->primindex != 0)
1000 {
1001 fun = nodefunction(ni);
1002 if (fun != NPUNKNOWN && fun != NPPIN && fun != NPCONTACT &&
1003 fun != NPNODE && fun != NPCONNECT && fun != NPART) continue;
1004 } else if (namesame(ni->proto->protoname, x_("monitor_probe")) == 0) continue;
1005
1006 /* ignore recursive references (showing icon in contents) */
1007 if (isiconof(ni->proto, np)) continue;
1008
1009 for (pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1010 {
1011 if ((pp->userbits & STATEBITS) == INPORT || (pp->userbits & STATEBITS) == REFINPORT)
1012 {
1013 onet = NONETWORK;
1014 for (pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1015 if (pi->proto == pp) break;
1016
1017 if (pi != NOPORTARCINST) onet = pi->conarcinst->network; else
1018 {
1019 for (pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1020 if (pe->proto == pp) break;
1021 if (pe != NOPORTEXPINST) onet = pe->exportproto->network;
1022 }
1023
1024 if (onet == NONETWORK)
1025 ttyputmsg(_("** WARNING - no connection to %s port %s on %s in %s"),
1026 (((pp->userbits & STATEBITS) == INPORT) ? _("input") : _("vbias")),
1027 pp->protoname, describenodeinst(ni),
1028 describenodeproto(ni->parent));
1029 else if (onet->buswidth < pp->network->buswidth)
1030 for (i = onet->buswidth; i != pp->network->buswidth; i++)
1031 ttyputmsg(_("** WARNING - no connection to %s port %s (signal %ld) on %s in %s"),
1032 ((pp->userbits & STATEBITS) == INPORT ? _("input") : _("vbias")),
1033 networkname(pp->network->networklist[i], 0), i,
1034 describenodeinst(ni), describenodeproto(ni->parent));
1035 }
1036 }
1037 }
1038
1039 transid(trans);
1040
1041 /* if there is anything to connect, write the networks in the cell */
1042 for (net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1043 {
1044 /* skip bus networks altogether (they are done wire by wire) */
1045 if (net->buswidth > 1)
1046 {
1047 /* handle bus description, note that most nets have single arc
1048 description which is handled below */
1049 /* evaluate the bus name, look for net arrays */
1050 if (net->namecount > 0)
1051 {
1052 /* EMPTY */
1053 }
1054 EO_open_block(edif_stream, x_("netBundle"));
1055 if (net->namecount > 0)
1056 {
1057 pt = networkname(net, 0);
1058 oname = io_ediftoken(pt);
1059 if (namesame(oname, pt))
1060 {
1061 /* different names */
1062 EO_open_block(edif_stream, x_("rename"));
1063 EO_put_identifier(edif_stream, oname);
1064 EO_put_string(edif_stream, pt);
1065 EO_close_block(edif_stream, x_("rename"));
1066 } else EO_put_identifier(edif_stream, oname);
1067 } else
1068 {
1069 net->temp1 = netindex++;
1070 (void)esnprintf(line, WORD+1, x_("BUS%ld"), net->temp1);
1071 EO_put_identifier(edif_stream, line);
1072 }
1073 EO_open_block(edif_stream, x_("listOfNets"));
1074
1075 /* now each sub-net name */
1076 for (i = 0; i < net->buswidth; i++)
1077 {
1078 EO_open_block(edif_stream, x_("net"));
1079
1080 /* now output this name */
1081 if (net->networklist[i]->namecount > 0)
1082 {
1083 pt = networkname(net, 0);
1084 oname = io_ediftoken(pt);
1085 if (namesame(oname, pt))
1086 {
1087 /* different names */
1088 EO_open_block(edif_stream, x_("rename"));
1089 EO_put_identifier(edif_stream, oname);
1090 EO_put_string(edif_stream, pt);
1091 EO_close_block(edif_stream, x_("rename"));
1092 } else EO_put_identifier(edif_stream, oname);
1093 (void)setvalkey((INTBIG)net, VNETWORK, EDIF_name_key, (INTBIG)line, VSTRING);
1094 } else
1095 {
1096 if (net->networklist[i]->temp1 != 0)
1097 net->networklist[i]->temp1 = netindex++;
1098 (void)esnprintf(line, WORD+1, x_("NET%ld"), net->networklist[i]->temp1);
1099 (void)setvalkey((INTBIG)net, VNETWORK, EDIF_name_key, (INTBIG)line, VSTRING);
1100 EO_put_identifier(edif_stream, line);
1101 }
1102 EO_close_block(edif_stream, x_("net"));
1103 }
1104
1105 /* now graphics for the bus */
1106 if (schematic_view)
1107 {
1108 /* output net graphic information */
1109 /* output all arc instances connected to this net */
1110 egraphic = EGUNKNOWN;
1111 egraphic_override = EGBUS;
1112 for (ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1113 if (ai->network == net) io_edifsymbol_arcinst(ai, trans);
1114 io_edifsetgraphic(EGUNKNOWN);
1115 egraphic_override = EGUNKNOWN;
1116 }
1117
1118 EO_close_block(edif_stream, x_("netBundle"));
1119 continue;
1120 }
1121
1122 /* skip networks that are not connected to anything real */
1123 if (net->buslinkcount == 0 && net->portcount == 0)
1124 {
1125 for (ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1126 {
1127 if (ni->proto->primindex == 0 && namesame(ni->proto->protoname,
1128 x_("monitor_probe")) == 0) continue;
1129
1130 for (pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1131 if (pi->conarcinst->network == net) break;
1132
1133 if (pi == NOPORTARCINST)
1134 {
1135 for (pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1136 if (pe->exportproto->network == net) break;
1137 if (pe == NOPORTEXPINST) continue;
1138 }
1139 if (ni->proto->primindex == 0) break;
1140
1141 fun = nodefunction(ni);
1142 if (fun != NPUNKNOWN && fun != NPPIN && fun != NPCONTACT &&
1143 fun != NPNODE && fun != NPCONNECT && fun != NPART) break;
1144 }
1145 if (ni == NONODEINST) continue;
1146 }
1147
1148 /* establish if this is a global net */
1149 globalport = FALSE;
1150 if ((pp = (PORTPROTO *) net->temp2) != NOPORTPROTO)
1151 globalport = io_edifisglobal(pp);
1152
1153 EO_open_block(edif_stream, x_("net"));
1154 if (net->namecount > 0)
1155 {
1156 pt = networkname(net, 0);
1157 if (globalport)
1158 {
1159 EO_open_block(edif_stream, x_("rename"));
1160 EO_put_identifier(edif_stream, io_ediftoken(pt));
1161 (void)esnprintf(name, WORD+1, x_("%s!"), io_ediftoken(pt));
1162 EO_put_identifier(edif_stream, name);
1163 EO_close_block(edif_stream, x_("rename"));
1164 EO_put_block(edif_stream, x_("property"), x_("GLOBAL"));
1165 } else
1166 {
1167 oname = io_ediftoken(pt);
1168 if (namesame(oname, pt))
1169 {
1170 /* different names */
1171 EO_open_block(edif_stream, x_("rename"));
1172 EO_put_identifier(edif_stream, oname);
1173 EO_put_string(edif_stream, pt);
1174 EO_close_block(edif_stream, x_("rename"));
1175 } else EO_put_identifier(edif_stream, oname);
1176 (void)setvalkey((INTBIG)net, VNETWORK, EDIF_name_key, (INTBIG)line, VSTRING);
1177 }
1178 } else
1179 {
1180 net->temp1 = netindex++;
1181 (void)esnprintf(line, WORD+1, x_("NET%ld"), net->temp1);
1182 (void)setvalkey((INTBIG)net, VNETWORK, EDIF_name_key, (INTBIG)line, VSTRING);
1183 EO_put_identifier(edif_stream, line);
1184 }
1185
1186 /* write net connections */
1187 EO_open_block(edif_stream, x_("joined"));
1188
1189 /* include exported ports (by net name) */
1190 if (pp != NOPORTPROTO && !globalport)
1191 EO_put_block(edif_stream, x_("portRef"), io_ediftoken(networkname(net, 0)));
1192
1193 /* now include components using existing net-port pointers */
1194 for (ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1195 {
1196 if (ni->proto->primindex != 0)
1197 {
1198 /* ignore passive components */
1199 fun = nodefunction(ni);
1200 if (fun == NPUNKNOWN || fun == NPPIN || fun == NPCONTACT ||
1201 fun == NPNODE || fun == NPCONNECT || fun == NPART) continue;
1202 cnp = ni->proto;
1203 } else
1204 {
1205 /* ignore recursive references (showing icon in contents) */
1206 if (isiconof(ni->proto, np)) continue;
1207
1208 if (namesame(ni->proto->protoname, x_("monitor_probe")) == 0)
1209 continue;
1210 fun = NPUNKNOWN;
1211
1212 /* get contents of the nodeinst to establish net connections */
1213 if ((cnp = contentsview(ni->proto)) == NONODEPROTO) cnp = ni->proto;
1214 }
1215
1216 /* be sure each connection is written only once */
1217 for (cpp = cnp->firstportproto; cpp != NOPORTPROTO; cpp = cpp->nextportproto)
1218 cpp->temp1 = 0;
1219
1220 /* write connection to ports exported directly */
1221 for (pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1222 {
1223 if (pe->exportproto != NOPORTPROTO && pe->exportproto->network == net)
1224 {
1225 /* locate the name being used */
1226 if ((cpp = equivalentport(ni->proto, pe->proto, cnp)) == NOPORTPROTO)
1227 cpp = pe->proto;
1228 if (ni->proto->primindex == 0 && (PORTPROTO *)(cpp->network->temp2) != NOPORTPROTO)
1229 cpp = (PORTPROTO *)(cpp->network->temp2);
1230 if (cpp->temp1++ != 0) continue;
1231
1232 if (ni->proto->primindex == 0) pt = networkname(cpp->network, 0); else
1233 pt = cpp->protoname;
1234
1235 EO_open_block(edif_stream, x_("portRef"));
1236 EO_put_identifier(edif_stream, io_ediftoken(pt));
1237 EO_put_block(edif_stream, x_("instanceRef"), io_edifwritecompname(ni, fun, 0));
1238 EO_close_block(edif_stream, x_("portRef"));
1239 cpp->temp1++;
1240 }
1241 }
1242
1243 /* write single-wire direct connections */
1244 for (pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1245 {
1246 if ((pi->conarcinst->network == net))
1247 {
1248 if ((cpp = equivalentport(ni->proto, pi->proto, cnp)) == NOPORTPROTO)
1249 cpp = pi->proto;
1250
1251 if (net_buswidth(pi->proto->protoname) == 1)
1252 {
1253 if (ni->proto->primindex == 0 && (PORTPROTO *)(cpp->network->temp2) != NOPORTPROTO)
1254 cpp = (PORTPROTO *)(cpp->network->temp2);
1255 if (cpp->temp1++ != 0) continue;
1256
1257 if (ni->proto->primindex == 0) pt = networkname(cpp->network, 0); else
1258 pt = cpp->protoname;
1259 EO_open_block(edif_stream, x_("portRef"));
1260 EO_put_identifier(edif_stream, io_ediftoken(pt));
1261 EO_put_block(edif_stream, x_("instanceRef"), io_edifwritecompname(ni, fun, 0));
1262 EO_close_block(edif_stream, x_("portRef"));
1263 } else
1264 {
1265 /* connect to first signal in the bus */
1266 if (ni->proto->primindex == 0)
1267 {
1268 EO_open_block(edif_stream, x_("portRef"));
1269 EO_put_identifier(edif_stream,
1270 io_ediftoken(networkname(pi->proto->network->networklist[0],0)));
1271 EO_open_block(edif_stream, x_("portRef"));
1272 EO_put_block(edif_stream, x_("instanceRef"),
1273 io_edifwritecompname(ni, fun, 0));
1274 EO_close_block(edif_stream, x_("portRef"));
1275 } else ttyputerr(_("Cannot handle primitives with bus pins"));
1276 }
1277 cpp->temp1++;
1278 }
1279 }
1280
1281 /* match up exported net with bus connections on this nodeinst */
1282 for (pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1283 {
1284 if ((netcount = pi->conarcinst->network->buswidth) > 1)
1285 {
1286 /* first, find the connection point if there is one */
1287 for (i = 0; i < netcount; i++)
1288 if (pi->conarcinst->network->networklist[i] == net) break;
1289 if (i == netcount) continue;
1290
1291 if ((cpp = equivalentport(ni->proto, pi->proto, cnp)) == NOPORTPROTO)
1292 cpp = pi->proto;
1293
1294 /* skip if already connected */
1295 if (cpp->temp1 != 0) continue;
1296
1297 /* associate by the i-th position in the connection */
1298 EO_open_block(edif_stream, x_("portRef"));
1299 if (cpp->network->buswidth > i)
1300 {
1301 if (cpp->network->buswidth > 1)
1302 cnet = cpp->network->networklist[i]; else
1303 cnet = cpp->network;
1304
1305 /* now transform to the port identification network */
1306 cpp = (PORTPROTO *) cnet->temp2;
1307
1308 /* skip if already connected */
1309 if (cpp->temp1++ != 0) continue;
1310 EO_put_identifier(edif_stream, io_ediftoken(networkname(cnet, 0)));
1311 } else
1312 {
1313 pt = networkname(cpp->network, 0);
1314 ttyputerr(_("Proto bus width too narrow at %s {signal %ld} in %s"),
1315 pt, i, describenodeproto(cpp->parent));
1316 EO_put_identifier(edif_stream,
1317 io_ediftoken(pt));
1318 }
1319 EO_put_block(edif_stream, x_("instanceRef"),
1320 io_edifwritecompname(ni, fun, 0));
1321 EO_close_block(edif_stream, x_("portRef"));
1322 }
1323 }
1324
1325 /* continue with connected busses */
1326 for (pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1327 {
1328 if ((netcount = pe->exportproto->network->buswidth) > 1)
1329 {
1330 /* first, find the connection point if there is one */
1331 for (i = 0; i < netcount; i++)
1332 if (pe->exportproto->network->networklist[i] == net) break;
1333 if (i == netcount) continue;
1334
1335 if ((cpp = equivalentport(ni->proto, pe->proto, cnp)) == NOPORTPROTO)
1336 cpp = pe->proto;
1337
1338 /* associate by the i-th position in the connection */
1339 EO_open_block(edif_stream, x_("portRef"));
1340 if (cpp->network->buswidth > i)
1341 {
1342 if (cpp->network->buswidth > 1)
1343 EO_put_identifier(edif_stream,
1344 io_ediftoken(networkname(cpp->network->networklist[i], 0)));
1345 else EO_put_identifier(edif_stream,
1346 io_ediftoken(networkname(cpp->network, 0)));
1347 } else
1348 {
1349 pt = networkname(cpp->network, 0);
1350 ttyputerr(_("Proto bus width too narrow at %s"),
1351 pt);
1352 EO_put_identifier(edif_stream,
1353 io_ediftoken(pt));
1354 }
1355 EO_put_block(edif_stream, x_("instanceRef"),
1356 io_edifwritecompname(ni, fun, 0));
1357 EO_close_block(edif_stream, x_("portRef"));
1358
1359 cpp->temp1++;
1360 }
1361 }
1362 } /* for ni = ... */
1363 EO_close_block(edif_stream, x_("joined"));
1364
1365 if (schematic_view)
1366 {
1367 /* output net graphic information */
1368 /* output all arc instances connected to this net */
1369 egraphic = EGUNKNOWN;
1370 egraphic_override = EGWIRE;
1371 for (ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1372 if (ai->network == net) io_edifsymbol_arcinst(ai, trans);
1373 io_edifsetgraphic(EGUNKNOWN);
1374 egraphic_override = EGUNKNOWN;
1375 }
1376
1377 if (globalport)
1378 EO_put_block(edif_stream, x_("userData"), x_("global"));
1379 EO_close_block(edif_stream, x_("net"));
1380 } /* for (net = ... */
1381 if (schematic_view && schematic)
1382 EO_close_block(edif_stream, x_("page"));
1383 } /* if np->firstnodeinst != NONODEINST */
1384
1385 if (schematic)
1386 {
1387 /* get next schematic */
1388 pageindex++;
1389 (void)esnprintf(page, 10, x_("P%ld"), pageindex);
1390 FOR_CELLGROUP(lnp, np)
1391 if (!namesame(lnp->cellview->sviewname, page))
1392 {
1393 /* list all ports in interface except global ports in network order */
1394 (void)io_edifmarknetports(lnp);
1395 break;
1396 }
1397 if (np == NONODEPROTO) break;
1398 } else break;
1399 } /* while np != NONODEPROTO */
1400 }
1401
1402 /* matches "(cell " */
1403 EO_close_block(edif_stream, x_("cell"));
1404 return(backannotate);
1405 }
1406
1407 /*
1408 * procedure to properly identify an instance of a primitive node
1409 * for ASPECT netlists
1410 */
io_edifdescribepriminst(NODEINST * ni,INTBIG fun)1411 CHAR *io_edifdescribepriminst(NODEINST *ni, INTBIG fun)
1412 {
1413 REGISTER VARIABLE *var;
1414 CHAR *model;
1415
1416 switch (fun)
1417 {
1418 case NPRESIST:
1419 var = getvalkey((INTBIG) ni, VNODEINST, VSTRING, sch_spicemodelkey);
1420 if (var == NOVARIABLE) return(x_("Resistor"));
1421
1422 model = (CHAR *) var->addr;
1423 if (namesamen(model, x_("PN"), 2) == 0) return(x_("res_pnpoly"));
1424 if (namesamen(model, x_("NP"), 2) == 0) return(x_("res_nppoly"));
1425 if (namesamen(model, x_("PP"), 2) == 0) return(x_("res_pppoly"));
1426 if (namesamen(model, x_("BL"), 2) == 0) return(x_("res_bl"));
1427 if (namesamen(model, x_("EP"), 2) == 0) return(x_("res_epi"));
1428 return(x_("Resistor"));
1429 case NPTRANPN:
1430 case NPTRANSREF:
1431 return(x_("npn"));
1432 case NPTRAPNP:
1433 return(x_("pnp"));
1434 case NPSUBSTRATE:
1435 return(x_("gtap"));
1436 case NPDIODE:
1437 var = getvalkey((INTBIG) ni, VNODEINST, VSTRING, sch_spicemodelkey);
1438 if (var != NOVARIABLE && namesamen(x_("subtap"), (CHAR *) var->addr, 6) == 0)
1439 return(x_("gtap"));
1440 }
1441 return(io_ediftoken(ni->proto->protoname));
1442 }
1443
1444 /*
1445 * Establish whether port 'pp' is a global port or not
1446 */
io_edifisglobal(PORTPROTO * pp)1447 BOOLEAN io_edifisglobal(PORTPROTO *pp)
1448 {
1449 NODEPROTO *inp;
1450
1451 /* pp is a global port if it is marked global */
1452 if ((pp->userbits & BODYONLY) != 0) return(TRUE);
1453
1454 /* or if it does not exist on the icon */
1455 if ((inp = iconview(pp->parent)) == NONODEPROTO) return(FALSE);
1456 if (equivalentport(pp->parent, pp, inp) == NOPORTPROTO) return(TRUE);
1457 return(FALSE);
1458 }
1459
1460 /*
1461 * routine to mark all nets' temp2 variables for interfacing purposes.
1462 * To determine the connection, temp2 is marked with a pointer to the
1463 * port which exports the net. Returns the number of nets exported.
1464 * Note: only single-wire nets are marked; all bus nets' temp2 are
1465 * marked NOPORTPROTO. Multiply exported nets have been collapsed at
1466 * both levels of hierarchy to a single net by the network maintainer.
1467 */
io_edifmarknetports(NODEPROTO * np)1468 INTBIG io_edifmarknetports(NODEPROTO *np)
1469 {
1470 NETWORK *net;
1471 PORTPROTO *pp;
1472 REGISTER INTBIG i, count, portnetcount;
1473
1474 for (net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1475 net->temp2 = (INTBIG) NOPORTPROTO;
1476
1477 /* initialize count of exported individual nets */
1478 portnetcount = 0;
1479 for (pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1480 {
1481 /* mark the nets that were exported with a pointer to their first port */
1482 if ((count = pp->network->buswidth) > 1)
1483 for (i = 0; i < count; i++)
1484 {
1485 if (pp->network->networklist[i]->temp2 == (INTBIG)NOPORTPROTO)
1486 {
1487 pp->network->networklist[i]->temp2 = (INTBIG)pp;
1488 portnetcount++;
1489 }
1490 } else if (pp->network->temp2 == (INTBIG)NOPORTPROTO)
1491 {
1492 pp->network->temp2 = (INTBIG)pp;
1493 portnetcount++;
1494 }
1495 }
1496 return(portnetcount);
1497 }
1498
1499 /*
1500 * function to incorporate external library interface data or reference file
1501 * for current cell into EDIF netlist - returns false if successful
1502 */
io_edifwritelibext(NODEPROTO * np)1503 BOOLEAN io_edifwritelibext(NODEPROTO *np)
1504 {
1505 REGISTER FILE *f;
1506 UCHAR1 buf[256];
1507 CHAR *filename;
1508 REGISTER INTBIG count;
1509 REGISTER VARIABLE *var;
1510
1511 /* import the external library for this cell, if it exists */
1512 var = getval((INTBIG) np, VNODEPROTO, VSTRING, x_("EDIF_external_lib"));
1513 if (var == NOVARIABLE) return(TRUE);
1514 f = xopen((CHAR *)var->addr, io_filetypeedif, x_(""), &filename);
1515 if (f == NULL)
1516 {
1517 ttyputerr(_("Cannot find EDIF external reference file %s on cell %s"),
1518 (CHAR *) var->addr, describenodeproto(np));
1519 return(TRUE);
1520 }
1521 for (;;)
1522 { /* copy the file */
1523 count = xfread(buf, 1, 256, f);
1524 if (count <= 0) break;
1525 if (xfwrite(buf, 1, count, edif_stream->file) != count)
1526 {
1527 ttyputerr(_("Error copying EDIF reference file %s"), (CHAR *) var->addr);
1528 xclose(f);
1529 return(TRUE);
1530 }
1531 }
1532 xclose(f);
1533 ttyputmsg(_("Incorporated external EDIF reference file %s"), (CHAR *) var->addr);
1534 return(FALSE);
1535 }
1536
1537 /*
1538 * convert a string token into a valid EDIF string token (note - NOT re-entrant coding)
1539 * In order to use NSC program ce2verilog, we need to suppress the '_' which replaces
1540 * ']' in bus definitions.
1541 */
io_ediftoken(CHAR * str)1542 CHAR *io_ediftoken(CHAR *str)
1543 {
1544 static CHAR token[100];
1545 CHAR *tkptr;
1546 REGISTER INTBIG i;
1547
1548 i = 0;
1549 if (*str >= '0' && *str <= '9') token[i++] = 'X';
1550 for (tkptr = token; (token[i++] = io_edifnotwhitespace(*str)); str++)
1551 {
1552 if (*str == ']') i--; /* suppress the ']' */
1553 else if (!io_edifvalid(*str)) token[i - 1] = '_';
1554 }
1555 token[i - 1] = '\0';
1556 return(tkptr);
1557 }
1558
io_edifnotwhitespace(CHAR ch)1559 CHAR io_edifnotwhitespace(CHAR ch)
1560 {
1561 if (ch == '\t' || ch == '\r' || ch == '\n' || ch == ' ') return('\0');
1562 return(ch);
1563 }
1564
io_edifvalid(CHAR ch)1565 BOOLEAN io_edifvalid(CHAR ch)
1566 {
1567 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
1568 (ch >= '0' && ch <= '9') || ch == '&' || ch == '_') return(TRUE);
1569 return(FALSE);
1570 }
1571
1572 /*
1573 * Returns 0 there is no valid name in "var", corrected name if valid.
1574 */
io_edifvalidname(VARIABLE * var)1575 CHAR *io_edifvalidname(VARIABLE *var)
1576 {
1577 CHAR *iptr;
1578 static CHAR name[WORD+1];
1579
1580 if (var == NOVARIABLE) return(0);
1581 estrcpy(name, (CHAR *)var->addr);
1582 if (estrlen(name) == 0) return(0);
1583 iptr = name;
1584
1585 /* allow '&' for the first character (this must be fixed latter if digit or '_') */
1586 if (*iptr == '&') iptr++;
1587
1588 /* allow _ and alphanumeric for others */
1589 for (iptr++; *iptr != 0; iptr++)
1590 if (*iptr != '_' && !(*iptr >= 'a' && *iptr <= 'z') && !(*iptr >= 'A' && *iptr <= 'Z') &&
1591 !(*iptr >= '0' && *iptr <= '9')) *iptr = '_';
1592
1593 return(name);
1594 }
1595
1596 /*
1597 * Write the EDIF format of the footprint, assuming standard
1598 * cell grid of routegrid (centimicrons) and standard connections
1599 * only on Metal1 and Metal2. cellType is obtained from the
1600 * stopExpand property, which is a property attached to
1601 * either the layout view or the schematic view (if there is one).
1602 */
io_edifwritefootprint(NODEPROTO * np,CHAR * name,INTBIG routegrid)1603 BOOLEAN io_edifwritefootprint(NODEPROTO *np, CHAR *name, INTBIG routegrid)
1604 {
1605 CHAR iname[100], *cellType, *cellRep, *portAccess, *defaultAccess, *truename;
1606 BOOLEAN connections;
1607 BOOLEAN allports;
1608 NODEPROTO *vnp;
1609 PORTPROTO *pp;
1610 VARIABLE *var;
1611 INTBIG width, height, accesskey;
1612 float route;
1613
1614 (void)estrcpy(iname, name);
1615 (void)estrcat(iname, x_(".foot"));
1616 io_fileout = xcreate(iname, io_filetypeedif, x_("EDIF File"), &truename);
1617 if (io_fileout == NULL)
1618 {
1619 if (truename != 0) ttyputerr(_("Cannot write %s"), iname);
1620 return(TRUE);
1621 }
1622
1623 /* make the access variable key */
1624 accesskey = makekey(x_("EDIF_access"));
1625
1626 /* calculate the actual routing grid in microns */
1627 route = (float)routegrid;
1628 route /= 100;
1629
1630 /* write the header */
1631 ttyputmsg(_("Writing footprint for cell %s"), io_ediftoken(np->protoname));
1632 xprintf(io_fileout, _("(footprint %.2fe-06\n"), route);
1633
1634 /* identify the layout type from the schematic 'stopExpand' property */
1635 var = NOVARIABLE;
1636 FOR_CELLGROUP(vnp, np)
1637 if (vnp->cellview == el_schematicview) break;
1638 if (vnp != NONODEPROTO)
1639 var = getval((INTBIG) vnp, VNODEPROTO, VSTRING, x_("EDIF_stopExpand"));
1640 if (var != NOVARIABLE) cellType = (CHAR *) var->addr; else
1641 {
1642 ttyputerr(_("cannot find stopExpand property on schematic view"));
1643 var = getval((INTBIG) np, VNODEPROTO, VSTRING, x_("EDIF_stopExpand"));
1644 if (var != NOVARIABLE)
1645 {
1646 cellType = (CHAR *) var->addr;
1647 ttyputmsg(_(" - - (but it is attached to the layout)"));
1648 } else cellType = x_("unknownLayoutRep");
1649 }
1650 if (namesamen(cellType, x_("subchip"), 7) == 0) cellType = x_("subchip");
1651 xprintf(io_fileout, x_(" (%s\n"), cellType);
1652
1653 /* get representation type from schematic (or layout) 'repType' property */
1654 var = NOVARIABLE;
1655 FOR_CELLGROUP(vnp, np)
1656 if (vnp->cellview == el_schematicview) break;
1657 if (vnp != NONODEPROTO)
1658 var = getval((INTBIG) vnp, VNODEPROTO, VSTRING, x_("EDIF_repType"));
1659 if (var != NOVARIABLE) cellRep = (CHAR *) var->addr; else
1660 {
1661 var = getval((INTBIG) np, VNODEPROTO, VSTRING, x_("EDIF_repType"));
1662 if (var != NOVARIABLE) cellRep = (CHAR *) var->addr; else
1663 if (namesame(cellType, x_("subchip")) == 0) cellRep = x_("logicCell"); else
1664 cellRep = x_("standard");
1665 }
1666
1667 /* get standard cell dimensions */
1668 width = (np->highx - np->lowx) / routegrid;
1669 height = (np->highy - np->lowy) / routegrid;
1670 xprintf(io_fileout, x_(" (%s %s (%ld %ld)\n"),
1671 io_ediftoken(np->protoname), cellRep, height, width);
1672
1673 /* find out if all port connections are wanted */
1674 var = getval((INTBIG) np, VNODEPROTO, VSTRING, x_("EDIF_placeallports"));
1675 if (var != NOVARIABLE)
1676 {
1677 allports = TRUE;
1678 defaultAccess = (CHAR *) var->addr;
1679 } else allports = FALSE;
1680
1681 /* find all ports */
1682 for (pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1683 {
1684 /* global connections are made in standard cells by abutment */
1685 if (!allports && (pp->userbits & BODYONLY) != 0) continue;
1686
1687 var = getvalkey((INTBIG) pp, VPORTPROTO, VSTRING, accesskey);
1688 if (var == NOVARIABLE)
1689 {
1690 var = getvalkey((INTBIG) pp->subnodeinst, VNODEINST, VSTRING, accesskey);
1691 if (!allports && var == NOVARIABLE)
1692 {
1693 ttyputmsg(_("Non-global port %s has no access direction"), pp->protoname);
1694 continue;
1695 }
1696 }
1697
1698 /* set up access field */
1699 if (var != NOVARIABLE) portAccess = (CHAR *) var->addr; else
1700 portAccess = defaultAccess;
1701
1702 /* find the connecting layers */
1703 connections = io_edifwriteportpositions(pp, np->lowx, np->lowy, portAccess, routegrid);
1704
1705 if (!connections)
1706 ttyputmsg(_("Non-global port %s has no connection access"), pp->protoname);
1707 }
1708
1709 /* finish up */
1710 xprintf(io_fileout, x_(")))\n"));
1711 xclose(io_fileout);
1712 ttyputmsg(_("%s written"), iname);
1713
1714 return(FALSE);
1715 }
1716
1717 /*
1718 * Access rules for port positions are in the port variable "EDIF_access"
1719 * which takes the form "material:DIR,material:DIR," for all valid
1720 * materials.
1721 */
io_edifwriteportpositions(PORTPROTO * pp,INTBIG cellx,INTBIG celly,CHAR * accessrules,INTBIG routegrid)1722 BOOLEAN io_edifwriteportpositions(PORTPROTO *pp, INTBIG cellx, INTBIG celly,
1723 CHAR *accessrules, INTBIG routegrid)
1724 {
1725 CHAR accessdirection[20], material[30], *pt, *portdirection;
1726 float xpos, ypos, scale;
1727 INTBIG xsize, ysize, cx, cy;
1728 INTBIG i, j;
1729 BOOLEAN connections;
1730 NODEINST *ni;
1731 PORTPROTO *ppt;
1732 static POLYGON *poly = NOPOLYGON;
1733
1734 /* establish the subnodeinst on which this port prototype resides */
1735 ni = pp->subnodeinst;
1736
1737 /* find which port proto is exported here */
1738 if (ni->parent->primindex != 0) ppt = pp; else
1739 ppt = pp->subportproto;
1740
1741 /* get the port signal direction */
1742 switch (pp->userbits & STATEBITS)
1743 {
1744 case REFINPORT:
1745 case INPORT:
1746 portdirection = x_("input");
1747 break;
1748 case REFOUTPORT:
1749 case OUTPORT:
1750 portdirection = x_("output");
1751 break;
1752 case BIDIRPORT:
1753 portdirection = x_("inout");
1754 break;
1755 default:
1756 if (namesamen(pp->protoname, x_("feed"), 4) == 0) portdirection = x_("feed"); else
1757 portdirection = x_("unknown");
1758 }
1759
1760 /* get polygon */
1761 (void)needstaticpolygon(&poly, 4, io_tool->cluster);
1762
1763 /* get this port geometry */
1764 shapeportpoly(ni, ppt, poly, FALSE);
1765 getcenter(poly, &cx, &cy);
1766
1767 /* offset center based on cell lower left corner */
1768 cx -= cellx;
1769 cy -= celly;
1770
1771 /* default all connection sizes to 4x4 microns */
1772 xsize = 4, ysize = 4;
1773
1774 /* make floating point port positions and scale them */
1775 scale = (float)routegrid;
1776 xpos = (float)cx;
1777 xpos /= scale;
1778 ypos = (float)cy;
1779 ypos /= scale;
1780
1781 i = j = 0;
1782 connections = FALSE;
1783 for (pt = accessrules;; pt++)
1784 {
1785 if (i == 0)
1786 {
1787 if (*pt == 0) break;
1788 if (*pt != ':')
1789 {
1790 material[j] = *pt;
1791 if (isupper(material[j])) tolower(material[j]);
1792 j++;
1793 continue;
1794 }
1795 material[j] = 0;
1796 i++;
1797 j = 0;
1798 continue;
1799 }
1800 if (*pt != ',' && *pt != 0)
1801 {
1802 accessdirection[j++] = *pt;
1803 continue;
1804 }
1805 accessdirection[j] = 0;
1806 xprintf(io_fileout, x_(" (%-9s %-7s (%-7s (%5.2f %5.2f) (%lde-6 %lde-6) %s))\n"),
1807 (namesame(portdirection, x_("feed")) == 0 ? io_edifupperstring(io_ediftoken(pp->protoname)) :
1808 io_ediflowerstring(io_ediftoken(pp->protoname))), portdirection, material,
1809 xpos, ypos, xsize, ysize, accessdirection);
1810 connections = TRUE;
1811
1812 if (*pt == 0) break;
1813 i = j = 0;
1814 }
1815 return(connections);
1816 }
1817
1818 /*
1819 * sometimes all the characters have to be lower case
1820 */
io_ediflowerstring(CHAR * str)1821 CHAR *io_ediflowerstring(CHAR *str)
1822 {
1823 CHAR *pt;
1824 static CHAR newstr[1000];
1825 INTBIG i;
1826
1827 for (pt = str, i = 0; *pt != 0; i++)
1828 newstr[i] = (isupper(*pt) ? tolower(*pt++) : *pt++);
1829 newstr[i] = '\0';
1830 return(newstr);
1831 }
1832
1833 /*
1834 * sometimes they all have to be upper case
1835 */
io_edifupperstring(CHAR * str)1836 CHAR *io_edifupperstring(CHAR *str)
1837 {
1838 CHAR *pt;
1839 static CHAR newstr[1000];
1840 INTBIG i;
1841
1842 for (pt = str, i = 0; *pt != 0; i++)
1843 newstr[i] = (islower(*pt) ? toupper(*pt++) : *pt++);
1844 newstr[i] = '\0';
1845 return(newstr);
1846 }
1847
1848 /* module: io_edifsymbol
1849 * function: will output all graphic objects of a symbol (extracted from
1850 * us_drawcell).
1851 */
io_edifsymbol(NODEPROTO * np)1852 void io_edifsymbol(NODEPROTO *np)
1853 {
1854 XARRAY trans;
1855 NODEINST *ni;
1856 ARCINST *ai;
1857 PORTPROTO *pp;
1858 static POLYGON *poly = NOPOLYGON;
1859
1860 /* get polygon */
1861 (void)needstaticpolygon(&poly, 4, io_tool->cluster);
1862
1863 EO_open_block(edif_stream, x_("symbol"));
1864 egraphic_override = EGWIRE;
1865 egraphic = EGUNKNOWN;
1866 for (pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1867 {
1868 EO_open_block(edif_stream, x_("portImplementation"));
1869 EO_put_identifier(edif_stream, io_ediftoken(pp->protoname));
1870 EO_open_block(edif_stream, x_("connectLocation"));
1871 shapeportpoly(pp->subnodeinst, pp->subportproto, poly, FALSE);
1872 io_edifsymbol_showpoly(poly);
1873
1874 /* close figure */
1875 io_edifsetgraphic(EGUNKNOWN);
1876 EO_close_block(edif_stream, x_("portImplementation"));
1877 }
1878 egraphic_override = EGUNKNOWN;
1879
1880 /* create the identity transform for this window */
1881 transid(trans);
1882
1883 for (ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1884 {
1885 io_edifsymbol_cell(ni, trans);
1886 }
1887 for (ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1888 {
1889 io_edifsymbol_arcinst(ai, trans);
1890 }
1891
1892 /* close figure */
1893 io_edifsetgraphic(EGUNKNOWN);
1894 EO_close_block(edif_stream, x_("symbol"));
1895 }
1896
1897 /* module: io_edifsymbol_cell
1898 * function: will output a specific symbol cell
1899 */
io_edifsymbol_cell(NODEINST * ni,XARRAY prevtrans)1900 void io_edifsymbol_cell(NODEINST *ni, XARRAY prevtrans)
1901 {
1902 XARRAY localtran, trans;
1903
1904 /* make transformation matrix within the current nodeinst */
1905 if (ni->rotation == 0 && ni->transpose == 0)
1906 {
1907 io_edifsymbol_nodeinst(ni, prevtrans);
1908 } else
1909 {
1910 makerot(ni, localtran);
1911 transmult(localtran, prevtrans, trans);
1912 io_edifsymbol_nodeinst(ni, trans);
1913 }
1914 }
1915
1916 /*
1917 * routine to symbol "ni" when transformed through "prevtrans".
1918 */
io_edifsymbol_nodeinst(NODEINST * ni,XARRAY prevtrans)1919 void io_edifsymbol_nodeinst(NODEINST *ni, XARRAY prevtrans)
1920 {
1921 INTBIG i, j, displaytotal, low, high, istext;
1922 CHAR *name;
1923 XARRAY localtran, subrot, trans;
1924 INTBIG bx, by, ux, uy, swap;
1925 static POLYGON *poly = NOPOLYGON;
1926 GRAPHICS *gra;
1927 NODEPROTO *np;
1928 PORTPROTO *pp;
1929 PORTEXPINST *pe;
1930 NODEINST *ino;
1931 ARCINST *iar;
1932 VARIABLE *var;
1933
1934 /* get polygon */
1935 (void)needstaticpolygon(&poly, 4, io_tool->cluster);
1936
1937 np = ni->proto;
1938
1939 /* get outline of nodeinst in the window */
1940 xform(ni->lowx, ni->lowy, &bx, &by, prevtrans);
1941 xform(ni->highx, ni->highy, &ux, &uy, prevtrans);
1942 if (bx > ux)
1943 {
1944 swap = bx;
1945 bx = ux;
1946 ux = swap;
1947 }
1948 if (by > uy)
1949 {
1950 swap = by;
1951 by = uy;
1952 uy = swap;
1953 }
1954
1955 /* write port names if appropriate */
1956 if (ni->firstportexpinst != NOPORTEXPINST)
1957 {
1958 for (pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1959 {
1960 /* us_writeprotoname(pe->exportproto, on, prevtrans, LAYERO,
1961 el_colcelltxt&on, w, 0, 0, 0, 0); */
1962 }
1963 }
1964
1965 /* primitive nodeinst: ask the technology how to draw it */
1966 if (np->primindex != 0)
1967 {
1968 high = nodepolys(ni, 0, NOWINDOWPART);
1969
1970 /* don't draw invisible pins */
1971 if (np == gen_invispinprim) low = 1; else
1972 low = 0;
1973
1974 for (j = low; j < high; j++)
1975 {
1976 /* get description of this layer */
1977 shapenodepoly(ni, j, poly);
1978
1979 /* ignore if this layer is not being displayed */
1980 gra = poly->desc;
1981 if ((gra->colstyle & INVISIBLE) != 0) continue;
1982
1983 /* draw the nodeinst */
1984 xformpoly(poly, prevtrans);
1985
1986 /* draw the nodeinst and restore the color */
1987 /* check for text ... */
1988 if (poly->style >= TEXTCENT && poly->style <= TEXTBOX)
1989 {
1990 istext = 1;
1991 /* close the current figure ... */
1992 io_edifsetgraphic(EGUNKNOWN);
1993 EO_open_block(edif_stream, x_("annotate"));
1994 } else istext = 0;
1995
1996 (void)io_edifsymbol_showpoly(poly);
1997 if (istext) EO_close_block(edif_stream, x_("annotate"));
1998 }
1999 } else
2000 {
2001 /* transform into the nodeinst for display of its guts */
2002 maketrans(ni, localtran);
2003 transmult(localtran, prevtrans, subrot);
2004
2005 /* get cell rectangle */
2006 maketruerectpoly(ni->lowx, ni->highx, ni->lowy, ni->highy, poly);
2007 poly->style = CLOSEDRECT;
2008 xformpoly(poly, prevtrans);
2009
2010 /* write ports that must always be displayed */
2011 for (pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2012 {
2013 if ((pp->userbits & PORTDRAWN) != 0)
2014 {
2015 if (pp->subnodeinst->rotation == 0 && pp->subnodeinst->transpose == 0)
2016 {
2017 /* EMPTY */
2018 /* us_writeprotoname(pp, LAYERA, subrot, LAYERO, el_colcelltxt, w,
2019 portcliplx, portcliphx, portcliply, portcliphy); */
2020 } else
2021 {
2022 makerot(pp->subnodeinst, localtran);
2023 transmult(localtran, subrot, trans);
2024 /* us_writeprotoname(pp, LAYERA, trans, LAYERO, el_colcelltxt, w,
2025 portcliplx, portcliphx, portcliply, portcliphy); */
2026 }
2027 }
2028 }
2029
2030 /* see if there are displayable variables on the cell */
2031 if ((displaytotal = tech_displayablenvars(ni, NOWINDOWPART, &tech_oneprocpolyloop)) != 0)
2032 io_edifsetgraphic(EGUNKNOWN);
2033 for (i = 0; i < displaytotal; i++)
2034 {
2035 var = tech_filldisplayablenvar(ni, poly, NOWINDOWPART, 0, &tech_oneprocpolyloop);
2036 xformpoly(poly, prevtrans);
2037 /* check for name */
2038 if (namesame((name = makename(var->key)), x_("EDIF_annotate")))
2039 {
2040 /* open the property */
2041 EO_open_block(edif_stream, x_("property"));
2042 EO_put_identifier(edif_stream, name);
2043 EO_open_block(edif_stream, x_("string"));
2044 } else
2045 {
2046 EO_open_block(edif_stream, x_("annotate"));
2047 name = NULL;
2048 }
2049 io_edifsymbol_showpoly(poly);
2050 if (name != NULL) EO_close_block(edif_stream, x_("property")); else
2051 EO_close_block(edif_stream, x_("annotate"));
2052 }
2053
2054 /* search through cell */
2055 for (ino = np->firstnodeinst; ino != NONODEINST; ino = ino->nextnodeinst)
2056 {
2057 io_edifsymbol_cell(ino, subrot);
2058 }
2059 for (iar = np->firstarcinst; iar != NOARCINST; iar = iar->nextarcinst)
2060 {
2061 io_edifsymbol_arcinst(iar, subrot);
2062 }
2063 }
2064 }
2065
2066 /*
2067 * routine to draw an arcinst. Returns indicator of what else needs to
2068 * be drawn. Returns negative if display interrupted
2069 */
io_edifsymbol_arcinst(ARCINST * ai,XARRAY trans)2070 void io_edifsymbol_arcinst(ARCINST *ai, XARRAY trans)
2071 {
2072 INTBIG i, j, displaytotal;
2073 INTBIG width;
2074 VARIABLE *var;
2075 CHAR *name;
2076 static POLYGON *poly = NOPOLYGON;
2077
2078 /* ask the technology how to draw the arcinst */
2079 /* get polygon */
2080 (void)needstaticpolygon(&poly, 4, io_tool->cluster);
2081
2082 i = arcpolys(ai, NOWINDOWPART);
2083
2084 /* get the endpoints of the arcinst */
2085 for (j = 0; j < i; j++)
2086 {
2087 /* generate a polygon, force line for path generation */
2088 width = ai->width;
2089 ai->width = 0;
2090 shapearcpoly(ai, j, poly);
2091 ai->width = width;
2092
2093 /* check for text (all arcs should not have text), do variables below */
2094 if (poly->style >= TEXTCENT && poly->style <= TEXTBOX) break;
2095
2096 /* draw the arcinst */
2097 xformpoly(poly, trans);
2098
2099 /* draw the arcinst and restore the color */
2100 io_edifsymbol_showpoly(poly);
2101 }
2102
2103 /* now get the variables */
2104 displaytotal = tech_displayableavars(ai, NOWINDOWPART, &tech_oneprocpolyloop);
2105 if (displaytotal != 0) io_edifsetgraphic(EGUNKNOWN);
2106 for (i = 0; i < displaytotal; i++)
2107 {
2108 var = tech_filldisplayableavar(ai, poly, NOWINDOWPART, 0, &tech_oneprocpolyloop);
2109 xformpoly(poly, trans);
2110
2111 /* check for name */
2112 if (namesame((name = makename(var->key)), x_("EDIF_annotate")))
2113 {
2114 /* open the property */
2115 EO_open_block(edif_stream, x_("property"));
2116 EO_put_identifier(edif_stream, name);
2117 EO_open_block(edif_stream, x_("string"));
2118 } else
2119 {
2120 EO_open_block(edif_stream, x_("annotate"));
2121 name = NULL;
2122 }
2123 io_edifsymbol_showpoly(poly);
2124 if (name != NULL) EO_close_block(edif_stream, x_("property")); else
2125 EO_close_block(edif_stream, x_("annotate"));
2126 }
2127 }
2128
io_edifsetgraphic(_egraphic type)2129 void io_edifsetgraphic(_egraphic type)
2130 {
2131 if (type == EGUNKNOWN)
2132 {
2133 /* terminate the figure */
2134 if (egraphic != EGUNKNOWN) EO_close_block(edif_stream, x_("figure"));
2135 egraphic = EGUNKNOWN;
2136 } else if (egraphic_override == EGUNKNOWN)
2137 {
2138 /* normal case */
2139 if (type != egraphic)
2140 {
2141 /* new egraphic type */
2142 if (egraphic != EGUNKNOWN) EO_close_block(edif_stream, x_("figure"));
2143 egraphic = type;
2144 EO_open_block(edif_stream, x_("figure"));
2145 EO_put_identifier(edif_stream, egraphic_text[egraphic]);
2146 }
2147 } else if (egraphic != egraphic_override)
2148 {
2149 /* override figure */
2150 if (egraphic != EGUNKNOWN) EO_close_block(edif_stream, x_("figure"));
2151 egraphic = egraphic_override;
2152 EO_open_block(edif_stream, x_("figure"));
2153 EO_put_identifier(edif_stream, egraphic_text[egraphic]);
2154 }
2155 }
2156
2157 /* module: io_edifsymbol_showpoly
2158 * function: will write polys into EDIF syntax
2159 * inputs: poly
2160 */
io_edifsymbol_showpoly(POLYGON * obj)2161 INTBIG io_edifsymbol_showpoly(POLYGON *obj)
2162 {
2163 INTBIG i, lx, ux, ly, uy, six, siy, height;
2164
2165 /* now draw the polygon */
2166 switch (obj->style)
2167 {
2168 case CIRCLE:
2169 case DISC: /* a circle */
2170 io_edifsetgraphic(EGART);
2171 i = computedistance(obj->xv[0], obj->yv[0], obj->xv[1], obj->yv[1]);
2172 EO_open_block(edif_stream, x_("circle"));
2173 io_edif_pt(obj->xv[0] - i, obj->yv[0]);
2174 io_edif_pt(obj->xv[0] + i, obj->yv[0]);
2175 EO_close_block(edif_stream, x_("circle"));
2176 return(0);
2177
2178 case CIRCLEARC:
2179 io_edifsetgraphic(EGART);
2180
2181 /* arcs at [i] points [1+i] [2+i] clockwise */
2182 if (obj->count == 0) return(1);
2183 if ((obj->count % 3) != 0) return(1);
2184 for (i = 0; i < obj->count; i += 3)
2185 {
2186 EO_open_block(edif_stream, x_("openShape"));
2187 EO_open_block(edif_stream, x_("curve"));
2188 EO_open_block(edif_stream, x_("arc"));
2189 io_edif_pt(obj->xv[i + 1], obj->yv[i + 1]);
2190
2191 /* calculate a point between the first and second point */
2192 io_compute_center(obj->xv[i], obj->yv[i],
2193 obj->xv[i + 1], obj->yv[i + 1], obj->xv[i + 2], obj->yv[i + 2], &six, &siy);
2194 io_edif_pt(six, siy);
2195 io_edif_pt(obj->xv[i + 2], obj->yv[i + 2]);
2196 EO_close_block(edif_stream, x_("openShape"));
2197 }
2198 return(0);
2199
2200 case FILLED: /* filled polygon */
2201 case FILLEDRECT: /* filled rectangle */
2202 case CLOSED: /* closed polygon outline */
2203 case CLOSEDRECT: /* closed rectangle outline */
2204 if (isbox(obj, &lx, &ux, &ly, &uy))
2205 {
2206 /* simple rectangular box */
2207 if (lx == ux && ly == uy)
2208 {
2209 if (egraphic_override == EGUNKNOWN) return(0);
2210 io_edifsetgraphic(EGART);
2211 EO_open_block(edif_stream, x_("dot"));
2212 io_edif_pt(lx, ly);
2213 EO_close_block(edif_stream, x_("dot"));
2214 } else
2215 {
2216 io_edifsetgraphic(EGART);
2217 EO_open_block(edif_stream, x_("rectangle"));
2218 io_edif_pt(lx, ly);
2219 io_edif_pt(ux, uy);
2220 EO_close_block(edif_stream, x_("rectangle"));
2221 }
2222 } else
2223 {
2224 io_edifsetgraphic(EGART);
2225 EO_open_block(edif_stream, x_("path"));
2226 EO_open_block(edif_stream, x_("pointList"));
2227 for (i = 0; i < obj->count; i++)
2228 io_edif_pt(obj->xv[i], obj->yv[i]);
2229 if (obj->count > 2) io_edif_pt(obj->xv[0], obj->yv[0]);
2230 EO_close_block(edif_stream, x_("path"));
2231 }
2232 return(0);
2233
2234 case TEXTCENT: /* text centered in box */
2235 case TEXTTOP: /* text below top of box */
2236 case TEXTBOT: /* text above bottom of box */
2237 case TEXTLEFT: /* text right of left edge of box */
2238 case TEXTRIGHT: /* text left of right edge of box */
2239 case TEXTTOPLEFT: /* text to lower-right of upper-left corner */
2240 case TEXTBOTLEFT: /* text to upper-right of lower-left corner */
2241 case TEXTTOPRIGHT: /* text to lower-left of upper-right corner */
2242 case TEXTBOTRIGHT: /* text to upper-left of lower-right corner */
2243 getbbox(obj, &lx, &ux, &ly, &uy);
2244 io_edifsetgraphic(EGUNKNOWN);
2245 EO_open_block(edif_stream, x_("stringDisplay"));
2246 EO_put_string(edif_stream, obj->string);
2247 EO_open_block(edif_stream, x_("display"));
2248 if (TXTGETPOINTS(TDGETSIZE(obj->textdescript)) != 0)
2249 {
2250 EO_open_block(edif_stream, x_("figureGroupOverride"));
2251 EO_put_identifier(edif_stream, egraphic_text[EGART]);
2252
2253 /* output the text height */
2254 EO_open_block(edif_stream, x_("textHeight"));
2255
2256 /* 2 pixels = 0.0278 in or 36 double pixels per inch */
2257 height = muldiv((el_curlib->lambda[el_curtech->techindex] * 10),
2258 TXTGETPOINTS(TDGETSIZE(obj->textdescript)), 36);
2259 EO_put_integer(edif_stream, io_edif_scale(height));
2260 EO_close_block(edif_stream, x_("figureGroupOverride"));
2261 } else EO_put_identifier(edif_stream, egraphic_text[EGART]);
2262 switch (obj->style)
2263 {
2264 case TEXTCENT:
2265 EO_put_block(edif_stream, x_("justify"), x_("CENTERCENTER"));
2266 break;
2267 case TEXTTOP: /* text below top of box */
2268 EO_put_block(edif_stream, x_("justify"), x_("LOWERCENTER"));
2269 break;
2270 case TEXTBOT: /* text above bottom of box */
2271 EO_put_block(edif_stream, x_("justify"), x_("UPPERCENTER"));
2272 break;
2273 case TEXTLEFT: /* text right of left edge of box */
2274 EO_put_block(edif_stream, x_("justify"), x_("CENTERRIGHT"));
2275 break;
2276 case TEXTRIGHT: /* text left of right edge of box */
2277 EO_put_block(edif_stream, x_("justify"), x_("CENTERLEFT"));
2278 break;
2279 case TEXTTOPLEFT: /* text to lower-right of upper-left corner */
2280 EO_put_block(edif_stream, x_("justify"), x_("LOWERRIGHT"));
2281 break;
2282 case TEXTBOTLEFT: /* text to upper-right of lower-left corner */
2283 EO_put_block(edif_stream, x_("justify"), x_("UPPERRIGHT"));
2284 break;
2285 case TEXTTOPRIGHT: /* text to lower-left of upper-right corner */
2286 EO_put_block(edif_stream, x_("justify"), x_("LOWERLEFT"));
2287 break;
2288 case TEXTBOTRIGHT: /* text to upper-left of lower-right corner */
2289 EO_put_block(edif_stream, x_("justify"), x_("UPPERLEFT"));
2290 break;
2291 }
2292 EO_put_block(edif_stream, x_("orientation"), x_("R0"));
2293 EO_open_block(edif_stream, x_("origin"));
2294 io_edif_pt(lx, ly);
2295 EO_close_block(edif_stream, x_("stringDisplay"));
2296 return(0);
2297
2298 case TEXTBOX: /* text centered and contained in box */
2299 getbbox(obj, &lx, &ux, &ly, &uy);
2300 return(0);
2301
2302 case OPENED: /* opened polygon outline */
2303 case OPENEDT1: /* opened polygon outline, texture 1 */
2304 case OPENEDT2: /* opened polygon outline, texture 2 */
2305 case OPENEDT3: /* opened polygon outline, texture 3 */
2306 case OPENEDO1: /* extended opened polygon outline */
2307 /* check for closed 4 sided figure */
2308 if (obj->count == 5 && obj->xv[4] == obj->xv[0] && obj->yv[4] == obj->yv[0])
2309 {
2310 obj->count = 4;
2311 i = obj->style;
2312 obj->style = CLOSED;
2313 if (isbox(obj, &lx, &ux, &ly, &uy))
2314 {
2315 /* simple rectangular box */
2316 if (lx == ux && ly == uy)
2317 {
2318 if (egraphic_override == EGUNKNOWN) return(0);
2319 io_edifsetgraphic(EGART);
2320 EO_open_block(edif_stream, x_("dot"));
2321 io_edif_pt(lx, ly);
2322 EO_close_block(edif_stream, x_("dot"));
2323 } else
2324 {
2325 io_edifsetgraphic(EGART);
2326 EO_open_block(edif_stream, x_("rectangle"));
2327 io_edif_pt(lx, ly);
2328 io_edif_pt(ux, uy);
2329 EO_close_block(edif_stream, x_("rectangle"));
2330 }
2331 obj->count = 5;
2332 obj->style = i;
2333 return(0);
2334 }
2335 obj->count = 5;
2336 obj->style = i;
2337 }
2338 io_edifsetgraphic(EGART);
2339 EO_open_block(edif_stream, x_("path"));
2340 EO_open_block(edif_stream, x_("pointList"));
2341 for (i = 0; i < obj->count; i++)
2342 io_edif_pt(obj->xv[i], obj->yv[i]);
2343 EO_close_block(edif_stream, x_("path"));
2344 return(0);
2345
2346 case VECTORS:
2347 io_edifsetgraphic(EGART);
2348 for (i = 0; i < obj->count; i += 2)
2349 {
2350 EO_open_block(edif_stream, x_("path"));
2351 EO_open_block(edif_stream, x_("pointList"));
2352 io_edif_pt(obj->xv[i], obj->yv[i]);
2353 io_edif_pt(obj->xv[i + 1], obj->yv[i + 1]);
2354 EO_close_block(edif_stream, x_("path"));
2355 }
2356 return(0);
2357
2358 /* unsupported operators */
2359 case CROSS: /* crosses (always have one point) */
2360 getcenter(obj, &six, &siy);
2361 return(0);
2362 }
2363
2364 /* unknown polygon type */
2365 return(1);
2366 }
2367
2368 /******** OUTPUT SUPPORT ********/
2369
2370 /* module: EO_open_stream
2371 function: Will create a stream block for a new edif file, this stream
2372 block is used for all future references.
2373 inputs:
2374 filename - the name of the file to open
2375 compress - the compress file or pretty-print
2376 returns: The new stream block
2377 */
EO_open_stream(CHAR * filename,INTBIG compress)2378 EO_STREAM_PTR EO_open_stream(CHAR *filename, INTBIG compress)
2379 {
2380 EO_STREAM_PTR stream;
2381 CHAR *truename;
2382
2383 /* get a new stream */
2384 if ((stream = EO_alloc_stream()) == NOEO_STREAM) return(NOEO_STREAM);
2385
2386 /* open the file */
2387 if ((stream->file = xcreate(filename, io_filetypeedif, _("EDIF File"), &truename)) == NULL)
2388 {
2389 if (truename != 0)
2390 {
2391 ttyputerr(_("edifout: could not create stream <%s>"), truename);
2392 ttyputerr(_("Cannot write %s"), truename);
2393 }
2394 (void)EO_free_stream(stream);
2395 return(NOEO_STREAM);
2396 }
2397
2398 /* update filename - allocate name and initialize the structure */
2399 if (allocstring(&stream->filename, truename, io_tool->cluster))
2400 {
2401 ttyputnomemory();
2402 return(NOEO_STREAM);
2403 }
2404
2405 stream->state = EO_OPENED;
2406 stream->compress = compress;
2407 return(stream);
2408 }
2409
2410 /* module: EO_close_stream
2411 function: Will close a stream file, and terminate all currently open
2412 blocks.
2413 returns: 0 on success, 1 on error
2414 */
EO_close_stream(EO_STREAM_PTR stream)2415 INTBIG EO_close_stream(EO_STREAM_PTR stream)
2416 {
2417 if (stream != NOEO_STREAM)
2418 {
2419 if (stream->blkstack_ptr)
2420 {
2421 if (EO_close_block(stream, stream->blkstack[0]))
2422 ttyputerr(_("edifout: internal error, closing stream <%s>"), stream->filename);
2423 }
2424 if (stream->state == EO_OPENED)
2425 {
2426 xprintf(stream->file, x_("\n"));
2427 xclose(stream->file);
2428 }
2429 (void)EO_free_stream(stream);
2430 return(0);
2431 }
2432 return(1);
2433 }
2434
2435 /* module: EO_open_block
2436 function: Will open a new keyword block, will indent the new block
2437 depending on depth of the keyword
2438 returns: 0 on success, 1 on error
2439 */
EO_open_block(EO_STREAM_PTR stream,CHAR * keyword)2440 INTBIG EO_open_block(EO_STREAM_PTR stream, CHAR *keyword)
2441 {
2442 if (stream != NOEO_STREAM && keyword != NULL)
2443 {
2444 /* output the new block */
2445 if (stream->blkstack_ptr)
2446 {
2447 xprintf(stream->file, x_("\n"));
2448 }
2449 if (allocstring(&stream->blkstack[stream->blkstack_ptr++], keyword,
2450 io_tool->cluster))
2451 {
2452 ttyputnomemory();
2453 return(1);
2454 }
2455
2456 /* output the keyword */
2457 xprintf(stream->file, x_("%s(%s%s"),
2458 GETBLANKS(stream->compress, stream->blkstack_ptr-1), DOSPACE, keyword);
2459 return(0);
2460 }
2461 return(1);
2462 }
2463
2464 /* module: EO_put_block
2465 function: Will output a one identifier block
2466 returns: 0 on success, 1 on error
2467 */
EO_put_block(EO_STREAM_PTR stream,CHAR * keyword,CHAR * identifier)2468 INTBIG EO_put_block(EO_STREAM_PTR stream, CHAR *keyword, CHAR *identifier)
2469 {
2470 if (stream != NOEO_STREAM && keyword != NULL)
2471 {
2472 /* output the new block */
2473 if (stream->blkstack_ptr)
2474 {
2475 (void)efprintf(stream->file, x_("\n"));
2476 }
2477
2478 /* output the keyword */
2479 xprintf(stream->file, x_("%s(%s%s %s%s)"),
2480 GETBLANKS(stream->compress, stream->blkstack_ptr), DOSPACE, keyword,
2481 identifier, DOSPACE);
2482 return(0);
2483 }
2484 return(1);
2485 }
2486
2487 /* module: EO_put_identifier
2488 function: Will output a string identifier to the stream file
2489 returns: 0 on success, 1 on error
2490 */
EO_put_identifier(EO_STREAM_PTR stream,CHAR * str)2491 INTBIG EO_put_identifier(EO_STREAM_PTR stream, CHAR *str)
2492 {
2493 if (stream != NOEO_STREAM && str != NULL)
2494 {
2495 xprintf(stream->file, x_(" %s"), str);
2496 return(0);
2497 }
2498 return(1);
2499 }
2500
2501 /* module: EO_put_string
2502 function: Will output a quoted string to the stream file
2503 returns: 0 on success, 1 on error
2504 */
EO_put_string(EO_STREAM_PTR stream,CHAR * str)2505 INTBIG EO_put_string(EO_STREAM_PTR stream, CHAR *str)
2506 {
2507 if (stream != NOEO_STREAM && str != NULL)
2508 {
2509 xprintf(stream->file, x_(" \"%s\""), str);
2510 return(0);
2511 }
2512 return(1);
2513 }
2514
2515 /* module: EO_put_integer
2516 function: Will output an integer to the stream edif file
2517 returns: 0 on success, 1 on error
2518 */
EO_put_integer(EO_STREAM_PTR stream,INTBIG val)2519 INTBIG EO_put_integer(EO_STREAM_PTR stream, INTBIG val)
2520 {
2521 if (stream != NOEO_STREAM)
2522 {
2523 xprintf(stream->file, x_(" %ld"), val);
2524 return(0);
2525 }
2526 return(1);
2527 }
2528
2529 /* module: EO_put_float
2530 function: Will output an integer to the stream edif file
2531 returns: 0 on success, 1 on error
2532 */
EO_put_float(EO_STREAM_PTR stream,double val)2533 INTBIG EO_put_float(EO_STREAM_PTR stream, double val)
2534 {
2535 if (stream != NOEO_STREAM)
2536 {
2537 xprintf(stream->file, x_("%s(%se %s%s)"), DOSPACE, DOSPACE, EO_get_exp(val), DOSPACE);
2538 return(0);
2539 }
2540 return(1);
2541 }
2542
EO_put_header(EO_STREAM_PTR stream,CHAR * program,CHAR * comment,CHAR * origin)2543 INTBIG EO_put_header(EO_STREAM_PTR stream, CHAR *program, CHAR *comment, CHAR *origin)
2544 {
2545 CHAR name[WORD+1];
2546 NODEPROTO *np;
2547
2548 /* output the standard EDIF 2 0 0 header */
2549 if (EO_open_block(stream, x_("edif"))) return(1);
2550 np = el_curlib->curnodeproto;
2551 (void)esnprintf(name, WORD+1, x_("%s"), np->protoname);
2552 if (EO_put_identifier(stream, name)) return(1);
2553 if (EO_put_block(stream, x_("edifVersion"), x_("2 0 0"))) return(1);
2554 if (EO_put_block(stream, x_("edifLevel"), x_("0"))) return(1);
2555 if (EO_open_block(stream, x_("keywordMap"))) return(1);
2556 if (EO_put_block(stream, x_("keywordLevel"), x_("0"))) return(1); /* was "1" */
2557 if (EO_close_block(stream, x_("keywordMap"))) return(1);
2558 if (EO_open_block(stream, x_("status"))) return(1);
2559 if (EO_open_block(stream, x_("written"))) return(1);
2560 if (EO_put_block(stream, x_("timeStamp"), EO_get_timestamp())) return(1);
2561 if (program != NULL && EO_put_block(stream, x_("program"), EO_make_string(program))) return(1);
2562 if (comment != NULL && EO_put_block(stream, x_("comment"), EO_make_string(comment))) return(1);
2563 if (origin != NULL && EO_put_block(stream, x_("dataOrigin"), EO_make_string(origin))) return(1);
2564 if (EO_close_block(stream, x_("status"))) return(1);
2565 return(0);
2566 }
2567
EO_close_block(EO_STREAM_PTR stream,CHAR * keyword)2568 INTBIG EO_close_block(EO_STREAM_PTR stream, CHAR *keyword)
2569 {
2570 INTBIG depth;
2571
2572 if (stream != NOEO_STREAM)
2573 {
2574 if (stream->blkstack_ptr == 0) return(0);
2575 if (keyword == NULL)
2576 {
2577 depth = 1;
2578 } else
2579 {
2580 /* scan for this saved keyword */
2581 for (depth = 1; depth <= stream->blkstack_ptr; depth++)
2582 {
2583 if (!namesame(stream->blkstack[stream->blkstack_ptr - depth ], keyword)) break;
2584 }
2585 if (depth > stream->blkstack_ptr)
2586 {
2587 ttyputerr(_("edifout: could not match keyword <%s>"), keyword);
2588 return(1);
2589 }
2590 }
2591
2592 /* now terminate and free keyword list */
2593 do
2594 {
2595 efree(stream->blkstack[--stream->blkstack_ptr]);
2596 xprintf(stream->file, x_("%s)"), DOSPACE);
2597 } while (--depth);
2598 return(0);
2599 }
2600 return(1);
2601 }
2602
2603 static EO_STREAM_PTR EO_stream_active = NOEO_STREAM;
2604
EO_alloc_stream(void)2605 EO_STREAM_PTR EO_alloc_stream(void)
2606 {
2607 EO_STREAM_PTR stream;
2608
2609 if ((stream = (EO_STREAM_PTR)emalloc(sizeof (EO_STREAM), io_tool->cluster)) == NOEO_STREAM)
2610 {
2611 ttyputnomemory();
2612 return(NOEO_STREAM);
2613 }
2614
2615 /* now initialize the structure */
2616 stream->filename = NULL;
2617 stream->file = NULL;
2618 stream->state = EO_CLOSED;
2619 stream->fpos = 0;
2620 stream->blkstack_ptr = 0;
2621
2622 /* add to the active list */
2623 stream->next = EO_stream_active;
2624 EO_stream_active = stream;
2625 return(stream);
2626 }
2627
EO_free_stream(EO_STREAM_PTR stream)2628 INTBIG EO_free_stream(EO_STREAM_PTR stream)
2629 {
2630 EO_STREAM_PTR temp;
2631
2632 if (stream == NOEO_STREAM)
2633 {
2634 ttyputerr(_("edifout: internal error, no stream block"));
2635 return(1);
2636 }
2637
2638 /* remove from the active list */
2639 if (stream == EO_stream_active) EO_stream_active = stream->next; else
2640 {
2641 /* scan for this stream */
2642 for (temp = EO_stream_active; temp != NOEO_STREAM; temp = temp->next)
2643 {
2644 if (temp->next == stream)
2645 {
2646 temp->next = stream->next;
2647 break;
2648 }
2649 }
2650 if (temp == NOEO_STREAM)
2651 {
2652 ttyputerr(_("edifout: internal error, can't find stream <%s>"),
2653 (stream->filename?stream->filename:x_("noname")));
2654 }
2655 }
2656 if (stream->filename != NULL)
2657 {
2658 efree(stream->filename);
2659 stream->filename = NULL;
2660 }
2661 efree((CHAR *)stream);
2662 return(0);
2663 }
2664
EO_get_timestamp(void)2665 CHAR *EO_get_timestamp(void)
2666 {
2667 static CHAR get_timestamp_buf[81];
2668 time_t t;
2669 CHAR month[4];
2670 unsigned short mon, yr, day, hour, min, sec;
2671
2672 t = getcurrenttime();
2673 (void)esscanf(timetostring(t), x_("%*s %s %hd %hd:%hd:%hd %hd"), &month[0], &day, &hour,
2674 &min, &sec, &yr);
2675
2676 mon = (unsigned short)parsemonth(month);
2677
2678 /* now make the time string */
2679 (void)esnprintf(get_timestamp_buf, 81, x_("%d %02d %02d %02d %02d %02d"),
2680 yr, mon, day, hour, min, sec);
2681 return(get_timestamp_buf);
2682 }
2683
2684 /* module: EO_make_string
2685 function: Will add quotes to a string
2686 returns: new string
2687 */
EO_make_string(CHAR * str)2688 CHAR *EO_make_string(CHAR *str)
2689 {
2690 static CHAR newstr[LINE+1];
2691
2692 (void)esnprintf(newstr, LINE+1, x_("\"%s\""), str);
2693 return(newstr);
2694 }
2695
2696 /* module: EO_get_exp
2697 function: Will expand an floating point number to a integer matissa and
2698 exponent
2699 inputs:
2700 val - the double to convert
2701 returns a pointer to the integer string
2702 */
EO_get_exp(double val)2703 CHAR *EO_get_exp(double val)
2704 {
2705 static CHAR result[WORD+1];
2706 CHAR temp[WORD+1], *pp, *rp;
2707 INTBIG nonzero, cnt, exp;
2708
2709 /* first generate an expanded value */
2710 (void)esnprintf(temp, WORD+1, x_("%9e"), val);
2711
2712 /* now parse out the result */
2713 pp = temp; rp = result;
2714 while (*pp != '.') *rp++ = *pp++;
2715
2716 /* now the rest of the matissa */
2717 nonzero = cnt = 0;
2718 pp++;
2719 while (*pp != 'e')
2720 {
2721 *rp++ = *pp;
2722 cnt++;
2723 if (*pp != '0') nonzero = cnt;
2724 pp++;
2725 }
2726
2727 /* now determine the integer conversion factor */
2728 rp -= (cnt - nonzero);
2729 *rp++ = ' ';
2730
2731 /* now convert the exponent */
2732 exp = eatoi(++pp);
2733 (void)esnprintf(rp, WORD-10, x_("%ld"), exp-nonzero);
2734 return(result);
2735 }
2736
2737 /* EDIF Options */
2738 static DIALOGITEM io_edifoptionsdialogitems[] =
2739 {
2740 /* 1 */ {0, {68,120,92,192}, BUTTON, N_("OK")},
2741 /* 2 */ {0, {68,16,92,88}, BUTTON, N_("Cancel")},
2742 /* 3 */ {0, {8,8,24,200}, CHECK, N_("Use Schematic View")},
2743 /* 4 */ {0, {36,8,52,96}, MESSAGE, N_("Input scale:")},
2744 /* 5 */ {0, {36,100,52,188}, EDITTEXT, x_("")}
2745 };
2746 static DIALOG io_edifoptionsdialog = {{50,75,151,284}, N_("EDIF Options"), 0, 5, io_edifoptionsdialogitems, 0, 0};
2747
2748 /* special items for the "EDIF Options" dialog: */
2749 #define DEDO_USESCHEMATIC 3 /* Use Schematic View (check) */
2750 #define DEDO_INPUTSCALE 5 /* Input scale (edit text) */
2751
io_edifoptionsdlog(void)2752 void io_edifoptionsdlog(void)
2753 {
2754 REGISTER INTBIG itemHit, i, *curstate;
2755 INTBIG newstate[NUMIOSTATEBITWORDS];
2756 REGISTER VARIABLE *var;
2757 CHAR line[50];
2758 float inputscale, newscale;
2759 void *dia;
2760
2761 dia = DiaInitDialog(&io_edifoptionsdialog);
2762 if (dia == 0) return;
2763 curstate = io_getstatebits();
2764 for(i=0; i<NUMIOSTATEBITWORDS; i++) newstate[i] = curstate[i];
2765 if ((curstate[0]&EDIFSCHEMATIC) != 0) DiaSetControl(dia, DEDO_USESCHEMATIC, 1);
2766 var = getval((INTBIG)io_tool, VTOOL, VFLOAT, x_("IO_edif_input_scale"));
2767 if (var == NOVARIABLE) inputscale = 1.0; else
2768 inputscale = castfloat(var->addr);
2769 esnprintf(line, 50, x_("%g"), inputscale);
2770 DiaSetText(dia, DEDO_INPUTSCALE, line);
2771
2772 /* loop until done */
2773 for(;;)
2774 {
2775 itemHit = DiaNextHit(dia);
2776 if (itemHit == OK || itemHit == CANCEL) break;
2777 if (itemHit == DEDO_USESCHEMATIC)
2778 {
2779 DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
2780 continue;
2781 }
2782 }
2783
2784 if (itemHit != CANCEL)
2785 {
2786 if (DiaGetControl(dia, DEDO_USESCHEMATIC) != 0) newstate[0] |= EDIFSCHEMATIC; else
2787 newstate[0] &= ~EDIFSCHEMATIC;
2788 for(i=0; i<NUMIOSTATEBITWORDS; i++) if (curstate[i] != newstate[i]) break;
2789 if (i < NUMIOSTATEBITWORDS) io_setstatebits(newstate);
2790 newscale = (float)eatof(DiaGetText(dia, DEDO_INPUTSCALE));
2791 if (newscale != inputscale)
2792 setval((INTBIG)io_tool, VTOOL, x_("IO_edif_input_scale"), castint(newscale), VFLOAT);
2793 }
2794 DiaDoneDialog(dia);
2795 }
2796
2797