1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: iotexti.c
6 * Input/output tool: textual format input
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 #include "global.h"
33 #include "database.h"
34 #include "eio.h"
35 #include "tecgen.h"
36 #include "tecart.h"
37 #include "tecschem.h"
38 #include "tecmocmos.h"
39 #include "tecmocmossub.h"
40 #include "edialogs.h"
41
42 #define REPORTRATE 100 /* number of elements between graphical update */
43
44 #define LONGJMPNOMEM 1 /* error: No Memory */
45 #define LONGJMPMISCOLON 2 /* error: Missing colon */
46 #define LONGJMPUKNKEY 3 /* error: Unknown keyword */
47 #define LONGJMPEOF 4 /* error: EOF too soon */
48 #define LONGJMPEOFVAR 5 /* error: EOF in variables */
49 #define LONGJMPMISCOLVAR 6 /* error: Missing ':' in variable */
50 #define LONGJMPMISOSBVAR 7 /* error: Missing '[' in variable */
51 #define LONGJMPMISOSBVARARR 8 /* error: Missing '[' in variable array */
52 #define LONGJMPSHORTARR 9 /* error: Short array specification */
53 #define LONGJMPUKNNOPROTO 10 /* error: Unknown node prototype */
54 #define LONGJMPMISVIEWABR 11 /* error: Missing view abbreviation */
55 #define LONGJMPBADVIEWABR 12 /* error: View abbreviation bad */
56 #define LONGJMPINCVIEWABR 13 /* error: View abbreviation inconsistent */
57 #define LONGJMPSECCELLNAME 14 /* error: Second cell name */
58 #define LONGJMPUKNTECH 15 /* error: Unknown technology */
59 #define LONGJMPINVARCPROTO 16 /* error: Invalid arc prototype */
60 #define LONGJMPUKNPORPROTO 17 /* error: Unknown port prototype name */
61
62 /* state of input (value of "io_txtindata.textlevel") */
63 #define INLIB 1
64 #define INCELL 2
65 #define INPORTPROTO 3
66 #define INNODEINST 4
67 #define INPOR 5
68 #define INARCINST 6
69 #define INARCEND 7
70
71 /* state of variable reading (value of "io_txtindata.varpos") */
72 #define INVTOOL 1
73 #define INVTECHNOLOGY 2
74 #define INVLIBRARY 3
75 #define INVNODEPROTO 4
76 #define INVNODEINST 5
77 #define INVPORTARCINST 6
78 #define INVPORTEXPINST 7
79 #define INVPORTPROTO 8
80 #define INVARCINST 9
81
82 typedef struct
83 {
84 INTBIG cellcount;
85 INTBIG textlevel;
86 INTBIG bitcount;
87 INTBIG maincell;
88 INTBIG curarcend;
89 INTBIG nodeinstcount;
90 INTBIG arcinstcount;
91 INTBIG varaddr;
92 INTBIG portprotocount;
93 INTBIG linenumber;
94 INTBIG curportcount;
95 INTBIG varpos;
96 INTBIG filelength;
97 INTBIG fileposition;
98 INTBIG curcellnumber;
99 CHAR *version;
100 INTBIG emajor, eminor, edetail;
101 NODEINST *curnodeinst;
102 ARCINST *curarcinst;
103 PORTPROTO *curportproto;
104 NODEPROTO *curnodeproto;
105 CHAR *cellnameread;
106 LIBRARY *curlib;
107 TECHNOLOGY *curtech;
108 PORTPROTO **portprotolist; /* list of portprotos for readin */
109 NODEPROTO **nodeprotolist; /* list of cells for readin */
110 ARCINST **arclist; /* list of arcs for readin */
111 NODEINST **nodelist; /* list of nodes for readin */
112 FILE *textfilein;
113 INTBIG nodeinsterror;
114 INTBIG portarcinsterror;
115 INTBIG portexpinsterror;
116 INTBIG portprotoerror;
117 INTBIG arcinsterror;
118 INTBIG geomerror;
119 INTBIG rtnodeerror;
120 INTBIG libraryerror;
121 INTBIG convertmosiscmostechnologies;
122 } TXTINPUTDATA;
123
124 static TXTINPUTDATA io_txtindata; /* all data pertaining to reading a file */
125
126 /* input string buffer */
127 static INTBIG io_maxinputline = 0;
128 static CHAR *io_keyword;
129
130 /* prototypes for local routines */
131 static void io_newlib(void);
132 static BOOLEAN io_getkeyword(void);
133 static BOOLEAN io_grabbuffers(INTBIG);
134 static PORTPROTO *io_getport(CHAR*, NODEPROTO*);
135 static void io_null(void);
136 static void io_newlib(void);
137 static void io_versn(void);
138 static void io_libkno(void);
139 static void io_libain(void);
140 static void io_libaib(void);
141 static void io_libbit(void);
142 static void io_libusb(void);
143 static void io_libte(void);
144 static void io_libten(void);
145 static void io_lambda(void);
146 static void io_getvar(void);
147 static INTBIG io_decode(CHAR*, INTBIG);
148 static void io_libcc(void);
149 static void io_libms(void);
150 static void io_libvie(void);
151 static void io_newcel(void);
152 static void io_celnam(void);
153 static void io_celver(void);
154 static void io_celcre(void);
155 static void io_celrev(void);
156 static void io_celext(void);
157 static void io_cellx(void);
158 static void io_celhx(void);
159 static void io_celly(void);
160 static void io_celhy(void);
161 static void io_tech(void);
162 static void io_celaad(void);
163 static void io_celbit(void);
164 static void io_celusb(void);
165 static void io_celnet(void);
166 static void io_celnoc(void);
167 static void io_celarc(void);
168 static void io_celptc(void);
169 static void io_celdon(void);
170 static void io_newno(void);
171 static void io_nodtyp(void);
172 static void io_nodlx(void);
173 static void io_nodhx(void);
174 static void io_nodly(void);
175 static void io_nodhy(void);
176 static void io_nodnam(void);
177 static void io_noddes(void);
178 static void io_nodrot(void);
179 static void io_nodtra(void);
180 static void io_nodkse(void);
181 static void io_nodpoc(void);
182 static void io_nodbit(void);
183 static void io_nodusb(void);
184 static void io_newpor(void);
185 static void io_porarc(void);
186 static void io_porexp(void);
187 static void io_newar(void);
188 static void io_arctyp(void);
189 static void io_arcnam(void);
190 static void io_arcwid(void);
191 static void io_arclen(void);
192 static void io_arcsig(void);
193 static void io_newend(void);
194 static void io_endnod(void);
195 static void io_endpt(void);
196 static void io_endxp(void);
197 static void io_endyp(void);
198 static void io_arckse(void);
199 static void io_arcbit(void);
200 static void io_arcusb(void);
201 static void io_arcnet(void);
202 static void io_newpt(void);
203 static void io_ptnam(void);
204 static void io_ptdes(void);
205 static void io_ptsno(void);
206 static void io_ptspt(void);
207 static void io_ptkse(void);
208 static void io_ptbit(void);
209 static void io_ptusb(void);
210 static void io_ptnet(void);
211 static TECHNOLOGY *io_gettechnology(CHAR*);
212
213 struct keyroutine
214 {
215 CHAR *matchstring;
216 void (*routine)(void);
217 };
218
219 /* possible keywords while reading libraries */
220 static struct keyroutine io_libraryroutines[] =
221 {
222 {x_("****library"), io_newlib},
223 {x_("bits"), io_libbit},
224 {x_("lambda"), io_lambda},
225 {x_("version"), io_versn},
226 {x_("aids"), io_libkno},
227 {x_("aidname"), io_libain},
228 {x_("aidbits"), io_libaib},
229 {x_("userbits"), io_libusb},
230 {x_("techcount"), io_libte},
231 {x_("techname"), io_libten},
232 {x_("cellcount"), io_libcc},
233 {x_("maincell"), io_libms},
234 {x_("view"), io_libvie},
235 {x_("***cell"), io_newcel},
236 {x_("variables"), io_getvar},
237 {NULL, NULL}
238 };
239
240 /* possible keywords while reading cells */
241 static struct keyroutine io_cellroutines[] =
242 {
243 {x_("bits"), io_celbit},
244 {x_("userbits"), io_celusb},
245 {x_("netnum"), io_celnet},
246 {x_("name"), io_celnam},
247 {x_("version"), io_celver},
248 {x_("creationdate"), io_celcre},
249 {x_("revisiondate"), io_celrev},
250 {x_("lowx"), io_cellx},
251 {x_("highx"), io_celhx},
252 {x_("lowy"), io_celly},
253 {x_("highy"), io_celhy},
254 {x_("externallibrary"), io_celext},
255 {x_("aadirty"), io_celaad},
256 {x_("nodes"), io_celnoc},
257 {x_("arcs"), io_celarc},
258 {x_("porttypes"), io_celptc},
259 {x_("celldone"), io_celdon},
260 {x_("technology"), io_tech},
261 {x_("**node"), io_newno},
262 {x_("**arc"), io_newar},
263 {x_("***cell"), io_newcel},
264 {x_("variables"), io_getvar},
265 {NULL, NULL}
266 };
267
268 /* possible keywords while reading ports */
269 static struct keyroutine io_portroutines[] =
270 {
271 {x_("bits"), io_ptbit},
272 {x_("userbits"), io_ptusb},
273 {x_("netnum"), io_ptnet},
274 {x_("subnode"), io_ptsno},
275 {x_("subport"), io_ptspt},
276 {x_("name"), io_ptnam},
277 {x_("descript"), io_ptdes},
278 {x_("aseen"), io_ptkse},
279 {x_("**porttype"), io_newpt},
280 {x_("**arc"), io_newar},
281 {x_("**node"), io_newno},
282 {x_("celldone"), io_celdon},
283 {x_("***cell"), io_newcel},
284 {x_("variables"), io_getvar},
285 {x_("arcbits"), io_null}, /* used no more: ignored for compatibility */
286 {NULL, NULL}
287 };
288
289 /* possible keywords while reading nodes */
290 static struct keyroutine io_noderoutines[] =
291 {
292 {x_("bits"), io_nodbit},
293 {x_("userbits"), io_nodusb},
294 {x_("type"), io_nodtyp},
295 {x_("lowx"), io_nodlx},
296 {x_("highx"), io_nodhx},
297 {x_("lowy"), io_nodly},
298 {x_("highy"), io_nodhy},
299 {x_("rotation"), io_nodrot},
300 {x_("transpose"), io_nodtra},
301 {x_("aseen"), io_nodkse},
302 {x_("name"), io_nodnam},
303 {x_("descript"), io_noddes},
304 {x_("*port"), io_newpor},
305 {x_("**node"), io_newno},
306 {x_("**porttype"), io_newpt},
307 {x_("**arc"), io_newar},
308 {x_("celldone"), io_celdon},
309 {x_("variables"), io_getvar},
310 {x_("***cell"), io_newcel},
311 {x_("ports"), io_nodpoc},
312 {x_("exportcount"), io_null}, /* used no more: ignored for compatibility */
313 {NULL, NULL}
314 };
315
316 /* possible keywords while reading portinsts */
317 static struct keyroutine io_portinstroutines[] =
318 {
319 {x_("arc"), io_porarc},
320 {x_("exported"), io_porexp},
321 {x_("*port"), io_newpor},
322 {x_("**node"), io_newno},
323 {x_("**porttype"), io_newpt},
324 {x_("**arc"), io_newar},
325 {x_("variables"), io_getvar},
326 {x_("celldone"), io_celdon},
327 {x_("***cell"), io_newcel},
328 {NULL, NULL}
329 };
330
331 /* possible keywords while reading arcs */
332 static struct keyroutine io_arcroutines[] =
333 {
334 {x_("bits"), io_arcbit},
335 {x_("userbits"), io_arcusb},
336 {x_("netnum"), io_arcnet},
337 {x_("type"), io_arctyp},
338 {x_("width"), io_arcwid},
339 {x_("length"), io_arclen},
340 {x_("signals"), io_arcsig},
341 {x_("aseen"), io_arckse},
342 {x_("name"), io_arcnam},
343 {x_("*end"), io_newend},
344 {x_("**arc"), io_newar},
345 {x_("**node"), io_newno},
346 {x_("variables"), io_getvar},
347 {x_("celldone"), io_celdon},
348 {x_("***cell"), io_newcel},
349 {NULL, NULL}
350 };
351
352 /* possible keywords while reading arc ends */
353 static struct keyroutine io_arcendroutines[] =
354 {
355 {x_("node"), io_endnod},
356 {x_("nodeport"), io_endpt},
357 {x_("xpos"), io_endxp},
358 {x_("ypos"), io_endyp},
359 {x_("*end"), io_newend},
360 {x_("**arc"), io_newar},
361 {x_("**node"), io_newno},
362 {x_("variables"), io_getvar},
363 {x_("celldone"), io_celdon},
364 {x_("***cell"), io_newcel},
365 {NULL, NULL}
366 };
367
io_readtextlibrary(LIBRARY * lib)368 BOOLEAN io_readtextlibrary(LIBRARY *lib)
369 {
370 REGISTER LIBRARY *olib, *nextlib;
371 REGISTER BOOLEAN ret;
372
373 /* mark all libraries as "not being read", but "wanted" */
374 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
375 {
376 olib->temp1 = 0;
377 olib->userbits &= ~UNWANTEDLIB;
378 }
379
380 ret = io_doreadtextlibrary(lib, TRUE);
381
382 /* delete unwanted libraries */
383 for(olib = el_curlib; olib != NOLIBRARY; olib = nextlib)
384 {
385 nextlib = olib->nextlibrary;
386 if ((olib->userbits&UNWANTEDLIB) == 0) continue;
387 killlibrary(olib);
388 }
389 return(ret);
390 }
391
io_doreadtextlibrary(LIBRARY * lib,BOOLEAN newprogress)392 BOOLEAN io_doreadtextlibrary(LIBRARY *lib, BOOLEAN newprogress)
393 {
394 struct keyroutine *table;
395 REGISTER CHAR *pp;
396 REGISTER INTBIG i, j, reportcount, lambda, errcode;
397 INTBIG num, den;
398 REGISTER INTBIG oldunit;
399 REGISTER NODEPROTO *np, *onp, *prevmatch;
400 REGISTER TECHNOLOGY *tech;
401 REGISTER NODEINST *ni;
402 REGISTER ARCINST *ai;
403 CHAR *filename;
404 REGISTER void *infstr;
405
406 /* initialize the input string buffers */
407 if (io_maxinputline == 0)
408 if (io_grabbuffers(1000)) return(TRUE);
409
410 io_txtindata.textfilein = xopen(truepath(lib->libfile), io_filetypetlib,
411 el_libdir, &filename);
412 if (io_txtindata.textfilein == NULL)
413 {
414 ttyputerr(_("File %s not found"), lib->libfile);
415 return(TRUE);
416 }
417
418 /* update the library file name if the true location is different */
419 if (estrcmp(filename, lib->libfile) != 0)
420 (void)reallocstring(&lib->libfile, filename, lib->cluster);
421
422 reportcount = io_txtindata.fileposition = 0;
423 if (io_verbose < 0)
424 {
425 io_txtindata.filelength = filesize(io_txtindata.textfilein);
426 if (io_txtindata.filelength > 0)
427 {
428 if (newprogress)
429 {
430 io_inputprogressdialog = DiaInitProgress(x_(""), _("Reading library"));
431 if (io_inputprogressdialog == 0)
432 {
433 xclose(io_txtindata.textfilein);
434 return(TRUE);
435 }
436 }
437 infstr = initinfstr();
438 formatinfstr(infstr, _("Reading library %s"), lib->libname);
439 DiaSetCaptionProgress(io_inputprogressdialog, returninfstr(infstr));
440 DiaSetTextProgress(io_inputprogressdialog, _("Initializing..."));
441 DiaSetProgress(io_inputprogressdialog, 0, io_txtindata.filelength);
442 }
443 } else io_txtindata.filelength = 0;
444
445 /* the error recovery point */
446 errcode = setjmp(io_filerror);
447 if (errcode != 0)
448 {
449 switch (errcode)
450 {
451 case LONGJMPNOMEM: pp = _("No Memory"); break;
452 case LONGJMPMISCOLON: pp = _("Missing colon"); break;
453 case LONGJMPUKNKEY: pp = _("Unknown keyword"); break;
454 case LONGJMPEOF: pp = _("EOF too soon"); break;
455 case LONGJMPEOFVAR: pp = _("EOF in variables"); break;
456 case LONGJMPMISCOLVAR: pp = _("Missing ':' in variable"); break;
457 case LONGJMPMISOSBVAR: pp = _("Missing '[' in variable"); break;
458 case LONGJMPMISOSBVARARR: pp = _("Missing '[' in variable array"); break;
459 case LONGJMPSHORTARR: pp = _("Short array specification"); break;
460 case LONGJMPUKNNOPROTO: pp = _("Unknown node prototype"); break;
461 case LONGJMPMISVIEWABR: pp = _("Missing view abbreviation"); break;
462 case LONGJMPBADVIEWABR: pp = _("View abbreviation bad"); break;
463 case LONGJMPINCVIEWABR: pp = _("View abbreviation inconsistent"); break;
464 case LONGJMPSECCELLNAME: pp = _("Second cell name"); break;
465 case LONGJMPUKNTECH: pp = _("Unknown technology"); break;
466 case LONGJMPINVARCPROTO: pp = _("Invalid arc prototype"); break;
467 case LONGJMPUKNPORPROTO: pp = _("Unknown port prototype name"); break;
468 default: pp = _("Unknown"); break;
469 }
470 ttyputerr(_("Error: %s on line %ld, keyword '%s'"), pp,
471 io_txtindata.linenumber, io_keyword);
472 xclose(io_txtindata.textfilein);
473 if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
474 {
475 DiaDoneProgress(io_inputprogressdialog);
476 io_inputprogressdialog = 0;
477 }
478 return(TRUE);
479 }
480
481 /* force the library name to be the proper file name without the "txt" */
482 infstr = initinfstr();
483 for(i=estrlen(lib->libfile)-1; i>=0; i--) if (lib->libfile[i] == DIRSEP) break;
484 pp = &lib->libfile[i+1];
485 j = estrlen(pp);
486 if (j > 4 && namesame(&pp[j-4], x_(".txt")) == 0) j -= 4;
487 for(i=0; i<j; i++) addtoinfstr(infstr, pp[i]);
488 if (reallocstring(&lib->libname, returninfstr(infstr), lib->cluster))
489 longjmp(io_filerror, LONGJMPNOMEM);
490
491 io_txtindata.curlib = lib;
492 eraselibrary(lib);
493
494 /* clear error counters */
495 io_txtindata.nodeinsterror = io_txtindata.portarcinsterror = 0;
496 io_txtindata.portexpinsterror = io_txtindata.portprotoerror = 0;
497 io_txtindata.arcinsterror = io_txtindata.geomerror = 0;
498 io_txtindata.libraryerror = io_txtindata.rtnodeerror = 0;
499
500 io_txtindata.textlevel = INLIB;
501 io_txtindata.linenumber = 0;
502 for(;;)
503 {
504 /* get keyword from file */
505 if (io_getkeyword()) break;
506 pp = io_keyword; while (*pp != 0) pp++;
507 if (pp[-1] != ':') longjmp(io_filerror, LONGJMPMISCOLON);
508 pp[-1] = 0;
509
510 if (reportcount++ > REPORTRATE)
511 {
512 reportcount = 0;
513 if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
514 DiaSetProgress(io_inputprogressdialog, io_txtindata.fileposition, io_txtindata.filelength);
515 }
516
517 /* determine which keyword table to use */
518 switch (io_txtindata.textlevel)
519 {
520 case INLIB: table = io_libraryroutines; break;
521 case INCELL: table = io_cellroutines; break;
522 case INPORTPROTO: table = io_portroutines; break;
523 case INNODEINST: table = io_noderoutines; break;
524 case INPOR: table = io_portinstroutines; break;
525 case INARCINST: table = io_arcroutines; break;
526 case INARCEND: table = io_arcendroutines; break;
527 }
528
529 /* parse keyword and argument */
530 for(i=0; table[i].matchstring != 0; i++)
531 if (estrcmp(table[i].matchstring, io_keyword) == 0) break;
532 if (table[i].matchstring == 0)
533 longjmp(io_filerror, LONGJMPUKNKEY);
534
535 /* get argument to routine and call it */
536 if (io_getkeyword()) longjmp(io_filerror, LONGJMPEOF);
537 (*(table[i].routine))();
538 }
539 xclose(io_txtindata.textfilein);
540 if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
541 {
542 DiaSetProgress(io_inputprogressdialog, 999, 1000);
543 DiaSetTextProgress(io_inputprogressdialog, _("Cleaning up..."));
544 }
545
546 /* set the former version number on the library */
547 nextchangequiet();
548 (void)setval((INTBIG)io_txtindata.curlib, VLIBRARY, x_("LIB_former_version"),
549 (INTBIG)io_txtindata.version, VSTRING|VDONTSAVE);
550
551 /* fill in any lambda values that are not specified */
552 oldunit = ((io_txtindata.curlib->userbits & LIBUNITS) >> LIBUNITSSH) << INTERNALUNITSSH;
553 if (oldunit == (el_units&INTERNALUNITS)) num = den = 1; else
554 db_getinternalunitscale(&num, &den, el_units, oldunit);
555 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
556 {
557 lambda = io_txtindata.curlib->lambda[tech->techindex];
558 if (lambda != 0) lambda = muldiv(lambda, den, num); else
559 {
560 lambda = el_curlib->lambda[tech->techindex];
561 if (lambda == 0) lambda = tech->deflambda;
562 }
563 io_txtindata.curlib->lambda[tech->techindex] = lambda;
564 }
565
566 /* see if cellgroup information was included */
567 for(np = io_txtindata.curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
568 if (np->temp1 == -1) break;
569 if (np != NONODEPROTO)
570 {
571 /* missing cellgroup information, construct it from names */
572 if (io_txtindata.emajor > 7 ||
573 (io_txtindata.emajor == 7 && io_txtindata.eminor > 0) ||
574 (io_txtindata.emajor == 7 && io_txtindata.eminor == 0 && io_txtindata.edetail > 11))
575 {
576 ttyputmsg(M_("Unusual! Version %s library has no cellgroup information"), io_txtindata.version);
577 }
578 io_buildcellgrouppointersfromnames(io_txtindata.curlib);
579 } else if (io_txtindata.curlib->firstnodeproto != NONODEPROTO)
580 {
581 /* convert numbers to cellgroup pointers */
582 if (io_txtindata.emajor < 7 ||
583 (io_txtindata.emajor == 7 && io_txtindata.eminor == 0 && io_txtindata.edetail <= 11))
584 {
585 ttyputmsg(M_("Unusual! Version %s library has cellgroup information"), io_txtindata.version);
586 }
587 for(np = io_txtindata.curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
588 np->nextcellgrp = NONODEPROTO;
589 for(np = io_txtindata.curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
590 {
591 if (np->nextcellgrp != NONODEPROTO) continue;
592 prevmatch = np;
593 for(onp = np->nextnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
594 {
595 if (onp->temp1 != prevmatch->temp1) continue;
596 prevmatch->nextcellgrp = onp;
597 prevmatch = onp;
598 }
599 prevmatch->nextcellgrp = np;
600 }
601 }
602
603 /* if converting MOSIS CMOS technologies, store lambda in the right place */
604 if (io_txtindata.convertmosiscmostechnologies != 0)
605 io_txtindata.curlib->lambda[mocmos_tech->techindex] =
606 io_txtindata.curlib->lambda[mocmossub_tech->techindex];
607
608 /* if this is to be the current library, adjust technologies */
609 if (io_txtindata.curlib == el_curlib)
610 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
611 changetechnologylambda(tech, io_txtindata.curlib->lambda[tech->techindex]);
612
613 /* warn if the MOSIS CMOS technologies were converted */
614 if (io_txtindata.convertmosiscmostechnologies != 0)
615 {
616 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
617 {
618 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
619 if (ni->proto->primindex != 0 && ni->proto->tech == mocmos_tech) break;
620 if (ni != NONODEINST) break;
621 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
622 if (ai->proto->tech == mocmos_tech) break;
623 if (ai != NOARCINST) break;
624 }
625 if (np != NONODEPROTO)
626 DiaMessageInDialog(
627 _("Warning: library %s has older 'mocmossub' technology, converted to new 'mocmos'"),
628 lib->libname);
629 }
630
631 /* print any variable-related error messages */
632 if (io_txtindata.nodeinsterror != 0)
633 ttyputmsg(_("Warning: %ld invalid NODEINST pointers"), io_txtindata.nodeinsterror);
634 if (io_txtindata.arcinsterror != 0)
635 ttyputmsg(_("Warning: %ld invalid ARCINST pointers"), io_txtindata.arcinsterror);
636 if (io_txtindata.portprotoerror != 0)
637 ttyputmsg(_("Warning: %ld invalid PORTPROTO pointers"), io_txtindata.portprotoerror);
638 if (io_txtindata.portarcinsterror != 0)
639 ttyputmsg(_("Warning: %ld PORTARCINST pointers not restored"), io_txtindata.portarcinsterror);
640 if (io_txtindata.portexpinsterror != 0)
641 ttyputmsg(_("Warning: %ld PORTEXPINST pointers not restored"), io_txtindata.portexpinsterror);
642 if (io_txtindata.geomerror != 0)
643 ttyputmsg(_("Warning: %ld GEOM pointers not restored"), io_txtindata.geomerror);
644 if (io_txtindata.rtnodeerror != 0)
645 ttyputmsg(_("Warning: %ld RTNODE pointers not restored"), io_txtindata.rtnodeerror);
646 if (io_txtindata.libraryerror != 0)
647 ttyputmsg(_("Warning: %ld LIBRARY pointers not restored"), io_txtindata.libraryerror);
648
649 if (io_txtindata.maincell != -1 && io_txtindata.maincell < io_txtindata.cellcount)
650 io_txtindata.curlib->curnodeproto = io_txtindata.nodeprotolist[io_txtindata.maincell]; else
651 io_txtindata.curlib->curnodeproto = NONODEPROTO;
652 if (io_txtindata.cellcount != 0) efree((CHAR *)io_txtindata.nodeprotolist);
653 if (io_verbose < 0 && io_txtindata.filelength > 0 && newprogress && io_inputprogressdialog != 0)
654 {
655 DiaDoneProgress(io_inputprogressdialog);
656 io_inputprogressdialog = 0;
657 }
658
659 /* clean up the library */
660 io_fixnewlib(io_txtindata.curlib, 0);
661 io_txtindata.curlib->userbits &= ~(LIBCHANGEDMAJOR | LIBCHANGEDMINOR);
662 efree(io_txtindata.version);
663 return(FALSE);
664 }
665
666 /******************** GENERAL PARSING ROUTINES ********************/
667
io_getkeyword(void)668 BOOLEAN io_getkeyword(void)
669 {
670 REGISTER INTBIG c, cindex, inquote;
671
672 /* skip leading blanks */
673 for(;;)
674 {
675 c = xgetc(io_txtindata.textfilein);
676 io_txtindata.fileposition++;
677 if (c == '\n')
678 {
679 io_txtindata.linenumber++;
680 if (io_verbose == 0 && io_txtindata.linenumber%1000 == 0)
681 ttyputmsg(_("%ld lines read"), io_txtindata.linenumber);
682 continue;
683 }
684 if (c != ' ') break;
685 }
686
687 /* if the file ended, quit now */
688 if (c == EOF) return(TRUE);
689
690 /* collect the word */
691 cindex = 0;
692 if (c == '"') inquote = 1; else inquote = 0;
693 io_keyword[cindex++] = (CHAR)c;
694 for(;;)
695 {
696 c = xgetc(io_txtindata.textfilein);
697 if (c == EOF) return(TRUE);
698 io_txtindata.fileposition++;
699 if (c == '\n' || (c == ' ' && inquote == 0)) break;
700 if (cindex >= io_maxinputline)
701 {
702 /* try to allocate more space */
703 if (io_grabbuffers(io_maxinputline*2)) break;
704 }
705 if (c == '"' && (cindex == 0 || io_keyword[cindex-1] != '^'))
706 inquote = 1 - inquote;
707 io_keyword[cindex++] = (CHAR)c;
708 }
709 if (c == '\n')
710 {
711 io_txtindata.linenumber++;
712 if (io_verbose == 0 && io_txtindata.linenumber%1000 == 0)
713 ttyputmsg(_("%ld lines read"), io_txtindata.linenumber);
714 }
715 io_keyword[cindex] = 0;
716 return(FALSE);
717 }
718
719 /*
720 * routine to allocate the keyword buffer to be the specified size
721 */
io_grabbuffers(INTBIG size)722 BOOLEAN io_grabbuffers(INTBIG size)
723 {
724 REGISTER CHAR *p;
725 REGISTER INTBIG i;
726
727 /* first get the new buffer */
728 p = (CHAR *)emalloc((size+1) * SIZEOFCHAR, io_tool->cluster);
729 if (p == 0)
730 {
731 ttyputnomemory();
732 return(TRUE);
733 }
734
735 /* if there was an old buffer, copy it */
736 if (io_maxinputline != 0)
737 {
738 for(i=0; i<io_maxinputline; i++) p[i] = io_keyword[i];
739 efree(io_keyword);
740 }
741
742 /* set the new size and buffer */
743 io_maxinputline = size;
744 io_keyword = p;
745 return(FALSE);
746 }
747
748 /*
749 * helper routine to parse a port prototype name "line" that should be
750 * in node prototype "np". The routine returns NOPORTPROTO if it cannot
751 * figure out what port this name refers to.
752 */
io_getport(CHAR * line,NODEPROTO * np)753 PORTPROTO *io_getport(CHAR *line, NODEPROTO *np)
754 {
755 REGISTER PORTPROTO *pp;
756 REGISTER INTBIG i;
757
758 pp = getportproto(np, line);
759 if (pp != NOPORTPROTO) return(pp);
760
761 /* convert special port names */
762 pp = io_convertoldportname(line, np);
763 if (pp != NOPORTPROTO) return(pp);
764
765 /* try to parse version 1 port names */
766 if (io_txtindata.version[0] == '1')
767 {
768 /* see if database uses shortened name */
769 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
770 {
771 i = estrlen(pp->protoname);
772 if (namesamen(line, pp->protoname, i) == 0) return(pp);
773 }
774
775 /* see if the port name ends in a digit, fake with that */
776 i = estrlen(line);
777 if (line[i-2] == '-' && line[i-1] >= '0' && line[i-1] <= '9')
778 {
779 i = (eatoi(&line[i-1])-1) / 3;
780 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
781 if (i-- == 0) return(pp);
782 }
783 }
784
785 /* sorry, cannot figure out what port prototype this is */
786 return(NOPORTPROTO);
787 }
788
789 /*
790 * null routine for ignoring keywords
791 */
io_null(void)792 void io_null(void) {}
793
794 /******************** LIBRARY PARSING ROUTINES ********************/
795
796 /*
797 * a new library is introduced (keyword "****library")
798 * This should be the first keyword in the file
799 */
io_newlib(void)800 void io_newlib(void)
801 {
802 REGISTER TECHNOLOGY *tech;
803
804 /* set defaults */
805 io_txtindata.maincell = -1;
806 (void)allocstring(&io_txtindata.version, x_("1.00"), el_tempcluster);
807 io_txtindata.varpos = INVTOOL;
808 io_txtindata.curtech = NOTECHNOLOGY;
809 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
810 io_txtindata.curlib->lambda[tech->techindex] = 0;
811 io_txtindata.textlevel = INLIB;
812 }
813
814 /*
815 * get the file's Electric version number (keyword "version")
816 */
io_versn(void)817 void io_versn(void)
818 {
819 (void)reallocstring(&io_txtindata.version, io_keyword, el_tempcluster);
820
821 /* for versions before 6.03q, convert MOSIS CMOS technology names */
822 parseelectricversion(io_txtindata.version, &io_txtindata.emajor, &io_txtindata.eminor,
823 &io_txtindata.edetail);
824 io_txtindata.convertmosiscmostechnologies = 0;
825 if (io_txtindata.emajor < 6 ||
826 (io_txtindata.emajor == 6 && io_txtindata.eminor < 3) ||
827 (io_txtindata.emajor == 6 && io_txtindata.eminor == 3 && io_txtindata.edetail < 17))
828 {
829 if ((asktech(mocmossub_tech, x_("get-state"))&MOCMOSSUBNOCONV) == 0)
830 io_txtindata.convertmosiscmostechnologies = 1;
831 }
832 #ifdef REPORTCONVERSION
833 ttyputmsg(x_("Library is version %s (%ld.%ld.%ld)"), io_txtindata.version, io_txtindata.emajor,
834 io_txtindata.eminor, io_txtindata.edetail);
835 if (io_txtindata.convertmosiscmostechnologies != 0)
836 ttyputmsg(x_(" Converting MOSIS CMOS technologies (mocmossub => mocmos)"));
837 #endif
838 }
839
840 /*
841 * get the number of tools (keyword "aids")
842 */
io_libkno(void)843 void io_libkno(void)
844 {
845 io_txtindata.bitcount = 0;
846 }
847
848 /*
849 * get the name of the tool (keyword "aidname")
850 */
io_libain(void)851 void io_libain(void)
852 {
853 REGISTER TOOL *tool;
854
855 tool = gettool(io_keyword);
856 if (tool == NOTOOL) io_txtindata.bitcount = -1; else
857 io_txtindata.bitcount = tool->toolindex + 1;
858 }
859
860 /*
861 * get the number of toolbits (keyword "aidbits")
862 */
io_libaib(void)863 void io_libaib(void)
864 {
865 io_txtindata.bitcount = 0;
866 }
867
868 /*
869 * get tool information for the library (keyword "bits")
870 */
io_libbit(void)871 void io_libbit(void)
872 {
873 if (io_txtindata.bitcount == 0)
874 io_txtindata.curlib->userbits = eatoi(io_keyword);
875 io_txtindata.bitcount++;
876 }
877
878 /*
879 * get the number of toolbits (keyword "userbits")
880 */
io_libusb(void)881 void io_libusb(void)
882 {
883 io_txtindata.curlib->userbits = eatoi(io_keyword);
884
885 /* this library came as readable dump, so don't automatically save it to disk */
886 io_txtindata.curlib->userbits &= ~READFROMDISK;
887 }
888
889 /*
890 * get the number of technologies (keyword "techcount")
891 */
io_libte(void)892 void io_libte(void)
893 {
894 io_txtindata.varpos = INVTECHNOLOGY;
895 io_txtindata.bitcount = 0;
896 }
897
898 /*
899 * get the name of the technology (keyword "techname")
900 */
io_libten(void)901 void io_libten(void)
902 {
903 REGISTER TECHNOLOGY *tech;
904
905 tech = gettechnology(io_keyword);
906 if (tech == NOTECHNOLOGY) io_txtindata.bitcount = -1; else
907 io_txtindata.bitcount = tech->techindex;
908 }
909
910 /*
911 * get lambda values for each technology in library (keyword "lambda")
912 */
io_lambda(void)913 void io_lambda(void)
914 {
915 REGISTER INTBIG lam;
916
917 if (io_txtindata.bitcount >= el_maxtech ||
918 io_txtindata.bitcount < 0) return;
919 lam = eatoi(io_keyword);
920
921 /* for version 4.0 and earlier, scale lambda by 20 */
922 if (eatoi(io_txtindata.version) <= 4) lam *= 20;
923 io_txtindata.curlib->lambda[io_txtindata.bitcount++] = lam;
924 }
925
926 /*
927 * get variables on current object (keyword "variables")
928 */
io_getvar(void)929 void io_getvar(void)
930 {
931 REGISTER INTBIG i, j, count, type, len, naddr, ntype, thisnaddr, *store, key, ret;
932 REGISTER float *fstore;
933 REGISTER INTSML *sstore;
934 UINTBIG descript[TEXTDESCRIPTSIZE];
935 REGISTER CHAR *pt, *start, *varname;
936 REGISTER VARIABLE *var;
937 REGISTER TECHNOLOGY *t;
938 REGISTER void *infstr;
939
940 naddr = -1;
941 switch (io_txtindata.varpos)
942 {
943 case INVTOOL: /* keyword applies to tools */
944 if (io_txtindata.bitcount < 0) break;
945 naddr = (INTBIG)&el_tools[io_txtindata.bitcount-1];
946 ntype = VTOOL;
947 break;
948 case INVTECHNOLOGY: /* keyword applies to technologies */
949 if (io_txtindata.bitcount < 0) break;
950 for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
951 if (t->techindex == io_txtindata.bitcount-1) break;
952 naddr = (INTBIG)t;
953 ntype = VTECHNOLOGY;
954 break;
955 case INVLIBRARY: /* keyword applies to library */
956 naddr = (INTBIG)io_txtindata.curlib;
957 ntype = VLIBRARY;
958 break;
959 case INVNODEPROTO: /* keyword applies to nodeproto */
960 naddr = (INTBIG)io_txtindata.curnodeproto; ntype = VNODEPROTO;
961 break;
962 case INVNODEINST: /* keyword applies to nodeinst */
963 naddr = (INTBIG)io_txtindata.curnodeinst; ntype = VNODEINST;
964 break;
965 case INVPORTARCINST: /* keyword applies to portarcinsts */
966 naddr = (INTBIG)io_txtindata.varaddr; ntype = VPORTARCINST;
967 break;
968 case INVPORTEXPINST: /* keyword applies to portexpinsts */
969 naddr = (INTBIG)io_txtindata.varaddr; ntype = VPORTEXPINST;
970 break;
971 case INVPORTPROTO: /* keyword applies to portproto */
972 naddr = (INTBIG)io_txtindata.curportproto; ntype = VPORTPROTO;
973 break;
974 case INVARCINST: /* keyword applies to arcinst */
975 naddr = (INTBIG)io_txtindata.curarcinst; ntype = VARCINST;
976 break;
977 }
978
979 /* find out how many variables to read */
980 count = eatoi(io_keyword);
981 for(i=0; i<count; i++)
982 {
983 /* read the first keyword with the name, type, and descriptor */
984 if (io_getkeyword()) longjmp(io_filerror, LONGJMPEOFVAR);
985 if (io_keyword[estrlen(io_keyword)-1] != ':')
986 longjmp(io_filerror, LONGJMPMISCOLVAR);
987
988 /* get the variable name */
989 infstr = initinfstr();
990 for(pt = io_keyword; *pt != 0; pt++)
991 {
992 if (*pt == '^' && pt[1] != 0)
993 {
994 pt++;
995 addtoinfstr(infstr, *pt);
996 }
997 if (*pt == '(' || *pt == '[' || *pt == ':') break;
998 addtoinfstr(infstr, *pt);
999 }
1000 varname = returninfstr(infstr);
1001 key = makekey(varname);
1002
1003 /* see if the variable is valid */
1004 thisnaddr = naddr;
1005 if (isdeprecatedvariable(naddr, ntype, varname)) thisnaddr = -1;
1006
1007 /* get optional length */
1008 if (*pt == '(')
1009 {
1010 len = myatoi(&pt[1]);
1011 while (*pt != '[' && *pt != ':' && *pt != 0) pt++;
1012 } else len = -1;
1013
1014 /* get type */
1015 if (*pt != '[') longjmp(io_filerror, LONGJMPMISOSBVAR);
1016 type = myatoi(&pt[1]);
1017
1018 /* get the descriptor */
1019 while (*pt != ',' && *pt != ':' && *pt != 0) pt++;
1020 TDCLEAR(descript);
1021 if (*pt == ',')
1022 {
1023 descript[0] = myatoi(&pt[1]);
1024 for(pt++; *pt != 0 && *pt != '/' && *pt != ']'; pt++) ;
1025 if (*pt == '/')
1026 descript[1] = myatoi(pt+1);
1027 }
1028
1029 /* get value */
1030 if (io_getkeyword()) longjmp(io_filerror, LONGJMPEOFVAR);
1031 if ((type&VISARRAY) != 0)
1032 {
1033 if (len < 0)
1034 {
1035 len = (type&VLENGTH) >> VLENGTHSH;
1036 store = emalloc((len * SIZEOFINTBIG), el_tempcluster);
1037 if (store == 0) longjmp(io_filerror, LONGJMPNOMEM);
1038 fstore = (float *)store;
1039 sstore = (INTSML *)store;
1040 } else
1041 {
1042 store = emalloc(((len+1) * SIZEOFINTBIG), el_tempcluster);
1043 if (store == 0) longjmp(io_filerror, LONGJMPNOMEM);
1044 fstore = (float *)store;
1045 sstore = (INTSML *)store;
1046 store[len] = -1;
1047 if ((type&VTYPE) == VFLOAT) fstore[len] = castfloat(-1);
1048 if ((type&VTYPE) == VSHORT) sstore[len] = -1;
1049 }
1050 pt = io_keyword;
1051 if (*pt++ != '[')
1052 longjmp(io_filerror, LONGJMPMISOSBVARARR);
1053 for(j=0; j<len; j++)
1054 {
1055 /* string arrays must be handled specially */
1056 if ((type&VTYPE) == VSTRING)
1057 {
1058 while (*pt != '"' && *pt != 0) pt++;
1059 if (*pt != 0)
1060 {
1061 start = pt++;
1062 for(;;)
1063 {
1064 if (pt[0] == '^' && pt[1] != 0)
1065 {
1066 pt += 2;
1067 continue;
1068 }
1069 if (pt[0] == '"' || pt[0] == 0) break;
1070 pt++;
1071 }
1072 if (*pt != 0) pt++;
1073 }
1074 } else
1075 {
1076 start = pt;
1077 while (*pt != ',' && *pt != ']' && *pt != 0) pt++;
1078 }
1079 if (*pt == 0)
1080 longjmp(io_filerror, LONGJMPSHORTARR);
1081 *pt++ = 0;
1082 if ((type&VTYPE) == VGENERAL)
1083 {
1084 if ((j&1) == 0)
1085 {
1086 store[j+1] = myatoi(start);
1087 } else
1088 {
1089 store[j-1] = io_decode(start, store[j]);
1090 }
1091 } else
1092 {
1093 if ((type&VTYPE) == VFLOAT)
1094 {
1095 fstore[j] = castfloat(io_decode(start, type));
1096 } else if ((type&VTYPE) == VSHORT)
1097 {
1098 sstore[j] = (INTSML)io_decode(start, type);
1099 } else
1100 {
1101 store[j] = io_decode(start, type);
1102 }
1103 }
1104 }
1105 if (thisnaddr != -1)
1106 {
1107 nextchangequiet();
1108 var = setvalkey(thisnaddr, ntype, key, (INTBIG)store, type);
1109 if (var == NOVARIABLE) longjmp(io_filerror, LONGJMPNOMEM);
1110 TDCOPY(var->textdescript, descript);
1111
1112 /* handle updating of technology caches */
1113 if (ntype == VTECHNOLOGY)
1114 changedtechnologyvariable(key);
1115 }
1116 efree((CHAR *)store);
1117 } else
1118 {
1119 ret = io_decode(io_keyword, type);
1120 if (thisnaddr != -1)
1121 {
1122 nextchangequiet();
1123 var = setvalkey(thisnaddr, ntype, key, ret, type);
1124 if (var == NOVARIABLE) longjmp(io_filerror, LONGJMPNOMEM);
1125 TDCOPY(var->textdescript, descript);
1126
1127 /* handle updating of technology caches */
1128 if (ntype == VTECHNOLOGY)
1129 changedtechnologyvariable(key);
1130 }
1131 }
1132 }
1133 }
1134
io_decode(CHAR * name,INTBIG type)1135 INTBIG io_decode(CHAR *name, INTBIG type)
1136 {
1137 REGISTER INTBIG thistype, cindex;
1138 REGISTER CHAR *out, *retur;
1139 REGISTER NODEPROTO *np;
1140
1141 thistype = type;
1142 if ((thistype&(VCODE1|VCODE2)) != 0) thistype = VSTRING;
1143
1144 switch (thistype&VTYPE)
1145 {
1146 case VINTEGER:
1147 case VSHORT:
1148 case VBOOLEAN:
1149 case VFRACT:
1150 case VADDRESS:
1151 return(myatoi(name));
1152 case VCHAR:
1153 return((INTBIG)name);
1154 case VSTRING:
1155 if (*name == '"') name++;
1156 retur = name;
1157 for(out = name; *name != 0; name++)
1158 {
1159 if (*name == '^' && name[1] != 0)
1160 {
1161 name++;
1162 *out++ = *name;
1163 continue;
1164 }
1165 if (*name == '"') break;
1166 *out++ = *name;
1167 }
1168 *out = 0;
1169 return((INTBIG)retur);
1170 case VFLOAT:
1171 case VDOUBLE:
1172 return(castint((float)eatof(name)));
1173 case VNODEINST:
1174 cindex = myatoi(name);
1175 if (cindex >= 0 && cindex < io_txtindata.nodeinstcount)
1176 return((INTBIG)io_txtindata.nodelist[cindex]);
1177 io_txtindata.nodeinsterror++;
1178 return(-1);
1179 case VNODEPROTO:
1180 cindex = myatoi(name);
1181 if (cindex == -1) return(-1);
1182
1183 /* see if there is a ":" in the type */
1184 for(out = name; *out != 0; out++) if (*out == ':') break;
1185 if (*out == 0)
1186 {
1187 cindex = eatoi(name);
1188 if (cindex == -1) return(-1);
1189 return((INTBIG)io_txtindata.nodeprotolist[cindex]);
1190 }
1191
1192 /* parse primitive nodeproto name */
1193 np = getnodeproto(name);
1194 if (np == NONODEPROTO)
1195 longjmp(io_filerror, LONGJMPUKNNOPROTO);
1196 if (np->primindex == 0)
1197 longjmp(io_filerror, LONGJMPUKNNOPROTO);
1198 return((INTBIG)np);
1199 case VPORTARCINST:
1200 io_txtindata.portarcinsterror++; break;
1201 case VPORTEXPINST:
1202 io_txtindata.portexpinsterror++; break;
1203 case VPORTPROTO:
1204 cindex = myatoi(name);
1205 if (cindex >= 0 && cindex < io_txtindata.portprotocount)
1206 return((INTBIG)io_txtindata.portprotolist[cindex]);
1207 io_txtindata.portprotoerror++;
1208 return(-1);
1209 case VARCINST:
1210 cindex = myatoi(name);
1211 if (cindex >= 0 && cindex < io_txtindata.arcinstcount)
1212 return((INTBIG)io_txtindata.arclist[cindex]);
1213 io_txtindata.arcinsterror++;
1214 return(-1);
1215 case VARCPROTO:
1216 return((INTBIG)getarcproto(name));
1217 case VGEOM:
1218 io_txtindata.geomerror++; break;
1219 case VLIBRARY:
1220 io_txtindata.libraryerror++; break;
1221 case VTECHNOLOGY:
1222 return((INTBIG)io_gettechnology(name));
1223 case VTOOL:
1224 return((INTBIG)gettool(name));
1225 case VRTNODE:
1226 io_txtindata.rtnodeerror++; break;
1227 }
1228 return(-1);
1229 }
1230
1231 /*
1232 * get the number of cells in this library (keyword "cellcount")
1233 */
io_libcc(void)1234 void io_libcc(void)
1235 {
1236 REGISTER INTBIG i;
1237
1238 io_txtindata.varpos = INVLIBRARY;
1239
1240 io_txtindata.cellcount = eatoi(io_keyword);
1241 if (io_txtindata.cellcount == 0)
1242 {
1243 io_txtindata.curlib->firstnodeproto = NONODEPROTO;
1244 io_txtindata.curlib->tailnodeproto = NONODEPROTO;
1245 io_txtindata.curlib->numnodeprotos = 0;
1246 return;
1247 }
1248
1249 /* allocate a list of node prototypes for this library */
1250 io_txtindata.nodeprotolist = (NODEPROTO **)emalloc(((sizeof (NODEPROTO *)) * io_txtindata.cellcount),
1251 el_tempcluster);
1252 if (io_txtindata.nodeprotolist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1253 for(i=0; i<io_txtindata.cellcount; i++)
1254 {
1255 io_txtindata.nodeprotolist[i] = allocnodeproto(io_txtindata.curlib->cluster);
1256 if (io_txtindata.nodeprotolist[i] == NONODEPROTO)
1257 longjmp(io_filerror, LONGJMPNOMEM);
1258 io_txtindata.nodeprotolist[i]->cellview = el_unknownview;
1259 io_txtindata.nodeprotolist[i]->newestversion = io_txtindata.nodeprotolist[i];
1260 io_txtindata.nodeprotolist[i]->primindex = 0;
1261 io_txtindata.nodeprotolist[i]->firstportproto = NOPORTPROTO;
1262 io_txtindata.nodeprotolist[i]->firstnodeinst = NONODEINST;
1263 io_txtindata.nodeprotolist[i]->firstarcinst = NOARCINST;
1264 }
1265 }
1266
1267 /*
1268 * get the main cell of this library (keyword "maincell")
1269 */
io_libms(void)1270 void io_libms(void)
1271 {
1272 io_txtindata.maincell = eatoi(io_keyword);
1273 }
1274
1275 /*
1276 * get a view (keyword "view")
1277 */
io_libvie(void)1278 void io_libvie(void)
1279 {
1280 REGISTER CHAR *pt;
1281 REGISTER INTBIG len;
1282 REGISTER VIEW *v;
1283
1284 pt = io_keyword;
1285 while (*pt != 0 && *pt != '{') pt++;
1286 if (*pt != '{') longjmp(io_filerror, LONGJMPMISVIEWABR);
1287 *pt++ = 0;
1288 len = estrlen(pt);
1289 if (pt[len-1] != '}') longjmp(io_filerror, LONGJMPBADVIEWABR);
1290 pt[len-1] = 0;
1291 v = getview(io_keyword);
1292 if (v == NOVIEW)
1293 {
1294 v = allocview();
1295 if (v == NOVIEW) longjmp(io_filerror, LONGJMPNOMEM);
1296 (void)allocstring(&v->viewname, io_keyword, db_cluster);
1297 (void)allocstring(&v->sviewname, pt, db_cluster);
1298 if (namesamen(io_keyword, x_("Schematic-Page-"), 15) == 0)
1299 v->viewstate |= MULTIPAGEVIEW;
1300 v->nextview = el_views;
1301 el_views = v;
1302 } else
1303 {
1304 if (namesame(v->sviewname, pt) != 0)
1305 longjmp(io_filerror, LONGJMPINCVIEWABR);
1306 }
1307 pt[-1] = '{'; pt[len-1] = '}';
1308 }
1309
1310 /******************** CELL PARSING ROUTINES ********************/
1311
1312 /*
1313 * initialize for a new cell (keyword "***cell")
1314 */
io_newcel(void)1315 void io_newcel(void)
1316 {
1317 REGISTER CHAR *pt;
1318
1319 io_txtindata.curcellnumber = eatoi(io_keyword);
1320 for(pt = io_keyword; *pt != 0; pt++) if (*pt == '/') break;
1321 io_txtindata.curnodeproto = io_txtindata.nodeprotolist[io_txtindata.curcellnumber];
1322 if (*pt == '/') io_txtindata.curnodeproto->temp1 = eatoi(pt+1); else
1323 io_txtindata.curnodeproto->temp1 = -1;
1324 io_txtindata.textlevel = INCELL;
1325 io_txtindata.varpos = INVNODEPROTO;
1326 }
1327
1328 /*
1329 * get the name of the current cell (keyword "name")
1330 */
io_celnam(void)1331 void io_celnam(void)
1332 {
1333 REGISTER CHAR *pt;
1334 REGISTER VIEW *v;
1335 REGISTER void *infstr;
1336
1337 if (io_verbose != 0)
1338 {
1339 if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
1340 {
1341 infstr = initinfstr();
1342 formatinfstr(infstr, _("Reading %s"), io_keyword);
1343 DiaSetTextProgress(io_inputprogressdialog, returninfstr(infstr));
1344 } else ttyputmsg(_("Reading %s"), io_keyword);
1345 }
1346 io_txtindata.curnodeproto->cellview = el_unknownview;
1347 pt = io_keyword;
1348 while (*pt != 0 && *pt != '{') pt++;
1349 if (*pt == '{')
1350 {
1351 *pt = 0;
1352 if (allocstring(&io_txtindata.curnodeproto->protoname, io_keyword,
1353 io_txtindata.curlib->cluster))
1354 longjmp(io_filerror, LONGJMPNOMEM);
1355 pt++;
1356 pt[estrlen(pt)-1] = 0;
1357 for(v = el_views; v != NOVIEW; v = v->nextview)
1358 if (*v->sviewname != 0 && namesame(pt, v->sviewname) == 0) break;
1359 if (v != NOVIEW) io_txtindata.curnodeproto->cellview = v;
1360 } else
1361 {
1362 if (allocstring(&io_txtindata.curnodeproto->protoname, io_keyword,
1363 io_txtindata.curlib->cluster))
1364 longjmp(io_filerror, LONGJMPNOMEM);
1365 }
1366 io_txtindata.curnodeproto->lib = io_txtindata.curlib;
1367 }
1368
1369 /*
1370 * get the version of the current cell (keyword "version")
1371 */
io_celver(void)1372 void io_celver(void)
1373 {
1374 io_txtindata.curnodeproto->version = eatoi(io_keyword);
1375 db_insertnodeproto(io_txtindata.curnodeproto);
1376 }
1377
1378 /*
1379 * get the creation date of the current cell (keyword "creationdate")
1380 */
io_celcre(void)1381 void io_celcre(void)
1382 {
1383 io_txtindata.curnodeproto->creationdate = eatoi(io_keyword);
1384 }
1385
1386 /*
1387 * get the revision date of the current cell (keyword "revisiondate")
1388 */
io_celrev(void)1389 void io_celrev(void)
1390 {
1391 io_txtindata.curnodeproto->revisiondate = eatoi(io_keyword);
1392 }
1393
1394 /*
1395 * get the external library file (keyword "externallibrary")
1396 */
io_celext(void)1397 void io_celext(void)
1398 {
1399 INTBIG len, filetype, filelen;
1400 REGISTER LIBRARY *elib;
1401 REGISTER CHAR *libname, *pt;
1402 CHAR *filename, *libfile, *oldline2, *libfilename, *libfilepath;
1403 FILE *io;
1404 REGISTER BOOLEAN failed;
1405 CHAR *cellname;
1406 REGISTER NODEPROTO *np, *onp;
1407 REGISTER NODEINST *ni;
1408 TXTINPUTDATA savetxtindata;
1409 REGISTER void *infstr;
1410
1411 /* get the path to the library file */
1412 libfile = io_keyword;
1413 if (libfile[0] == '"')
1414 {
1415 libfile++;
1416 len = estrlen(libfile) - 1;
1417 if (libfile[len] == '"') libfile[len] = 0;
1418 }
1419
1420 /* see if this library is already read in */
1421 infstr = initinfstr();
1422 addstringtoinfstr(infstr, skippath(libfile));
1423 libname = returninfstr(infstr);
1424 len = estrlen(libname);
1425 filelen = estrlen(libfile);
1426 if (len < filelen)
1427 {
1428 libfilename = &libfile[filelen-len-1];
1429 *libfilename++ = 0;
1430 libfilepath = libfile;
1431 } else
1432 {
1433 libfilename = libfile;
1434 libfilepath = x_("");
1435 }
1436
1437 filetype = io_filetypetlib;
1438 if (len > 5 && namesame(&libname[len-5], x_(".elib")) == 0)
1439 {
1440 libname[len-5] = 0;
1441 filetype = io_filetypeblib;
1442 } else
1443 {
1444 if (len > 4 && namesame(&libname[len-4], x_(".txt")) == 0) libname[len-4] = 0;
1445 }
1446 elib = getlibrary(libname);
1447 if (elib == NOLIBRARY)
1448 {
1449 /* library does not exist: see if file is there */
1450 io = xopen(libfilename, filetype, truepath(libfilepath), &filename);
1451 if (io == 0)
1452 {
1453 /* try the library area */
1454 io = xopen(libfilename, filetype, el_libdir, &filename);
1455 }
1456 if (io != 0)
1457 {
1458 xclose(io);
1459 ttyputmsg(_("Reading referenced library %s"), libname);
1460 } else
1461 {
1462 infstr = initinfstr();
1463 formatinfstr(infstr, _("Reference library '%s'"), libname);
1464 pt = fileselect(returninfstr(infstr), filetype, x_(""));
1465 if (pt != 0)
1466 {
1467 estrcpy(libfile, pt);
1468 filename = libfile;
1469 }
1470 }
1471 elib = newlibrary(libname, filename);
1472 if (elib == NOLIBRARY) return;
1473
1474 /* read the external library */
1475 savetxtindata = io_txtindata;
1476 if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
1477 {
1478 (void)allocstring(&oldline2, DiaGetTextProgress(io_inputprogressdialog), el_tempcluster);
1479 }
1480
1481 len = estrlen(libfilename);
1482 io_libinputrecursivedepth++;
1483 io_libinputreadmany++;
1484 if (len > 4 && namesame(&libfilename[len-4], x_(".txt")) == 0)
1485 {
1486 /* ends in ".txt", presume text file */
1487 failed = io_doreadtextlibrary(elib, FALSE);
1488 } else
1489 {
1490 /* all other endings: presume binary file */
1491 failed = io_doreadbinlibrary(elib, FALSE);
1492 }
1493 io_libinputrecursivedepth--;
1494 if (failed) elib->userbits |= UNWANTEDLIB; else
1495 {
1496 /* queue this library for announcement through change control */
1497 io_queuereadlibraryannouncement(elib);
1498 }
1499 io_txtindata = savetxtindata;
1500 if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
1501 {
1502 DiaSetProgress(io_inputprogressdialog, io_txtindata.fileposition, io_txtindata.filelength);
1503 infstr = initinfstr();
1504 formatinfstr(infstr, _("Reading library %s"), io_txtindata.curlib->libname);
1505 DiaSetCaptionProgress(io_inputprogressdialog, returninfstr(infstr));
1506 DiaSetTextProgress(io_inputprogressdialog, oldline2);
1507 efree(oldline2);
1508 }
1509 }
1510
1511 /* find this cell in the external library */
1512 cellname = io_txtindata.curnodeproto->protoname;
1513 for(np = elib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1514 {
1515 if (namesame(np->protoname, cellname) != 0) continue;
1516 if (np->cellview != io_txtindata.curnodeproto->cellview) continue;
1517 if (np->version != io_txtindata.curnodeproto->version) continue;
1518 break;
1519 }
1520 if (np == NONODEPROTO)
1521 {
1522 /* cell not found in library: issue warning */
1523 infstr = initinfstr();
1524 addstringtoinfstr(infstr, cellname);
1525 if (io_txtindata.curnodeproto->cellview != el_unknownview)
1526 {
1527 addtoinfstr(infstr, '{');
1528 addstringtoinfstr(infstr, io_txtindata.curnodeproto->cellview->sviewname);
1529 addtoinfstr(infstr, '}');
1530 }
1531 ttyputerr(_("Cannot find cell %s in library %s..creating dummy version"),
1532 returninfstr(infstr), elib->libname);
1533 } else
1534 {
1535 /* cell found: make sure it is valid */
1536 if (np->revisiondate != io_txtindata.curnodeproto->revisiondate ||
1537 np->lowx != io_txtindata.curnodeproto->lowx ||
1538 np->highx != io_txtindata.curnodeproto->highx ||
1539 np->lowy != io_txtindata.curnodeproto->lowy ||
1540 np->highy != io_txtindata.curnodeproto->highy)
1541 {
1542 ttyputerr(_("Warning: cell %s in library %s has been modified"),
1543 describenodeproto(np), elib->libname);
1544 np = NONODEPROTO;
1545 }
1546 }
1547 if (np != NONODEPROTO)
1548 {
1549 /* get rid of existing cell and plug in the external reference */
1550 onp = io_txtindata.nodeprotolist[io_txtindata.curcellnumber];
1551 db_retractnodeproto(onp);
1552 freenodeproto(onp);
1553 io_txtindata.nodeprotolist[io_txtindata.curcellnumber] = np;
1554 } else
1555 {
1556 /* rename the cell */
1557 np = io_txtindata.curnodeproto;
1558 infstr = initinfstr();
1559 formatinfstr(infstr, x_("%sFROM%s"), cellname, elib->libname);
1560 db_retractnodeproto(np);
1561
1562 cellname = returninfstr(infstr);
1563 (void)allocstring(&np->protoname, cellname, io_txtindata.curlib->cluster);
1564 db_insertnodeproto(np);
1565
1566 /* create an artwork "Crossed box" to define the cell size */
1567 ni = allocnodeinst(io_txtindata.curlib->cluster);
1568 ni->proto = art_crossedboxprim;
1569 ni->parent = np;
1570 ni->nextnodeinst = np->firstnodeinst;
1571 np->firstnodeinst = ni;
1572 ni->lowx = np->lowx; ni->highx = np->highx;
1573 ni->lowy = np->lowy; ni->highy = np->highy;
1574 ni->geom = allocgeom(io_txtindata.curlib->cluster);
1575 ni->geom->entryisnode = TRUE; ni->geom->entryaddr.ni = ni;
1576 linkgeom(ni->geom, np);
1577 }
1578 }
1579
1580 /*
1581 * get the boundary of the current cell
1582 */
io_cellx(void)1583 void io_cellx(void)
1584 {
1585 io_txtindata.curnodeproto->lowx = eatoi(io_keyword);
1586 }
1587
io_celhx(void)1588 void io_celhx(void)
1589 {
1590 io_txtindata.curnodeproto->highx = eatoi(io_keyword);
1591 }
1592
io_celly(void)1593 void io_celly(void)
1594 {
1595 io_txtindata.curnodeproto->lowy = eatoi(io_keyword);
1596 }
1597
io_celhy(void)1598 void io_celhy(void)
1599 {
1600 io_txtindata.curnodeproto->highy = eatoi(io_keyword);
1601 }
1602
1603 /*
1604 * get the default technology for objects in this cell (keyword "technology")
1605 */
io_tech(void)1606 void io_tech(void)
1607 {
1608 REGISTER TECHNOLOGY *tech;
1609
1610 tech = io_gettechnology(io_keyword);
1611 if (tech == NOTECHNOLOGY) longjmp(io_filerror, LONGJMPUKNTECH);
1612 io_txtindata.curtech = tech;
1613 }
1614
1615 /*
1616 * get the tool dirty word for the current cell (keyword "aadirty")
1617 */
io_celaad(void)1618 void io_celaad(void)
1619 {
1620 io_txtindata.curnodeproto->adirty = eatoi(io_keyword);
1621 io_txtindata.bitcount = 0;
1622 }
1623
1624 /*
1625 * get tool information for current cell (keyword "bits")
1626 */
io_celbit(void)1627 void io_celbit(void)
1628 {
1629 if (io_txtindata.bitcount == 0) io_txtindata.curnodeproto->userbits = eatoi(io_keyword);
1630 io_txtindata.bitcount++;
1631 }
1632
1633 /*
1634 * get tool information for current cell (keyword "userbits")
1635 */
io_celusb(void)1636 void io_celusb(void)
1637 {
1638 io_txtindata.curnodeproto->userbits = eatoi(io_keyword);
1639 }
1640
1641 /*
1642 * get tool information for current cell (keyword "netnum")
1643 */
io_celnet(void)1644 void io_celnet(void) {}
1645
1646 /*
1647 * get the number of node instances in the current cell (keyword "nodes")
1648 */
io_celnoc(void)1649 void io_celnoc(void)
1650 {
1651 REGISTER INTBIG i;
1652 REGISTER NODEINST *ni;
1653 REGISTER GEOM **geomlist;
1654
1655 io_txtindata.nodeinstcount = eatoi(io_keyword);
1656 if (io_txtindata.nodeinstcount == 0) return;
1657 io_txtindata.nodelist = (NODEINST **)emalloc(((sizeof (NODEINST *)) * io_txtindata.nodeinstcount),
1658 el_tempcluster);
1659 if (io_txtindata.nodelist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1660 geomlist = (GEOM **)emalloc(((sizeof (GEOM *)) * io_txtindata.nodeinstcount), el_tempcluster);
1661 if (geomlist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1662 for(i=0; i<io_txtindata.nodeinstcount; i++)
1663 {
1664 ni = allocnodeinst(io_txtindata.curlib->cluster);
1665 geomlist[i] = allocgeom(io_txtindata.curlib->cluster);
1666 if (ni == NONODEINST || geomlist[i] == NOGEOM)
1667 longjmp(io_filerror, LONGJMPNOMEM);
1668 io_txtindata.nodelist[i] = ni;
1669 ni->parent = io_txtindata.curnodeproto;
1670 ni->firstportarcinst = NOPORTARCINST;
1671 ni->firstportexpinst = NOPORTEXPINST;
1672 ni->geom = geomlist[i];
1673
1674 /* compute linked list of nodes in this cell */
1675 if (io_txtindata.curnodeproto->firstnodeinst != NONODEINST)
1676 io_txtindata.curnodeproto->firstnodeinst->prevnodeinst = ni;
1677 ni->nextnodeinst = io_txtindata.curnodeproto->firstnodeinst;
1678 ni->prevnodeinst = NONODEINST;
1679 io_txtindata.curnodeproto->firstnodeinst = ni;
1680 }
1681 efree((CHAR *)geomlist);
1682 }
1683
1684 /*
1685 * get the number of arc instances in the current cell (keyword "arcs")
1686 */
io_celarc(void)1687 void io_celarc(void)
1688 {
1689 REGISTER INTBIG i;
1690 REGISTER ARCINST *ai;
1691 REGISTER GEOM **geomlist;
1692
1693 io_txtindata.arcinstcount = eatoi(io_keyword);
1694 if (io_txtindata.arcinstcount == 0) return;
1695 io_txtindata.arclist = (ARCINST **)emalloc(((sizeof (ARCINST *)) * io_txtindata.arcinstcount),
1696 el_tempcluster);
1697 if (io_txtindata.arclist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1698 geomlist = (GEOM **)emalloc(((sizeof (GEOM *)) * io_txtindata.arcinstcount), el_tempcluster);
1699 if (geomlist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1700 for(i=0; i<io_txtindata.arcinstcount; i++)
1701 {
1702 ai = allocarcinst(io_txtindata.curlib->cluster);
1703 geomlist[i] = allocgeom(io_txtindata.curlib->cluster);
1704 if (ai == NOARCINST || geomlist[i] == NOGEOM)
1705 longjmp(io_filerror, LONGJMPNOMEM);
1706 io_txtindata.arclist[i] = ai;
1707 ai->parent = io_txtindata.curnodeproto;
1708 ai->geom = geomlist[i];
1709
1710 /* compute linked list of arcs in this cell */
1711 if (io_txtindata.curnodeproto->firstarcinst != NOARCINST)
1712 io_txtindata.curnodeproto->firstarcinst->prevarcinst = ai;
1713 ai->nextarcinst = io_txtindata.curnodeproto->firstarcinst;
1714 ai->prevarcinst = NOARCINST;
1715 io_txtindata.curnodeproto->firstarcinst = ai;
1716 }
1717 efree((CHAR *)geomlist);
1718 }
1719
1720 /*
1721 * get the number of port prototypes in the current cell (keyword "porttypes")
1722 */
io_celptc(void)1723 void io_celptc(void)
1724 {
1725 REGISTER INTBIG i;
1726
1727 io_txtindata.portprotocount = eatoi(io_keyword);
1728 io_txtindata.curnodeproto->numportprotos = io_txtindata.portprotocount;
1729 if (io_txtindata.portprotocount == 0) return;
1730 io_txtindata.portprotolist = (PORTPROTO **)emalloc(((sizeof (PORTPROTO *)) *
1731 io_txtindata.portprotocount), el_tempcluster);
1732 if (io_txtindata.portprotolist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1733 for(i=0; i<io_txtindata.portprotocount; i++)
1734 {
1735 io_txtindata.portprotolist[i] = allocportproto(io_txtindata.curlib->cluster);
1736 if (io_txtindata.portprotolist[i] == NOPORTPROTO)
1737 longjmp(io_filerror, LONGJMPNOMEM);
1738 io_txtindata.portprotolist[i]->parent = io_txtindata.curnodeproto;
1739 }
1740
1741 /* link the portprotos */
1742 io_txtindata.curnodeproto->firstportproto = io_txtindata.portprotolist[0];
1743 for(i=1; i<io_txtindata.portprotocount; i++)
1744 io_txtindata.portprotolist[i-1]->nextportproto = io_txtindata.portprotolist[i];
1745 io_txtindata.portprotolist[io_txtindata.portprotocount-1]->nextportproto = NOPORTPROTO;
1746 }
1747
1748 /*
1749 * close the current cell (keyword "celldone")
1750 */
io_celdon(void)1751 void io_celdon(void)
1752 {
1753 REGISTER INTBIG i;
1754 REGISTER NODEINST *ni;
1755 REGISTER ARCINST *ai;
1756 REGISTER PORTARCINST *pi;
1757 REGISTER GEOM *geom;
1758
1759 /* verify cell name */
1760 if (namesame(io_keyword, io_txtindata.curnodeproto->protoname) != 0)
1761 ttyputmsg(_("Warning: cell '%s' wants to be '%s'"),
1762 io_txtindata.curnodeproto->protoname, io_keyword);
1763
1764 /* silly hack: convert arcinst->end->portarcinst pointers */
1765 for(i=0; i<io_txtindata.nodeinstcount; i++)
1766 {
1767 ni = io_txtindata.nodelist[i];
1768 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1769 {
1770 ai = pi->conarcinst;
1771 if (ai->end[0].nodeinst != ni)
1772 {
1773 ai->end[1].portarcinst = pi;
1774 continue;
1775 }
1776 if (ai->end[1].nodeinst != ni)
1777 {
1778 ai->end[0].portarcinst = pi;
1779 continue;
1780 }
1781 if ((PORTPROTO *)ai->end[0].portarcinst == pi->proto) ai->end[0].portarcinst = pi;
1782 if ((PORTPROTO *)ai->end[1].portarcinst == pi->proto) ai->end[1].portarcinst = pi;
1783 }
1784 }
1785
1786 /* create geometry structure in the cell */
1787 if (geomstructure(io_txtindata.curnodeproto))
1788 longjmp(io_filerror, LONGJMPNOMEM);
1789
1790 /* fill geometry module for each nodeinst */
1791 for(i=0; i<io_txtindata.nodeinstcount; i++)
1792 {
1793 ni = io_txtindata.nodelist[i];
1794 geom = ni->geom;
1795 geom->entryisnode = TRUE; geom->entryaddr.ni = ni;
1796 linkgeom(geom, io_txtindata.curnodeproto);
1797 }
1798
1799 /* fill geometry modules for each arcinst */
1800 for(i=0; i<io_txtindata.arcinstcount; i++)
1801 {
1802 ai = io_txtindata.arclist[i];
1803 (void)setshrinkvalue(ai, FALSE);
1804 geom = ai->geom;
1805 geom->entryisnode = FALSE; geom->entryaddr.ai = ai;
1806 linkgeom(geom, io_txtindata.curnodeproto);
1807 }
1808
1809 /* free the lists of objects in this cell */
1810 if (io_txtindata.nodeinstcount != 0) efree((CHAR *)io_txtindata.nodelist);
1811 if (io_txtindata.portprotocount != 0) efree((CHAR *)io_txtindata.portprotolist);
1812 if (io_txtindata.arcinstcount != 0) efree((CHAR *)io_txtindata.arclist);
1813 }
1814
1815 /******************** NODE INSTANCE PARSING ROUTINES ********************/
1816
1817 /*
1818 * initialize for a new node instance (keyword "**node")
1819 */
io_newno(void)1820 void io_newno(void)
1821 {
1822 io_txtindata.curnodeinst = io_txtindata.nodelist[eatoi(io_keyword)];
1823 io_txtindata.textlevel = INNODEINST;
1824 io_txtindata.varpos = INVNODEINST;
1825 }
1826
1827 /*
1828 * get the type of the current nodeinst (keyword "type")
1829 */
io_nodtyp(void)1830 void io_nodtyp(void)
1831 {
1832 REGISTER NODEPROTO *np;
1833 REGISTER TECHNOLOGY *tech;
1834 REGISTER CHAR *pt, *line;
1835 CHAR orig[50];
1836 static INTBIG orignodenamekey = 0;
1837
1838 line = io_keyword;
1839 if (*line == '[')
1840 {
1841 io_txtindata.curnodeinst->proto = io_txtindata.nodeprotolist[eatoi(&line[1])];
1842 } else
1843 {
1844 for(pt = line; *pt != 0; pt++) if (*pt == ':') break;
1845 if (*pt == ':')
1846 {
1847 *pt = 0;
1848 tech = io_gettechnology(line);
1849 if (tech == NOTECHNOLOGY) longjmp(io_filerror, LONGJMPUKNTECH);
1850 *pt++ = ':';
1851 line = pt;
1852 } else tech = io_txtindata.curtech;
1853 if (io_txtindata.curtech == NOTECHNOLOGY) io_txtindata.curtech = tech;
1854 for(np = tech->firstnodeproto; np != NONODEPROTO;
1855 np = np->nextnodeproto) if (namesame(np->protoname, line) == 0)
1856 {
1857 io_txtindata.curnodeinst->proto = np;
1858 return;
1859 }
1860
1861 /* convert "Active-Node" to "P-Active-Node" (MOSIS CMOS) */
1862 if (estrcmp(line, x_("Active-Node")) == 0)
1863 {
1864 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1865 if (estrcmp(np->protoname, x_("P-Active-Node")) == 0)
1866 {
1867 io_txtindata.curnodeinst->proto = np;
1868 return;
1869 }
1870 }
1871
1872 /* convert "message" and "cell-center" nodes */
1873 io_txtindata.curnodeinst->proto = io_convertoldprimitives(tech, line);
1874 if (io_txtindata.curnodeinst->proto == gen_invispinprim)
1875 {
1876 (void)estrcpy(orig, x_("artwork:"));
1877 (void)estrcat(orig, line);
1878 if (orignodenamekey == 0) orignodenamekey = makekey(x_("NODE_original_name"));
1879 nextchangequiet();
1880 (void)setvalkey((INTBIG)io_txtindata.curnodeinst, VNODEINST,
1881 orignodenamekey, (INTBIG)orig, VSTRING|VDONTSAVE);
1882 }
1883 if (io_txtindata.curnodeinst->proto != NONODEPROTO) return;
1884
1885 longjmp(io_filerror, LONGJMPUKNNOPROTO);
1886 }
1887 }
1888
1889 /*
1890 * get the bounding box information for the current node instance
1891 */
io_nodlx(void)1892 void io_nodlx(void)
1893 {
1894 io_txtindata.curnodeinst->lowx = eatoi(io_keyword);
1895 }
1896
io_nodhx(void)1897 void io_nodhx(void)
1898 {
1899 io_txtindata.curnodeinst->highx = eatoi(io_keyword);
1900 }
1901
io_nodly(void)1902 void io_nodly(void)
1903 {
1904 io_txtindata.curnodeinst->lowy = eatoi(io_keyword);
1905 }
1906
io_nodhy(void)1907 void io_nodhy(void)
1908 {
1909 io_txtindata.curnodeinst->highy = eatoi(io_keyword);
1910 }
1911
1912 /*
1913 * get the instance name of the current node instance (keyword "name")
1914 */
io_nodnam(void)1915 void io_nodnam(void)
1916 {
1917 nextchangequiet();
1918 (void)setvalkey((INTBIG)io_txtindata.curnodeinst, VNODEINST, el_node_name_key,
1919 (INTBIG)io_keyword, VSTRING|VDISPLAY);
1920 }
1921
1922 /*
1923 * get the text descriptor of the current node instance (keyword "descript")
1924 */
io_noddes(void)1925 void io_noddes(void)
1926 {
1927 REGISTER CHAR *pt;
1928
1929 io_txtindata.curnodeinst->textdescript[0] = eatoi(io_keyword);
1930 for(pt = io_keyword; *pt != 0 && *pt != '/'; pt++) ;
1931 if (*pt == 0)
1932 {
1933 io_txtindata.curnodeinst->textdescript[1] = 0;
1934 } else
1935 {
1936 io_txtindata.curnodeinst->textdescript[1] = eatoi(pt+1);
1937 }
1938 }
1939
1940 /*
1941 * get the rotation for the current nodeinst (keyword "rotation");
1942 */
io_nodrot(void)1943 void io_nodrot(void)
1944 {
1945 io_txtindata.curnodeinst->rotation = eatoi(io_keyword);
1946 }
1947
1948 /*
1949 * get the transposition for the current nodeinst (keyword "transpose")
1950 */
io_nodtra(void)1951 void io_nodtra(void)
1952 {
1953 REGISTER INTSML tvalue;
1954
1955 tvalue = eatoi(io_keyword);
1956
1957 /* in 7.01 and higher, allow mirror bits */
1958 if (io_txtindata.emajor > 7 ||
1959 (io_txtindata.emajor == 7 && io_txtindata.eminor >= 1))
1960 {
1961 /* new version: allow mirror bits */
1962 io_txtindata.curnodeinst->transpose = 0;
1963 if ((tvalue&1) != 0)
1964 {
1965 /* the old-style transpose bit */
1966 io_txtindata.curnodeinst->transpose = 1;
1967 } else
1968 {
1969 /* check for new style mirror bits */
1970 if ((tvalue&2) != 0)
1971 {
1972 if ((tvalue&4) != 0)
1973 {
1974 /* mirror in X and Y */
1975 io_txtindata.curnodeinst->rotation = (io_txtindata.curnodeinst->rotation + 1800) % 3600;
1976 } else
1977 {
1978 /* mirror in X */
1979 io_txtindata.curnodeinst->rotation = (io_txtindata.curnodeinst->rotation + 900) % 3600;
1980 io_txtindata.curnodeinst->transpose = 1;
1981 }
1982 } else if ((tvalue&4) != 0)
1983 {
1984 /* mirror in Y */
1985 io_txtindata.curnodeinst->rotation = (io_txtindata.curnodeinst->rotation + 2700) % 3600;
1986 io_txtindata.curnodeinst->transpose = 1;
1987 }
1988 }
1989 } else
1990 {
1991 /* old version: just treat it as a transpose */
1992 io_txtindata.curnodeinst->transpose = tvalue;
1993 }
1994 }
1995
1996 /*
1997 * get the tool seen bits for the current nodeinst (keyword "aseen")
1998 */
io_nodkse(void)1999 void io_nodkse(void)
2000 {
2001 io_txtindata.bitcount = 0;
2002 }
2003
2004 /*
2005 * get the port count for the current nodeinst (keyword "ports")
2006 */
io_nodpoc(void)2007 void io_nodpoc(void)
2008 {
2009 io_txtindata.curportcount = eatoi(io_keyword);
2010 }
2011
2012 /*
2013 * get tool information for current nodeinst (keyword "bits")
2014 */
io_nodbit(void)2015 void io_nodbit(void)
2016 {
2017 if (io_txtindata.bitcount == 0) io_txtindata.curnodeinst->userbits = eatoi(io_keyword);
2018 io_txtindata.bitcount++;
2019 }
2020
2021 /*
2022 * get tool information for current nodeinst (keyword "userbits")
2023 */
io_nodusb(void)2024 void io_nodusb(void)
2025 {
2026 io_txtindata.curnodeinst->userbits = eatoi(io_keyword);
2027 }
2028
2029 /*
2030 * initialize for a new portinst on the current nodeinst (keyword "*port")
2031 */
io_newpor(void)2032 void io_newpor(void)
2033 {
2034 REGISTER INTBIG i, cindex;
2035 REGISTER PORTPROTO *pp;
2036
2037 if (io_txtindata.version[0] == '1')
2038 {
2039 /* version 1 files used an index here */
2040 cindex = eatoi(io_keyword);
2041
2042 /* dividing is a heuristic used to decypher version 1 files */
2043 for(pp = io_txtindata.curnodeinst->proto->firstportproto, i=0; pp != NOPORTPROTO;
2044 pp = pp->nextportproto) i++;
2045 if (i < io_txtindata.curportcount)
2046 {
2047 for(;;)
2048 {
2049 cindex /= 3;
2050 if (cindex < i) break;
2051 }
2052 }
2053
2054 for(io_txtindata.curportproto = io_txtindata.curnodeinst->proto->firstportproto, i=0;
2055 io_txtindata.curportproto != NOPORTPROTO;
2056 io_txtindata.curportproto = io_txtindata.curportproto->nextportproto, i++)
2057 if (i == cindex) break;
2058 } else
2059 {
2060 /* version 2 and later use port prototype names */
2061 io_txtindata.curportproto = io_getport(io_keyword, io_txtindata.curnodeinst->proto);
2062 }
2063 io_txtindata.textlevel = INPOR;
2064 }
2065
2066 /*
2067 * get an arc connection for the current nodeinst (keyword "arc")
2068 */
io_porarc(void)2069 void io_porarc(void)
2070 {
2071 REGISTER PORTARCINST *pi;
2072
2073 pi = allocportarcinst(io_txtindata.curlib->cluster);
2074 if (pi == NOPORTARCINST) longjmp(io_filerror, LONGJMPNOMEM);
2075 pi->proto = io_txtindata.curportproto;
2076 db_addportarcinst(io_txtindata.curnodeinst, pi);
2077 pi->conarcinst = io_txtindata.arclist[eatoi(io_keyword)];
2078 io_txtindata.varpos = INVPORTARCINST;
2079 io_txtindata.varaddr = (INTBIG)pi;
2080 }
2081
2082 /*
2083 * get an export site for the current nodeinst (keyword "exported")
2084 */
io_porexp(void)2085 void io_porexp(void)
2086 {
2087 REGISTER PORTEXPINST *pe;
2088
2089 pe = allocportexpinst(io_txtindata.curlib->cluster);
2090 if (pe == NOPORTEXPINST) longjmp(io_filerror, LONGJMPNOMEM);
2091 pe->proto = io_txtindata.curportproto;
2092 db_addportexpinst(io_txtindata.curnodeinst, pe);
2093 pe->exportproto = io_txtindata.portprotolist[eatoi(io_keyword)];
2094 io_txtindata.varpos = INVPORTEXPINST;
2095 io_txtindata.varaddr = (INTBIG)pe;
2096 }
2097
2098 /******************** ARC INSTANCE PARSING ROUTINES ********************/
2099
2100 /*
2101 * initialize for a new arc instance (keyword "**arc")
2102 */
io_newar(void)2103 void io_newar(void)
2104 {
2105 io_txtindata.curarcinst = io_txtindata.arclist[eatoi(io_keyword)];
2106 io_txtindata.textlevel = INARCINST;
2107 io_txtindata.varpos = INVARCINST;
2108 }
2109
2110 /*
2111 * get the type of the current arc instance (keyword "type")
2112 */
io_arctyp(void)2113 void io_arctyp(void)
2114 {
2115 REGISTER ARCPROTO *ap;
2116 REGISTER CHAR *pt, *line;
2117 REGISTER TECHNOLOGY *tech;
2118
2119 line = io_keyword;
2120 for(pt = line; *pt != 0; pt++) if (*pt == ':') break;
2121 if (*pt == ':')
2122 {
2123 *pt = 0;
2124 tech = io_gettechnology(line);
2125 if (tech == NOTECHNOLOGY) longjmp(io_filerror, LONGJMPUKNTECH);
2126 *pt++ = ':';
2127 line = pt;
2128 } else tech = io_txtindata.curtech;
2129 if (io_txtindata.curtech == NOTECHNOLOGY) io_txtindata.curtech = tech;
2130 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
2131 if (namesame(line, ap->protoname) == 0)
2132 {
2133 io_txtindata.curarcinst->proto = ap;
2134 return;
2135 }
2136
2137 /* convert old Artwork names */
2138 if (tech == art_tech)
2139 {
2140 if (estrcmp(line, x_("Dash-1")) == 0)
2141 {
2142 io_txtindata.curarcinst->proto = art_dottedarc;
2143 return;
2144 }
2145 if (estrcmp(line, x_("Dash-2")) == 0)
2146 {
2147 io_txtindata.curarcinst->proto = art_dashedarc;
2148 return;
2149 }
2150 if (estrcmp(line, x_("Dash-3")) == 0)
2151 {
2152 io_txtindata.curarcinst->proto = art_thickerarc;
2153 return;
2154 }
2155 }
2156
2157 /* special hack: try the generic technology if name is not found */
2158 for(ap = gen_tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
2159 if (namesame(line, ap->protoname) == 0)
2160 {
2161 io_txtindata.curarcinst->proto = ap;
2162 return;
2163 }
2164
2165 longjmp(io_filerror, LONGJMPINVARCPROTO);
2166 }
2167
2168 /*
2169 * get the instance name of the current arc instance (keyword "name")
2170 */
io_arcnam(void)2171 void io_arcnam(void)
2172 {
2173 nextchangequiet();
2174 (void)setvalkey((INTBIG)io_txtindata.curarcinst, VARCINST, el_arc_name_key,
2175 (INTBIG)io_keyword, VSTRING|VDISPLAY);
2176 }
2177
2178 /*
2179 * get the width of the current arc instance (keyword "width")
2180 */
io_arcwid(void)2181 void io_arcwid(void)
2182 {
2183 io_txtindata.curarcinst->width = eatoi(io_keyword);
2184 }
2185
2186 /*
2187 * get the length of the current arc instance (keyword "length")
2188 */
io_arclen(void)2189 void io_arclen(void)
2190 {
2191 io_txtindata.curarcinst->length = eatoi(io_keyword);
2192 }
2193
2194 /*
2195 * get the signals information of the current arc instance (keyword "signals")
2196 */
io_arcsig(void)2197 void io_arcsig(void) {}
2198
2199 /*
2200 * initialize for an end of the current arcinst (keyword "*end")
2201 */
io_newend(void)2202 void io_newend(void)
2203 {
2204 io_txtindata.curarcend = eatoi(io_keyword);
2205 io_txtindata.textlevel = INARCEND;
2206 }
2207
2208 /*
2209 * get the node at the current end of the current arcinst (keyword "node")
2210 */
io_endnod(void)2211 void io_endnod(void)
2212 {
2213 io_txtindata.curarcinst->end[io_txtindata.curarcend].nodeinst = io_txtindata.nodelist[eatoi(io_keyword)];
2214 }
2215
2216 /*
2217 * get the porttype at the current end of current arcinst (keyword "nodeport")
2218 */
io_endpt(void)2219 void io_endpt(void)
2220 {
2221 REGISTER PORTPROTO *pp;
2222
2223 pp = io_getport(io_keyword,io_txtindata.curarcinst->end[io_txtindata.curarcend].nodeinst->proto);
2224 if (pp == NOPORTPROTO) longjmp(io_filerror, LONGJMPUKNPORPROTO);
2225 io_txtindata.curarcinst->end[io_txtindata.curarcend].portarcinst = (PORTARCINST *)pp;
2226 }
2227
2228 /*
2229 * get the coordinates of the current end of the current arcinst
2230 */
io_endxp(void)2231 void io_endxp(void)
2232 {
2233 io_txtindata.curarcinst->end[io_txtindata.curarcend].xpos = eatoi(io_keyword);
2234 }
2235
io_endyp(void)2236 void io_endyp(void)
2237 {
2238 io_txtindata.curarcinst->end[io_txtindata.curarcend].ypos = eatoi(io_keyword);
2239 }
2240
2241 /*
2242 * get the tool information for the current arcinst (keyword "aseen")
2243 */
io_arckse(void)2244 void io_arckse(void)
2245 {
2246 io_txtindata.bitcount = 0;
2247 }
2248
2249 /*
2250 * get tool information for current arcinst (keyword "bits")
2251 */
io_arcbit(void)2252 void io_arcbit(void)
2253 {
2254 if (io_txtindata.bitcount == 0) io_txtindata.curarcinst->userbits = eatoi(io_keyword);
2255 io_txtindata.bitcount++;
2256 }
2257
2258 /*
2259 * get tool information for current arcinst (keyword "userbits")
2260 */
io_arcusb(void)2261 void io_arcusb(void)
2262 {
2263 io_txtindata.curarcinst->userbits = eatoi(io_keyword);
2264 }
2265
2266 /*
2267 * get tool information for current arcinst (keyword "netnum")
2268 */
io_arcnet(void)2269 void io_arcnet(void) {}
2270
2271 /******************** PORT PROTOTYPE PARSING ROUTINES ********************/
2272
2273 /*
2274 * initialize for a new port prototype (keyword "**porttype")
2275 */
io_newpt(void)2276 void io_newpt(void)
2277 {
2278 io_txtindata.curportproto = io_txtindata.portprotolist[eatoi(io_keyword)];
2279 io_txtindata.textlevel = INPORTPROTO;
2280 io_txtindata.varpos = INVPORTPROTO;
2281 }
2282
2283 /*
2284 * get the name for the current port prototype (keyword "name")
2285 */
io_ptnam(void)2286 void io_ptnam(void)
2287 {
2288 if (allocstring(&io_txtindata.curportproto->protoname, io_keyword, io_txtindata.curlib->cluster))
2289 longjmp(io_filerror, LONGJMPNOMEM);
2290 }
2291
2292 /*
2293 * get the text descriptor for the current port prototype (keyword "descript")
2294 */
io_ptdes(void)2295 void io_ptdes(void)
2296 {
2297 REGISTER CHAR *pt;
2298
2299 io_txtindata.curportproto->textdescript[0] = eatoi(io_keyword);
2300 for(pt = io_keyword; *pt != 0 && *pt != '/'; pt++) ;
2301 if (*pt == 0)
2302 {
2303 io_txtindata.curportproto->textdescript[1] = 0;
2304 } else
2305 {
2306 io_txtindata.curportproto->textdescript[1] = eatoi(pt+1);
2307 }
2308 }
2309
2310 /*
2311 * get the sub-nodeinst for the current port prototype (keyword "subnode")
2312 */
io_ptsno(void)2313 void io_ptsno(void)
2314 {
2315 io_txtindata.curportproto->subnodeinst = io_txtindata.nodelist[eatoi(io_keyword)];
2316 }
2317
2318 /*
2319 * get the sub-portproto for the current port prototype (keyword "subport")
2320 */
io_ptspt(void)2321 void io_ptspt(void)
2322 {
2323 REGISTER PORTPROTO *pp;
2324
2325 pp = io_getport(io_keyword, io_txtindata.curportproto->subnodeinst->proto);
2326 if (pp == NOPORTPROTO) longjmp(io_filerror, LONGJMPUKNPORPROTO);
2327 io_txtindata.curportproto->subportproto = pp;
2328 }
2329
2330 /*
2331 * get the tool seen for the current port prototype (keyword "aseen")
2332 */
io_ptkse(void)2333 void io_ptkse(void)
2334 {
2335 io_txtindata.bitcount = 0;
2336 }
2337
2338 /*
2339 * get the tool data for the current port prototype (keyword "bits")
2340 */
io_ptbit(void)2341 void io_ptbit(void)
2342 {
2343 if (io_txtindata.bitcount == 0) io_txtindata.curportproto->userbits = eatoi(io_keyword);
2344 io_txtindata.bitcount++;
2345 }
2346
2347 /*
2348 * get the tool data for the current port prototype (keyword "userbits")
2349 */
io_ptusb(void)2350 void io_ptusb(void)
2351 {
2352 io_txtindata.curportproto->userbits = eatoi(io_keyword);
2353 }
2354
2355 /*
2356 * get the tool data for the current port prototype (keyword "netnum")
2357 */
io_ptnet(void)2358 void io_ptnet(void) {}
2359
2360 /*
2361 * routine to convert the technology name in "line" to a technology.
2362 * also handles conversion of the old technology name "logic"
2363 */
io_gettechnology(CHAR * line)2364 TECHNOLOGY *io_gettechnology(CHAR *line)
2365 {
2366 REGISTER TECHNOLOGY *tech;
2367
2368 tech = NOTECHNOLOGY;
2369 if (io_txtindata.convertmosiscmostechnologies != 0)
2370 {
2371 if (namesame(line, x_("mocmossub")) == 0) tech = gettechnology(x_("mocmos")); else
2372 if (namesame(line, x_("mocmos")) == 0) tech = gettechnology(x_("mocmosold"));
2373 }
2374 if (tech == NOTECHNOLOGY) tech = gettechnology(line);
2375 if (tech != NOTECHNOLOGY) return(tech);
2376 if (namesame(line, x_("logic")) == 0) tech = sch_tech;
2377 return(tech);
2378 }
2379
2380 /*
2381 * Routine to free all memory associated with this module.
2382 */
io_freetextinmemory(void)2383 void io_freetextinmemory(void)
2384 {
2385 if (io_maxinputline != 0)
2386 efree(io_keyword);
2387 }
2388