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