1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: iosuei.c
6 * Input/output tool: SUE (Schematic User Environment) 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 #include "config.h"
33 #include "global.h"
34 #include "edialogs.h"
35 #include "egraphics.h"
36 #include "eio.h"
37 #include "tech.h"
38 #include "tecart.h"
39 #include "tecgen.h"
40 #include "tecschem.h"
41 #include "network.h"
42 #include "usr.h"
43
44 /* #define SHOWORIGINAL 1 */ /* uncomment to show original nodes */
45
46 #define E0 (WHOLE/8) /* 0.125 */
47 #define S1 (T1+E0) /* 1.875 */
48 #define F3 (K3+H0+E0) /* 3.625 */
49 #define S6 (T6+E0) /* 6.875 */
50 #define Q11 (K11+Q0) /* 11.25 */
51
52 /*************** SUE EQUIVALENCES ***************/
53
54 typedef struct
55 {
56 CHAR *portname;
57 INTBIG xoffset;
58 INTBIG yoffset;
59 } SUEEXTRAWIRE;
60
61 typedef struct
62 {
63 CHAR *suename;
64 NODEPROTO **intproto;
65 INTBIG netateoutput;
66 INTBIG rotation;
67 INTBIG transpose;
68 INTBIG xoffset;
69 INTBIG yoffset;
70 INTBIG detailbits;
71 INTBIG numextrawires;
72 SUEEXTRAWIRE *extrawires;
73 } SUEEQUIV;
74
75 SUEEXTRAWIRE io_suetransistorwires[] =
76 {
77 {x_("d"), K3, 0},
78 {x_("s"), -K3, 0},
79 {x_("g"), 0, H4}
80 };
81
82 SUEEXTRAWIRE io_suetransistor4wires[] =
83 {
84 {x_("d"), K3, 0},
85 {x_("s"), -K3, 0},
86 {x_("b"), -Q0, -H2},
87 {x_("g"), 0, H4}
88 };
89
90 SUEEXTRAWIRE io_sueresistorwires[] =
91 {
92 {x_("a"), -K3, 0},
93 {x_("b"), K3, 0}
94 };
95
96 SUEEXTRAWIRE io_suecapacitorwires[] =
97 {
98 {x_("a"), 0, T1},
99 {x_("b"), 0, -T1}
100 };
101
102 SUEEXTRAWIRE io_suesourcewires[] =
103 {
104 {x_("minus"), 0, -Q1},
105 {x_("plus"), 0, H1}
106 };
107
108 SUEEXTRAWIRE io_suetwoportwires[] =
109 {
110 {x_("a"), -Q11, F3},
111 {x_("b"), -Q11, -F3},
112 {x_("x"), Q11, F3},
113 {x_("y"), Q11, -F3}
114 };
115
116 SUEEQUIV io_sueequivs[] =
117 {
118 /* name primitive NEG ANG X Y BITS WIR EXTRA-WIRES */
119 {x_("pmos10"), &sch_transistorprim, 0, 900,0, -K2, 0, TRANPMOS, 3, io_suetransistorwires},
120 {x_("nmos10"), &sch_transistorprim, 0, 900,0, -K2, 0, TRANNMOS, 3, io_suetransistorwires},
121 {x_("pmos4"), &sch_transistorprim, 0, 900,0, -K2, 0, TRANPMOS, 3, io_suetransistorwires},
122 {x_("nmos4"), &sch_transistorprim, 0, 900,0, -K2, 0, TRANNMOS, 3, io_suetransistorwires},
123 {x_("pmos"), &sch_transistorprim, 0, 900,0, -K2, 0, TRANPMOS, 3, io_suetransistorwires},
124 {x_("nmos"), &sch_transistorprim, 0, 900,0, -K2, 0, TRANNMOS, 3, io_suetransistorwires},
125 {x_("capacitor"), &sch_capacitorprim, 0, 0,0, 0, 0, 0, 2, io_suecapacitorwires},
126 {x_("resistor"), &sch_resistorprim, 0, 900,0, 0, 0, 0, 2, io_sueresistorwires},
127 {x_("inductor"), &sch_inductorprim, 0, 0,0, 0, 0, 0, 0, 0},
128 {x_("cccs"), &sch_twoportprim, 0, 0,0, Q1,-S6, TWOPCCCS, 4, io_suetwoportwires},
129 {x_("ccvs"), &sch_twoportprim, 0, 0,0, Q1,-S6, TWOPCCVS, 4, io_suetwoportwires},
130 {x_("vcvs"), &sch_twoportprim, 0, 0,0, Q1,-S6, TWOPVCVS, 4, io_suetwoportwires},
131 {x_("vccs"), &sch_twoportprim, 0, 0,0, -S1,-K5, TWOPVCCS, 0, 0},
132 {0, 0, 0, 0, 0, 0, 0, 0, 0}
133 };
134
135 SUEEQUIV io_sueequivs4[] =
136 {
137 /* name primitive NEG ANG X Y BITS WIR EXTRA-WIRES */
138 {x_("pmos10"), &sch_transistor4prim, 0, 0,1, -K2, 0, TRANPMOS, 4, io_suetransistor4wires},
139 {x_("nmos10"), &sch_transistor4prim, 0, 900,0, -K2, 0, TRANNMOS, 4, io_suetransistor4wires},
140 {x_("pmos4"), &sch_transistor4prim, 0, 0,1, -K2, 0, TRANPMOS, 4, io_suetransistor4wires},
141 {x_("nmos4"), &sch_transistor4prim, 0, 900,0, -K2, 0, TRANNMOS, 4, io_suetransistor4wires},
142 {x_("pmos"), &sch_transistor4prim, 0, 0,1, -K2, 0, TRANPMOS, 4, io_suetransistor4wires},
143 {x_("nmos"), &sch_transistor4prim, 0, 900,0, -K2, 0, TRANNMOS, 4, io_suetransistor4wires},
144 {x_("capacitor"), &sch_capacitorprim, 0, 0,0, 0, 0, 0, 2, io_suecapacitorwires},
145 {x_("resistor"), &sch_resistorprim, 0, 900,0, 0, 0, 0, 2, io_sueresistorwires},
146 {x_("inductor"), &sch_inductorprim, 0, 0,0, 0, 0, 0, 0, 0},
147 {x_("cccs"), &sch_twoportprim, 0, 0,0, Q1,-S6, TWOPCCCS, 4, io_suetwoportwires},
148 {x_("ccvs"), &sch_twoportprim, 0, 0,0, Q1,-S6, TWOPCCVS, 4, io_suetwoportwires},
149 {x_("vcvs"), &sch_twoportprim, 0, 0,0, Q1,-S6, TWOPVCVS, 4, io_suetwoportwires},
150 {x_("vccs"), &sch_twoportprim, 0, 0,0, -S1,-K5, TWOPVCCS, 0, 0},
151 {0, 0, 0, 0, 0, 0, 0, 0, 0}
152 };
153
154 /*************** SUE WIRES ***************/
155
156 #define NOSUEWIRE ((SUEWIRE *)-1)
157
158 typedef struct Isuewire
159 {
160 INTBIG x[2], y[2];
161 NODEINST *ni[2];
162 PORTPROTO *pp[2];
163 ARCPROTO *proto;
164 struct Isuewire *nextsuewire;
165 } SUEWIRE;
166
167 SUEWIRE *io_suefreewire = NOSUEWIRE;
168
169 /*************** SUE NETWORKS ***************/
170
171 #define NOSUENET ((SUENET *)-1)
172
173 typedef struct Isuenet
174 {
175 INTBIG x, y;
176 CHAR *label;
177 struct Isuenet *nextsuenet;
178 } SUENET;
179
180 SUENET *io_suefreenet = NOSUENET;
181
182 /*************** MISCELLANEOUS ***************/
183
184 #define MAXLINE 300 /* maximum characters on an input line */
185 #define MAXKEYWORDS 50 /* maximum keywords on an input line */
186 #define MAXICONPOINTS 25 /* maximum coordinates on an "icon_line" line */
187
188 static INTBIG io_suelineno;
189 static INTBIG io_suefilesize;
190 static CHAR io_suelastline[MAXLINE];
191 static CHAR io_sueorigline[MAXLINE];
192 static CHAR io_suecurline[MAXLINE];
193 static CHAR **io_suedirectories;
194 INTBIG io_suenumdirectories = 0;
195 static FILE *io_suefilein;
196
197 /* prototypes for local routines */
198 static BOOLEAN io_sueadddirectory(CHAR *directory);
199 static void io_suecleardirectories(void);
200 static CHAR *io_suefindbusname(ARCINST *ai);
201 static BOOLEAN io_suefindnode(INTBIG *x, INTBIG *y, INTBIG ox, INTBIG oy, NODEPROTO *np,
202 NODEINST **ni, PORTPROTO **pp, NODEINST *notthisnode, INTBIG lambda);
203 static NODEINST *io_suefindpinnode(INTBIG x, INTBIG y, NODEPROTO *np, PORTPROTO **thepp);
204 static void io_suefreenets(SUENET *firstsn);
205 static void io_suefreewires(SUEWIRE *firstsw);
206 static INTBIG io_suegetnextline(CHAR **keywords, INTBIG curlydepth, void *dia);
207 static NODEPROTO *io_suegetnodeproto(LIBRARY *lib, CHAR *protoname);
208 static void io_suekillnet(SUENET *sn);
209 static void io_suekillwire(SUEWIRE *sw);
210 static INTBIG io_suemakex(INTBIG x, INTBIG lambda);
211 static INTBIG io_suemakey(INTBIG y, INTBIG lambda);
212 static PORTPROTO *io_suenewexport(NODEPROTO *cell, NODEINST *ni, PORTPROTO *pp, CHAR *thename);
213 static SUENET *io_suenewnet(void);
214 static SUEWIRE *io_suenewwire(void);
215 static void io_sueplacenets(SUENET *firstsuenet, NODEPROTO *cell);
216 static CHAR *io_sueparseexpression(CHAR *expression);
217 static void io_sueparseparameters(CHAR **keywords, INTBIG count, INTBIG *x, INTBIG *y, INTBIG lambda,
218 INTBIG *rot, INTBIG *trn, INTBIG *type, CHAR **thename, CHAR **thelabel, CHAR **thetext,
219 void *dia);
220 static void io_sueplacewires(SUEWIRE *firstsuewire, SUENET *firstsuenet, NODEPROTO *cell, INTBIG lambda);
221 static NODEPROTO *io_suereadfile(LIBRARY *lib, CHAR *cellname, void *dia);
222 static NODEPROTO *io_suereadfromdisk(LIBRARY *lib, CHAR *name, void *dia);
223 static CHAR *io_suesearchbusname(ARCINST *ai);
224 static PORTPROTO *io_suewiredport(NODEINST *ni, INTBIG *x, INTBIG *y, INTBIG ox, INTBIG oy);
225
226 /*
227 * Routine to free all memory associated with this module.
228 */
io_freesuememory(void)229 void io_freesuememory(void)
230 {
231 SUEWIRE *sw;
232 SUENET *sn;
233
234 while (io_suefreewire != NOSUEWIRE)
235 {
236 sw = io_suefreewire;
237 io_suefreewire = io_suefreewire->nextsuewire;
238 efree((CHAR *)sw);
239 }
240 while (io_suefreenet != NOSUENET)
241 {
242 sn = io_suefreenet;
243 io_suefreenet = io_suefreenet->nextsuenet;
244 efree((CHAR *)sn);
245 }
246 io_suecleardirectories();
247 }
248
io_readsuelibrary(LIBRARY * lib)249 BOOLEAN io_readsuelibrary(LIBRARY *lib)
250 {
251 REGISTER INTBIG len, i, filecount;
252 REGISTER NODEPROTO *topcell;
253 CHAR cellname[300], dirname[300], topdirname[300], truesuefile[300],
254 *filename, **filelist;
255 void *dia;
256
257 /* open the file */
258 io_suefilein = xopen(lib->libfile, io_filetypesue, x_(""), &filename);
259 if (io_suefilein == 0)
260 {
261 ttyputerr(_("File %s not found"), lib->libfile);
262 return(TRUE);
263 }
264
265 /* determine the cell name */
266 estrcpy(truesuefile, filename);
267 estrcpy(cellname, filename);
268 len = estrlen(cellname);
269 if (namesame(&cellname[len-4], x_(".sue")) == 0)
270 cellname[len-4] = 0;
271 for(i = estrlen(cellname)-1; i>0; i--)
272 if (cellname[i] == DIRSEP) break;
273 i++;
274 estrcpy(cellname, &cellname[i]);
275
276 /* initialize the number of directories that need to be searched */
277 io_suecleardirectories();
278
279 /* determine the current directory */
280 estrcpy(topdirname, filename);
281 len = estrlen(topdirname);
282 for(i = len-1; i>0; i--)
283 if (topdirname[i] == DIRSEP) break;
284 topdirname[i+1] = 0;
285 if (io_sueadddirectory(topdirname)) return(TRUE);
286
287 /* find all subdirectories that start with "suelib_" and include them in the search */
288 filecount = filesindirectory(topdirname, &filelist);
289 for(i=0; i<filecount; i++)
290 {
291 if (namesamen(filelist[i], x_("suelib_"), 7) != 0) continue;
292 estrcpy(dirname, topdirname);
293 estrcat(dirname, filelist[i]);
294 if (fileexistence(dirname) != 2) continue;
295 estrcat(dirname, DIRSEPSTR);
296 if (io_sueadddirectory(dirname)) return(TRUE);
297 }
298
299 /* see if the current directory is inside of a SUELIB */
300 len = estrlen(topdirname);
301 for(i = len-2; i>0; i--)
302 if (topdirname[i] == DIRSEP) break;
303 i++;
304 if (namesamen(&topdirname[i], x_("suelib_"), 7) == 0)
305 {
306 topdirname[i] = 0;
307 filecount = filesindirectory(topdirname, &filelist);
308 for(i=0; i<filecount; i++)
309 {
310 if (namesamen(filelist[i], x_("suelib_"), 7) != 0) continue;
311 estrcpy(dirname, topdirname);
312 estrcat(dirname, filelist[i]);
313 if (fileexistence(dirname) != 2) continue;
314 estrcat(dirname, DIRSEPSTR);
315 if (io_sueadddirectory(dirname)) return(TRUE);
316 }
317 }
318
319 /* prepare for input */
320 io_suefilesize = filesize(io_suefilein);
321 dia = DiaInitProgress(_("Reading SUE file..."), 0);
322 if (dia == 0)
323 {
324 xclose(io_suefilein);
325 return(TRUE);
326 }
327 io_suelineno = 0;
328
329 /* read the file */
330 DiaSetProgress(dia, 0, io_suefilesize);
331 topcell = io_suereadfile(lib, cellname, dia);
332 if (topcell != NONODEPROTO)
333 lib->curnodeproto = topcell;
334 (void)asktool(net_tool, x_("total-re-number"));
335
336 /* clean up */
337 DiaDoneProgress(dia);
338 xclose(io_suefilein);
339 ttyputmsg(_("%s read"), truesuefile);
340
341 return(FALSE);
342 }
343
344 /*
345 * Routine to read the SUE file in "f"/
346 */
io_suereadfile(LIBRARY * lib,CHAR * cellname,void * dia)347 NODEPROTO *io_suereadfile(LIBRARY *lib, CHAR *cellname, void *dia)
348 {
349 CHAR *keywords[MAXKEYWORDS], *thename, *thelabel, *thetext, *namestring;
350 CHAR suevarname[200], *pt, *cpt, *startkey, save;
351 CHAR **argnames, **argvalues, **newargnames, **newargvalues;
352 INTBIG outline[MAXICONPOINTS*2], x, y, type, dx, dy, px, py, pinx, piny, xoff, yoff,
353 numargs, namestrlen, rot, trn, rotation, transpose, *curstate;
354 REGISTER INTBIG count, i, j, lx, hx, ly, hy, curly, xshrink, yshrink,
355 varcount, varindex, varoffset, pos, invertoutput, lambda, detailbits,
356 keycount, cx, cy, p1x, p1y, p2x, p2y, start, extent, numextrawires, len,
357 iconx, icony, newaddr, newtype, xpos, ypos, numericlambda, bits;
358 REGISTER BOOLEAN halvesize, placeicon, varissize, isparam;
359 XARRAY trans;
360 double rextent, rstart;
361 float f;
362 REGISTER NODEPROTO *cell, *schemcell, *iconcell, *proto, *np, *cnp;
363 REGISTER PORTPROTO *pp, *ppt;
364 PORTPROTO *npp;
365 REGISTER VARIABLE *var;
366 REGISTER TECHNOLOGY *inischemtech;
367 REGISTER NODEINST *ni;
368 NODEINST *nni;
369 REGISTER ARCINST *ai;
370 REGISTER SUEWIRE *sw, *firstsuewire;
371 REGISTER SUENET *sn, *firstsuenet;
372 REGISTER SUEEXTRAWIRE *extrawires;
373 REGISTER SUEEQUIV *curequivs;
374 REGISTER void *infstr;
375
376 firstsuewire = NOSUEWIRE;
377 firstsuenet = NOSUENET;
378 schemcell = iconcell = cell = NONODEPROTO;
379 io_suelastline[0] = 0;
380 numargs = 0;
381 namestrlen = 0;
382 lambda = lib->lambda[sch_tech->techindex];
383 inischemtech = defschematictechnology(el_curtech);
384 numericlambda = lib->lambda[inischemtech->techindex];
385 for(;;)
386 {
387 /* get the next line of text */
388 count = io_suegetnextline(keywords, 0, dia);
389 if (count < 0) break;
390 if (count == 0) continue;
391
392 /* handle "proc" for defining views */
393 if (namesame(keywords[0], x_("proc")) == 0)
394 {
395 /* write any wires from the last proc */
396 if (cell != NONODEPROTO)
397 {
398 io_sueplacewires(firstsuewire, firstsuenet, cell, lambda);
399 io_suefreewires(firstsuewire);
400 io_sueplacenets(firstsuenet, cell);
401 io_suefreenets(firstsuenet);
402 firstsuewire = NOSUEWIRE;
403 firstsuenet = NOSUENET;
404 }
405
406 if (count < 2)
407 {
408 ttyputerr(_("Cell %s, line %ld: 'proc' is missing arguments: %s"),
409 cellname, io_suelineno, io_sueorigline);
410 continue;
411 }
412
413 if (namesamen(keywords[1], x_("SCHEMATIC_"), 10) == 0)
414 {
415 /* create the schematic cell */
416 infstr = initinfstr();
417 if (namesame(&keywords[1][10], x_("[get_file_name]")) == 0)
418 addstringtoinfstr(infstr, cellname); else
419 addstringtoinfstr(infstr, &keywords[1][10]);
420 addstringtoinfstr(infstr, x_("{sch}"));
421 schemcell = cell = us_newnodeproto(returninfstr(infstr), lib);
422 placeicon = FALSE;
423 } else if (namesamen(keywords[1], x_("ICON_"), 5) == 0)
424 {
425 /* create the icon cell */
426 infstr = initinfstr();
427 if (namesame(&keywords[1][5], x_("[get_file_name]")) == 0)
428 addstringtoinfstr(infstr, cellname); else
429 addstringtoinfstr(infstr, &keywords[1][5]);
430 addstringtoinfstr(infstr, x_("{ic}"));
431 iconcell = cell = us_newnodeproto(returninfstr(infstr), lib);
432 } else
433 {
434 ttyputerr(_("Cell %s, line %ld: unknown 'proc' statement: %s"),
435 cellname, io_suelineno, io_sueorigline);
436 }
437 continue;
438 }
439
440 /* handle "make" for defining components */
441 if (namesame(keywords[0], x_("make")) == 0)
442 {
443 if (count < 2)
444 {
445 ttyputerr(_("Cell %s, line %ld: 'make' is missing arguments: %s"),
446 cellname, io_suelineno, io_sueorigline);
447 continue;
448 }
449
450 /* extract parameters */
451 io_sueparseparameters(&keywords[2], count-2, &x, &y, lambda, &rot, &trn,
452 &type, &thename, &thelabel, &thetext, dia);
453
454 /* save the name string */
455 if (thename != 0)
456 {
457 len = estrlen(thename) + 1;
458 if (len > namestrlen)
459 {
460 /* LINTED "namestring" used in proper order */
461 if (namestrlen > 0) efree(namestring);
462 namestring = (CHAR *)emalloc(len * SIZEOFCHAR, el_tempcluster);
463 namestrlen = len;
464 }
465 estrcpy(namestring, thename);
466 thename = namestring;
467 }
468
469 /* ignore self-references */
470 if (namesame(keywords[1], cellname) == 0)
471 {
472 if (x != 0 || y != 0)
473 {
474 /* queue icon placement */
475 iconx = x; icony = y;
476 placeicon = TRUE;
477 }
478 continue;
479 }
480
481 /* special case for network names: queue them */
482 if (namesame(keywords[1], x_("name_net_m")) == 0 ||
483 namesame(keywords[1], x_("name_net_s")) == 0 ||
484 namesame(keywords[1], x_("name_net")) == 0)
485 {
486 sn = io_suenewnet();
487 sn->x = x;
488 sn->y = y;
489 (void)allocstring(&sn->label, thename, io_tool->cluster);
490 sn->nextsuenet = firstsuenet;
491 firstsuenet = sn;
492 continue;
493 }
494
495 /* first check for special names */
496 proto = NONODEPROTO;
497 invertoutput = 0;
498 rotation = transpose = 0;
499 xoff = yoff = 0;
500 xshrink = yshrink = 0;
501 detailbits = 0;
502 numextrawires = 0;
503 extrawires = 0;
504 type = 0;
505 if (namesame(keywords[1], x_("inout")) == 0)
506 {
507 proto = sch_offpageprim;
508 makeangle(rot, trn, trans);
509 xform(K2, 0, &xoff, &yoff, trans);
510 xoff = muldiv(xoff, lambda, WHOLE);
511 yoff = muldiv(yoff, lambda, WHOLE);
512 type = BIDIRPORT;
513 } else if (namesame(keywords[1], x_("input")) == 0)
514 {
515 proto = sch_offpageprim;
516 makeangle(rot, trn, trans);
517 xform(-K2, 0, &xoff, &yoff, trans);
518 xoff = muldiv(xoff, lambda, WHOLE);
519 yoff = muldiv(yoff, lambda, WHOLE);
520 type = INPORT;
521 } else if (namesame(keywords[1], x_("output")) == 0)
522 {
523 proto = sch_offpageprim;
524 makeangle(rot, trn, trans);
525 xform(K2, 0, &xoff, &yoff, trans);
526 xoff = muldiv(xoff, lambda, WHOLE);
527 yoff = muldiv(yoff, lambda, WHOLE);
528 type = OUTPORT;
529 } else if (namesame(keywords[1], x_("rename_net")) == 0)
530 {
531 proto = sch_wirepinprim;
532 } else if (namesame(keywords[1], x_("global")) == 0)
533 {
534 if (net_buswidth(thename) > 1) proto = sch_buspinprim; else
535 {
536 proto = sch_wirepinprim;
537 if (namesame(thename, x_("gnd")) == 0)
538 {
539 makeangle(rot, trn, trans);
540 xform(0, -K2, &xoff, &yoff, trans);
541 xoff = muldiv(xoff, lambda, WHOLE);
542 yoff = muldiv(yoff, lambda, WHOLE);
543 proto = sch_gndprim;
544 type = GNDPORT;
545 }
546 if (namesame(thename, x_("vdd")) == 0)
547 {
548 proto = sch_pwrprim;
549 type = PWRPORT;
550 }
551 }
552 } else if (namesame(keywords[1], x_("join_net")) == 0)
553 {
554 proto = sch_wireconprim;
555 xshrink = -K2;
556 makeangle(rot, trn, trans);
557 xform(Q1, 0, &xoff, &yoff, trans);
558 xoff = muldiv(xoff, lambda, WHOLE);
559 yoff = muldiv(yoff, lambda, WHOLE);
560 }
561
562 /* now check for internal associations to known primitives */
563 if (proto == NONODEPROTO)
564 {
565 curstate = io_getstatebits();
566 if ((curstate[1]&SUEUSE4PORTTRANS) != 0) curequivs = io_sueequivs4; else
567 curequivs = io_sueequivs;
568 for(i=0; curequivs[i].suename != 0; i++)
569 if (namesame(keywords[1], curequivs[i].suename) == 0) break;
570 if (curequivs[i].suename != 0)
571 {
572 proto = *curequivs[i].intproto;
573 invertoutput = curequivs[i].netateoutput;
574 rotation = curequivs[i].rotation;
575 transpose = curequivs[i].transpose;
576 makeangle(rot, trn, trans);
577 xform(curequivs[i].xoffset, curequivs[i].yoffset, &xoff, &yoff, trans);
578 xoff = muldiv(xoff, lambda, WHOLE);
579 yoff = muldiv(yoff, lambda, WHOLE);
580
581 if (transpose != 0)
582 {
583 trn = 1 - trn;
584 rot = rotation - rot;
585 if (rot < 0) rot += 3600;
586 } else
587 {
588 rot += rotation;
589 if (rot >= 3600) rot -= 3600;
590 }
591 detailbits = curequivs[i].detailbits;
592 numextrawires = curequivs[i].numextrawires;
593 extrawires = curequivs[i].extrawires;
594 #ifdef SHOWORIGINAL
595 defaultnodesize(proto, &px, &py);
596 lx = x - px/2 + xoff; hx = lx + px;
597 ly = y - py/2 + yoff; hy = ly + py;
598 ni = newnodeinst(proto, lx, hx, ly, hy, trn, rot, cell);
599 if (ni == NONODEINST) continue;
600 ni->userbits |= detailbits;
601 endobjectchange((INTBIG)ni, VNODEINST);
602 proto = NONODEPROTO;
603 invertoutput = 0;
604 rotation = transpose = 0;
605 xoff = yoff = 0;
606 detailbits = 0;
607 numextrawires = 0;
608 extrawires = 0;
609 #endif
610 }
611 }
612
613 /* now check for references to cells */
614 if (proto == NONODEPROTO)
615 {
616 /* find node or read it from disk */
617 proto = io_suegetnodeproto(lib, keywords[1]);
618 if (proto == NONODEPROTO)
619 proto = io_suereadfromdisk(lib, keywords[1], dia);
620
621 /* set proper offsets for the cell */
622 if (proto != NONODEPROTO)
623 {
624 np = iconview(proto);
625 if (np != NONODEPROTO) proto = np;
626 xoff = (proto->lowx + proto->highx) / 2;
627 yoff = (proto->lowy + proto->highy) / 2;
628 makeangle(rot, trn, trans);
629 xform(xoff, yoff, &xoff, &yoff, trans);
630 }
631 }
632
633 /* ignore "title" specifications */
634 if (namesamen(keywords[1], x_("title_"), 6) == 0) continue;
635
636 /* stop now if SUE node is unknown */
637 if (proto == NONODEPROTO)
638 {
639 ttyputmsg(_("Cannot make '%s' in cell %s"), keywords[1], describenodeproto(cell));
640 continue;
641 }
642
643 /* create the instance */
644 defaultnodesize(proto, &px, &py);
645 px -= muldiv(xshrink, lambda, WHOLE);
646 py -= muldiv(yshrink, lambda, WHOLE);
647 lx = x - px/2 + xoff; hx = lx + px;
648 ly = y - py/2 + yoff; hy = ly + py;
649 ni = newnodeinst(proto, lx, hx, ly, hy, trn, rot, cell);
650 if (ni == NONODEINST) continue;
651 ni->userbits |= detailbits;
652 ni->temp1 = invertoutput;
653 if (proto->primindex == 0 && proto->cellview == el_iconview)
654 ni->userbits |= NEXPAND;
655 endobjectchange((INTBIG)ni, VNODEINST);
656 if (cell->tech == gen_tech)
657 cell->tech = whattech(cell);
658
659 /* add any extra wires to the node */
660 for(i=0; i<numextrawires; i++)
661 {
662 pp = getportproto(proto, extrawires[i].portname);
663 if (pp == NOPORTPROTO) continue;
664 portposition(ni, pp, &x, &y);
665 makeangle(ni->rotation, ni->transpose, trans);
666 px = muldiv(extrawires[i].xoffset, lambda, WHOLE);
667 py = muldiv(extrawires[i].yoffset, lambda, WHOLE);
668 xform(px, py, &dx, &dy, trans);
669 defaultnodesize(sch_wirepinprim, &px, &py);
670 pinx = x + dx; piny = y + dy;
671 nni = io_suefindpinnode(pinx, piny, cell, &npp);
672 if (nni == NONODEINST)
673 {
674 lx = pinx - px/2; hx = lx + px;
675 ly = piny - py/2; hy = ly + py;
676 nni = newnodeinst(sch_wirepinprim, lx, hx, ly, hy, 0, 0, cell);
677 if (nni == NONODEINST) continue;
678 npp = nni->proto->firstportproto;
679 }
680 bits = us_makearcuserbits(sch_wirearc);
681 if (x != pinx && y != piny) bits &= ~FIXANG;
682 ai = newarcinst(sch_wirearc, 0, bits, ni, pp, x, y, nni, npp, pinx, piny, cell);
683 if (ai == NOARCINST)
684 {
685 ttyputerr(_("Error adding extra wires to node %s"), keywords[1]);
686 break;
687 }
688 }
689
690 /* handle names assigned to the node */
691 if (thename != 0)
692 {
693 /* export a port if this is an input, output, inout */
694 if (proto == sch_offpageprim && thename != 0)
695 {
696 pp = proto->firstportproto;
697 if (namesame(keywords[1], x_("output")) == 0) pp = pp->nextportproto;
698 ppt = io_suenewexport(cell, ni, pp, thename);
699 if (ppt == NOPORTPROTO)
700 {
701 ttyputmsg(_("Cell %s, line %ld, could not create port %s"),
702 cellname, io_suelineno, thename);
703 } else
704 {
705 defaulttextdescript(ppt->textdescript, NOGEOM);
706 defaulttextsize(1, ppt->textdescript);
707 ppt->userbits = (ppt->userbits & ~STATEBITS) | type;
708 endobjectchange((INTBIG)ppt, VPORTPROTO);
709 }
710 } else
711 {
712 /* just name the node */
713 var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key, (INTBIG)thename,
714 VSTRING|VDISPLAY);
715 if (var != NOVARIABLE)
716 defaulttextsize(3, var->textdescript);
717 net_setnodewidth(ni);
718 }
719 }
720
721 /* count the variables */
722 varcount = 0;
723 for(i=2; i<count; i += 2)
724 {
725 if (keywords[i][0] != '-') continue;
726 if (namesame(keywords[i], x_("-origin")) == 0 ||
727 namesame(keywords[i], x_("-orient")) == 0 ||
728 namesame(keywords[i], x_("-type")) == 0 ||
729 namesame(keywords[i], x_("-name")) == 0) continue;
730 varcount++;
731 }
732
733 /* add variables */
734 varindex = 1;
735 varoffset = (ni->highy - ni->lowy) / (varcount+1);
736 for(i=2; i<count; i += 2)
737 {
738 if (keywords[i][0] != '-') continue;
739 if (namesame(keywords[i], x_("-origin")) == 0 ||
740 namesame(keywords[i], x_("-orient")) == 0 ||
741 namesame(keywords[i], x_("-type")) == 0 ||
742 namesame(keywords[i], x_("-name")) == 0) continue;
743 varissize = FALSE;
744 halvesize = FALSE;
745 isparam = FALSE;
746 if (namesame(&keywords[i][1], x_("w")) == 0)
747 {
748 estrcpy(suevarname, x_("ATTR_width"));
749 varissize = TRUE;
750 xpos = 2;
751 ypos = -4;
752 } else if (namesame(&keywords[i][1], x_("l")) == 0)
753 {
754 estrcpy(suevarname, x_("ATTR_length"));
755 varissize = TRUE;
756 xpos = -2;
757 ypos = -4;
758 halvesize = TRUE;
759 } else
760 {
761 esnprintf(suevarname, 200, x_("ATTR_%s"), &keywords[i][1]);
762 for(pt = suevarname; *pt != 0; pt++) if (*pt == ' ')
763 {
764 ttyputmsg(_("Cell %s, line %ld, bad variable name (%s)"),
765 cellname, io_suelineno, suevarname);
766 break;
767 }
768 xpos = 0;
769 pos = (ni->highy - ni->lowy) / 2 - varindex * varoffset;
770 ypos = pos * 4 / lambda;
771 isparam = TRUE;
772 }
773 newtype = 0;
774 if (keywords[i][1] == 'W' && keywords[i][2] != 0)
775 {
776 infstr = initinfstr();
777 addstringtoinfstr(infstr, &keywords[i][2]);
778 addstringtoinfstr(infstr, x_(":"));
779 addstringtoinfstr(infstr, io_sueparseexpression(keywords[i+1]));
780 newaddr = (INTBIG)returninfstr(infstr);
781 newtype = VSTRING;
782 } else
783 {
784 pt = keywords[i+1];
785 len = estrlen(pt) - 1;
786 if (tolower(pt[len]) == 'u')
787 {
788 pt[len] = 0;
789 if (isanumber(pt))
790 {
791 newaddr = scalefromdispunit((float)eatof(pt), DISPUNITMIC) * WHOLE / numericlambda;
792 newtype = VFRACT;
793 }
794 pt[len] = 'u';
795 }
796 if (newtype == 0 && isanumber(pt))
797 {
798 newtype = VINTEGER;
799 newaddr = eatoi(pt);
800 for(cpt = pt; *cpt != 0; cpt++) if (*cpt == '.' || *cpt == 'e' || *cpt == 'E')
801 {
802 f = (float)eatof(pt);
803 j = (INTBIG)(f * WHOLE);
804 if (j / WHOLE == f)
805 {
806 newtype = VFRACT;
807 newaddr = j;
808 } else
809 {
810 newtype = VFLOAT;
811 newaddr = castint(f);
812 }
813 break;
814 }
815 }
816 if (newtype == 0)
817 {
818 newaddr = (INTBIG)io_sueparseexpression(pt);
819 newtype = VSTRING;
820 }
821 }
822 #if LANGJAVA
823 /* see if the string should be Java code */
824 if (newtype == VSTRING)
825 {
826 for(cpt = (CHAR *)newaddr; *cpt != 0; cpt++)
827 {
828 if (*cpt == '@') break;
829 if (tolower(*cpt) == 'p' && cpt[1] == '(') break;
830 }
831 if (*cpt != 0)
832 newtype = VFLOAT|VJAVA;
833 }
834 #endif
835 var = setval((INTBIG)ni, VNODEINST, suevarname, newaddr,
836 newtype|VDISPLAY);
837 if (var != NOVARIABLE)
838 {
839 defaulttextdescript(var->textdescript, ni->geom);
840 varindex++;
841 TDSETOFF(var->textdescript, xpos, ypos);
842 if (halvesize)
843 TDSETSIZE(var->textdescript, TDGETSIZE(var->textdescript)/2);
844 if (isparam)
845 {
846 TDSETISPARAM(var->textdescript, VTISPARAMETER);
847 TDSETDISPPART(var->textdescript, VTDISPLAYNAMEVALUE);
848
849 /* make sure the parameter exists in the cell definition */
850 cnp = contentsview(ni->proto);
851 if (cnp == NONODEPROTO) cnp = ni->proto;
852 var = getval((INTBIG)cnp, VNODEPROTO, -1, suevarname);
853 if (var == NOVARIABLE)
854 {
855 var = setval((INTBIG)cnp, VNODEPROTO, suevarname, newaddr,
856 newtype|VDISPLAY);
857 if (var != NOVARIABLE)
858 {
859 TDSETISPARAM(var->textdescript, VTISPARAMETER);
860 TDSETDISPPART(var->textdescript, VTDISPLAYNAMEVALINH);
861 }
862 }
863 }
864 }
865 }
866 continue;
867 }
868
869 /* handle "make_wire" for defining arcs */
870 if (namesame(keywords[0], x_("make_wire")) == 0)
871 {
872 sw = io_suenewwire();
873 sw->x[0] = io_suemakex(eatoi(keywords[1]), lambda);
874 sw->y[0] = io_suemakey(eatoi(keywords[2]), lambda);
875 sw->x[1] = io_suemakex(eatoi(keywords[3]), lambda);
876 sw->y[1] = io_suemakey(eatoi(keywords[4]), lambda);
877 sw->nextsuewire = firstsuewire;
878 firstsuewire = sw;
879 continue;
880 }
881
882 /* handle "icon_term" for defining ports in icons */
883 if (namesame(keywords[0], x_("icon_term")) == 0)
884 {
885 io_sueparseparameters(&keywords[1], count-1, &x, &y, lambda, &rot, &trn,
886 &type, &thename, &thelabel, &thetext, dia);
887 estrcpy(suevarname, thename);
888
889 proto = sch_buspinprim;
890 defaultnodesize(proto, &px, &py);
891 lx = x - px/2; hx = lx + px;
892 ly = y - py/2; hy = ly + py;
893 ni = newnodeinst(proto, lx, hx, ly, hy, trn, rot%3600, cell);
894 if (ni == NONODEINST) continue;
895 endobjectchange((INTBIG)ni, VNODEINST);
896
897 ppt = io_suenewexport(cell, ni, proto->firstportproto, suevarname);
898 if (ppt == NOPORTPROTO)
899 {
900 ttyputmsg(_("Cell %s, line %ld, could not create port %s"),
901 cellname, io_suelineno, suevarname);
902 } else
903 {
904 defaulttextdescript(ppt->textdescript, NOGEOM);
905 defaulttextsize(1, ppt->textdescript);
906 ppt->userbits = (ppt->userbits & ~STATEBITS) | type;
907 endobjectchange((INTBIG)ppt, VPORTPROTO);
908 }
909 continue;
910 }
911
912 /* handle "icon_arc" for defining icon curves */
913 if (namesame(keywords[0], x_("icon_arc")) == 0)
914 {
915 if (count != 9)
916 {
917 ttyputerr(_("Cell %s, line %ld: needs 9 arguments, has %ld: %s"),
918 cellname, io_suelineno, count, io_sueorigline);
919 continue;
920 }
921 start = 0; extent = 359;
922 p1x = io_suemakex(eatoi(keywords[1]), lambda);
923 p1y = io_suemakey(eatoi(keywords[2]), lambda);
924 p2x = io_suemakex(eatoi(keywords[3]), lambda);
925 p2y = io_suemakey(eatoi(keywords[4]), lambda);
926 if (namesame(keywords[5], x_("-start")) == 0) start = eatoi(keywords[6]);
927 if (namesame(keywords[7], x_("-extent")) == 0) extent = eatoi(keywords[8]);
928 lx = mini(p1x, p2x); hx = maxi(p1x, p2x);
929 ly = mini(p1y, p2y); hy = maxi(p1y, p2y);
930
931 ni = newnodeinst(art_circleprim, lx, hx, ly, hy, 0, 0, cell);
932 if (ni == NONODEINST) continue;
933 if (extent != 359)
934 {
935 if (extent < 0)
936 {
937 start += extent;
938 extent = -extent;
939 }
940 rextent = extent+1; rextent = rextent * EPI / 180.0;
941 rstart = start * EPI / 180.0;
942 setarcdegrees(ni, rstart, rextent);
943 }
944 endobjectchange((INTBIG)ni, VNODEINST);
945 continue;
946 }
947
948 /* handle "icon_line" for defining icon outlines */
949 if (namesame(keywords[0], x_("icon_line")) == 0)
950 {
951 for(i=1; i<count; i++)
952 {
953 if (namesame(keywords[i], x_("-tags")) == 0) break;
954 if ((i%2) != 0) outline[i-1] = io_suemakex(eatoi(keywords[i]), lambda); else
955 outline[i-1] = io_suemakey(eatoi(keywords[i]), lambda);
956 }
957 keycount = i / 2;
958
959 /* determine bounds of icon */
960 lx = hx = outline[0];
961 ly = hy = outline[1];
962 for(i=1; i<keycount; i++)
963 {
964 if (outline[i*2] < lx) lx = outline[i*2];
965 if (outline[i*2] > hx) hx = outline[i*2];
966 if (outline[i*2+1] < ly) ly = outline[i*2+1];
967 if (outline[i*2+1] > hy) hy = outline[i*2+1];
968 }
969 ni = newnodeinst(art_openedpolygonprim, lx, hx, ly, hy, 0, 0, cell);
970 if (ni == NONODEINST) return(NONODEPROTO);
971 cx = (lx + hx) / 2; cy = (ly + hy) / 2;
972 for(i=0; i<keycount; i++)
973 {
974 outline[i*2] -= cx; outline[i*2+1] -= cy;
975 }
976 (void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)outline,
977 VINTEGER|VISARRAY|((keycount*2)<<VLENGTHSH));
978 endobjectchange((INTBIG)ni, VNODEINST);
979 continue;
980 }
981
982 /* handle "icon_setup" for defining variables */
983 if (namesame(keywords[0], x_("icon_setup")) == 0)
984 {
985 /* extract parameters */
986 if (namesame(keywords[1], x_("$args")) != 0)
987 {
988 ttyputerr(_("Cell %s, line %ld: has unrecognized 'icon_setup'"),
989 cellname, io_suelineno);
990 continue;
991 }
992 pt = keywords[2];
993 if (*pt == '{') pt++;
994 for(;;)
995 {
996 while (*pt == ' ') pt++;
997 if (*pt == '}' || *pt == 0) break;
998
999 /* collect up to a space or close curly */
1000 startkey = pt;
1001 curly = 0;
1002 for(;;)
1003 {
1004 if (curly == 0)
1005 {
1006 if (*pt == 0 || *pt == ' ' || *pt == '}') break;
1007 }
1008 if (*pt == '{') curly++;
1009 if (*pt == '}') curly--;
1010 if (*pt == 0) break;
1011 pt++;
1012 }
1013 save = *pt;
1014 *pt = 0;
1015
1016 /* parse the keyword pair in "startkey" */
1017 i = numargs+1;
1018 newargnames = (CHAR **)emalloc(i * (sizeof (CHAR *)), el_tempcluster);
1019 newargvalues = (CHAR **)emalloc(i * (sizeof (CHAR *)), el_tempcluster);
1020 for(i=0; i<numargs; i++)
1021 {
1022 /* LINTED "argnames" used in proper order */
1023 newargnames[i] = argnames[i];
1024
1025 /* LINTED "argvalues" used in proper order */
1026 newargvalues[i] = argvalues[i];
1027 }
1028 if (numargs > 0)
1029 {
1030 efree((CHAR *)argnames);
1031 efree((CHAR *)argvalues);
1032 }
1033 argnames = newargnames;
1034 argvalues = newargvalues;
1035 startkey++;
1036 for(cpt = startkey; *cpt != 0; cpt++) if (*cpt == ' ') break;
1037 if (*cpt != 0) *cpt++ = 0;
1038 (void)allocstring(&argnames[numargs], startkey, el_tempcluster);
1039 while (*cpt == ' ') cpt++;
1040 if (*cpt == '{') cpt++;
1041 startkey = cpt;
1042 for(cpt = startkey; *cpt != 0; cpt++) if (*cpt == '}') break;
1043 if (*cpt != 0) *cpt++ = 0;
1044 (void)allocstring(&argvalues[numargs], startkey, el_tempcluster);
1045 numargs++;
1046
1047 *pt = save;
1048 }
1049 continue;
1050 }
1051
1052 /* handle "icon_property" for defining icon strings */
1053 if (namesame(keywords[0], x_("icon_property")) == 0)
1054 {
1055 /* extract parameters */
1056 io_sueparseparameters(&keywords[1], count-1, &x, &y, lambda, &rot, &trn,
1057 &type, &thename, &thelabel, &thetext, dia);
1058 if (thelabel == 0) continue;
1059
1060 /* substitute parameters */
1061 infstr = initinfstr();
1062 for(pt = thelabel; *pt != 0; pt++)
1063 {
1064 if (*pt == '$')
1065 {
1066 for(i=0; i<numargs; i++)
1067 if (namesamen(&pt[1], argnames[i], estrlen(argnames[i])) == 0) break;
1068 if (i < numargs)
1069 {
1070 addstringtoinfstr(infstr, argvalues[i]);
1071 pt += estrlen(argnames[i]);
1072 continue;
1073 }
1074 }
1075 addtoinfstr(infstr, *pt);
1076 }
1077 thelabel = returninfstr(infstr);
1078
1079 ni = newnodeinst(gen_invispinprim, x, x, y, y, 0, 0, cell);
1080 if (ni == NONODEINST) continue;
1081 var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)thelabel, VSTRING|VDISPLAY);
1082 if (var != NOVARIABLE)
1083 {
1084 defaulttextsize(2, var->textdescript);
1085 TDSETPOS(var->textdescript, VTPOSCENT);
1086 }
1087 endobjectchange((INTBIG)ni, VNODEINST);
1088 continue;
1089 }
1090
1091 /* handle "make_text" for placing strings */
1092 if (namesame(keywords[0], x_("make_text")) == 0)
1093 {
1094 /* extract parameters */
1095 io_sueparseparameters(&keywords[1], count-1, &x, &y, lambda, &rot, &trn,
1096 &type, &thename, &thelabel, &thetext, dia);
1097 if (thetext == 0) continue;
1098
1099 ni = newnodeinst(gen_invispinprim, x, x, y, y, 0, 0, cell);
1100 if (ni == NONODEINST) continue;
1101 var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)thetext, VSTRING|VDISPLAY);
1102 if (var != NOVARIABLE)
1103 {
1104 defaulttextsize(2, var->textdescript);
1105 TDSETPOS(var->textdescript, VTPOSCENT);
1106 }
1107 endobjectchange((INTBIG)ni, VNODEINST);
1108 continue;
1109 }
1110
1111 /* ignore known keywords */
1112 if (namesame(keywords[0], x_("icon_title")) == 0 ||
1113 namesame(keywords[0], x_("make_line")) == 0 ||
1114 namesame(keywords[0], x_("}")) == 0)
1115 {
1116 continue;
1117 }
1118
1119 ttyputerr(_("Cell %s, line %ld: unknown keyword (%s): %s"), cellname,
1120 io_suelineno, keywords[0], io_sueorigline);
1121 }
1122
1123 /* place an icon instance in the schematic if requested */
1124 if (placeicon && schemcell != NONODEPROTO &&
1125 iconcell != NONODEPROTO)
1126 {
1127 px = iconcell->highx - iconcell->lowx;
1128 py = iconcell->highy - iconcell->lowy;
1129 lx = iconx - px/2; hx = lx + px;
1130 ly = icony - py/2; hy = ly + py;
1131 ni = newnodeinst(iconcell, lx, hx, ly, hy, 0, 0, schemcell);
1132 if (ni != NONODEINST)
1133 {
1134 ni->userbits |= NEXPAND;
1135 endobjectchange((INTBIG)ni, VNODEINST);
1136 }
1137 }
1138
1139 for(i=0; i<numargs; i++)
1140 {
1141 efree(argnames[i]);
1142 efree(argvalues[i]);
1143 }
1144 if (numargs > 0)
1145 {
1146 efree((CHAR *)argnames);
1147 efree((CHAR *)argvalues);
1148 }
1149 if (namestrlen > 0) efree(namestring);
1150
1151 /* cleanup the current cell */
1152 if (cell != NONODEPROTO)
1153 {
1154 io_sueplacewires(firstsuewire, firstsuenet, cell, lambda);
1155 io_suefreewires(firstsuewire);
1156 io_sueplacenets(firstsuenet, cell);
1157 io_suefreenets(firstsuenet);
1158 }
1159
1160 /* make sure cells are the right size */
1161 if (schemcell != NONODEPROTO) (*el_curconstraint->solve)(schemcell);
1162 if (iconcell != NONODEPROTO) (*el_curconstraint->solve)(iconcell);
1163
1164 /* return the cell */
1165 if (schemcell != NONODEPROTO) return(schemcell);
1166 return(iconcell);
1167
1168 }
1169
1170 /*
1171 * Routine to examine a SUE expression and add "@" in front of variable names.
1172 */
io_sueparseexpression(CHAR * expression)1173 CHAR *io_sueparseexpression(CHAR *expression)
1174 {
1175 REGISTER void *infstr;
1176 REGISTER CHAR *keyword;
1177
1178 infstr = initinfstr();
1179 while (*expression != 0)
1180 {
1181 keyword = getkeyword(&expression, x_(" \t,+-*/()"));
1182 if (keyword == NOSTRING) break;
1183 if (*keyword != 0)
1184 {
1185 if (isdigit(keyword[0]))
1186 {
1187 addstringtoinfstr(infstr, keyword);
1188 } else
1189 {
1190 if (*expression != '(')
1191 addtoinfstr(infstr, '@');
1192 addstringtoinfstr(infstr, keyword);
1193 }
1194 if (*expression != 0)
1195 addtoinfstr(infstr, *expression++);
1196 }
1197 }
1198 return(returninfstr(infstr));
1199 }
1200
1201 /*
1202 * Routine to parse the "count" parameters in "keywords" and fill in the values
1203 * that are found. Fills in:
1204 * "-origin" placed into "x" and "y"
1205 * "-orient" placed into "rot" and "trn"
1206 * "-type" placed into "type"
1207 * "-name" placed into "thename".
1208 * "-label" placed into "thelabel".
1209 * "-text" placed into "thetext".
1210 */
io_sueparseparameters(CHAR ** keywords,INTBIG count,INTBIG * x,INTBIG * y,INTBIG lambda,INTBIG * rot,INTBIG * trn,INTBIG * type,CHAR ** thename,CHAR ** thelabel,CHAR ** thetext,void * dia)1211 void io_sueparseparameters(CHAR **keywords, INTBIG count, INTBIG *x, INTBIG *y, INTBIG lambda,
1212 INTBIG *rot, INTBIG *trn, INTBIG *type, CHAR **thename, CHAR **thelabel, CHAR **thetext,
1213 void *dia)
1214 {
1215 CHAR *pt;
1216 REGISTER INTBIG textloc, i;
1217 REGISTER void *infstr;
1218
1219 *x = *y = 0;
1220 *rot = 0;
1221 *trn = 0;
1222 *type = 0;
1223 *thename = 0;
1224 *thelabel = 0;
1225 *thetext = 0;
1226 for(i=0; i<count; i += 2)
1227 {
1228 if (namesame(keywords[i], x_("-origin")) == 0)
1229 {
1230 pt = keywords[i+1];
1231 if (*pt == '{') pt++;
1232 *x = eatoi(pt);
1233 while (*pt != ' ' && *pt != '\t' && *pt != 0) pt++;
1234 while (*pt == ' ' || *pt == '\t') pt++;
1235 *y = eatoi(pt);
1236 }
1237 if (namesame(keywords[i], x_("-orient")) == 0)
1238 {
1239 if (namesame(keywords[i+1], x_("R90")) == 0) { *rot = 900; } else
1240 if (namesame(keywords[i+1], x_("R270")) == 0) { *rot = 2700; } else
1241 if (namesame(keywords[i+1], x_("RXY")) == 0) { *rot = 1800; } else
1242 if (namesame(keywords[i+1], x_("RY")) == 0) { *rot = 900; *trn = 1; } else
1243 if (namesame(keywords[i+1], x_("R90X")) == 0) { *rot = 0; *trn = 1; } else
1244 if (namesame(keywords[i+1], x_("R90Y")) == 0) { *rot = 1800; *trn = 1; } else
1245 if (namesame(keywords[i+1], x_("RX")) == 0) { *rot = 2700; *trn = 1; }
1246 }
1247 if (namesame(keywords[i], x_("-type")) == 0)
1248 {
1249 if (namesame(keywords[i+1], x_("input")) == 0) *type = INPORT; else
1250 if (namesame(keywords[i+1], x_("output")) == 0) *type = OUTPORT; else
1251 if (namesame(keywords[i+1], x_("inout")) == 0) *type = BIDIRPORT;
1252 }
1253 if (namesame(keywords[i], x_("-name")) == 0 ||
1254 namesame(keywords[i], x_("-label")) == 0 ||
1255 namesame(keywords[i], x_("-text")) == 0)
1256 {
1257 if (namesame(keywords[i], x_("-name")) == 0) textloc = 0; else
1258 if (namesame(keywords[i], x_("-label")) == 0) textloc = 1; else
1259 textloc = 2;
1260 infstr = initinfstr();
1261 pt = keywords[i+1];
1262 if (pt[0] != '{') addstringtoinfstr(infstr, pt); else
1263 {
1264 pt++;
1265 for(;;)
1266 {
1267 while (*pt != 0)
1268 {
1269 if (*pt == '}') break;
1270 addtoinfstr(infstr, *pt);
1271 pt++;
1272 }
1273 if (*pt == '}') break;
1274 addtoinfstr(infstr, ' ');
1275
1276 count = io_suegetnextline(keywords, 1, dia);
1277 if (count < 0) break;
1278 if (count == 0) continue;
1279 pt = keywords[0];
1280 i = -1;
1281 }
1282 }
1283 switch (textloc)
1284 {
1285 case 0: *thename = returninfstr(infstr); break;
1286 case 1: *thelabel = returninfstr(infstr); break;
1287 case 2: *thetext = returninfstr(infstr); break;
1288 }
1289 }
1290 }
1291 *x = io_suemakex(*x, lambda);
1292 *y = io_suemakey(*y, lambda);
1293 *rot = (3600 - *rot) % 3600;
1294 }
1295
1296 /*
1297 * Routine to find cell "protoname" in library "lib".
1298 */
io_suegetnodeproto(LIBRARY * lib,CHAR * protoname)1299 NODEPROTO *io_suegetnodeproto(LIBRARY *lib, CHAR *protoname)
1300 {
1301 REGISTER NODEPROTO *np;
1302
1303 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1304 if (namesame(protoname, np->protoname) == 0) return(np);
1305 return(NONODEPROTO);
1306 }
1307
1308 /*
1309 * Routine to create a port called "thename" on port "pp" of node "ni" in cell "cell".
1310 * The name is modified if it already exists.
1311 */
io_suenewexport(NODEPROTO * cell,NODEINST * ni,PORTPROTO * pp,CHAR * thename)1312 PORTPROTO *io_suenewexport(NODEPROTO *cell, NODEINST *ni, PORTPROTO *pp, CHAR *thename)
1313 {
1314 REGISTER PORTPROTO *ppt;
1315 REGISTER INTBIG i;
1316 REGISTER CHAR *portname, *pt;
1317 CHAR numbuf[20];
1318 REGISTER void *infstr;
1319
1320 portname = thename;
1321 for(i=0; ; i++)
1322 {
1323 ppt = getportproto(cell, portname);
1324 if (ppt == NOPORTPROTO)
1325 {
1326 ppt = newportproto(cell, ni, pp, portname);
1327 break;
1328 }
1329
1330 /* make space for modified name */
1331 infstr = initinfstr();
1332 for(pt = thename; *pt != 0 && *pt != '['; pt++)
1333 addtoinfstr(infstr, *pt);
1334 esnprintf(numbuf, 20, x_("-%ld"), i);
1335 addstringtoinfstr(infstr, numbuf);
1336 for( ; *pt != 0; pt++)
1337 addtoinfstr(infstr, *pt);
1338 portname = returninfstr(infstr);
1339 }
1340 return(ppt);
1341 }
1342
1343 /* Routine to convert SUE X coordinate "x" to Electric coordinates */
io_suemakex(INTBIG x,INTBIG lambda)1344 INTBIG io_suemakex(INTBIG x, INTBIG lambda)
1345 {
1346 return(x * lambda / 8);
1347 }
1348
1349 /* Routine to convert SUE Y coordinate "y" to Electric coordinates */
io_suemakey(INTBIG y,INTBIG lambda)1350 INTBIG io_suemakey(INTBIG y, INTBIG lambda)
1351 {
1352 return(-y * lambda / 8);
1353 }
1354
1355 /*
1356 * Routine to place all SUE nets into the cell (they are in a linked
1357 * list headed by "firstsuenet").
1358 */
io_sueplacenets(SUENET * firstsuenet,NODEPROTO * cell)1359 void io_sueplacenets(SUENET *firstsuenet, NODEPROTO *cell)
1360 {
1361 SUENET *sn;
1362 REGISTER INTBIG pass;
1363 REGISTER BOOLEAN isbus;
1364 REGISTER ARCINST *ai, *bestai;
1365 REGISTER INTBIG cx, cy, dist, bestdist, sea;
1366 REGISTER GEOM *geom;
1367 REGISTER CHAR *netname, *busname;
1368 REGISTER void *infstr;
1369
1370 /* 3 passes: qualified labels, unqualified busses, unqualified wires */
1371 for(pass=0; pass<3; pass++)
1372 {
1373 for(sn = firstsuenet; sn != NOSUENET; sn = sn->nextsuenet)
1374 {
1375 /* unqualified labels (starting with "[") happen second */
1376 if (*sn->label == '[')
1377 {
1378 /* unqualified label: pass 2 or 3 only */
1379 if (pass == 0) continue;
1380 } else
1381 {
1382 /* qualified label: pass 1 only */
1383 if (pass != 0) continue;
1384 }
1385
1386 /* see if this is a bus */
1387 if (net_buswidth(sn->label) > 1) isbus = TRUE; else isbus = FALSE;
1388
1389 sea = initsearch(sn->x, sn->x, sn->y, sn->y, cell);
1390 bestai = NOARCINST;
1391 for(;;)
1392 {
1393 geom = nextobject(sea);
1394 if (geom == NOGEOM) break;
1395 if (geom->entryisnode) continue;
1396 ai = geom->entryaddr.ai;
1397 if (isbus)
1398 {
1399 if (ai->proto != sch_busarc) continue;
1400 } else
1401 {
1402 if (ai->proto == sch_busarc) continue;
1403 }
1404 cx = (ai->end[0].xpos + ai->end[1].xpos) / 2;
1405 cy = (ai->end[0].ypos + ai->end[1].ypos) / 2;
1406 dist = computedistance(cx, cy, sn->x, sn->y);
1407
1408 /* LINTED "bestdist" used in proper order */
1409 if (bestai == NOARCINST || dist < bestdist)
1410 {
1411 bestai = ai;
1412 bestdist = dist;
1413 }
1414 }
1415 if (bestai != NOARCINST)
1416 {
1417 if (pass == 1)
1418 {
1419 /* only allow busses */
1420 if (bestai->proto != sch_busarc) continue;
1421 } else if (pass == 2)
1422 {
1423 /* disallow busses */
1424 if (bestai->proto == sch_busarc) continue;
1425 }
1426 netname = sn->label;
1427 if (*netname == '[')
1428 {
1429 /* find the proper name of the network */
1430 busname = io_suefindbusname(bestai);
1431 if (busname != 0)
1432 {
1433 infstr = initinfstr();
1434 addstringtoinfstr(infstr, busname);
1435 addstringtoinfstr(infstr, netname);
1436 netname = returninfstr(infstr);
1437 }
1438 }
1439 us_setarcname(bestai, netname);
1440 }
1441 }
1442 }
1443 }
1444
1445 /*
1446 * Routine to start at "ai" and search all wires until it finds a named bus.
1447 * Returns zero if no bus name is found.
1448 */
io_suefindbusname(ARCINST * ai)1449 CHAR *io_suefindbusname(ARCINST *ai)
1450 {
1451 REGISTER ARCINST *oai;
1452 REGISTER CHAR *busname, *pt;
1453 REGISTER VARIABLE *var;
1454 static CHAR pseudobusname[50];
1455 REGISTER INTBIG index, len;
1456
1457 for(oai = ai->parent->firstarcinst; oai != NOARCINST; oai = oai->nextarcinst)
1458 oai->temp1 = 0;
1459 busname = io_suesearchbusname(ai);
1460 if (busname == 0)
1461 {
1462 for(index=1; ; index++)
1463 {
1464 esnprintf(pseudobusname, 50, x_("NET%ld"), index);
1465 len = estrlen(pseudobusname);
1466 for(oai = ai->parent->firstarcinst; oai != NOARCINST; oai = oai->nextarcinst)
1467 {
1468 var = getvalkey((INTBIG)oai, VARCINST, VSTRING, el_arc_name_key);
1469 if (var == NOVARIABLE) continue;
1470 pt = (CHAR *)var->addr;
1471 if (namesame(pseudobusname, pt) == 0) break;
1472 if (namesamen(pseudobusname, pt, len) == 0 &&
1473 pt[len] == '[') break;
1474 }
1475 if (oai == NOARCINST) break;
1476 }
1477 busname = pseudobusname;
1478 }
1479 return(busname);
1480 }
1481
io_suesearchbusname(ARCINST * ai)1482 CHAR *io_suesearchbusname(ARCINST *ai)
1483 {
1484 REGISTER ARCINST *oai;
1485 REGISTER CHAR *busname;
1486 REGISTER INTBIG i;
1487 REGISTER NODEINST *ni;
1488 REGISTER PORTARCINST *pi;
1489 REGISTER PORTEXPINST *pe;
1490 REGISTER PORTPROTO *pp;
1491 REGISTER VARIABLE *var;
1492 REGISTER void *infstr;
1493
1494 ai->temp1 = 1;
1495 if (ai->proto == sch_busarc)
1496 {
1497 var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
1498 if (var != NOVARIABLE)
1499 {
1500 infstr = initinfstr();
1501 for(busname = (CHAR *)var->addr; *busname != 0; busname++)
1502 {
1503 if (*busname == '[') break;
1504 addtoinfstr(infstr, *busname);
1505 }
1506 return(returninfstr(infstr));
1507 }
1508 }
1509 for(i=0; i<2; i++)
1510 {
1511 ni = ai->end[i].nodeinst;
1512 if (ni->proto != sch_wirepinprim && ni->proto != sch_buspinprim &&
1513 ni->proto != sch_offpageprim) continue;
1514 if (ni->proto == sch_buspinprim || ni->proto == sch_offpageprim)
1515 {
1516 /* see if there is an arrayed port here */
1517 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1518 {
1519 pp = pe->exportproto;
1520 for(busname = pp->protoname; *busname != 0; busname++)
1521 if (*busname == '[') break;
1522 if (*busname != 0)
1523 {
1524 infstr = initinfstr();
1525 for(busname = pp->protoname; *busname != 0; busname++)
1526 {
1527 if (*busname == '[') break;
1528 addtoinfstr(infstr, *busname);
1529 }
1530 return(returninfstr(infstr));
1531 }
1532 }
1533 }
1534 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1535 {
1536 oai = pi->conarcinst;
1537 if (oai->temp1 != 0) continue;
1538 busname = io_suesearchbusname(oai);
1539 if (busname != 0) return(busname);
1540 }
1541 }
1542 return(0);
1543 }
1544
1545 /*
1546 * Routine to place all SUE wires into the cell (they are in a linked
1547 * list headed by "firstsuewire").
1548 */
io_sueplacewires(SUEWIRE * firstsuewire,SUENET * firstsuenet,NODEPROTO * cell,INTBIG lambda)1549 void io_sueplacewires(SUEWIRE *firstsuewire, SUENET *firstsuenet, NODEPROTO *cell, INTBIG lambda)
1550 {
1551 SUEWIRE *sw, *osw;
1552 SUENET *sn;
1553 REGISTER INTBIG i, j, wid, px, py, lx, hx, ly, hy, sea, bits;
1554 REGISTER BOOLEAN propagatedbus, isbus;
1555 INTBIG xsize, ysize, x, y, ox, oy;
1556 REGISTER NODEPROTO *proto;
1557 REGISTER GEOM *geom;
1558 REGISTER PORTEXPINST *pe;
1559 NODEINST *ni;
1560 REGISTER ARCPROTO *ap;
1561 REGISTER NODEINST *bottomni, *oni;
1562 PORTPROTO *pp;
1563 REGISTER PORTPROTO *bottompp, *opp;
1564 REGISTER ARCINST *ai;
1565
1566 /* mark all wire ends as "unassigned", all wire types as unknown */
1567 for(sw = firstsuewire; sw != NOSUEWIRE; sw = sw->nextsuewire)
1568 {
1569 sw->ni[0] = sw->ni[1] = NONODEINST;
1570 sw->proto = NOARCPROTO;
1571 }
1572
1573 /* examine all network names and assign wire types appropriately */
1574 for(sn = firstsuenet; sn != NOSUENET; sn = sn->nextsuenet)
1575 {
1576 for(sw = firstsuewire; sw != NOSUEWIRE; sw = sw->nextsuewire)
1577 {
1578 for(i=0; i<2; i++)
1579 {
1580 if (sw->x[i] == sn->x && sw->y[i] == sn->y)
1581 {
1582 if (net_buswidth(sn->label) > 1) sw->proto = sch_busarc; else
1583 sw->proto = sch_wirearc;
1584 }
1585 }
1586 }
1587 }
1588
1589 /* find connections that are exactly on existing nodes */
1590 for(sw = firstsuewire; sw != NOSUEWIRE; sw = sw->nextsuewire)
1591 {
1592 for(i=0; i<2; i++)
1593 {
1594 if (sw->ni[i] != NONODEINST) continue;
1595 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1596 {
1597 pp = io_suewiredport(ni, &sw->x[i], &sw->y[i], sw->x[1-i], sw->y[1-i]);
1598 if (pp == NOPORTPROTO) continue;
1599 sw->ni[i] = ni;
1600 sw->pp[i] = pp;
1601
1602 /* determine whether this port is a bus */
1603 isbus = FALSE;
1604 bottomni = ni; bottompp = pp;
1605 while (bottomni->proto->primindex == 0)
1606 {
1607 bottomni = bottompp->subnodeinst;
1608 bottompp = bottompp->subportproto;
1609 }
1610 if (bottomni->proto == sch_wireconprim) continue;
1611 if (!isbus && ni->proto == sch_offpageprim)
1612 {
1613 /* see if there is a bus port on this primitive */
1614 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1615 {
1616 if (net_buswidth(pe->exportproto->protoname) > 1) isbus = TRUE;
1617 }
1618 }
1619
1620 if (isbus)
1621 {
1622 sw->proto = sch_busarc;
1623 } else
1624 {
1625 if (sw->proto == NOARCPROTO)
1626 sw->proto = sch_wirearc;
1627 }
1628 }
1629 }
1630 }
1631
1632 /* now iteratively extend bus wires to connections with others */
1633 propagatedbus = TRUE;
1634 while (propagatedbus)
1635 {
1636 propagatedbus = FALSE;
1637 for(sw = firstsuewire; sw != NOSUEWIRE; sw = sw->nextsuewire)
1638 {
1639 if (sw->proto != sch_busarc) continue;
1640 for(osw = firstsuewire; osw != NOSUEWIRE; osw = osw->nextsuewire)
1641 {
1642 if (osw->proto != NOARCPROTO) continue;
1643 for(i=0; i<2; i++)
1644 {
1645 for(j=0; j<2; j++)
1646 {
1647 if (sw->x[i] == osw->x[j] && sw->y[i] == osw->y[j])
1648 {
1649 /* common point found: continue the bus request */
1650 osw->proto = sch_busarc;
1651 propagatedbus = TRUE;
1652 }
1653 }
1654 }
1655 }
1656 }
1657 }
1658
1659 /* now make pins where wires meet */
1660 for(sw = firstsuewire; sw != NOSUEWIRE; sw = sw->nextsuewire)
1661 {
1662 for(i=0; i<2; i++)
1663 {
1664 if (sw->ni[i] != NONODEINST) continue;
1665 if (sw->proto == sch_busarc) proto = sch_buspinprim; else
1666 proto = sch_wirepinprim;
1667
1668 /* look at all other wires at this point and figure out type of pin to make */
1669 for(osw = firstsuewire; osw != NOSUEWIRE; osw = osw->nextsuewire)
1670 {
1671 if (osw == sw) continue;
1672 for(j=0; j<2; j++)
1673 {
1674 if (sw->x[i] != osw->x[j] || sw->y[i] != osw->y[j]) continue;
1675 if (osw->ni[j] != NONODEINST)
1676 {
1677 sw->ni[i] = osw->ni[j];
1678 sw->pp[i] = osw->pp[j];
1679 break;
1680 }
1681 if (osw->proto == sch_busarc) proto = sch_buspinprim;
1682 }
1683 if (sw->ni[i] != NONODEINST) break;
1684 }
1685
1686 /* make the pin if it doesn't exist */
1687 if (sw->ni[i] == NONODEINST)
1688 {
1689 /* common point found: make a pin */
1690 defaultnodesize(proto, &xsize , &ysize);
1691 sw->ni[i] = newnodeinst(proto, sw->x[i] - xsize/2,
1692 sw->x[i] + xsize/2, sw->y[i] - ysize/2,
1693 sw->y[i] + ysize/2, 0, 0, cell);
1694 endobjectchange((INTBIG)sw->ni[i], VNODEINST);
1695 sw->pp[i] = proto->firstportproto;
1696 }
1697
1698 /* put that node in all appropriate locations */
1699 for(osw = firstsuewire; osw != NOSUEWIRE; osw = osw->nextsuewire)
1700 {
1701 if (osw == sw) continue;
1702 for(j=0; j<2; j++)
1703 {
1704 if (sw->x[i] != osw->x[j] || sw->y[i] != osw->y[j]) continue;
1705 if (osw->ni[j] != NONODEINST) continue;
1706 osw->ni[j] = sw->ni[i];
1707 osw->pp[j] = sw->pp[i];
1708 }
1709 }
1710 }
1711 }
1712
1713 /* make pins at all of the remaining wire ends */
1714 for(sw = firstsuewire; sw != NOSUEWIRE; sw = sw->nextsuewire)
1715 {
1716 for(i=0; i<2; i++)
1717 {
1718 if (sw->ni[i] != NONODEINST) continue;
1719 if (!io_suefindnode(&sw->x[i], &sw->y[i], sw->x[1-i], sw->y[1-i], cell,
1720 &sw->ni[i], &sw->pp[i], sw->ni[1-i], lambda))
1721 {
1722 if (sw->proto == sch_busarc) proto = sch_buspinprim; else
1723 proto = sch_wirepinprim;
1724 defaultnodesize(proto, &xsize , &ysize);
1725 sw->ni[i] = newnodeinst(proto, sw->x[i] - xsize/2,
1726 sw->x[i] + xsize/2, sw->y[i] - ysize/2, sw->y[i] + ysize/2,
1727 0, 0, cell);
1728 endobjectchange((INTBIG)sw->ni[i], VNODEINST);
1729 sw->pp[i] = sw->ni[i]->proto->firstportproto;
1730 }
1731 }
1732 }
1733
1734 /* now make the connections */
1735 for(sw = firstsuewire; sw != NOSUEWIRE; sw = sw->nextsuewire)
1736 {
1737 if (sw->proto == NOARCPROTO) sw->proto = sch_wirearc;
1738 wid = defaultarcwidth(sw->proto);
1739
1740 /* if this is a bus, make sure it can connect */
1741 if (sw->proto == sch_busarc)
1742 {
1743 for(i=0; i<2; i++)
1744 {
1745 for(j=0; sw->pp[i]->connects[j] != NOARCPROTO; j++)
1746 if (sw->pp[i]->connects[j] == sch_busarc) break;
1747 if (sw->pp[i]->connects[j] == NOARCPROTO)
1748 {
1749 /* this end cannot connect: fake the connection */
1750 px = (sw->x[0] + sw->x[1]) / 2;
1751 py = (sw->y[0] + sw->y[1]) / 2;
1752 defaultnodesize(sch_buspinprim, &xsize , &ysize);
1753 lx = px - xsize/2; hx = lx + xsize;
1754 ly = py - ysize/2; hy = ly + ysize;
1755 ni = newnodeinst(sch_buspinprim, lx, hx, ly, hy, 0, 0, cell);
1756 if (ni == NONODEINST) break;
1757 endobjectchange((INTBIG)ni, VNODEINST);
1758 pp = ni->proto->firstportproto;
1759 ai = newarcinst(gen_unroutedarc, defaultarcwidth(gen_unroutedarc),
1760 us_makearcuserbits(gen_unroutedarc), ni, pp, px, py,
1761 sw->ni[i], sw->pp[i], sw->x[i], sw->y[i], cell);
1762 if (ai == NOARCINST)
1763 {
1764 ttyputerr(_("Error making fake connection"));
1765 break;
1766 }
1767 endobjectchange((INTBIG)ai, VARCINST);
1768 sw->ni[i] = ni;
1769 sw->pp[i] = pp;
1770 sw->x[i] = px;
1771 sw->y[i] = py;
1772 }
1773 }
1774 }
1775
1776 ai = newarcinst(sw->proto, wid, us_makearcuserbits(sw->proto),
1777 sw->ni[0], sw->pp[0], sw->x[0], sw->y[0],
1778 sw->ni[1], sw->pp[1], sw->x[1], sw->y[1], cell);
1779 if (ai == NOARCINST)
1780 {
1781 ttyputerr(_("Could not run a wire from %s to %s in cell %s"),
1782 describenodeinst(sw->ni[0]), describenodeinst(sw->ni[1]),
1783 describenodeproto(cell));
1784 continue;
1785 }
1786
1787 /* negate the wire if requested */
1788 if (sw->ni[0]->temp1 != 0 &&
1789 estrcmp(sw->pp[0]->protoname, x_("y")) == 0)
1790 {
1791 ai->userbits |= ISNEGATED;
1792 } else if (sw->ni[1]->temp1 != 0 &&
1793 estrcmp(sw->pp[1]->protoname, x_("y")) == 0)
1794 {
1795 ai->userbits |= ISNEGATED | REVERSEEND;
1796 }
1797 endobjectchange((INTBIG)ai, VARCINST);
1798 }
1799
1800 /* now look for implicit connections where "offpage" connectors touch */
1801 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1802 {
1803 if (ni->proto != sch_offpageprim) continue;
1804 if (ni->firstportarcinst != NOPORTARCINST) continue;
1805 pp = ni->proto->firstportproto->nextportproto;
1806 portposition(ni, pp, &x, &y);
1807 sea = initsearch(x, x, y, y, cell);
1808 for(;;)
1809 {
1810 geom = nextobject(sea);
1811 if (geom == NOGEOM) break;
1812 if (!geom->entryisnode) continue;
1813 oni = geom->entryaddr.ni;
1814 if (oni == ni) continue;
1815 for(opp = oni->proto->firstportproto; opp != NOPORTPROTO; opp = opp->nextportproto)
1816 {
1817 portposition(oni, opp, &ox, &oy);
1818 if (ox != x || oy != y) continue;
1819 for(i=0; i<3; i++)
1820 {
1821 switch (i)
1822 {
1823 case 0: ap = sch_busarc; break;
1824 case 1: ap = sch_wirearc; break;
1825 case 2: ap = gen_unroutedarc; break;
1826 }
1827 for(j=0; pp->connects[j] != NOARCPROTO; j++)
1828 if (pp->connects[j] == ap) break;
1829 if (pp->connects[j] == NOARCPROTO) continue;
1830 for(j=0; opp->connects[j] != NOARCPROTO; j++)
1831 if (opp->connects[j] == ap) break;
1832 if (opp->connects[j] == NOARCPROTO) continue;
1833 break;
1834 }
1835
1836 wid = defaultarcwidth(ap);
1837 bits = us_makearcuserbits(ap);
1838 ai = newarcinst(ap, wid, bits, ni, pp, x, y, oni, opp, x, y, cell);
1839 if (ai != NOARCINST)
1840 endobjectchange((INTBIG)ai, VARCINST);
1841 break;
1842 }
1843 if (opp != NOPORTPROTO) break;
1844 }
1845 }
1846 }
1847
1848 /*
1849 * Routine to find the port on node "ni" that attaches to the wire from (x,y) to (ox,oy).
1850 * Returns NOPORTPROTO if not found.
1851 */
io_suewiredport(NODEINST * ni,INTBIG * x,INTBIG * y,INTBIG ox,INTBIG oy)1852 PORTPROTO *io_suewiredport(NODEINST *ni, INTBIG *x, INTBIG *y, INTBIG ox, INTBIG oy)
1853 {
1854 REGISTER PORTPROTO *pp, *bestpp;
1855 REGISTER INTBIG dist, bestdist;
1856 INTBIG px, py;
1857 static POLYGON *poly = NOPOLYGON;
1858
1859 /* make sure there is a polygon */
1860 (void)needstaticpolygon(&poly, 4, io_tool->cluster);
1861 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1862 {
1863 shapeportpoly(ni, pp, poly, FALSE);
1864 if (isinside(*x, *y, poly)) return(pp);
1865 }
1866 if ((ni->lowx+ni->highx) / 2 != *x ||
1867 (ni->lowy+ni->highy) / 2 != *y) return(NOPORTPROTO);
1868
1869 /* find port that is closest to OTHER end */
1870 bestdist = MAXINTBIG;
1871 bestpp = NOPORTPROTO;
1872 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1873 {
1874 portposition(ni, pp, &px, &py);
1875 dist = computedistance(px, py, ox, oy);
1876 if (dist > bestdist) continue;
1877 bestdist = dist;
1878 bestpp = pp;
1879 }
1880 portposition(ni, bestpp, x, y);
1881 return(bestpp);
1882 }
1883
1884 /*
1885 * Routine to find the pin at (x, y) and return it.
1886 */
io_suefindpinnode(INTBIG x,INTBIG y,NODEPROTO * np,PORTPROTO ** thepp)1887 NODEINST *io_suefindpinnode(INTBIG x, INTBIG y, NODEPROTO *np, PORTPROTO **thepp)
1888 {
1889 REGISTER GEOM *geom;
1890 REGISTER INTBIG sea;
1891 REGISTER NODEINST *ni;
1892 REGISTER PORTPROTO *pp;
1893 INTBIG px, py;
1894
1895 *thepp = NOPORTPROTO;
1896 sea = initsearch(x, x, y, y, np);
1897 for(;;)
1898 {
1899 geom = nextobject(sea);
1900 if (geom == NOGEOM) break;
1901 if (!geom->entryisnode) continue;
1902 ni = geom->entryaddr.ni;
1903
1904 /* find closest port */
1905 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1906 {
1907 /* make sure there is a polygon */
1908 portposition(ni, pp, &px, &py);
1909 if (px == x && py == y)
1910 {
1911 *thepp = pp;
1912 termsearch(sea);
1913 return(ni);
1914 }
1915 }
1916 }
1917 return(NONODEINST);
1918 }
1919
1920 /*
1921 * Routine to find the node at (x, y) and return it.
1922 */
io_suefindnode(INTBIG * x,INTBIG * y,INTBIG ox,INTBIG oy,NODEPROTO * np,NODEINST ** rni,PORTPROTO ** rpp,NODEINST * notthisnode,INTBIG lambda)1923 BOOLEAN io_suefindnode(INTBIG *x, INTBIG *y, INTBIG ox, INTBIG oy,
1924 NODEPROTO *np, NODEINST **rni, PORTPROTO **rpp, NODEINST *notthisnode, INTBIG lambda)
1925 {
1926 REGISTER GEOM *geom;
1927 REGISTER INTBIG sea;
1928 REGISTER NODEINST *ni, *bestni;
1929 INTBIG plx, phx, ply, phy;
1930 REGISTER INTBIG dist, bestdist, thisx, thisy, bestx, besty, slop;
1931 REGISTER PORTPROTO *pp, *bestpp;
1932 static POLYGON *poly = NOPOLYGON;
1933
1934 slop = lambda * 10;
1935 sea = initsearch(*x-slop, *x+slop, *y-slop, *y+slop, np);
1936 bestpp = NOPORTPROTO;
1937 for(;;)
1938 {
1939 geom = nextobject(sea);
1940 if (geom == NOGEOM) break;
1941 if (!geom->entryisnode) continue;
1942 ni = geom->entryaddr.ni;
1943 if (ni == notthisnode) continue;
1944
1945 /* ignore pins */
1946 if (ni->proto == sch_wirepinprim) continue;
1947
1948 /* find closest port */
1949 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1950 {
1951 /* make sure there is a polygon */
1952 (void)needstaticpolygon(&poly, 4, io_tool->cluster);
1953
1954 /* get the polygon describing the port */
1955 shapeportpoly(ni, pp, poly, FALSE);
1956 getbbox(poly, &plx, &phx, &ply, &phy);
1957
1958 /* find out if the line crosses the polygon */
1959 if (*x == ox)
1960 {
1961 /* line is vertical: look for intersection with polygon */
1962 if (ox < plx || ox > phx) continue;
1963 thisx = ox;
1964 thisy = (ply+phy)/2;
1965 } else if (*y == oy)
1966 {
1967 /* line is horizontal: look for intersection with polygon */
1968 if (oy < ply || oy > phy) continue;
1969 thisx = (plx+phx)/2;
1970 thisy = oy;
1971 } else
1972 {
1973 if (!isinside(ox, oy, poly)) continue;
1974 thisx = ox;
1975 thisy = oy;
1976 }
1977
1978 dist = computedistance(ox, oy, thisx, thisy);
1979
1980 /* LINTED "bestdist" used in proper order */
1981 if (bestpp == NOPORTPROTO || dist < bestdist)
1982 {
1983 bestpp = pp;
1984 bestni = ni;
1985 bestdist = dist;
1986 bestx = thisx;
1987 besty = thisy;
1988 }
1989 }
1990 }
1991
1992 /* report the hit */
1993 if (bestpp == NOPORTPROTO) return(FALSE);
1994 *rni = bestni; *rpp = bestpp;
1995 *x = bestx; *y = besty;
1996 return(TRUE);
1997 }
1998
1999 /*
2000 * Routine to find the SUE file "name" on disk, and read it into library "lib".
2001 * Returns NONODEPROTO if the file is not found or not read properly.
2002 */
io_suereadfromdisk(LIBRARY * lib,CHAR * name,void * dia)2003 NODEPROTO *io_suereadfromdisk(LIBRARY *lib, CHAR *name, void *dia)
2004 {
2005 REGISTER INTBIG i, savelineno, filepos, savefilesize;
2006 CHAR suevarname[200], subfilename[300], savesuelastline[MAXLINE], saveorigline[MAXLINE],
2007 lastprogressmsg[MAXLINE], savecurline[MAXLINE], *truename;
2008 REGISTER FILE *f, *savefp;
2009 REGISTER NODEPROTO *proto;
2010
2011 /* look for another "sue" file that describes this cell */
2012 for(i=0; i<io_suenumdirectories; i++)
2013 {
2014 estrcpy(subfilename, io_suedirectories[i]);
2015 estrcat(subfilename, name);
2016 estrcat(subfilename, x_(".sue"));
2017 f = xopen(subfilename, io_filetypesue, x_(""), &truename);
2018 if (f != 0)
2019 {
2020 savefp = io_suefilein;
2021 io_suefilein = f;
2022 for(i=0; i<MAXLINE; i++) savecurline[i] = io_suecurline[i];
2023 estrcpy(saveorigline, io_sueorigline);
2024 estrcpy(savesuelastline, io_suelastline);
2025 estrcpy(lastprogressmsg, DiaGetTextProgress(dia));
2026 estrcpy(suevarname, _("Reading "));
2027 estrcat(suevarname, name);
2028 estrcat(suevarname, x_("..."));
2029 DiaSetTextProgress(dia, suevarname);
2030
2031 estrcpy(subfilename, name);
2032 savefilesize = io_suefilesize;
2033 savelineno = io_suelineno;
2034 io_suefilesize = filesize(io_suefilein);
2035 DiaSetProgress(dia, 0, io_suefilesize);
2036 io_suelineno = 0;
2037 (void)io_suereadfile(lib, subfilename, dia);
2038 xclose(io_suefilein);
2039 io_suefilein = savefp;
2040 io_suefilesize = savefilesize;
2041 io_suelineno = savelineno;
2042 estrcpy(io_suelastline, savesuelastline);
2043 estrcpy(io_sueorigline, saveorigline);
2044 for(i=0; i<MAXLINE; i++) io_suecurline[i] = savecurline[i];
2045 filepos = xtell(io_suefilein);
2046 DiaSetTextProgress(dia, lastprogressmsg);
2047 DiaSetProgress(dia, filepos, io_suefilesize);
2048
2049 /* now try to find the cell in the library */
2050 proto = io_suegetnodeproto(lib, subfilename);
2051 return(proto);
2052 }
2053 }
2054 return(NONODEPROTO);
2055 }
2056
2057 /*
2058 * Routine to read the next line from file "io_suefilein" and break
2059 * it up into space-separated keywords. Returns the number
2060 * of keywords (-1 on EOF)
2061 */
io_suegetnextline(CHAR ** keywords,INTBIG curlydepth,void * dia)2062 INTBIG io_suegetnextline(CHAR **keywords, INTBIG curlydepth, void *dia)
2063 {
2064 CHAR *pt;
2065 REGISTER INTBIG filepos, keypos, lineno;
2066 REGISTER BOOLEAN inblank;
2067
2068 for(lineno=0; ; lineno++)
2069 {
2070 if (io_suelastline[0] == 0)
2071 {
2072 if (xfgets(io_suelastline, MAXLINE, io_suefilein)) return(-1);
2073 io_suelineno++;
2074 if ((io_suelineno%50) == 0)
2075 {
2076 filepos = xtell(io_suefilein);
2077 DiaSetProgress(dia, filepos, io_suefilesize);
2078 }
2079 }
2080 if (lineno == 0)
2081 {
2082 /* first line: use it */
2083 estrcpy(io_suecurline, io_suelastline);
2084 } else
2085 {
2086 /* subsequent line: use it only if a continuation */
2087 if (io_suelastline[0] != '+') break;
2088 estrcat(io_suecurline, &io_suelastline[1]);
2089 }
2090 io_suelastline[0] = 0;
2091 }
2092 estrcpy(io_sueorigline, io_suecurline);
2093
2094 /* parse the line */
2095 inblank = TRUE;
2096 keypos = 0;
2097 for(pt=io_suecurline; *pt != 0; pt++)
2098 {
2099 if (*pt == '{') curlydepth++;
2100 if (*pt == '}') curlydepth--;
2101 if ((*pt == ' ' || *pt == '\t') && curlydepth == 0)
2102 {
2103 *pt = 0;
2104 inblank = TRUE;
2105 } else
2106 {
2107 if (inblank)
2108 {
2109 keywords[keypos++] = pt;
2110 }
2111 inblank = FALSE;
2112 }
2113 }
2114 return(keypos);
2115 }
2116
2117 /*
2118 * Routine to add "directory" to the list of places where SUE files may be found.
2119 */
io_sueadddirectory(CHAR * directory)2120 BOOLEAN io_sueadddirectory(CHAR *directory)
2121 {
2122 REGISTER INTBIG newnumdir, i;
2123 CHAR **newdir;
2124
2125 newnumdir = io_suenumdirectories + 1;
2126 newdir = (CHAR **)emalloc(newnumdir * (sizeof (CHAR *)), io_tool->cluster);
2127 if (newdir == 0) return(TRUE);
2128 for(i=0; i<io_suenumdirectories; i++)
2129 newdir[i] = io_suedirectories[i];
2130 if (allocstring(&newdir[io_suenumdirectories], directory, io_tool->cluster)) return(TRUE);
2131 if (io_suenumdirectories > 0) efree((CHAR *)io_suedirectories);
2132 io_suedirectories = newdir;
2133 io_suenumdirectories = newnumdir;
2134 return(FALSE);
2135 }
2136
io_suecleardirectories(void)2137 void io_suecleardirectories(void)
2138 {
2139 REGISTER INTBIG i;
2140
2141 for(i=0; i<io_suenumdirectories; i++)
2142 efree((CHAR *)io_suedirectories[i]);
2143 if (io_suenumdirectories > 0) efree((CHAR *)io_suedirectories);
2144 io_suenumdirectories = 0;
2145 }
2146
2147 /*************************** OBJECT MANAGEMENT ***************************/
2148
io_suenewwire(void)2149 SUEWIRE *io_suenewwire(void)
2150 {
2151 SUEWIRE *sw;
2152
2153 if (io_suefreewire != NOSUEWIRE)
2154 {
2155 sw = io_suefreewire;
2156 io_suefreewire = sw->nextsuewire;
2157 } else
2158 {
2159 sw = (SUEWIRE *)emalloc(sizeof(SUEWIRE), io_tool->cluster);
2160 }
2161 return(sw);
2162 }
2163
io_suekillwire(SUEWIRE * sw)2164 void io_suekillwire(SUEWIRE *sw)
2165 {
2166 sw->nextsuewire = io_suefreewire;
2167 io_suefreewire = sw;
2168 }
2169
io_suefreewires(SUEWIRE * firstsw)2170 void io_suefreewires(SUEWIRE *firstsw)
2171 {
2172 SUEWIRE *sw, *nextsw;
2173
2174 for(sw = firstsw; sw != NOSUEWIRE; sw = nextsw)
2175 {
2176 nextsw = sw->nextsuewire;
2177 io_suekillwire(sw);
2178 }
2179 }
2180
io_suenewnet(void)2181 SUENET *io_suenewnet(void)
2182 {
2183 SUENET *sn;
2184
2185 if (io_suefreenet != NOSUENET)
2186 {
2187 sn = io_suefreenet;
2188 io_suefreenet = sn->nextsuenet;
2189 } else
2190 {
2191 sn = (SUENET *)emalloc(sizeof(SUENET), io_tool->cluster);
2192 }
2193 sn->label = 0;
2194 return(sn);
2195 }
2196
io_suekillnet(SUENET * sn)2197 void io_suekillnet(SUENET *sn)
2198 {
2199 sn->nextsuenet = io_suefreenet;
2200 io_suefreenet = sn;
2201 if (sn->label != 0) efree(sn->label);
2202 }
2203
io_suefreenets(SUENET * firstsn)2204 void io_suefreenets(SUENET *firstsn)
2205 {
2206 SUENET *sn, *nextsn;
2207
2208 for(sn = firstsn; sn != NOSUENET; sn = nextsn)
2209 {
2210 nextsn = sn->nextsuenet;
2211 io_suekillnet(sn);
2212 }
2213 }
2214