1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: iodefi.c
6  * Input/output tool: DEF (Design Exchange Format) reader
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 /*
33  * Note that this reader was built by examining DEF files and reverse-engineering them.
34  * It does not claim to be compliant with the DEF specification, but it also does not
35  * claim to define a new specification.  It is merely incomplete.
36  */
37 
38 #include "config.h"
39 #include "global.h"
40 #include "egraphics.h"
41 #include "efunction.h"
42 #include "edialogs.h"
43 #include "iolefdef.h"
44 #include "tecart.h"
45 #include "tecgen.h"
46 #include "eio.h"
47 #include "usr.h"
48 
49 /*************** MISCELLANEOUS ***************/
50 
51 #define MAXLINE 2500
52 
53 static COMCOMP iodefop = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
54 	INPUTOPT, x_(" \t"), M_("DEF options"), 0};
55 
56 static INTBIG  io_deffilesize;
57 static INTBIG  io_deflineno;
58 static CHAR    io_defline[MAXLINE];
59 static CHAR    io_deffilename[300];
60 static INTBIG  io_deflinepos;
61 static INTBIG  io_defunits;
62 static VIADEF *io_deffirstviadef;
63 static void   *io_defprogressdialog;
64 
65 /* prototypes for local routines */
66 static CHAR      *io_defgetkeyword(FILE *f);
67 static BOOLEAN    io_defignoreblock(FILE *f, CHAR *command);
68 static BOOLEAN    io_defignoretosemicolon(FILE *f, CHAR *command);
69 static BOOLEAN    io_defreadfile(FILE *f, LIBRARY *lib);
70 static BOOLEAN    io_defreadpropertydefinitions(FILE *f);
71 static BOOLEAN    io_defreadnets(FILE *f, NODEPROTO *cell, BOOLEAN special, INTBIG options);
72 static BOOLEAN    io_defreadpins(FILE *f, NODEPROTO *cell);
73 static BOOLEAN    io_defreadcomponents(FILE *f, NODEPROTO *cell);
74 static BOOLEAN    io_defreadvias(FILE *f, NODEPROTO *cell);
75 static BOOLEAN    io_defreadcomponent(FILE *f, NODEPROTO *cell);
76 static BOOLEAN    io_defreadcoordinate(FILE *f, INTBIG *x, INTBIG *y);
77 static NODEPROTO *io_defgetnodeproto(CHAR *name, LIBRARY *curlib);
78 static BOOLEAN    io_defreadpin(FILE *f, NODEPROTO *cell);
79 static BOOLEAN    io_defreadorientation(FILE *f, INTSML *rot, INTSML *trans);
80 static void       io_defgetlayernodes(CHAR *name, NODEPROTO **pin, NODEPROTO **pure, ARCPROTO **arc);
81 static BOOLEAN    io_defreadunits(FILE *f);
82 static CHAR      *io_defmustgetkeyword(FILE *f, CHAR *where);
83 static BOOLEAN    io_defreadvia(FILE *f);
84 static BOOLEAN    io_defreadnet(FILE *f, NODEPROTO *cell, BOOLEAN special, INTBIG options);
85 static void       io_definerror(CHAR *command, ...);
86 static BOOLEAN    io_defgetpin(INTBIG x, INTBIG y, ARCPROTO *ap, NODEPROTO *cell,
87 					NODEINST **theni, PORTPROTO **thepp);
88 static void       io_defoptionsdlog(void);
89 static BOOLEAN    io_deffindconnection(INTBIG x, INTBIG y, ARCPROTO *ap, NODEPROTO *cell,
90 					NODEINST *noti, NODEINST **theni, PORTPROTO **thepp);
91 
92 /*
93  * Routine to free all memory associated with this module.
94  */
io_freedefimemory(void)95 void io_freedefimemory(void)
96 {
97 }
98 
99 /*
100  * Routine to initialize DEF I/O.
101  */
io_initdef(void)102 void io_initdef(void)
103 {
104 	DiaDeclareHook(x_("defopt"), &iodefop, io_defoptionsdlog);
105 }
106 
io_readdeflibrary(LIBRARY * lib)107 BOOLEAN io_readdeflibrary(LIBRARY *lib)
108 {
109 	FILE *fp;
110 	REGISTER BOOLEAN ret;
111 	CHAR *filename;
112 
113 	/* open the file */
114 	fp = xopen(lib->libfile, io_filetypedef, x_(""), &filename);
115 	if (fp == NULL)
116 	{
117 		ttyputerr(_("File %s not found"), lib->libfile);
118 		return(TRUE);
119 	}
120 	estrcpy(io_deffilename, filename);
121 
122 	/* prepare for input */
123 	io_deffilesize = filesize(fp);
124 	io_defprogressdialog = DiaInitProgress(_("Reading DEF file..."), 0);
125 	if (io_defprogressdialog == 0)
126 	{
127 		xclose(fp);
128 		return(TRUE);
129 	}
130 	DiaSetProgress(io_defprogressdialog, 0, io_deffilesize);
131 	io_deflineno = 0;
132 	io_deflinepos = 0;
133 	io_defline[0] = 0;
134 	io_defunits = 1000;
135 	io_deffirstviadef = NOVIADEF;
136 
137 	/* read the file */
138 	ret = io_defreadfile(fp, lib);
139 
140 	/* clean up */
141 	DiaDoneProgress(io_defprogressdialog);
142 	xclose(fp);
143 	if (!ret) ttyputmsg(_("DEF file %s is read"), lib->libfile); else
144 		ttyputmsg(_("Error reading DEF file %s"), lib->libfile);
145 	return(FALSE);
146 }
147 
148 /*
149  * Routine to read the DEF file in "f".
150  */
io_defreadfile(FILE * f,LIBRARY * lib)151 BOOLEAN io_defreadfile(FILE *f, LIBRARY *lib)
152 {
153 	REGISTER CHAR *key, *cellname;
154 	REGISTER INTBIG *options;
155 	CHAR curkey[200];
156 	REGISTER NODEPROTO *cell;
157 
158 	options = io_getstatebits();
159 
160 	for(;;)
161 	{
162 		/* get the next keyword */
163 		key = io_defgetkeyword(f);
164 		if (key == 0) break;
165 		if (namesame(key, x_("VERSION")) == 0 || namesame(key, x_("NAMESCASESENSITIVE")) == 0 ||
166 			namesame(key, x_("DIVIDERCHAR")) == 0 || namesame(key, x_("BUSBITCHARS")) == 0 ||
167 			namesame(key, x_("DIEAREA")) == 0 || namesame(key, x_("ROW")) == 0 ||
168 			namesame(key, x_("TRACKS")) == 0 || namesame(key, x_("GCELLGRID")) == 0 ||
169 			namesame(key, x_("HISTORY")) == 0 || namesame(key, x_("TECHNOLOGY")) == 0)
170 		{
171 			estrcpy(curkey, key);
172 			if (io_defignoretosemicolon(f, curkey)) return(TRUE);
173 			continue;
174 		}
175 		if (namesame(key, x_("DEFAULTCAP")) == 0 || namesame(key, x_("REGIONS")) == 0)
176 		{
177 			if (io_defignoreblock(f, key)) return(TRUE);
178 			continue;
179 		}
180 		if (namesame(key, x_("DESIGN")) == 0)
181 		{
182 			cellname = io_defmustgetkeyword(f, x_("DESIGN"));
183 			if (cellname == 0) return(TRUE);
184 			cell = us_newnodeproto(cellname, lib);
185 			if (cell == NONODEPROTO)
186 			{
187 				io_definerror(_("Cannot create cell '%s'"), cellname);
188 				return(TRUE);
189 			}
190 			if (io_defignoretosemicolon(f, _("DESIGN"))) return(TRUE);
191 			continue;
192 		}
193 
194 		if (namesame(key, x_("UNITS")) == 0)
195 		{
196 			if (io_defreadunits(f)) return(TRUE);
197 			continue;
198 		}
199 
200 		if (namesame(key, x_("PROPERTYDEFINITIONS")) == 0)
201 		{
202 			if (io_defreadpropertydefinitions(f)) return(TRUE);
203 			continue;
204 		}
205 
206 		if (namesame(key, x_("VIAS")) == 0)
207 		{
208 			if (io_defreadvias(f, cell)) return(TRUE);
209 			continue;
210 		}
211 
212 		if (namesame(key, x_("COMPONENTS")) == 0)
213 		{
214 			if (io_defreadcomponents(f, cell)) return(TRUE);
215 			continue;
216 		}
217 
218 		if (namesame(key, x_("PINS")) == 0)
219 		{
220 			if (io_defreadpins(f, cell)) return(TRUE);
221 			continue;
222 		}
223 
224 		if (namesame(key, x_("SPECIALNETS")) == 0)
225 		{
226 			if (io_defreadnets(f, cell, TRUE, options[0])) return(TRUE);
227 			continue;
228 		}
229 
230 		if (namesame(key, x_("NETS")) == 0)
231 		{
232 			if (io_defreadnets(f, cell, FALSE, options[0])) return(TRUE);
233 			continue;
234 		}
235 
236 		if (namesame(key, x_("END")) == 0)
237 		{
238 			key = io_defgetkeyword(f);
239 			break;
240 		}
241 	}
242 	return(FALSE);
243 }
244 
245 /*************** VIAS ***************/
246 
io_defreadvias(FILE * f,NODEPROTO * cell)247 BOOLEAN io_defreadvias(FILE *f, NODEPROTO *cell)
248 {
249 	REGISTER CHAR *key;
250 	CHAR curkey[200];
251 
252 	if (io_defignoretosemicolon(f, _("VIAS"))) return(TRUE);
253 	for(;;)
254 	{
255 		/* get the next keyword */
256 		key = io_defmustgetkeyword(f, x_("VIAs"));
257 		if (key == 0) return(TRUE);
258 		if (namesame(key, x_("-")) == 0)
259 		{
260 			if (io_defreadvia(f)) return(TRUE);
261 			continue;
262 		}
263 
264 		if (namesame(key, x_("END")) == 0)
265 		{
266 			key = io_defgetkeyword(f);
267 			break;
268 		}
269 
270 		/* ignore the keyword */
271 		estrcpy(curkey, key);
272 		if (io_defignoretosemicolon(f, curkey)) return(TRUE);
273 	}
274 	return(FALSE);
275 }
276 
io_defreadvia(FILE * f)277 BOOLEAN io_defreadvia(FILE *f)
278 {
279 	REGISTER CHAR *key;
280 	INTBIG lx, hx, ly, hy;
281 	NODEPROTO *pin, *pure;
282 	ARCPROTO *ap;
283 	REGISTER VIADEF *vd;
284 
285 	/* get the via name */
286 	key = io_defmustgetkeyword(f, x_("VIA"));
287 	if (key == 0) return(TRUE);
288 
289 	/* create a new via definition */
290 	vd = (VIADEF *)emalloc(sizeof (VIADEF), io_tool->cluster);
291 	if (vd == 0) return(TRUE);
292 	(void)allocstring(&vd->vianame, key, io_tool->cluster);
293 	vd->sx = vd->sy = 0;
294 	vd->via = NONODEPROTO;
295 	vd->lay1 = vd->lay2 = NOARCPROTO;
296 	vd->nextviadef = io_deffirstviadef;
297 	io_deffirstviadef = vd;
298 
299 	for(;;)
300 	{
301 		/* get the next keyword */
302 		key = io_defmustgetkeyword(f, x_("VIA"));
303 		if (key == 0) return(TRUE);
304 		if (namesame(key, x_("+")) == 0)
305 		{
306 			key = io_defmustgetkeyword(f, x_("VIA"));
307 			if (key == 0) return(TRUE);
308 			if (namesame(key, x_("RECT")) == 0)
309 			{
310 				/* handle definition of a via rectangle */
311 				key = io_defmustgetkeyword(f, x_("VIA"));
312 				if (key == 0) return(TRUE);
313 				io_defgetlayernodes(key, &pin, &pure, &ap);
314 				if (pure == NONODEPROTO)
315 				{
316 					io_definerror(_("Layer %s not in current technology"), key);
317 					pure = NONODEPROTO;
318 				}
319 				if (namesamen(key, x_("VIA"), 3) == 0)
320 				{
321 					if (pin == NONODEPROTO) pin = gen_univpinprim;
322 					vd->via = pin;
323 				}
324 				if (namesamen(key, x_("METAL"), 5) == 0)
325 				{
326 					if (ap == NOARCPROTO) ap = gen_universalarc;
327 					if (vd->lay1 == NOARCPROTO) vd->lay1 = ap; else
328 						vd->lay2 = ap;
329 				}
330 				if (io_defreadcoordinate(f, &lx, &ly)) return(TRUE);
331 				if (io_defreadcoordinate(f, &hx, &hy)) return(TRUE);
332 
333 				/* accumulate largest contact size */
334 				if (hx-lx > vd->sx) vd->sx = hx - lx;
335 				if (hy-ly > vd->sy) vd->sy = hy - ly;
336 				continue;
337 			}
338 			continue;
339 		}
340 
341 		if (namesame(key, x_(";")) == 0)
342 			break;
343 	}
344 	if (vd->via != NONODEPROTO)
345 	{
346 		if (vd->sx == 0) vd->sx = vd->via->highx - vd->via->lowx;
347 		if (vd->sy == 0) vd->sy = vd->via->highy - vd->via->lowy;
348 	}
349 	return(FALSE);
350 }
351 
352 /*************** COMPONENTS ***************/
353 
io_defreadcomponents(FILE * f,NODEPROTO * cell)354 BOOLEAN io_defreadcomponents(FILE *f, NODEPROTO *cell)
355 {
356 	REGISTER CHAR *key;
357 	CHAR curkey[200];
358 
359 	if (io_defignoretosemicolon(f, _("COMPONENTS"))) return(1);
360 	for(;;)
361 	{
362 		/* get the next keyword */
363 		key = io_defmustgetkeyword(f, x_("COMPONENTs"));
364 		if (key == 0) return(TRUE);
365 		if (namesame(key, x_("-")) == 0)
366 		{
367 			if (io_defreadcomponent(f, cell)) return(TRUE);
368 			continue;
369 		}
370 
371 		if (namesame(key, x_("END")) == 0)
372 		{
373 			key = io_defgetkeyword(f);
374 			break;
375 		}
376 
377 		/* ignore the keyword */
378 		estrcpy(curkey, key);
379 		if (io_defignoretosemicolon(f, curkey)) return(TRUE);
380 	}
381 	return(FALSE);
382 }
383 
io_defreadcomponent(FILE * f,NODEPROTO * cell)384 BOOLEAN io_defreadcomponent(FILE *f, NODEPROTO *cell)
385 {
386 	REGISTER CHAR *key;
387 	INTBIG x, y, cx, cy;
388 	INTBIG sx, sy;
389 	REGISTER INTBIG lx, hx, ly, hy;
390 	REGISTER NODEINST *ni;
391 	REGISTER NODEPROTO *np;
392 	REGISTER VARIABLE *var;
393 	INTSML rot, trans;
394 	CHAR compname[200], modelname[200];
395 
396 	/* get the component name and model name */
397 	key = io_defmustgetkeyword(f, x_("COMPONENT"));
398 	if (key == 0) return(TRUE);
399 	estrcpy(compname, key);
400 	key = io_defmustgetkeyword(f, x_("COMPONENT"));
401 	if (key == 0) return(TRUE);
402 	estrcpy(modelname, key);
403 
404 	/* find the named cell */
405 	np = io_defgetnodeproto(modelname, cell->lib);
406 	if (np == NONODEPROTO)
407 	{
408 		io_definerror(_("Unknown cell (%s)"), modelname);
409 		return(TRUE);
410 	}
411 
412 	for(;;)
413 	{
414 		/* get the next keyword */
415 		key = io_defmustgetkeyword(f, x_("COMPONENT"));
416 		if (key == 0) return(TRUE);
417 		if (namesame(key, x_("+")) == 0)
418 		{
419 			key = io_defmustgetkeyword(f, x_("COMPONENT"));
420 			if (key == 0) return(TRUE);
421 			if (namesame(key, x_("PLACED")) == 0 || namesame(key, x_("FIXED")) == 0)
422 			{
423 				/* handle placement */
424 				if (io_defreadcoordinate(f, &x, &y)) return(TRUE);
425 				if (io_defreadorientation(f, &rot, &trans)) return(TRUE);
426 
427 				/* place the node */
428 				defaultnodesize(np, &sx, &sy);
429 				corneroffset(NONODEINST, np, 0, 0, &cx, &cy, FALSE);
430 				lx = x - cx;   hx = lx + sx;
431 				ly = y - cy;   hy = ly + sy;
432 				ni = newnodeinst(np, lx, hx, ly, hy, trans, rot, cell);
433 				if (ni == NONODEINST)
434 				{
435 					io_definerror(_("Unable to create node"));
436 					return(TRUE);
437 				}
438 				endobjectchange((INTBIG)ni, VNODEINST);
439 				var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key,
440 					(INTBIG)compname, VSTRING|VDISPLAY);
441 				if (var != NOVARIABLE)
442 					defaulttextsize(3, var->textdescript);
443 				continue;
444 			}
445 			continue;
446 		}
447 
448 		if (namesame(key, x_(";")) == 0)
449 			break;
450 	}
451 	return(FALSE);
452 }
453 
454 /*************** PINS ***************/
455 
io_defreadpins(FILE * f,NODEPROTO * cell)456 BOOLEAN io_defreadpins(FILE *f, NODEPROTO *cell)
457 {
458 	REGISTER CHAR *key;
459 	CHAR curkey[200];
460 
461 	if (io_defignoretosemicolon(f, _("PINS"))) return(TRUE);
462 	for(;;)
463 	{
464 		/* get the next keyword */
465 		key = io_defmustgetkeyword(f, x_("PINs"));
466 		if (key == 0) return(TRUE);
467 		if (namesame(key, x_("-")) == 0)
468 		{
469 			if (io_defreadpin(f, cell)) return(TRUE);
470 			continue;
471 		}
472 
473 		if (namesame(key, x_("END")) == 0)
474 		{
475 			key = io_defgetkeyword(f);
476 			break;
477 		}
478 
479 		/* ignore the keyword */
480 		estrcpy(curkey, key);
481 		if (io_defignoretosemicolon(f, curkey)) return(TRUE);
482 	}
483 	return(FALSE);
484 }
485 
io_defreadpin(FILE * f,NODEPROTO * cell)486 BOOLEAN io_defreadpin(FILE *f, NODEPROTO *cell)
487 {
488 	REGISTER CHAR *key;
489 	INTBIG lx, hx, ly, hy, x, y;
490 	REGISTER INTBIG portbits, i, havecoord;
491 	REGISTER NODEINST *ni;
492 	NODEPROTO *np, *pure;
493 	ARCPROTO *ap;
494 	REGISTER PORTPROTO *pp;
495 	INTSML rot, trn;
496 	CHAR pinname[200];
497 	XARRAY trans;
498 
499 	/* get the pin name */
500 	key = io_defmustgetkeyword(f, x_("PIN"));
501 	if (key == 0) return(TRUE);
502 	estrcpy(pinname, key);
503 	portbits = havecoord = 0;
504 	np = NONODEPROTO;
505 
506 	for(;;)
507 	{
508 		/* get the next keyword */
509 		key = io_defmustgetkeyword(f, x_("PIN"));
510 		if (key == 0) return(TRUE);
511 		if (namesame(key, x_("+")) == 0)
512 		{
513 			key = io_defmustgetkeyword(f, x_("PIN"));
514 			if (key == 0) return(TRUE);
515 			if (namesame(key, x_("NET")) == 0)
516 			{
517 				key = io_defmustgetkeyword(f, _("net name"));
518 				if (key == 0) return(TRUE);
519 				continue;
520 			}
521 			if (namesame(key, x_("DIRECTION")) == 0)
522 			{
523 				key = io_defmustgetkeyword(f, x_("DIRECTION"));
524 				if (key == 0) return(TRUE);
525 				if (namesame(key, x_("INPUT")) == 0) portbits = INPORT; else
526 				if (namesame(key, x_("OUTPUT")) == 0) portbits = OUTPORT; else
527 				if (namesame(key, x_("INOUT")) == 0) portbits = BIDIRPORT; else
528 				if (namesame(key, x_("FEEDTHRU")) == 0) portbits = BIDIRPORT; else
529 				{
530 					io_definerror(_("Unknown direction (%s)"), key);
531 					return(TRUE);
532 				}
533 				continue;
534 			}
535 			if (namesame(key, x_("USE")) == 0)
536 			{
537 				key = io_defmustgetkeyword(f, x_("USE"));
538 				if (key == 0) return(TRUE);
539 				if (namesame(key, x_("SIGNAL")) == 0) portbits = portbits; else
540 				if (namesame(key, x_("POWER")) == 0) portbits = PWRPORT; else
541 				if (namesame(key, x_("GROUND")) == 0) portbits = GNDPORT; else
542 				if (namesame(key, x_("CLOCK")) == 0) portbits = CLKPORT; else
543 				if (namesame(key, x_("TIEOFF")) == 0) portbits = portbits; else
544 				if (namesame(key, x_("ANALOG")) == 0) portbits = portbits; else
545 				{
546 					io_definerror(_("Unknown usage (%s)"), key);
547 					return(TRUE);
548 				}
549 				continue;
550 			}
551 			if (namesame(key, x_("LAYER")) == 0)
552 			{
553 				key = io_defmustgetkeyword(f, x_("LAYER"));
554 				if (key == 0) return(TRUE);
555 				io_defgetlayernodes(key, &np, &pure, &ap);
556 				if (np == NONODEPROTO)
557 				{
558 					io_definerror(_("Unknown layer (%s)"), key);
559 					return(TRUE);
560 				}
561 				if (io_defreadcoordinate(f, &lx, &ly)) return(TRUE);
562 				if (io_defreadcoordinate(f, &hx, &hy)) return(TRUE);
563 				continue;
564 			}
565 			if (namesame(key, x_("PLACED")) == 0)
566 			{
567 				/* get pin location and orientation */
568 				if (io_defreadcoordinate(f, &x, &y)) return(TRUE);
569 				if (io_defreadorientation(f, &rot, &trn)) return(TRUE);
570 				havecoord = 1;
571 				continue;
572 			}
573 			continue;
574 		}
575 
576 		if (namesame(key, x_(";")) == 0)
577 			break;
578 	}
579 
580 	/* all factors read, now place the pin */
581 	if (np != NONODEPROTO && havecoord != 0)
582 	{
583 		/* determine the pin size */
584 		makeangle(rot, trn, trans);
585 		rot = trn = 0;
586 		xform(lx, ly, &lx, &ly, trans);
587 		xform(hx, hy, &hx, &hy, trans);
588 		if (lx > hx) { i = lx;   lx = hx;   hx = i; }
589 		if (ly > hy) { i = ly;   ly = hy;   hy = i; }
590 		lx += x;   hx += x;
591 		ly += y;   hy += y;
592 
593 		/* make the pin */
594 		ni = newnodeinst(np, lx, hx, ly, hy, trn, rot, cell);
595 		if (ni == NONODEINST)
596 		{
597 			io_definerror(_("Unable to create pin"));
598 			return(TRUE);
599 		}
600 		endobjectchange((INTBIG)ni, VNODEINST);
601 		pp = newportproto(cell, ni, np->firstportproto, pinname);
602 		if (pp == NOPORTPROTO)
603 		{
604 			io_definerror(_("Unable to create pin name"));
605 			return(TRUE);
606 		}
607 		pp->userbits = (pp->userbits & ~STATEBITS) | portbits;
608 	}
609 	return(FALSE);
610 }
611 
612 /*************** NETS ***************/
613 
io_defreadnets(FILE * f,NODEPROTO * cell,BOOLEAN special,INTBIG options)614 BOOLEAN io_defreadnets(FILE *f, NODEPROTO *cell, BOOLEAN special, INTBIG options)
615 {
616 	REGISTER CHAR *key;
617 	CHAR curkey[200];
618 
619 	for(;;)
620 	{
621 		/* get the next keyword */
622 		key = io_defmustgetkeyword(f, x_("NETs"));
623 		if (key == 0) return(TRUE);
624 		if (namesame(key, x_("-")) == 0)
625 		{
626 			if (io_defreadnet(f, cell, special, options)) return(TRUE);
627 			continue;
628 		}
629 		if (namesame(key, x_("END")) == 0)
630 		{
631 			key = io_defgetkeyword(f);
632 			break;
633 		}
634 
635 		/* ignore the keyword */
636 		estrcpy(curkey, key);
637 		if (io_defignoretosemicolon(f, curkey)) return(TRUE);
638 	}
639 	return(FALSE);
640 }
641 
io_defreadnet(FILE * f,NODEPROTO * cell,BOOLEAN special,INTBIG options)642 BOOLEAN io_defreadnet(FILE *f, NODEPROTO *cell, BOOLEAN special, INTBIG options)
643 {
644 	REGISTER CHAR *key;
645 	INTBIG lx, hx, ly, hy, plx, ply, phx, phy, sx, sy, fx, fy, tx, ty;
646 	REGISTER INTBIG i, curx, cury, lastx, lasty, pathstart, placedvia, width,
647 		wantpinpairs, specialwidth, bits;
648 	NODEINST *ni, *lastni, *nextni;
649 	REGISTER NODEINST *lastlogni;
650 	REGISTER ARCINST *ai;
651 	REGISTER BOOLEAN foundcoord;
652 	PORTPROTO *pp, *lastpp, *nextpp;
653 	REGISTER PORTPROTO *lastlogpp;
654 	REGISTER NODEPROTO *np;
655 	NODEPROTO *pin, *pure;
656 	ARCPROTO *routap;
657 	REGISTER VARIABLE *var;
658 	float v;
659 	CHAR netname[200];
660 	REGISTER VIADEF *vd;
661 
662 	/* get the net name */
663 	key = io_defmustgetkeyword(f, x_("NET"));
664 	if (key == 0) return(TRUE);
665 	estrcpy(netname, key);
666 
667 	/* get the next keyword */
668 	key = io_defmustgetkeyword(f, x_("NET"));
669 	if (key == 0) return(TRUE);
670 
671 	/* scan the "net" statement */
672 	wantpinpairs = 1;
673 	lastx = lasty = 0;
674 	pathstart = 1;
675 	lastlogni = NONODEINST;
676 	for(;;)
677 	{
678 		/* examine the next keyword */
679 		if (namesame(key, x_(";")) == 0) break;
680 
681 		if (namesame(key, x_("+")) == 0)
682 		{
683 			wantpinpairs = 0;
684 			key = io_defmustgetkeyword(f, x_("NET"));
685 			if (key == 0) return(TRUE);
686 
687 			if (namesame(key, x_("USE")) == 0)
688 			{
689 				/* ignore "USE" keyword */
690 				key = io_defmustgetkeyword(f, x_("NET"));
691 				if (key == 0) return(TRUE);
692 			} else if (namesame(key, x_("ROUTED")) == 0)
693 			{
694 				/* handle "ROUTED" keyword */
695 				key = io_defmustgetkeyword(f, x_("NET"));
696 				if (key == 0) return(TRUE);
697 				io_defgetlayernodes(key, &pin, &pure, &routap);
698 				if (pin == NONODEPROTO)
699 				{
700 					io_definerror(_("Unknown layer (%s)"), key);
701 					return(TRUE);
702 				}
703 				pathstart = 1;
704 				if (special)
705 				{
706 					/* specialnets have width here */
707 					key = io_defmustgetkeyword(f, x_("NET"));
708 					if (key == 0) return(TRUE);
709 					v = (float)eatof(key) / (float)io_defunits;
710 					specialwidth = scalefromdispunit(v, DISPUNITMIC);
711 				}
712 			} else if (namesame(key, x_("FIXED")) == 0)
713 			{
714 				/* handle "FIXED" keyword */
715 				key = io_defmustgetkeyword(f, x_("NET"));
716 				if (key == 0) return(TRUE);
717 				io_defgetlayernodes(key, &pin, &pure, &routap);
718 				if (pin == NONODEPROTO)
719 				{
720 					io_definerror(_("Unknown layer (%s)"), key);
721 					return(TRUE);
722 				}
723 				pathstart = 1;
724 			} else if (namesame(key, x_("SHAPE")) == 0)
725 			{
726 				/* handle "SHAPE" keyword */
727 				key = io_defmustgetkeyword(f, x_("NET"));
728 				if (key == 0) return(TRUE);
729 			} else
730 			{
731 				io_definerror(_("Cannot handle '%s' nets"), key);
732 				return(TRUE);
733 			}
734 
735 			/* get next keyword */
736 			key = io_defmustgetkeyword(f, x_("NET"));
737 			if (key == 0) return(TRUE);
738 			continue;
739 		}
740 
741 		/* if still parsing initial pin pairs, do so */
742 		if (wantpinpairs != 0)
743 		{
744 			/* it must be the "(" of a pin pair */
745 			if (namesame(key, x_("(")) != 0)
746 			{
747 				io_definerror(_("Expected '(' of pin pair"));
748 				return(TRUE);
749 			}
750 
751 			/* get the pin names */
752 			key = io_defmustgetkeyword(f, x_("NET"));
753 			if (key == 0) return(TRUE);
754 			if (namesame(key, x_("PIN")) == 0)
755 			{
756 				/* find the export */
757 				key = io_defmustgetkeyword(f, x_("NET"));
758 				if (key == 0) return(TRUE);
759 				pp = getportproto(cell, key);
760 				if (pp == NOPORTPROTO)
761 				{
762 					io_definerror(_("Warning: unknown pin '%s'"), key);
763 					if (io_defignoretosemicolon(f, _("NETS"))) return(TRUE);
764 					return(FALSE);
765 				}
766 				ni = pp->subnodeinst;
767 				pp = pp->subportproto;
768 			} else
769 			{
770 				for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
771 				{
772 					var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
773 					if (var == NOVARIABLE) continue;
774 					if (namesame((CHAR *)var->addr, key) == 0) break;
775 				}
776 				if (ni == NONODEINST)
777 				{
778 					io_definerror(_("Unknown component '%s'"), key);
779 					return(TRUE);
780 				}
781 
782 				/* get the port name */
783 				key = io_defmustgetkeyword(f, x_("NET"));
784 				if (key == 0) return(TRUE);
785 				pp = getportproto(ni->proto, key);
786 				if (pp == NOPORTPROTO)
787 				{
788 					io_definerror(_("Unknown port '%s' on component '%s'"),
789 						key, (CHAR *)var->addr);
790 					return(TRUE);
791 				}
792 			}
793 
794 			/* get the close parentheses */
795 			key = io_defmustgetkeyword(f, x_("NET"));
796 			if (key == 0) return(TRUE);
797 			if (namesame(key, x_(")")) != 0)
798 			{
799 				io_definerror(_("Expected ')' of pin pair"));
800 				return(TRUE);
801 			}
802 
803 			if (lastlogni != NONODEINST && (options&DEFNOLOGICAL) == 0)
804 			{
805 				portposition(ni, pp, &fx, &fy);
806 
807 				/* LINTED "lastlogpp" used in proper order */
808 				portposition(lastlogni, lastlogpp, &tx, &ty);
809 				bits = us_makearcuserbits(gen_unroutedarc);
810 				ai = newarcinst(gen_unroutedarc, defaultarcwidth(gen_unroutedarc), bits,
811 					ni, pp, fx, fy, lastlogni, lastlogpp, tx, ty, cell);
812 				if (ai == NOARCINST)
813 				{
814 					io_definerror(_("Could not create unrouted arc"));
815 					return(TRUE);
816 				}
817 				endobjectchange((INTBIG)ai, VARCINST);
818 			}
819 			lastlogni = ni;
820 			lastlogpp = pp;
821 
822 			/* get the next keyword and continue parsing */
823 			key = io_defmustgetkeyword(f, x_("NET"));
824 			if (key == 0) return(TRUE);
825 			continue;
826 		}
827 
828 		/* handle "new" start of coordinate trace */
829 		if (namesame(key, x_("NEW")) == 0)
830 		{
831 			key = io_defmustgetkeyword(f, x_("NET"));
832 			if (key == 0) return(TRUE);
833 			io_defgetlayernodes(key, &pin, &pure, &routap);
834 			if (pin == NONODEPROTO)
835 			{
836 				io_definerror(_("Unknown layer (%s)"), key);
837 				return(TRUE);
838 			}
839 			pathstart = 1;
840 			key = io_defmustgetkeyword(f, x_("NET"));
841 			if (key == 0) return(TRUE);
842 			if (special)
843 			{
844 				/* specialnets have width here */
845 				v = (float)eatof(key) / (float)io_defunits;
846 				specialwidth = scalefromdispunit(v, DISPUNITMIC);
847 
848 				/* get the next keyword */
849 				key = io_defmustgetkeyword(f, x_("NET"));
850 				if (key == 0) return(TRUE);
851 			}
852 			continue;
853 		}
854 
855 		foundcoord = FALSE;
856 		if (namesame(key, x_("(")) == 0)
857 		{
858 			/* get the X coordinate */
859 			foundcoord = TRUE;
860 			key = io_defmustgetkeyword(f, x_("NET"));
861 			if (key == 0) return(TRUE);
862 			if (estrcmp(key, x_("*")) == 0) curx = lastx; else
863 			{
864 				v = (float)eatof(key) / (float)io_defunits;
865 				curx = scalefromdispunit(v, DISPUNITMIC);
866 			}
867 
868 			/* get the Y coordinate */
869 			key = io_defmustgetkeyword(f, x_("NET"));
870 			if (key == 0) return(TRUE);
871 			if (estrcmp(key, x_("*")) == 0) cury = lasty; else
872 			{
873 				v = (float)eatof(key) / (float)io_defunits;
874 				cury = scalefromdispunit(v, DISPUNITMIC);
875 			}
876 
877 			/* get the close parentheses */
878 			key = io_defmustgetkeyword(f, x_("NET"));
879 			if (key == 0) return(TRUE);
880 			if (namesame(key, x_(")")) != 0)
881 			{
882 				io_definerror(_("Expected ')' of coordinate pair"));
883 				return(TRUE);
884 			}
885 		}
886 
887 		/* get the next keyword */
888 		key = io_defmustgetkeyword(f, x_("NET"));
889 		if (key == 0) return(TRUE);
890 
891 		/* see if it is a via name */
892 		for(vd = io_deffirstviadef; vd != NOVIADEF; vd = vd->nextviadef)
893 			if (namesame(key, vd->vianame) == 0) break;
894 		if (vd == NOVIADEF)
895 		{
896 			/* see if the via name is from the LEF file */
897 			for(vd = io_leffirstviadef; vd != NOVIADEF; vd = vd->nextviadef)
898 				if (namesame(key, vd->vianame) == 0) break;
899 		}
900 
901 		/* stop now if not placing physical nets */
902 		if ((options&DEFNOPHYSICAL) != 0)
903 		{
904 			/* ignore the next keyword if a via name is coming */
905 			if (vd != NOVIADEF)
906 			{
907 				key = io_defmustgetkeyword(f, x_("NET"));
908 				if (key == 0) return(TRUE);
909 			}
910 			continue;
911 		}
912 
913 		/* if a via is mentioned next, use it */
914 		if (vd != NOVIADEF)
915 		{
916 			/* place the via at this location */
917 			sx = vd->sx;
918 			sy = vd->sy;
919 			lx = curx - sx / 2;   hx = lx + sx;
920 			ly = cury - sy / 2;   hy = ly + sy;
921 			if (vd->via == NONODEPROTO)
922 			{
923 				io_definerror(_("Cannot to create via"));
924 				return(TRUE);
925 			}
926 
927 			/* see if there is a connection point here when starting a path */
928 			if (pathstart != 0)
929 			{
930 				if (!io_deffindconnection(curx, cury, routap, cell, NONODEINST,
931 					&lastni, &lastpp)) lastni = NONODEINST;
932 			}
933 
934 			/* create the via */
935 			nodeprotosizeoffset(vd->via, &plx, &ply, &phx, &phy, cell);
936 			ni = newnodeinst(vd->via, lx-plx, hx+phx, ly-ply, hy+phy, 0, 0, cell);
937 			if (ni == NONODEINST)
938 			{
939 				io_definerror(_("Unable to create via layer"));
940 				return(TRUE);
941 			}
942 			endobjectchange((INTBIG)ni, VNODEINST);
943 			pp = ni->proto->firstportproto;
944 
945 			/* if the path starts with a via, wire it */
946 			if (pathstart != 0 && lastni != NONODEINST && foundcoord)
947 			{
948 				if (special) width = specialwidth; else
949 				{
950 					var = getval((INTBIG)routap, VARCPROTO, VINTEGER, x_("IO_lef_width"));
951 					if (var == NOVARIABLE) width = defaultarcwidth(routap); else
952 						width = var->addr;
953 				}
954 				ai = newarcinst(routap, width, us_makearcuserbits(routap),
955 					lastni, lastpp, curx, cury, ni, pp, curx, cury, cell);
956 				if (ai == NOARCINST)
957 				{
958 					io_definerror(_("Unable to create net starting point"));
959 					return(TRUE);
960 				}
961 				endobjectchange((INTBIG)ai, VARCINST);
962 			}
963 
964 			/* remember that a via was placed */
965 			placedvia = 1;
966 
967 			/* get the next keyword */
968 			key = io_defmustgetkeyword(f, x_("NET"));
969 			if (key == 0) return(TRUE);
970 		} else
971 		{
972 			/* no via mentioned: just make a pin */
973 			if (io_defgetpin(curx, cury, routap, cell, &ni, &pp)) return(TRUE);
974 			placedvia = 0;
975 		}
976 		if (!foundcoord) continue;
977 
978 		/* run the wire */
979 		if (pathstart == 0)
980 		{
981 			/* make sure that this arc can connect to the current pin */
982 			for(i=0; pp->connects[i] != NOARCPROTO; i++)
983 				if (pp->connects[i] == routap) break;
984 			if (pp->connects[i] == NOARCPROTO)
985 			{
986 				np = getpinproto(routap);
987 				defaultnodesize(np, &sx, &sy);
988 				lx = curx - sx / 2;   hx = lx + sx;
989 				ly = cury - sy / 2;   hy = ly + sy;
990 				ni = newnodeinst(np, lx, hx, ly, hy, 0, 0, cell);
991 				if (ni == NONODEINST)
992 				{
993 					io_definerror(_("Unable to create net pin"));
994 					return(TRUE);
995 				}
996 				endobjectchange((INTBIG)ni, VNODEINST);
997 				pp = ni->proto->firstportproto;
998 			}
999 
1000 			/* run the wire */
1001 			if (special) width = specialwidth; else
1002 			{
1003 				var = getval((INTBIG)routap, VARCPROTO, VINTEGER, x_("IO_lef_width"));
1004 				if (var == NOVARIABLE) width = defaultarcwidth(routap); else
1005 					width = var->addr;
1006 			}
1007 			ai = newarcinst(routap, width, us_makearcuserbits(routap),
1008 				lastni, lastpp, lastx, lasty, ni, pp, curx, cury, cell);
1009 			if (ai == NOARCINST)
1010 			{
1011 				io_definerror(_("Unable to create net path"));
1012 				return(TRUE);
1013 			}
1014 			endobjectchange((INTBIG)ai, VARCINST);
1015 		}
1016 		lastx = curx;   lasty = cury;
1017 		pathstart = 0;
1018 		lastni = ni;
1019 		lastpp = pp;
1020 
1021 		/* switch layers to the other one supported by the via */
1022 		if (placedvia != 0)
1023 		{
1024 			if (routap == vd->lay1)
1025 			{
1026 				routap = vd->lay2;
1027 			} else if (routap == vd->lay2)
1028 			{
1029 				routap = vd->lay1;
1030 			}
1031 			pin = getpinproto(routap);
1032 		}
1033 
1034 		/* if the path ends here, connect it */
1035 		if (namesame(key, x_("NEW")) == 0 || namesame(key, x_(";")) == 0)
1036 		{
1037 			/* see if there is a connection point here when starting a path */
1038 			if (!io_deffindconnection(curx, cury, routap, cell, ni, &nextni, &nextpp))
1039 				nextni = NONODEINST;
1040 
1041 			/* if the path starts with a via, wire it */
1042 			if (nextni != NONODEINST)
1043 			{
1044 				if (special) width = specialwidth; else
1045 				{
1046 					var = getval((INTBIG)routap, VARCPROTO, VINTEGER, x_("IO_lef_width"));
1047 					if (var == NOVARIABLE) width = defaultarcwidth(routap); else
1048 						width = var->addr;
1049 				}
1050 				ai = newarcinst(routap, width, us_makearcuserbits(routap),
1051 					ni, pp, curx, cury, nextni, nextpp, curx, cury, cell);
1052 				if (ai == NOARCINST)
1053 				{
1054 					io_definerror(_("Unable to create net ending point"));
1055 					return(TRUE);
1056 				}
1057 				endobjectchange((INTBIG)ai, VARCINST);
1058 			}
1059 		}
1060 	}
1061 	return(FALSE);
1062 }
1063 
1064 /*
1065  * Routine to look for a connection to arcs of type "ap" in cell "cell"
1066  * at (x, y).  The connection can not be on "not" (if it is not NONODEINST).
1067  * If found, return true and places the node and port in "theni" and "thepp".
1068  */
io_deffindconnection(INTBIG x,INTBIG y,ARCPROTO * ap,NODEPROTO * cell,NODEINST * noti,NODEINST ** theni,PORTPROTO ** thepp)1069 BOOLEAN io_deffindconnection(INTBIG x, INTBIG y, ARCPROTO *ap, NODEPROTO *cell, NODEINST *noti,
1070 	NODEINST **theni, PORTPROTO **thepp)
1071 {
1072 	REGISTER INTBIG sea, i;
1073 	REGISTER NODEINST *ni;
1074 	REGISTER PORTPROTO *pp;
1075 	REGISTER GEOM *geom;
1076 	static POLYGON *poly = NOPOLYGON;
1077 
1078 	/* get polygons */
1079 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
1080 
1081 	sea = initsearch(x, x, y, y, cell);
1082 	for(;;)
1083 	{
1084 		geom = nextobject(sea);
1085 		if (geom == NOGEOM) break;
1086 		if (!geom->entryisnode) continue;
1087 		ni = geom->entryaddr.ni;
1088 		if (ni == noti) continue;
1089 		for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1090 		{
1091 			for(i=0; pp->connects[i] != NOARCPROTO; i++)
1092 				if (pp->connects[i] == ap) break;
1093 			if (pp->connects[i] == NOARCPROTO) continue;
1094 			shapeportpoly(ni, pp, poly, FALSE);
1095 			if (isinside(x, y, poly))
1096 			{
1097 				termsearch(sea);
1098 				*theni = ni;
1099 				*thepp = pp;
1100 				return(TRUE);
1101 			}
1102 		}
1103 	}
1104 	return(FALSE);
1105 }
1106 
1107 /*
1108  * Routine to look for a connection to arcs of type "ap" in cell "cell"
1109  * at (x, y).  If nothing is found, create a pin.  In any case, return
1110  * the node and port in "theni" and "thepp".  Returns true on error.
1111  */
io_defgetpin(INTBIG x,INTBIG y,ARCPROTO * ap,NODEPROTO * cell,NODEINST ** theni,PORTPROTO ** thepp)1112 BOOLEAN io_defgetpin(INTBIG x, INTBIG y, ARCPROTO *ap, NODEPROTO *cell,
1113 	NODEINST **theni, PORTPROTO **thepp)
1114 {
1115 	INTBIG sx, sy;
1116 	REGISTER INTBIG lx, hx, ly, hy;
1117 	REGISTER NODEINST *ni;
1118 	REGISTER NODEPROTO *pin;
1119 
1120 	/* if there is an existing connection, return it */
1121 	if (io_deffindconnection(x, y, ap, cell, NONODEINST, theni, thepp)) return(FALSE);
1122 
1123 	/* nothing found at this location: create a pin */
1124 	pin = getpinproto(ap);
1125 	defaultnodesize(pin, &sx, &sy);
1126 	lx = x - sx / 2;   hx = lx + sx;
1127 	ly = y - sy / 2;   hy = ly + sy;
1128 	ni = newnodeinst(pin, lx, hx, ly, hy, 0, 0, cell);
1129 	if (ni == NONODEINST)
1130 	{
1131 		io_definerror(_("Unable to create net pin"));
1132 		return(TRUE);
1133 	}
1134 	endobjectchange((INTBIG)ni, VNODEINST);
1135 	*theni = ni;
1136 	*thepp = ni->proto->firstportproto;
1137 	return(FALSE);
1138 }
1139 
1140 /*************** UNITS ***************/
1141 
io_defreadunits(FILE * f)1142 BOOLEAN io_defreadunits(FILE *f)
1143 {
1144 	REGISTER CHAR *key;
1145 
1146 	/* get the "DISTANCE" keyword */
1147 	key = io_defmustgetkeyword(f, x_("UNITS"));
1148 	if (key == 0) return(TRUE);
1149 	if (namesame(key, x_("DISTANCE")) != 0)
1150 	{
1151 		io_definerror(_("Expected 'DISTANCE' after 'UNITS'"));
1152 		return(TRUE);
1153 	}
1154 
1155 	/* get the "MICRONS" keyword */
1156 	key = io_defmustgetkeyword(f, x_("UNITS"));
1157 	if (key == 0) return(TRUE);
1158 	if (namesame(key, x_("MICRONS")) != 0)
1159 	{
1160 		io_definerror(_("Expected 'MICRONS' after 'UNITS'"));
1161 		return(TRUE);
1162 	}
1163 
1164 	/* get the amount */
1165 	key = io_defmustgetkeyword(f, x_("UNITS"));
1166 	if (key == 0) return(TRUE);
1167 	io_defunits = eatoi(key);
1168 
1169 	/* ignore the keyword */
1170 	if (io_defignoretosemicolon(f, _("UNITS"))) return(TRUE);
1171 	return(FALSE);
1172 }
1173 
1174 /*************** PROPERTY DEFINITIONS ***************/
1175 
io_defreadpropertydefinitions(FILE * f)1176 BOOLEAN io_defreadpropertydefinitions(FILE *f)
1177 {
1178 	REGISTER CHAR *key;
1179 	CHAR curkey[200];
1180 
1181 	for(;;)
1182 	{
1183 		/* get the next keyword */
1184 		key = io_defmustgetkeyword(f, x_("PROPERTYDEFINITION"));
1185 		if (key == 0) return(TRUE);
1186 		if (namesame(key, x_("END")) == 0)
1187 		{
1188 			key = io_defgetkeyword(f);
1189 			break;
1190 		}
1191 
1192 		/* ignore the keyword */
1193 		estrcpy(curkey, key);
1194 		if (io_defignoretosemicolon(f, curkey)) return(TRUE);
1195 	}
1196 	return(FALSE);
1197 }
1198 
1199 /*************** DATABASE SUPPORT ***************/
1200 
io_defgetnodeproto(CHAR * name,LIBRARY * curlib)1201 NODEPROTO *io_defgetnodeproto(CHAR *name, LIBRARY *curlib)
1202 {
1203 	REGISTER NODEPROTO *np, *newnp;
1204 	REGISTER LIBRARY *lib;
1205 
1206 	/* first see if this cell is in the current library */
1207 	for(np = curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1208 		if (namesame(name, np->protoname) == 0) return(np);
1209 
1210 	/* now look in other libraries */
1211 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1212 	{
1213 		if (lib == curlib) continue;
1214 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1215 			if (namesame(name, np->protoname) == 0) break;
1216 		if (np != NONODEPROTO)
1217 		{
1218 			/* must copy the cell */
1219 			newnp = us_copyrecursively(np, np->protoname, curlib, np->cellview,
1220 				FALSE, FALSE, x_(""), FALSE, FALSE, FALSE);
1221 			return(newnp);
1222 		}
1223 	}
1224 	return(NONODEPROTO);
1225 }
1226 
1227 /* returns nonzero on error */
io_defgetlayernodes(CHAR * name,NODEPROTO ** pin,NODEPROTO ** pure,ARCPROTO ** arc)1228 void io_defgetlayernodes(CHAR *name, NODEPROTO **pin, NODEPROTO **pure, ARCPROTO **arc)
1229 {
1230 	REGISTER INTBIG laynum, i, j, lfunc;
1231 	REGISTER INTBIG afunc, afunc1, afunc2, ap1found, ap2found, vialayer;
1232 	REGISTER ARCPROTO *ap, *ap1, *ap2;
1233 	REGISTER NODEPROTO *np;
1234 	REGISTER NODEINST *ni;
1235 	NODEINST node;
1236 	REGISTER PORTPROTO *pp;
1237 	static POLYGON *poly = NOPOLYGON;
1238 
1239 	/* initialize */
1240 	(void)needstaticpolygon(&poly, 4, io_tool->cluster);
1241 	*pin = NONODEPROTO;
1242 	*pure = NONODEPROTO;
1243 	*arc = NOARCPROTO;
1244 
1245 	/* handle via layers */
1246 	j = 0;
1247 	if (namesamen(name, x_("VIA"), 3) == 0) j = 3; else
1248 		if (namesamen(name, x_("V"), 1) == 0) j = 1;
1249 	if (j != 0)
1250 	{
1251 		/* find the two layer functions */
1252 		if (name[j] == 0)
1253 		{
1254 			afunc1 = APMETAL1;
1255 			afunc2 = APMETAL2;
1256 		} else if (name[j+1] == 0)
1257 		{
1258 			afunc1 = name[j] - '1' + APMETAL1;
1259 			afunc2 = afunc1 + 1;
1260 		} else
1261 		{
1262 			afunc1 = name[j] - '1' + APMETAL1;
1263 			afunc2 = name[j+1] - '1' + APMETAL1;
1264 		}
1265 
1266 		/* find the arcprotos that embody these layers */
1267 		for(ap1 = el_curtech->firstarcproto; ap1 != NOARCPROTO; ap1 = ap1->nextarcproto)
1268 			if ((INTBIG)((ap1->userbits&AFUNCTION)>>AFUNCTIONSH) == afunc1) break;
1269 		for(ap2 = el_curtech->firstarcproto; ap2 != NOARCPROTO; ap2 = ap2->nextarcproto)
1270 			if ((INTBIG)((ap2->userbits&AFUNCTION)>>AFUNCTIONSH) == afunc2) break;
1271 		if (ap1 == NOARCPROTO || ap2 == NOARCPROTO) return;
1272 
1273 		/* find the via that connects these two arcs */
1274 		for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1275 		{
1276 			/* must have just one port */
1277 			pp = np->firstportproto;
1278 			if (pp == NOPORTPROTO) continue;
1279 			if (pp->nextportproto != NOPORTPROTO) continue;
1280 
1281 			/* port must connect to both arcs */
1282 			ap1found = ap2found = 0;
1283 			for(i=0; pp->connects[i] != NOARCPROTO; i++)
1284 			{
1285 				if (pp->connects[i] == ap1) ap1found++;
1286 				if (pp->connects[i] == ap2) ap2found++;
1287 			}
1288 			if (ap1found != 0 && ap2found != 0) break;
1289 		}
1290 		*pin = np;
1291 
1292 		/* find the pure layer node that is the via contact */
1293 		if (np != NONODEPROTO)
1294 		{
1295 			/* find the layer on this node that is of type "contact" */
1296 			ni = &node;   initdummynode(ni);
1297 			ni->proto = np;
1298 			ni->lowx = 0;   ni->highx = 1000;
1299 			ni->lowy = 0;   ni->highy = 1000;
1300 			j = nodepolys(ni, 0, NOWINDOWPART);
1301 			for(i=0; i<j; i++)
1302 			{
1303 				shapenodepoly(ni, i, poly);
1304 				vialayer = poly->layer;
1305 				lfunc = layerfunction(el_curtech, vialayer) & LFTYPE;
1306 				if (layeriscontact(lfunc)) break;
1307 			}
1308 			if (i >= j) return;
1309 
1310 			/* now find the pure layer node that has this layer */
1311 			np = getpurelayernode(el_curtech, vialayer, 0);
1312 			*pure = np;
1313 		}
1314 		return;
1315 	}
1316 
1317 	/* handle metal layers */
1318 	j = 0;
1319 	if (namesamen(name, x_("METAL"), 5) == 0) j = 5; else
1320 		if (namesamen(name, x_("MET"), 3) == 0) j = 3; else
1321 			if (namesamen(name, x_("M"), 1) == 0) j = 1;
1322 	if (j != 0)
1323 	{
1324 		laynum = eatoi(&name[j]);
1325 		afunc = APUNKNOWN;
1326 		lfunc = LFUNKNOWN;
1327 		switch (laynum)
1328 		{
1329 			case 1:  afunc = APMETAL1;   lfunc = LFMETAL1;   break;
1330 			case 2:  afunc = APMETAL2;   lfunc = LFMETAL2;   break;
1331 			case 3:  afunc = APMETAL3;   lfunc = LFMETAL3;   break;
1332 			case 4:  afunc = APMETAL4;   lfunc = LFMETAL4;   break;
1333 			case 5:  afunc = APMETAL5;   lfunc = LFMETAL5;   break;
1334 			case 6:  afunc = APMETAL6;   lfunc = LFMETAL6;   break;
1335 			case 7:  afunc = APMETAL7;   lfunc = LFMETAL7;   break;
1336 			case 8:  afunc = APMETAL8;   lfunc = LFMETAL8;   break;
1337 			case 9:  afunc = APMETAL9;   lfunc = LFMETAL9;   break;
1338 			case 10: afunc = APMETAL10;  lfunc = LFMETAL10;  break;
1339 			case 11: afunc = APMETAL11;  lfunc = LFMETAL11;  break;
1340 			case 12: afunc = APMETAL12;  lfunc = LFMETAL12;  break;
1341 		}
1342 		if (afunc == APUNKNOWN || lfunc == LFUNKNOWN) return;
1343 
1344 		/* find the arc with this function */
1345 		for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1346 			if ((INTBIG)((ap->userbits&AFUNCTION)>>AFUNCTIONSH) == afunc) break;
1347 		if (ap != NOARCPROTO)
1348 		{
1349 			*arc = ap;
1350 			*pin = getpinproto(ap);
1351 		}
1352 
1353 		/* find the pure layer node with this function */
1354 		np = getpurelayernode(el_curtech, -1, lfunc);
1355 		*pure = np;
1356 		return;
1357 	}
1358 }
1359 
1360 /*************** FILE SUPPORT ***************/
1361 
io_defreadcoordinate(FILE * f,INTBIG * x,INTBIG * y)1362 BOOLEAN io_defreadcoordinate(FILE *f, INTBIG *x, INTBIG *y)
1363 {
1364 	CHAR *key;
1365 	float v;
1366 
1367 	/* get "(" */
1368 	key = io_defmustgetkeyword(f, _("coordinate"));
1369 	if (key == 0) return(TRUE);
1370 	if (estrcmp(key, x_("(")) != 0)
1371 	{
1372 		io_definerror(_("Expected '(' in coordinate"));
1373 		return(TRUE);
1374 	}
1375 
1376 	/* get X */
1377 	key = io_defmustgetkeyword(f, _("coordinate"));
1378 	if (key == 0) return(TRUE);
1379 	v = (float)eatof(key) / (float)io_defunits;
1380 	*x = scalefromdispunit(v, DISPUNITMIC);
1381 
1382 	/* get Y */
1383 	key = io_defmustgetkeyword(f, _("coordinate"));
1384 	if (key == 0) return(TRUE);
1385 	v = (float)eatof(key) / (float)io_defunits;
1386 	*y = scalefromdispunit(v, DISPUNITMIC);
1387 
1388 	/* get ")" */
1389 	key = io_defmustgetkeyword(f, _("coordinate"));
1390 	if (key == 0) return(TRUE);
1391 	if (estrcmp(key, x_(")")) != 0)
1392 	{
1393 		io_definerror(_("Expected ')' in coordinate"));
1394 		return(TRUE);
1395 	}
1396 	return(FALSE);
1397 }
1398 
io_defreadorientation(FILE * f,INTSML * rot,INTSML * trans)1399 BOOLEAN io_defreadorientation(FILE *f, INTSML *rot, INTSML *trans)
1400 {
1401 	REGISTER CHAR *key;
1402 
1403 	key = io_defmustgetkeyword(f, _("orientation"));
1404 	if (key == 0) return(TRUE);
1405 	if (namesame(key, x_("N"))  == 0) { *rot = 0;    *trans = 0; } else
1406 	if (namesame(key, x_("S"))  == 0) { *rot = 1800; *trans = 0; } else
1407 	if (namesame(key, x_("E"))  == 0) { *rot = 2700; *trans = 0; } else
1408 	if (namesame(key, x_("W"))  == 0) { *rot = 900;  *trans = 0; } else
1409 	if (namesame(key, x_("FN")) == 0) { *rot = 900;  *trans = 1; } else
1410 	if (namesame(key, x_("FS")) == 0) { *rot = 2700; *trans = 1; } else
1411 	if (namesame(key, x_("FE")) == 0) { *rot = 1800; *trans = 1; } else
1412 	if (namesame(key, x_("FW")) == 0) { *rot = 0;    *trans = 1; } else
1413 	{
1414 		io_definerror(_("Unknown orientation (%s)"), key);
1415 		return(TRUE);
1416 	}
1417 	return(FALSE);
1418 }
1419 
io_defignoretosemicolon(FILE * f,CHAR * command)1420 BOOLEAN io_defignoretosemicolon(FILE *f, CHAR *command)
1421 {
1422 	REGISTER CHAR *key;
1423 
1424 	/* ignore up to the next semicolon */
1425 	for(;;)
1426 	{
1427 		key = io_defmustgetkeyword(f, command);
1428 		if (key == 0) return(TRUE);
1429 		if (estrcmp(key, x_(";")) == 0) break;
1430 	}
1431 	return(FALSE);
1432 }
1433 
io_defignoreblock(FILE * f,CHAR * command)1434 BOOLEAN io_defignoreblock(FILE *f, CHAR *command)
1435 {
1436 	REGISTER CHAR *key;
1437 
1438 	for(;;)
1439 	{
1440 		/* get the next keyword */
1441 		key = io_defmustgetkeyword(f, command);
1442 		if (key == 0) return(TRUE);
1443 
1444 		if (namesame(key, x_("END")) == 0)
1445 		{
1446 			(void)io_defgetkeyword(f);
1447 			break;
1448 		}
1449 	}
1450 	return(FALSE);
1451 }
1452 
io_defmustgetkeyword(FILE * f,CHAR * where)1453 CHAR *io_defmustgetkeyword(FILE *f, CHAR *where)
1454 {
1455 	CHAR *key;
1456 
1457 	key = io_defgetkeyword(f);
1458 	if (key == 0) io_definerror(_("EOF parsing %s"), where);
1459 	return(key);
1460 }
1461 
io_defgetkeyword(FILE * f)1462 CHAR *io_defgetkeyword(FILE *f)
1463 {
1464 	REGISTER CHAR *ret;
1465 	REGISTER INTBIG filepos;
1466 
1467 	/* keep reading from file until something is found on a line */
1468 	while (io_defline[io_deflinepos] == 0)
1469 	{
1470 		/* read a line from the file, exit at EOF */
1471 		if (xfgets(io_defline, MAXLINE, f)) return(0);
1472 		io_deflineno++;
1473 		if ((io_deflineno%50) == 0)
1474 		{
1475 			filepos = xtell(f);
1476 			DiaSetProgress(io_defprogressdialog, filepos, io_deffilesize);
1477 		}
1478 
1479 		/* look for the first text on the line */
1480 		io_deflinepos = 0;
1481 		while (io_defline[io_deflinepos] == ' ' || io_defline[io_deflinepos] == '\t')
1482 			io_deflinepos++;
1483 	}
1484 
1485 	/* remember where the keyword begins */
1486 	ret = &io_defline[io_deflinepos];
1487 
1488 	/* scan to the end of the keyword */
1489 	while (io_defline[io_deflinepos] != 0 && io_defline[io_deflinepos] != ' ' &&
1490 		io_defline[io_deflinepos] != '\t') io_deflinepos++;
1491 	if (io_defline[io_deflinepos] != 0) io_defline[io_deflinepos++] = 0;
1492 
1493 	/* advance to the start of the next keyword */
1494 	while (io_defline[io_deflinepos] == ' ' || io_defline[io_deflinepos] == '\t')
1495 		io_deflinepos++;
1496 	return(ret);
1497 }
1498 
io_definerror(CHAR * command,...)1499 void io_definerror(CHAR *command, ...)
1500 {
1501 	va_list ap;
1502 	CHAR line[500];
1503 
1504 	var_start(ap, command);
1505 	evsnprintf(line, 500, command, ap);
1506 	va_end(ap);
1507 	ttyputerr(_("File %s, line %ld: %s"), io_deffilename, io_deflineno, line);
1508 }
1509 
1510 /* DEF Options */
1511 static DIALOGITEM io_defoptionsdialogitems[] =
1512 {
1513  /*  1 */ {0, {64,156,88,228}, BUTTON, N_("OK")},
1514  /*  2 */ {0, {64,16,88,88}, BUTTON, N_("Cancel")},
1515  /*  3 */ {0, {32,8,48,230}, CHECK, N_("Place logical interconnect")},
1516  /*  4 */ {0, {8,8,24,230}, CHECK, N_("Place physical interconnect")}
1517 };
1518 static DIALOG io_defoptionsdialog = {{50,75,147,314}, N_("DEF Options"), 0, 4, io_defoptionsdialogitems, 0, 0};
1519 
1520 /* special items for the "DEF Options" dialog: */
1521 #define DDFO_PLACELOGICAL    3	/* Place logical interconnect (check) */
1522 #define DDFO_PLACEPHYSICAL   4	/* Place physical interconnect (check) */
1523 
io_defoptionsdlog(void)1524 void io_defoptionsdlog(void)
1525 {
1526 	REGISTER INTBIG itemHit, *curstate, i;
1527 	INTBIG newstate[NUMIOSTATEBITWORDS];
1528 	REGISTER void *dia;
1529 
1530 	dia = DiaInitDialog(&io_defoptionsdialog);
1531 	if (dia == 0) return;
1532 	curstate = io_getstatebits();
1533 	for(i=0; i<NUMIOSTATEBITWORDS; i++) newstate[i] = curstate[i];
1534 	if ((curstate[0]&DEFNOLOGICAL) == 0) DiaSetControl(dia, DDFO_PLACELOGICAL, 1);
1535 	if ((curstate[0]&DEFNOPHYSICAL) == 0) DiaSetControl(dia, DDFO_PLACEPHYSICAL, 1);
1536 
1537 	/* loop until done */
1538 	for(;;)
1539 	{
1540 		itemHit = DiaNextHit(dia);
1541 		if (itemHit == OK || itemHit == CANCEL) break;
1542 		if (itemHit == DDFO_PLACELOGICAL || itemHit == DDFO_PLACEPHYSICAL)
1543 		{
1544 			DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
1545 			continue;
1546 		}
1547 	}
1548 
1549 	if (itemHit != CANCEL)
1550 	{
1551 		if (DiaGetControl(dia, DDFO_PLACELOGICAL) == 0) newstate[0] |= DEFNOLOGICAL; else
1552 			newstate[0] &= ~DEFNOLOGICAL;
1553 		if (DiaGetControl(dia, DDFO_PLACEPHYSICAL) == 0) newstate[0] |= DEFNOPHYSICAL; else
1554 			newstate[0] &= ~DEFNOPHYSICAL;
1555 		for(i=0; i<NUMIOSTATEBITWORDS; i++) if (curstate[i] != newstate[i]) break;
1556 		if (i < NUMIOSTATEBITWORDS) io_setstatebits(newstate);
1557 	}
1558 	DiaDoneDialog(dia);
1559 }
1560