1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: usrctech.c
6 * User interface tool: technology translation module
7 * Written by: Steven M. Rubin, Static Free Software
8 * Schematic conversion written by: Nora Ryan, Schlumberger Palo Alto Research
9 *
10 * Copyright (c) 2000 Static Free Software.
11 *
12 * Electric(tm) is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * Electric(tm) is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with Electric(tm); see the file COPYING. If not, write to
24 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
25 * Boston, Mass 02111-1307, USA.
26 *
27 * Static Free Software
28 * 4119 Alpine Road
29 * Portola Valley, California 94028
30 * info@staticfreesoft.com
31 */
32
33 #include "global.h"
34 #include "efunction.h"
35 #include "egraphics.h"
36 #include "tech.h"
37 #include "tecgen.h"
38 #include "tecschem.h"
39 #include "usr.h"
40 #include "drc.h"
41 #include "usredtec.h" /* for technology documentation */
42 #include <math.h>
43
44 #define TRAN_PIN -1
45 #define TRAN_CELL -2
46
47 /* prototypes for local routines */
48 static PORTPROTO *us_convport(NODEINST*, NODEINST*, PORTPROTO*);
49 static void us_dumpfields(CHAR***, INTBIG, INTBIG, FILE*, CHAR*);
50 static ARCPROTO *us_figurenewaproto(ARCPROTO*, TECHNOLOGY*);
51 static NODEPROTO *us_figurenewnproto(NODEINST*, TECHNOLOGY*);
52 static PORTPROTO *us_tranconvpp(NODEINST*, PORTPROTO*);
53 static PORTPROTO *us_trangetproto(NODEINST*, INTBIG);
54 static INTBIG us_tranismos(NODEINST*);
55 static void us_tranplacenode(NODEINST*, NODEPROTO*, NODEPROTO*, TECHNOLOGY*, TECHNOLOGY*);
56 static NODEPROTO *us_tran_linkage(CHAR*, VIEW*, NODEPROTO*);
57 static void us_tran_logmakearcs(NODEPROTO*, NODEPROTO*);
58 static NODEINST *us_tran_logmakenode(NODEPROTO*, NODEINST*, INTSML, INTSML, NODEPROTO*, TECHNOLOGY*);
59 static void us_tran_logmakenodes(NODEPROTO*, NODEPROTO*, TECHNOLOGY*);
60 static NODEPROTO *us_tran_makelayoutcells(NODEPROTO*, CHAR*, TECHNOLOGY*, TECHNOLOGY*, VIEW*);
61 static BOOLEAN us_tran_makelayoutparts(NODEPROTO*, NODEPROTO*, TECHNOLOGY*, TECHNOLOGY*, VIEW*);
62 static void us_tran_makemanhattan(NODEPROTO*);
63
64 /*
65 * this routine converts cell "oldcell" to one of technology "newtech".
66 * Returns the address of the new cell (NONODEPROTO on error).
67 */
us_convertcell(NODEPROTO * oldcell,TECHNOLOGY * newtech)68 NODEPROTO *us_convertcell(NODEPROTO *oldcell, TECHNOLOGY *newtech)
69 {
70 NODEPROTO *newcell, *np;
71 NODEPROTO *(*localconversion)(NODEPROTO*, TECHNOLOGY*);
72 REGISTER TECHNOLOGY *oldtech, *tech;
73 REGISTER ARCINST *ai;
74 VARIABLE *var;
75
76 /* cannot convert text-only views */
77 if ((oldcell->cellview->viewstate&TEXTVIEW) != 0)
78 {
79 ttyputerr(_("Cannot convert textual views: only layout and schematic"));
80 return(NONODEPROTO);
81 }
82
83 /* separate code if converting to the schematic technology */
84 if (newtech == sch_tech)
85 {
86 /*
87 * Look to see if the technology has its own routine.
88 * Note that it may call some of the functions in this file!
89 */
90 var = getval((INTBIG)el_curtech, VTECHNOLOGY, VADDRESS, x_("TECH_schematic_conversion"));
91 if (var != NOVARIABLE)
92 {
93 localconversion = (NODEPROTO *(*)(NODEPROTO*, TECHNOLOGY*))var->addr;
94 newcell = (*(localconversion))(oldcell, newtech);
95 if (newcell == NONODEPROTO) return(NONODEPROTO);
96 } else /* Convert to schematic here */
97 {
98 /* create cell in new technology */
99 newcell = us_tran_linkage(oldcell->protoname, el_schematicview, oldcell);
100 if (newcell == NONODEPROTO) return(NONODEPROTO);
101
102 /* create the parts in this cell */
103 us_tran_logmakenodes(oldcell, newcell, newtech);
104 us_tran_logmakearcs(oldcell, newcell);
105
106 /* now make adjustments for manhattan-ness */
107 us_tran_makemanhattan(newcell);
108
109 /* set "FIXANG" if reasonable */
110 for(ai = newcell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
111 {
112 if (ai->end[0].xpos == ai->end[1].xpos &&
113 ai->end[0].ypos == ai->end[1].ypos) continue;
114 if ((figureangle(ai->end[0].xpos, ai->end[0].ypos, ai->end[1].xpos,
115 ai->end[1].ypos)%450) == 0) ai->userbits |= FIXANG;
116 }
117 }
118
119 /* after adjusting contents, must re-solve to get proper cell size */
120 (*el_curconstraint->solve)(newcell);
121 } else
122 {
123 /* do general conversion between technologies */
124 oldtech = oldcell->tech;
125
126 /* reset flag that primitive cannot be converted */
127 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
128 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
129 np->temp1 = 0;
130 newcell = us_tran_makelayoutcells(oldcell, oldcell->protoname,
131 oldtech, newtech, el_layoutview);
132 }
133 return(newcell);
134 }
135
136 /*
137 * routine to create a new cell called "newcellname" that is to be the
138 * equivalent to an old cell in "cell". The view type of the new cell is
139 * in "newcellview" and the view type of the old cell is in "cellview"
140 */
us_tran_linkage(CHAR * newcellname,VIEW * newcellview,NODEPROTO * cell)141 NODEPROTO *us_tran_linkage(CHAR *newcellname, VIEW *newcellview, NODEPROTO *cell)
142 {
143 NODEPROTO *newcell;
144 REGISTER CHAR *cellname;
145 REGISTER void *infstr;
146
147 /* create the new cell */
148 if (newcellview->sviewname[0] == 0) cellname = newcellname; else
149 {
150 infstr = initinfstr();
151 addstringtoinfstr(infstr, newcellname);
152 addtoinfstr(infstr, '{');
153 addstringtoinfstr(infstr, newcellview->sviewname);
154 addtoinfstr(infstr, '}');
155 cellname = returninfstr(infstr);
156 }
157 newcell = us_newnodeproto(cellname, cell->lib);
158 if (newcell == NONODEPROTO)
159 ttyputmsg(_("Could not create cell: %s"), cellname); else
160 ttyputmsg(_("Creating new cell: %s"), cellname);
161 return(newcell);
162 }
163
164 /********************** CODE FOR CONVERSION TO SCHEMATIC **********************/
165
us_tran_logmakenodes(NODEPROTO * cell,NODEPROTO * newcell,TECHNOLOGY * newtech)166 void us_tran_logmakenodes(NODEPROTO *cell, NODEPROTO *newcell, TECHNOLOGY *newtech)
167 {
168 NODEINST *ni, *schemni;
169 NODEPROTO *onp;
170 PORTEXPINST *pexp;
171 REGISTER PORTPROTO *pp, *pp2;
172 REGISTER PORTARCINST *pi;
173 REGISTER VARIABLE *var;
174 INTSML rotate, trans;
175 INTBIG type, len, wid, lambda, xoff, yoff, i, size;
176 UINTBIG descript[TEXTDESCRIPTSIZE];
177
178 /*
179 * for each node, create a new node in the newcell, of the correct
180 * logical type. Also, store a pointer to the new node in the old
181 * node's temp1. This is used in the arc translation part of the
182 * program to find the new ends of each arc.
183 */
184 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
185 {
186 type = us_tranismos(ni);
187 switch (type)
188 {
189 case TRAN_PIN:
190 /* compute new x, y coordinates */
191 schemni = us_tran_logmakenode(sch_wirepinprim, ni, 0, 0, newcell, newtech);
192 break;
193 case TRAN_CELL:
194 FOR_CELLGROUP(onp, ni->proto)
195 if (onp->cellview == el_schematicview) break;
196 if (onp == NONODEPROTO)
197 {
198 onp = us_convertcell(ni->proto, newtech);
199 if (onp == NONODEPROTO) break;
200 }
201 schemni = us_tran_logmakenode(onp, ni, ni->transpose, ni->rotation,
202 newcell, newtech);
203 break;
204 case NPUNKNOWN: /* could not match it */
205 schemni = NONODEINST;
206 break;
207 default: /* always a transistor */
208 rotate = ni->rotation;
209 trans = ni->transpose;
210 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
211 if (pi->proto == ni->proto->firstportproto) break;
212 if (pi != NOPORTARCINST)
213 {
214 if (trans == 0) rotate += 900; else rotate += 2700;
215 trans = 1 - trans;
216 }
217 rotate += 2700;
218 while (rotate >= 3600) rotate -= 3600;
219 schemni = us_tran_logmakenode(sch_transistorprim, ni, trans, rotate,
220 newcell, newtech);
221
222 /* set the type of the transistor */
223 switch (type)
224 {
225 case NPTRAPMOS: schemni->userbits |= TRANPMOS; break;
226 case NPTRANMOS: schemni->userbits |= TRANNMOS; break;
227 case NPTRADMOS: schemni->userbits |= TRANDMOS; break;
228 case NPTRAPNP: schemni->userbits |= TRANPNP; break;
229 case NPTRANPN: schemni->userbits |= TRANNPN; break;
230 case NPTRANJFET: schemni->userbits |= TRANNJFET; break;
231 case NPTRAPJFET: schemni->userbits |= TRANPJFET; break;
232 case NPTRADMES: schemni->userbits |= TRANDMES; break;
233 case NPTRAEMES: schemni->userbits |= TRANEMES; break;
234 }
235
236 /* add in the size */
237 transistorsize(ni, &len, &wid);
238 if (len >= 0 && wid >= 0)
239 {
240 TDCLEAR(descript);
241 defaulttextsize(3, descript);
242 lambda = lambdaofnode(ni);
243 if (type == NPTRAPMOS || type == NPTRANMOS || type == NPTRADMOS ||
244 type == NPTRANJFET || type == NPTRAPJFET ||
245 type == NPTRADMES || type == NPTRAEMES)
246 {
247 /* set length/width */
248 us_getlenwidoffset(schemni, descript, &xoff, &yoff);
249 var = setvalkey((INTBIG)schemni, VNODEINST, el_attrkey_length,
250 len*WHOLE/lambda, VFRACT|VDISPLAY);
251 if (var != NOVARIABLE)
252 {
253 TDCOPY(var->textdescript, descript);
254 size = TDGETSIZE(var->textdescript);
255 i = TXTGETPOINTS(size);
256 if (i > 3) size = TXTSETPOINTS(i-2); else
257 {
258 i = TXTGETQLAMBDA(size);
259 if (i > 3) size = TXTSETQLAMBDA(i-2);
260 }
261 TDSETSIZE(var->textdescript, size);
262 TDSETOFF(var->textdescript, TDGETXOFF(descript)-xoff,
263 TDGETYOFF(descript)-yoff);
264 }
265 var = setvalkey((INTBIG)schemni, VNODEINST, el_attrkey_width,
266 wid*WHOLE/lambda, VFRACT|VDISPLAY);
267 if (var != NOVARIABLE)
268 {
269 TDCOPY(var->textdescript, descript);
270 TDSETOFF(var->textdescript, TDGETXOFF(descript)+xoff,
271 TDGETYOFF(descript)+yoff);
272 }
273 } else
274 {
275 /* set area */
276 var = setvalkey((INTBIG)schemni, VNODEINST, el_attrkey_area,
277 len*WHOLE/lambda, VFRACT|VDISPLAY);
278 if (var != NOVARIABLE)
279 TDCOPY(var->textdescript, descript);
280 }
281 }
282 }
283
284 /* store the new node in the old node */
285 ni->temp1 = (INTBIG)schemni;
286
287 /* reexport ports */
288 if (schemni != NONODEINST)
289 {
290 for(pexp = ni->firstportexpinst; pexp != NOPORTEXPINST; pexp = pexp->nextportexpinst)
291 {
292 pp = us_tranconvpp(ni, pexp->proto);
293 if (pp == NOPORTPROTO) continue;
294 pp2 = newportproto(newcell, schemni, pp, pexp->exportproto->protoname);
295 if (pp2 == NOPORTPROTO) return;
296 pp2->userbits = (pp2->userbits & ~STATEBITS) |
297 (pexp->exportproto->userbits & STATEBITS);
298 TDCOPY(pp2->textdescript, pexp->exportproto->textdescript);
299 if (copyvars((INTBIG)pexp->exportproto, VPORTPROTO, (INTBIG)pp2, VPORTPROTO, FALSE))
300 return;
301 }
302 endobjectchange((INTBIG)schemni, VNODEINST);
303 }
304 }
305 }
306
us_tran_logmakenode(NODEPROTO * prim,NODEINST * orig,INTSML trn,INTSML rot,NODEPROTO * newcell,TECHNOLOGY * newtech)307 NODEINST *us_tran_logmakenode(NODEPROTO *prim, NODEINST *orig, INTSML trn, INTSML rot,
308 NODEPROTO *newcell, TECHNOLOGY *newtech)
309 {
310 REGISTER INTBIG cx, cy, scaleu, scaled;
311 INTBIG sx, sy;
312 REGISTER NODEINST *newni;
313 REGISTER TECHNOLOGY *oldtech;
314
315 scaleu = el_curlib->lambda[newtech->techindex];
316 oldtech = orig->proto->tech;
317 scaled = el_curlib->lambda[oldtech->techindex];
318 cx = muldiv((orig->lowx+orig->highx)/2, scaleu, scaled) - (prim->highx-prim->lowx)/2;
319 cy = muldiv((orig->lowy+orig->highy)/2, scaleu, scaled) - (prim->highy-prim->lowy)/2;
320 defaultnodesize(prim, &sx, &sy);
321 newni = newnodeinst(prim, cx, cx+sx, cy, cy+sy, trn, rot, newcell);
322 return(newni);
323 }
324
us_tran_logmakearcs(NODEPROTO * cell,NODEPROTO * newcell)325 void us_tran_logmakearcs(NODEPROTO *cell, NODEPROTO *newcell)
326 {
327 PORTPROTO *oldpp1, *oldpp2, *newpp1, *newpp2;
328 ARCINST *oldai, *newai;
329 NODEINST *newni1, *newni2;
330 INTBIG x1, x2, y1, y2, bits;
331
332 /*
333 * for each arc in cell, find the ends in the new technology, and
334 * make a new arc to connect them in the new cell.
335 */
336 for(oldai = cell->firstarcinst; oldai != NOARCINST; oldai = oldai->nextarcinst)
337 {
338 newni1 = (NODEINST *)oldai->end[0].nodeinst->temp1;
339 newni2 = (NODEINST *)oldai->end[1].nodeinst->temp1;
340 if (newni1 == NONODEINST || newni2 == NONODEINST) continue;
341 oldpp1 = oldai->end[0].portarcinst->proto;
342 oldpp2 = oldai->end[1].portarcinst->proto;
343
344 /* find the logical portproto for the first end node */
345 newpp1 = us_tranconvpp(oldai->end[0].nodeinst, oldpp1);
346 if (newpp1 == NOPORTPROTO) continue;
347
348 /* find the logical portproto for the second end node */
349 newpp2 = us_tranconvpp(oldai->end[1].nodeinst, oldpp2);
350 if (newpp2 == NOPORTPROTO) continue;
351
352 /* find the endpoints of the arc */
353 portposition(newni1, newpp1, &x1, &y1);
354 portposition(newni2, newpp2, &x2, &y2);
355
356 /* create the new arc */
357 bits = us_makearcuserbits(sch_wirearc) & ~(FIXANG|FIXED);
358 newai = newarcinst(sch_wirearc, defaultarcwidth(sch_wirearc), bits,
359 newni1, newpp1, x1, y1, newni2, newpp2, x2, y2, newcell);
360 if (newai == NOARCINST) break;
361 endobjectchange((INTBIG)newai, VARCINST);
362 }
363 }
364
365 #define MAXADJUST 5
366
us_tran_makemanhattan(NODEPROTO * newcell)367 void us_tran_makemanhattan(NODEPROTO *newcell)
368 {
369 REGISTER NODEINST *ni;
370 REGISTER PORTARCINST *pi;
371 REGISTER ARCINST *ai;
372 REGISTER INTBIG e, count, i, j;
373 REGISTER INTBIG dist, bestdist, bestx, besty, xp, yp;
374 INTBIG x[MAXADJUST], y[MAXADJUST];
375
376 /* adjust this cell */
377 for(ni = newcell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
378 {
379 if (ni->proto->primindex == 0) continue;
380 if (((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH) != NPPIN) continue;
381
382 /* see if this pin can be adjusted so that all wires are manhattan */
383 count = 0;
384 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
385 {
386 ai = pi->conarcinst;
387 if (ai->end[0].nodeinst == ni)
388 {
389 if (ai->end[1].nodeinst == ni) continue;
390 e = 1;
391 } else e = 0;
392 x[count] = ai->end[e].xpos; y[count] = ai->end[e].ypos;
393 count++;
394 if (count >= MAXADJUST) break;
395 }
396 if (count == 0) continue;
397
398 /* now adjust for all these points */
399 xp = (ni->lowx + ni->highx) / 2; yp = (ni->lowy + ni->highy) / 2;
400 bestdist = MAXINTBIG;
401 for(i=0; i<count; i++) for(j=0; j<count; j++)
402 {
403 dist = abs(xp - x[i]) + abs(yp - y[j]);
404 if (dist > bestdist) continue;
405 bestdist = dist;
406 bestx = x[i]; besty = y[j];
407 }
408
409 /* if there was a better place, move the node */
410 if (bestdist != MAXINTBIG)
411 modifynodeinst(ni, bestx-xp, besty-yp, bestx-xp, besty-yp, 0, 0);
412 }
413 }
414
415 /* find the logical portproto corresponding to the mos portproto of ni */
us_tranconvpp(NODEINST * ni,PORTPROTO * mospp)416 PORTPROTO *us_tranconvpp(NODEINST *ni, PORTPROTO *mospp)
417 {
418 PORTPROTO *schempp, *pp;
419 NODEINST *schemni;
420 INTBIG port;
421
422 schemni = (NODEINST *)ni->temp1;
423
424 switch (us_tranismos(schemni))
425 {
426 case TRAN_PIN:
427 schempp = schemni->proto->firstportproto;
428 break;
429 case TRAN_CELL:
430 schempp = getportproto(schemni->proto, mospp->protoname);
431 break;
432 default: /* transistor */
433 for(port = 1, pp = ni->proto->firstportproto; pp != NOPORTPROTO;
434 pp = pp->nextportproto, port++)
435 if (pp == mospp) break; /* partic. port in MOS */
436 schempp = us_trangetproto(schemni, port);
437 break;
438 }
439 return(schempp);
440 }
441
442 /*
443 * this routine figures out if the current nodeinst is a MOS component
444 * (a wire or transistor). If it's a transistor, return corresponding
445 * define from efunction.h; if it's a passive connector, return TRAN_PIN;
446 * if it's a cell, return TRAN_CELL; else return NPUNKNOWN.
447 */
us_tranismos(NODEINST * ni)448 INTBIG us_tranismos(NODEINST *ni)
449 {
450 INTBIG fun;
451
452 if (ni->proto->primindex == 0) return(TRAN_CELL);
453 fun = (ni->proto->userbits & NFUNCTION) >> NFUNCTIONSH;
454 switch(fun)
455 {
456 case NPTRANMOS: case NPTRA4NMOS:
457 case NPTRADMOS: case NPTRA4DMOS:
458 case NPTRAPMOS: case NPTRA4PMOS:
459 case NPTRANPN: case NPTRA4NPN:
460 case NPTRAPNP: case NPTRA4PNP:
461 case NPTRANJFET: case NPTRA4NJFET:
462 case NPTRAPJFET: case NPTRA4PJFET:
463 case NPTRADMES: case NPTRA4DMES:
464 case NPTRAEMES: case NPTRA4EMES:
465 case NPTRANSREF:
466 return(fun);
467 case NPPIN:
468 case NPCONTACT:
469 case NPNODE:
470 case NPCONNECT:
471 case NPSUBSTRATE:
472 case NPWELL:
473 return(TRAN_PIN);
474 }
475 return(NPUNKNOWN);
476 }
477
us_trangetproto(NODEINST * ni,INTBIG port)478 PORTPROTO *us_trangetproto(NODEINST *ni, INTBIG port)
479 {
480 PORTPROTO *pp;
481 INTBIG count = port, i;
482
483 if (count == 4) count = 3; else
484 if (count == 3) count = 1;
485
486 for(i = 1, pp = ni->proto->firstportproto; pp != NOPORTPROTO && i < count;
487 pp = pp->nextportproto, i++) /* get portproto for schematic */
488 ;
489 return(pp);
490 }
491
492 /************************* CODE FOR CONVERSION TO LAYOUT *************************/
493
494 /*
495 * routine to recursively descend from cell "oldcell" and find subcells that
496 * have to be converted. When all subcells have been converted, convert this
497 * one into a new one called "newcellname". The technology for the old cell
498 * is "oldtech" and the technology to use for the new cell is "newtech". The
499 * old view type is "oldview" and the new view type is "nview".
500 */
us_tran_makelayoutcells(NODEPROTO * oldcell,CHAR * newcellname,TECHNOLOGY * oldtech,TECHNOLOGY * newtech,VIEW * nview)501 NODEPROTO *us_tran_makelayoutcells(NODEPROTO *oldcell, CHAR *newcellname,
502 TECHNOLOGY *oldtech, TECHNOLOGY *newtech, VIEW *nview)
503 {
504 REGISTER NODEPROTO *newcell, *rnp;
505 REGISTER INTBIG bits;
506 REGISTER NODEINST *ni;
507 REGISTER ARCINST *ai;
508 CHAR *str;
509
510 /* first convert the sub-cells */
511 for(ni = oldcell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
512 {
513 /* ignore primitives */
514 if (ni->proto->primindex != 0) continue;
515
516 /* ignore recursive references (showing icon in contents) */
517 if (isiconof(ni->proto, oldcell)) continue;
518
519 /* ignore cells with associations */
520 FOR_CELLGROUP(rnp, ni->proto)
521 if (rnp->cellview == nview) break;
522 if (rnp != NONODEPROTO) continue;
523
524 /* make up a name for this cell */
525 (void)allocstring(&str, ni->proto->protoname, el_tempcluster);
526
527 (void)us_tran_makelayoutcells(ni->proto, str, oldtech, newtech, nview);
528 efree(str);
529 }
530
531 /* create the cell and fill it with parts */
532 newcell = us_tran_linkage(newcellname, nview, oldcell);
533 if (newcell == NONODEPROTO) return(NONODEPROTO);
534 if (us_tran_makelayoutparts(oldcell, newcell, oldtech, newtech, nview))
535 {
536 /* adjust for maximum Manhattan-ness */
537 us_tran_makemanhattan(newcell);
538
539 /* reset shrinkage values and constraints to defaults (is this needed? !!!) */
540 for(ai = newcell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
541 {
542 bits = us_makearcuserbits(ai->proto);
543 if ((bits&FIXED) != 0) ai->userbits |= FIXED;
544 if ((bits&FIXANG) != 0) ai->userbits |= FIXANG;
545 (void)setshrinkvalue(ai, FALSE);
546 }
547 }
548
549 return(newcell);
550 }
551
552 /*
553 * routine to create a new cell in "newcell" from the contents of an old cell
554 * in "oldcell". The technology for the old cell is "oldtech" and the
555 * technology to use for the new cell is "newtech".
556 */
us_tran_makelayoutparts(NODEPROTO * oldcell,NODEPROTO * newcell,TECHNOLOGY * oldtech,TECHNOLOGY * newtech,VIEW * nview)557 BOOLEAN us_tran_makelayoutparts(NODEPROTO *oldcell, NODEPROTO *newcell,
558 TECHNOLOGY *oldtech, TECHNOLOGY *newtech, VIEW *nview)
559 {
560 REGISTER NODEPROTO *newnp;
561 REGISTER NODEINST *ni, *end1, *end2;
562 ARCPROTO *ap, *newap;
563 ARCINST *ai;
564 REGISTER PORTPROTO *mospp1, *mospp2, *schempp1, *schempp2;
565 INTBIG x1, y1, x2, y2, lx1, hx1, ly1, hy1, lx2, hx2, ly2, hy2, tx1, ty1, tx2, ty2;
566 REGISTER INTBIG newwid, newbits, oldlambda, newlambda, defwid, curwid;
567 REGISTER INTBIG badarcs, i, j;
568 REGISTER BOOLEAN univarcs;
569 static POLYGON *poly1 = NOPOLYGON, *poly2 = NOPOLYGON;
570
571 /* get a polygon */
572 (void)needstaticpolygon(&poly1, 4, us_tool->cluster);
573 (void)needstaticpolygon(&poly2, 4, us_tool->cluster);
574
575 /* get lambda values */
576 oldlambda = el_curlib->lambda[oldtech->techindex];
577 newlambda = el_curlib->lambda[newtech->techindex];
578
579 /* first convert the nodes */
580 for(ni = oldcell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
581 ni->temp1 = 0;
582 for(ni = oldcell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
583 {
584 /* handle sub-cells */
585 if (ni->proto->primindex == 0)
586 {
587 FOR_CELLGROUP(newnp, ni->proto)
588 if (newnp->cellview == nview) break;
589 if (newnp == NONODEPROTO)
590 {
591 ttyputerr(_("No equivalent cell for %s"), describenodeproto(ni->proto));
592 continue;
593 }
594 us_tranplacenode(ni, newnp, newcell, oldtech, newtech);
595 continue;
596 }
597
598 /* handle primitives */
599 if (ni->proto == gen_cellcenterprim) continue;
600 newnp = us_figurenewnproto(ni, newtech);
601 us_tranplacenode(ni, newnp, newcell, oldtech, newtech);
602 }
603
604 /*
605 * for each arc in cell, find the ends in the new technology, and
606 * make a new arc to connect them in the new cell
607 */
608 badarcs = 0;
609 univarcs = FALSE;
610 for(ai = oldcell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
611 {
612 /* get the nodes and ports on the two ends of the arc */
613 end1 = (NODEINST *)ai->end[0].nodeinst->temp1;
614 end2 = (NODEINST *)ai->end[1].nodeinst->temp1;
615 if (end1 == 0 || end2 == 0) continue;
616 mospp1 = ai->end[0].portarcinst->proto;
617 mospp2 = ai->end[1].portarcinst->proto;
618 schempp1 = us_convport(ai->end[0].nodeinst, end1, mospp1);
619 schempp2 = us_convport(ai->end[1].nodeinst, end2, mospp2);
620
621 /* set bits in arc prototypes that can make the connection */
622 for(ap = newtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
623 ap->userbits &= ~CANCONNECT;
624 for(i=0; schempp1->connects[i] != NOARCPROTO; i++)
625 {
626 for(j=0; schempp2->connects[j] != NOARCPROTO; j++)
627 {
628 if (schempp1->connects[i] != schempp2->connects[j]) continue;
629 schempp1->connects[i]->userbits |= CANCONNECT;
630 break;
631 }
632 }
633
634 /* compute arc type and see if it is acceptable */
635 newap = us_figurenewaproto(ai->proto, newtech);
636 if (newap->tech == newtech && (newap->userbits&CANCONNECT) == 0)
637 {
638 /* not acceptable: see if there are any valid ones */
639 for(newap = newtech->firstarcproto; newap != NOARCPROTO; newap = newap->nextarcproto)
640 if ((newap->userbits&CANCONNECT) != 0) break;
641
642 /* none are valid: use universal */
643 if (newap == NOARCPROTO) newap = gen_universalarc;
644 }
645
646 /* determine new arc width */
647 newbits = ai->userbits;
648 if (newap == gen_universalarc)
649 {
650 newwid = 0;
651 univarcs = TRUE;
652 newbits &= ~(FIXED | FIXANG);
653 } else
654 {
655 defwid = ai->proto->nominalwidth - arcprotowidthoffset(ai->proto);
656 curwid = ai->width - arcwidthoffset(ai);
657 newwid = muldiv(newap->nominalwidth - arcprotowidthoffset(newap), curwid, defwid) +
658 arcprotowidthoffset(newap);
659 if (newwid <= 0) newwid = defaultarcwidth(newap);
660 }
661
662 /* find the endpoints of the arc */
663 x1 = muldiv(ai->end[0].xpos, newlambda, oldlambda);
664 y1 = muldiv(ai->end[0].ypos, newlambda, oldlambda);
665 shapeportpoly(end1, schempp1, poly1, FALSE);
666 x2 = muldiv(ai->end[1].xpos, newlambda, oldlambda);
667 y2 = muldiv(ai->end[1].ypos, newlambda, oldlambda);
668 shapeportpoly(end2, schempp2, poly2, FALSE);
669
670 /* see if the new arc can connect without end adjustment */
671 if (!isinside(x1, y1, poly1) || !isinside(x2, y2, poly2))
672 {
673 /* arc cannot be run exactly ... presume port centers */
674 portposition(end1, schempp1, &x1, &y1);
675 portposition(end2, schempp2, &x2, &y2);
676 if ((newbits & FIXANG) != 0)
677 {
678 /* old arc was fixed-angle so look for a similar-angle path */
679 reduceportpoly(poly1, end1, schempp1, newwid-arcprotowidthoffset(newap), -1);
680 getbbox(poly1, &lx1, &hx1, &ly1, &hy1);
681 reduceportpoly(poly2, end2, schempp2, newwid-arcprotowidthoffset(newap), -1);
682 getbbox(poly2, &lx2, &hx2, &ly2, &hy2);
683 if (!arcconnects(((ai->userbits&AANGLE) >> AANGLESH) * 10, lx1, hx1, ly1, hy1,
684 lx2, hx2, ly2, hy2, &tx1, &ty1, &tx2, &ty2)) badarcs++; else
685 {
686 x1 = tx1; y1 = ty1;
687 x2 = tx2; y2 = ty2;
688 }
689 }
690 }
691 /* create the new arc */
692 if (newarcinst(newap, newwid, newbits, end1, schempp1, x1, y1,
693 end2, schempp2, x2, y2, newcell) == NOARCINST)
694 {
695 ttyputmsg(_("Cell %s: can't run arc from node %s port %s at (%s,%s)"),
696 describenodeproto(newcell), describenodeinst(end1),
697 schempp1->protoname, latoa(x1, 0), latoa(y1, 0));
698 ttyputmsg(_(" to node %s port %s at (%s,%s)"), describenodeinst(end2),
699 schempp2->protoname, latoa(x2, 0), latoa(y2, 0));
700 }
701 }
702
703 /* print warning if arcs were made nonmanhattan */
704 if (badarcs != 0)
705 ttyputmsg(_("WARNING: %ld %s made not-fixed-angle in cell %s"), badarcs,
706 makeplural(_("arc"), badarcs), describenodeproto(newcell));
707 return(univarcs);
708 }
709
us_tranplacenode(NODEINST * ni,NODEPROTO * newnp,NODEPROTO * newcell,TECHNOLOGY * oldtech,TECHNOLOGY * newtech)710 void us_tranplacenode(NODEINST *ni, NODEPROTO *newnp, NODEPROTO *newcell,
711 TECHNOLOGY *oldtech, TECHNOLOGY *newtech)
712 {
713 INTBIG lx, ly, hx, hy, nlx, nly, nhx, nhy, bx, by, length, width;
714 REGISTER INTBIG i, len, newsx, newsy, x1, y1, newlx, newhx, newly, newhy, *newtrace,
715 oldlambda, newlambda, thissizex, thissizey, defsizex, defsizey;
716 XARRAY trans;
717 REGISTER INTSML trn;
718 REGISTER PORTEXPINST *pexp;
719 REGISTER NODEINST *newni;
720 REGISTER PORTPROTO *pp, *pp2;
721 REGISTER VARIABLE *var;
722
723 oldlambda = el_curlib->lambda[oldtech->techindex];
724 newlambda = el_curlib->lambda[newtech->techindex];
725
726 /* scale edge offsets if this is a primitive */
727 trn = ni->transpose;
728 if (ni->proto->primindex != 0)
729 {
730 /* get offsets for new node type */
731 nodeprotosizeoffset(newnp, &nlx, &nly, &nhx, &nhy, NONODEPROTO);
732
733 /* special case for schematic transistors: get size from description */
734 if (((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH) == NPTRANS)
735 {
736 transistorsize(ni, &length, &width);
737 if (length < 0) length = newnp->highy - newnp->lowy - nly - nhy;
738 if (width < 0) width = newnp->highx - newnp->lowx - nlx - nhx;
739 lx = (ni->lowx + ni->highx - width) / 2;
740 hx = (ni->lowx + ni->highx + width) / 2;
741 ly = (ni->lowy + ni->highy - length) / 2;
742 hy = (ni->lowy + ni->highy + length) / 2;
743 trn = 1 - trn;
744
745 /* compute scaled size for new node */
746 newsx = muldiv(hx - lx, newlambda, oldlambda);
747 newsy = muldiv(hy - ly, newlambda, oldlambda);
748 } else
749 {
750 /* determine this node's percentage of the default node's size */
751 nodeprotosizeoffset(ni->proto, &lx, &ly, &hx, &hy, NONODEPROTO);
752 defsizex = (ni->proto->highx - hx) - (ni->proto->lowx + lx);
753 defsizey = (ni->proto->highy - hy) - (ni->proto->lowy + ly);
754
755 nodesizeoffset(ni, &lx, &ly, &hx, &hy);
756 thissizex = (ni->highx - hx) - (ni->lowx + lx);
757 thissizey = (ni->highy - hy) - (ni->lowy + ly);
758
759 /* compute size of new node that is the same percentage of its default */
760 newsx = muldiv((newnp->highx - nhx) - (newnp->lowx + nlx), thissizex, defsizex);
761 newsy = muldiv((newnp->highy - nhy) - (newnp->lowy + nly), thissizey, defsizey);
762
763 /* determine location of new node */
764 lx = ni->lowx + lx; hx = ni->highx - hx;
765 ly = ni->lowy + ly; hy = ni->highy - hy;
766 }
767
768 /* compute center of old node */
769 x1 = muldiv((hx + lx) / 2, newlambda, oldlambda);
770 y1 = muldiv((hy + ly) / 2, newlambda, oldlambda);
771
772 /* compute bounds of the new node */
773 newlx = x1 - newsx/2 - nlx; newhx = newlx + newsx + nlx + nhx;
774 newly = y1 - newsy/2 - nly; newhy = newly + newsy + nly + nhy;
775 } else
776 {
777 x1 = (newnp->highx+newnp->lowx)/2 - (ni->proto->highx+ni->proto->lowx)/2;
778 y1 = (newnp->highy+newnp->lowy)/2 - (ni->proto->highy+ni->proto->lowy)/2;
779 makeangle(ni->rotation, ni->transpose, trans);
780 xform(x1, y1, &bx, &by, trans);
781 newlx = ni->lowx + bx; newhx = ni->highx + bx;
782 newly = ni->lowy + by; newhy = ni->highy + by;
783 newlx += ((newhx-newlx) - (newnp->highx-newnp->lowx)) / 2;
784 newhx = newlx + newnp->highx - newnp->lowx;
785 newly += ((newhy-newly) - (newnp->highy-newnp->lowy)) / 2;
786 newhy = newly + newnp->highy - newnp->lowy;
787 }
788
789 /* create the node */
790 newni = newnodeinst(newnp, newlx, newhx, newly, newhy, trn, ni->rotation, newcell);
791 if (newni == NONODEINST) return;
792 newni->userbits |= (ni->userbits & (NEXPAND | WIPED | NSHORT));
793 ni->temp1 = (INTBIG)newni;
794 (void)copyvars((INTBIG)ni, VNODEINST, (INTBIG)newni, VNODEINST, FALSE);
795
796 /* copy "trace" information if there is any */
797 var = gettrace(ni);
798 if (var != NOVARIABLE)
799 {
800 len = getlength(var);
801 newtrace = emalloc((len * SIZEOFINTBIG), el_tempcluster);
802 if (newtrace == 0) return;
803 for(i=0; i<len; i++)
804 newtrace[i] = muldiv(((INTBIG *)var->addr)[i], newlambda, oldlambda);
805 (void)setvalkey((INTBIG)newni, VNODEINST, el_trace_key, (INTBIG)newtrace,
806 VINTEGER|VISARRAY|(len<<VLENGTHSH));
807 efree((CHAR *)newtrace);
808 }
809 endobjectchange((INTBIG)newni, VNODEINST);
810
811 /* re-export any ports on the node */
812 for(pexp = ni->firstportexpinst; pexp != NOPORTEXPINST; pexp = pexp->nextportexpinst)
813 {
814 pp = us_convport(ni, newni, pexp->proto);
815 pp2 = newportproto(newcell, newni, pp, pexp->exportproto->protoname);
816 if (pp2 == NOPORTPROTO) return;
817 pp2->userbits = (pp2->userbits & ~STATEBITS) | (pexp->exportproto->userbits & STATEBITS);
818 TDCOPY(pp2->textdescript, pexp->exportproto->textdescript);
819 if (copyvars((INTBIG)pexp->exportproto, VPORTPROTO, (INTBIG)pp2, VPORTPROTO, FALSE))
820 return;
821 }
822 }
823
824 /*
825 * routine to determine the port to use on node "newni" assuming that it should
826 * be the same as port "oldpp" on equivalent node "ni"
827 */
us_convport(NODEINST * ni,NODEINST * newni,PORTPROTO * oldpp)828 PORTPROTO *us_convport(NODEINST *ni, NODEINST *newni, PORTPROTO *oldpp)
829 {
830 REGISTER PORTPROTO *pp, *npp;
831 REGISTER INTBIG oldfun, newfun;
832
833 if (newni->proto->primindex == 0)
834 {
835 /* cells can associate by comparing names */
836 pp = getportproto(newni->proto, oldpp->protoname);
837 if (pp != NOPORTPROTO) return(pp);
838 }
839
840 /* if functions are different, handle some special cases */
841 oldfun = (ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH;
842 newfun = (newni->proto->userbits&NFUNCTION) >> NFUNCTIONSH;
843 if (oldfun != newfun)
844 {
845 if (oldfun == NPTRANS && isfet(newni->geom))
846 {
847 /* converting from stick-figure to layout */
848 pp = ni->proto->firstportproto; npp = newni->proto->firstportproto;
849 if (pp == oldpp) return(npp);
850 pp = pp->nextportproto; npp = npp->nextportproto;
851 if (pp == oldpp) return(npp);
852 pp = pp->nextportproto; npp = npp->nextportproto->nextportproto;
853 if (pp == oldpp) return(npp);
854 }
855 }
856
857 /* associate by position in port list */
858 for(pp = ni->proto->firstportproto, npp = newni->proto->firstportproto;
859 pp != NOPORTPROTO && npp != NOPORTPROTO;
860 pp = pp->nextportproto, npp = npp->nextportproto)
861 if (pp == oldpp) return(npp);
862
863 /* special case again: one-port capacitors are OK */
864 if (oldfun == NPCAPAC && newfun == NPCAPAC) return(newni->proto->firstportproto);
865
866 /* association has failed: assume the first port */
867 ttyputmsg(_("No port association between %s, port %s and %s"),
868 describenodeproto(ni->proto), oldpp->protoname,
869 describenodeproto(newni->proto));
870 return(newni->proto->firstportproto);
871 }
872
873 /*
874 * routine to determine the equivalent prototype in technology "newtech" for
875 * node prototype "oldnp".
876 */
us_figurenewaproto(ARCPROTO * oldap,TECHNOLOGY * newtech)877 ARCPROTO *us_figurenewaproto(ARCPROTO *oldap, TECHNOLOGY *newtech)
878 {
879 REGISTER INTBIG type;
880 REGISTER ARCPROTO *ap;
881
882 /* schematic wires become universal arcs */
883 if (oldap == sch_wirearc) return(gen_universalarc);
884
885 /* determine the proper association of this node */
886 type = (oldap->userbits & AFUNCTION) >> AFUNCTIONSH;
887 for(ap = newtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
888 if ((INTBIG)((ap->userbits&AFUNCTION) >> AFUNCTIONSH) == type) break;
889 if (ap == NOARCPROTO)
890 {
891 ttyputmsg(_("No equivalent arc for %s"), describearcproto(oldap));
892 return(oldap);
893 }
894 return(ap);
895 }
896
897 /*
898 * routine to determine the equivalent prototype in technology "newtech" for
899 * node prototype "oldnp".
900 */
us_figurenewnproto(NODEINST * oldni,TECHNOLOGY * newtech)901 NODEPROTO *us_figurenewnproto(NODEINST *oldni, TECHNOLOGY *newtech)
902 {
903 REGISTER INTBIG type, i, j, k;
904 REGISTER ARCPROTO *ap, *oap;
905 REGISTER INTBIG important, funct;
906 REGISTER NODEPROTO *np, *rnp, *oldnp;
907 REGISTER NODEINST *ni;
908 NODEINST node;
909 static POLYGON *poly = NOPOLYGON;
910
911 /* get a polygon */
912 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
913
914 /* easy translation if complex or already in the proper technology */
915 oldnp = oldni->proto;
916 if (oldnp->primindex == 0 || oldnp->tech == newtech) return(oldnp);
917
918 /* if this is a layer node, check the layer functions */
919 type = nodefunction(oldni);
920 if (type == NPNODE)
921 {
922 /* get the polygon describing the first box of the old node */
923 (void)nodepolys(oldni, 0, NOWINDOWPART);
924 shapenodepoly(oldni, 0, poly);
925 important = LFTYPE | LFPSEUDO | LFNONELEC;
926 funct = layerfunction(oldnp->tech, poly->layer) & important;
927
928 /* now search for that function in the other technology */
929 for(np = newtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
930 {
931 if (((np->userbits&NFUNCTION) >> NFUNCTIONSH) != NPNODE) continue;
932 ni = &node; initdummynode(ni);
933 ni->proto = np;
934 (void)nodepolys(ni, 0, NOWINDOWPART);
935 shapenodepoly(ni, 0, poly);
936 if ((layerfunction(newtech, poly->layer)&important) == funct)
937 return(np);
938 }
939 }
940
941 /* see if one node in the new technology has the same function */
942 for(i = 0, np = newtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
943 if ((INTBIG)((np->userbits&NFUNCTION) >> NFUNCTIONSH) == type)
944 {
945 rnp = np; i++;
946 }
947 if (i == 1) return(rnp);
948
949 /* if there are too many matches, determine which is proper from arcs */
950 if (i > 1)
951 {
952 for(np = newtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
953 {
954 if ((INTBIG)((np->userbits&NFUNCTION) >> NFUNCTIONSH) != type) continue;
955
956 /* see if this node has equivalent arcs */
957 for(j=0; oldnp->firstportproto->connects[j] != NOARCPROTO; j++)
958 {
959 oap = oldnp->firstportproto->connects[j];
960 if (oap->tech == gen_tech) continue;
961
962 for(k=0; np->firstportproto->connects[k] != NOARCPROTO; k++)
963 {
964 ap = np->firstportproto->connects[k];
965 if (ap->tech == gen_tech) continue;
966 if ((ap->userbits&AFUNCTION) == (oap->userbits&AFUNCTION)) break;
967 }
968 if (np->firstportproto->connects[k] == NOARCPROTO) break;
969 }
970 if (oldnp->firstportproto->connects[j] == NOARCPROTO) break;
971 }
972 if (np != NONODEPROTO)
973 {
974 rnp = np;
975 i = 1;
976 }
977 }
978
979 /* give up if it still cannot be determined */
980 if (i != 1)
981 {
982 if (oldnp->temp1 == 0)
983 ttyputmsg(_("Node %s (function %s) has no equivalent in the %s technology"),
984 describenodeproto(oldnp), nodefunctionname(type, oldni),
985 newtech->techname);
986 oldnp->temp1 = 1;
987 return(oldnp);
988 }
989 return(rnp);
990 }
991
992 /************************* CODE FOR PRINTING TECHNOLOGIES *************************/
993
994 extern LIST us_teclayer_functions[];
995 extern LIST us_tecarc_functions[];
996
997 #define MAXCOLS 10
998
us_printtechnology(TECHNOLOGY * tech)999 void us_printtechnology(TECHNOLOGY *tech)
1000 {
1001 FILE *f;
1002 CHAR *name, *fieldname, *colorsymbol, thefield[50], *truename, **fields[MAXCOLS];
1003 REGISTER CHAR **names, **colors, **styles, **cifs, **gdss,
1004 **funcs, **layers, **layersizes, **extensions, **angles, **wipes, **ports,
1005 **portsizes, **portangles, **connections;
1006 REGISTER INTBIG i, j, k, l, m, tot, base;
1007 REGISTER INTBIG saveunit;
1008 REGISTER INTBIG func, area, bits, lambda;
1009 INTBIG lx, hx, ly, hy;
1010 REGISTER ARCINST *ai;
1011 REGISTER ARCPROTO *ap;
1012 REGISTER NODEINST *ni;
1013 REGISTER NODEPROTO *np;
1014 REGISTER PORTPROTO *pp;
1015 REGISTER VARIABLE *cifvar, *gdsvar, *funcvar, *var;
1016 GRAPHICS *gra;
1017 REGISTER TECH_ARCLAY *arclay;
1018 REGISTER TECH_NODES *nodestr;
1019 TECH_POLYGON *lay;
1020 NODEINST node;
1021 ARCINST arc;
1022 static POLYGON *poly = NOPOLYGON;
1023 REGISTER void *infstr;
1024
1025 /* get polygon */
1026 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
1027
1028 infstr = initinfstr();
1029 addstringtoinfstr(infstr, tech->techname);
1030 addstringtoinfstr(infstr, x_(".doc"));
1031 name = returninfstr(infstr);
1032 f = xcreate(name, el_filetypetext, _("Technology Documentation File"), &truename);
1033 if (f == NULL)
1034 {
1035 if (truename != 0) us_abortcommand(_("Cannot write %s"), truename);
1036 return;
1037 }
1038 ttyputverbose(M_("Writing: %s"), name);
1039
1040 /****************************** dump layers ******************************/
1041
1042 /* get layer variables */
1043 cifvar = getval((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, x_("IO_cif_layer_names"));
1044 gdsvar = getval((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, x_("IO_gds_layer_numbers"));
1045 funcvar = getval((INTBIG)tech, VTECHNOLOGY, VINTEGER|VISARRAY, x_("TECH_layer_function"));
1046
1047 /* allocate space for all layer fields */
1048 names = (CHAR **)emalloc((tech->layercount+1) * (sizeof (CHAR *)), el_tempcluster);
1049 colors = (CHAR **)emalloc((tech->layercount+1) * (sizeof (CHAR *)), el_tempcluster);
1050 styles = (CHAR **)emalloc((tech->layercount+1) * (sizeof (CHAR *)), el_tempcluster);
1051 cifs = (CHAR **)emalloc((tech->layercount+1) * (sizeof (CHAR *)), el_tempcluster);
1052 gdss = (CHAR **)emalloc((tech->layercount+1) * (sizeof (CHAR *)), el_tempcluster);
1053 funcs = (CHAR **)emalloc((tech->layercount+1) * (sizeof (CHAR *)), el_tempcluster);
1054 if (names == 0 || colors == 0 || styles == 0 || cifs == 0 || gdss == 0 || funcs == 0)
1055 return;
1056
1057 /* load the header */
1058 (void)allocstring(&names[0], x_("Layer"), el_tempcluster);
1059 (void)allocstring(&colors[0], x_("Color"), el_tempcluster);
1060 (void)allocstring(&styles[0], x_("Style"), el_tempcluster);
1061 (void)allocstring(&cifs[0], x_("CIF"), el_tempcluster);
1062 (void)allocstring(&gdss[0], x_("GDS"), el_tempcluster);
1063 (void)allocstring(&funcs[0], x_("Function"), el_tempcluster);
1064
1065 /* compute each layer */
1066 for(i=0; i<tech->layercount; i++)
1067 {
1068 (void)allocstring(&names[i+1], layername(tech, i), el_tempcluster);
1069
1070 gra = tech->layers[i];
1071 if (ecolorname(gra->col, &fieldname, &colorsymbol)) fieldname = x_("?");
1072 (void)allocstring(&colors[i+1], fieldname, el_tempcluster);
1073
1074 if (el_curwindowpart == NOWINDOWPART) fieldname = x_("unkwn."); else
1075 {
1076 switch (gra->colstyle&(NATURE|INVISIBLE))
1077 {
1078 case SOLIDC: fieldname = x_("solid"); break;
1079 case PATTERNED: fieldname = x_("pat."); break;
1080 case INVISIBLE|SOLIDC: fieldname = x_("INVsol"); break;
1081 case INVISIBLE|PATTERNED: fieldname = x_("INVpat"); break;
1082 }
1083 }
1084 (void)allocstring(&styles[i+1], fieldname, el_tempcluster);
1085
1086 if (cifvar == NOVARIABLE) fieldname = x_("---"); else
1087 fieldname = ((CHAR **)cifvar->addr)[i];
1088 (void)allocstring(&cifs[i+1], fieldname, el_tempcluster);
1089
1090 if (gdsvar == NOVARIABLE) fieldname = x_("---"); else
1091 fieldname = ((CHAR **)gdsvar->addr)[i];
1092 (void)allocstring(&gdss[i+1], fieldname, el_tempcluster);
1093
1094 if (funcvar == NOVARIABLE) fieldname = x_("---"); else
1095 {
1096 func = ((INTBIG *)funcvar->addr)[i];
1097 infstr = initinfstr();
1098 us_tecedaddfunstring(infstr, func);
1099 fieldname = returninfstr(infstr);
1100 }
1101 (void)allocstring(&funcs[i+1], fieldname, el_tempcluster);
1102 }
1103
1104 /* write the layer information */
1105 fields[0] = names; fields[1] = colors; fields[2] = styles;
1106 fields[3] = cifs; fields[4] = gdss; fields[5] = funcs;
1107 us_dumpfields(fields, 6, tech->layercount+1, f, x_("LAYERS"));
1108 for(i=0; i<=tech->layercount; i++)
1109 {
1110 efree(names[i]);
1111 efree(colors[i]);
1112 efree(styles[i]);
1113 efree(cifs[i]);
1114 efree(gdss[i]);
1115 efree(funcs[i]);
1116 }
1117 efree((CHAR *)names);
1118 efree((CHAR *)colors);
1119 efree((CHAR *)styles);
1120 efree((CHAR *)cifs);
1121 efree((CHAR *)gdss);
1122 efree((CHAR *)funcs);
1123
1124 /****************************** dump arcs ******************************/
1125
1126 /* allocate space for all arc fields */
1127 ai = &arc; initdummyarc(ai);
1128 ai->end[0].xpos = -2000; ai->end[0].ypos = 0;
1129 ai->end[1].xpos = 2000; ai->end[1].ypos = 0;
1130 ai->length = 4000;
1131 ai->userbits |= NOEXTEND;
1132 tot = 1;
1133 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1134 {
1135 ai->proto = ap;
1136 if (tech->arcpolys != 0) j = (*(tech->arcpolys))(ai, NOWINDOWPART); else
1137 j = tech->arcprotos[ap->arcindex]->laycount;
1138 tot += j;
1139 }
1140 names = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1141 layers = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1142 layersizes = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1143 extensions = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1144 angles = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1145 wipes = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1146 funcs = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1147 if (names == 0 || layers == 0 || layersizes == 0 || extensions == 0 || angles == 0 ||
1148 wipes == 0 || funcs == 0) return;
1149
1150 /* load the header */
1151 (void)allocstring(&names[0], x_("Arc"), el_tempcluster);
1152 (void)allocstring(&layers[0], x_("Layer"), el_tempcluster);
1153 (void)allocstring(&layersizes[0], x_("Size"), el_tempcluster);
1154 (void)allocstring(&extensions[0], x_("Extend"), el_tempcluster);
1155 (void)allocstring(&angles[0], x_("Angle"), el_tempcluster);
1156 (void)allocstring(&wipes[0], x_("Wipes"), el_tempcluster);
1157 (void)allocstring(&funcs[0], x_("Function"), el_tempcluster);
1158
1159 tot = 1;
1160 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1161 {
1162 (void)allocstring(&names[tot], ap->protoname, el_tempcluster);
1163
1164 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
1165 if (var != NOVARIABLE) bits = var->addr; else
1166 bits = ap->userbits;
1167 if ((bits&WANTNOEXTEND) == 0) fieldname = x_("yes"); else fieldname = x_("no");
1168 (void)allocstring(&extensions[tot], fieldname, el_tempcluster);
1169 (void)esnprintf(thefield, 50, x_("%ld"), (ap->userbits&AANGLEINC) >> AANGLEINCSH);
1170 (void)allocstring(&angles[tot], thefield, el_tempcluster);
1171 if ((ap->userbits&CANWIPE) == 0) fieldname = x_("no"); else fieldname = x_("yes");
1172 (void)allocstring(&wipes[tot], fieldname, el_tempcluster);
1173 func = (ap->userbits&AFUNCTION) >> AFUNCTIONSH;
1174 (void)allocstring(&funcs[tot], us_tecarc_functions[func].name, el_tempcluster);
1175
1176 ai->proto = ap;
1177 if (tech->arcpolys != 0) j = (*(tech->arcpolys))(ai, NOWINDOWPART); else
1178 tech_oneprocpolyloop.realpolys = j = tech->arcprotos[ap->arcindex]->laycount;
1179 for(k=0; k<j; k++)
1180 {
1181 ai->width = defaultarcwidth(ap);
1182 if (tech->shapearcpoly != 0) (*(tech->shapearcpoly))(ai, k, poly); else
1183 {
1184 arclay = &tech->arcprotos[ap->arcindex]->list[k];
1185 makearcpoly(ai->length, defaultarcwidth(ap)-arclay->off*lambdaofarc(ai)/WHOLE,
1186 ai, poly, arclay->style);
1187 poly->layer = arclay->lay;
1188 }
1189 (void)allocstring(&layers[tot], layername(tech, poly->layer), el_tempcluster);
1190 area = (INTBIG)(fabs(areapoly(poly)) / 4000.0);
1191 saveunit = el_units & DISPLAYUNITS;
1192 el_units = (el_units & ~DISPLAYUNITS) | DISPUNITMIC;
1193 (void)allocstring(&layersizes[tot], latoa(area, 0), el_tempcluster);
1194 el_units = (el_units & ~DISPLAYUNITS) | saveunit;
1195 if (k > 0)
1196 {
1197 (void)allocstring(&names[tot], x_(""), el_tempcluster);
1198 (void)allocstring(&extensions[tot], x_(""), el_tempcluster);
1199 (void)allocstring(&angles[tot], x_(""), el_tempcluster);
1200 (void)allocstring(&wipes[tot], x_(""), el_tempcluster);
1201 (void)allocstring(&funcs[tot], x_(""), el_tempcluster);
1202 }
1203 tot++;
1204 }
1205 }
1206
1207 /* write the arc information */
1208 fields[0] = names; fields[1] = layers; fields[2] = layersizes;
1209 fields[3] = extensions; fields[4] = angles; fields[5] = wipes;
1210 fields[6] = funcs;
1211 us_dumpfields(fields, 7, tot, f, x_("ARCS"));
1212 for(i=0; i<tot; i++)
1213 {
1214 efree(names[i]);
1215 efree(layers[i]);
1216 efree(layersizes[i]);
1217 efree(extensions[i]);
1218 efree(angles[i]);
1219 efree(wipes[i]);
1220 efree(funcs[i]);
1221 }
1222 efree((CHAR *)names);
1223 efree((CHAR *)layers);
1224 efree((CHAR *)layersizes);
1225 efree((CHAR *)extensions);
1226 efree((CHAR *)angles);
1227 efree((CHAR *)wipes);
1228 efree((CHAR *)funcs);
1229
1230 /****************************** dump nodes ******************************/
1231
1232 /* allocate space for all node fields */
1233 ni = &node; initdummynode(ni);
1234 tot = 1;
1235 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1236 {
1237 ni->proto = np;
1238 if (tech->nodepolys != 0) j = (*(tech->nodepolys))(ni, 0, NOWINDOWPART); else
1239 j = tech->nodeprotos[np->primindex-1]->layercount;
1240 l = 0;
1241 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1242 {
1243 m = 0;
1244 for(k=0; pp->connects[k] != NOARCPROTO; k++)
1245 if (pp->connects[k]->tech == tech) m++;
1246 if (m == 0) m = 1;
1247 l += m;
1248 }
1249 tot += maxi(j, l);
1250 }
1251 names = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1252 funcs = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1253 layers = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1254 layersizes = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1255 ports = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1256 portsizes = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1257 portangles = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1258 connections = (CHAR **)emalloc(tot * (sizeof (CHAR *)), el_tempcluster);
1259 if (names == 0 || funcs == 0 || layers == 0 || layersizes == 0 || ports == 0 ||
1260 portsizes == 0 || portangles == 0 || connections == 0) return;
1261
1262 /* load the header */
1263 (void)allocstring(&names[0], x_("Node"), el_tempcluster);
1264 (void)allocstring(&funcs[0], x_("Function"), el_tempcluster);
1265 (void)allocstring(&layers[0], x_("Layers"), el_tempcluster);
1266 (void)allocstring(&layersizes[0], x_("Size"), el_tempcluster);
1267 (void)allocstring(&ports[0], x_("Ports"), el_tempcluster);
1268 (void)allocstring(&portsizes[0], x_("Size"), el_tempcluster);
1269 (void)allocstring(&portangles[0], x_("Angle"), el_tempcluster);
1270 (void)allocstring(&connections[0], x_("Connections"), el_tempcluster);
1271
1272 tot = 1;
1273 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1274 {
1275 base = tot;
1276 (void)allocstring(&names[tot], np->protoname, el_tempcluster);
1277
1278 func = (np->userbits&NFUNCTION) >> NFUNCTIONSH;
1279 (void)allocstring(&funcs[tot], nodefunctionname(func, NONODEINST), el_tempcluster);
1280
1281 ni->proto = np;
1282 ni->lowx = np->lowx; ni->highx = np->highx;
1283 ni->lowy = np->lowy; ni->highy = np->highy;
1284 if (tech->nodepolys != 0) j = (*(tech->nodepolys))(ni, 0, NOWINDOWPART); else
1285 tech_oneprocpolyloop.realpolys = j = tech->nodeprotos[np->primindex-1]->layercount;
1286 for(k=0; k<j; k++)
1287 {
1288 if (tech->shapenodepoly != 0) (*(tech->shapenodepoly))(ni, k, poly); else
1289 {
1290 nodestr = tech->nodeprotos[np->primindex-1];
1291 lambda = el_curlib->lambda[tech->techindex];
1292 if (nodestr->special == SERPTRANS)
1293 {
1294 tech_filltrans(poly, &lay, nodestr->gra, ni,
1295 lambda, k, (TECH_PORTS *)0, &tech_oneprocpolyloop);
1296 } else
1297 {
1298 lay = &nodestr->layerlist[k];
1299 tech_fillpoly(poly, lay, ni, lambda, FILLED);
1300 }
1301 }
1302 (void)allocstring(&layers[tot], layername(tech, poly->layer), el_tempcluster);
1303 getbbox(poly, &lx, &hx, &ly, &hy);
1304 saveunit = el_units & DISPLAYUNITS;
1305 el_units = (el_units & ~DISPLAYUNITS) | DISPUNITMIC;
1306 (void)esnprintf(thefield, 50, x_("%s x %s"), latoa(hx-lx, 0), latoa(hy-ly, 0));
1307 (void)allocstring(&layersizes[tot], thefield, el_tempcluster);
1308 el_units = (el_units & ~DISPLAYUNITS) | saveunit;
1309 if (k > 0)
1310 {
1311 (void)allocstring(&names[tot], x_(""), el_tempcluster);
1312 (void)allocstring(&funcs[tot], x_(""), el_tempcluster);
1313 }
1314 tot++;
1315 }
1316 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1317 {
1318 (void)allocstring(&ports[base], pp->protoname, el_tempcluster);
1319 shapeportpoly(ni, pp, poly, FALSE);
1320 getbbox(poly, &lx, &hx, &ly, &hy);
1321 saveunit = el_curtech->userbits & DISPLAYUNITS;
1322 el_units = (el_units & ~DISPLAYUNITS) | DISPUNITMIC;
1323 (void)esnprintf(thefield, 50, x_("%s x %s"), latoa(hx-lx, 0), latoa(hy-ly, 0));
1324 (void)allocstring(&portsizes[base], thefield, el_tempcluster);
1325 el_units = (el_units & ~DISPLAYUNITS) | saveunit;
1326 if (((pp->userbits&PORTARANGE) >> PORTARANGESH) == 180) (void)estrcpy(thefield, x_("")); else
1327 (void)esnprintf(thefield, 50, x_("%ld"), (pp->userbits&PORTANGLE) >> PORTANGLESH);
1328 (void)allocstring(&portangles[base], thefield, el_tempcluster);
1329 m = 0;
1330 for(k=0; pp->connects[k] != NOARCPROTO; k++)
1331 {
1332 if (pp->connects[k]->tech != tech) continue;
1333 (void)allocstring(&connections[base], pp->connects[k]->protoname, el_tempcluster);
1334 if (m != 0)
1335 {
1336 (void)allocstring(&ports[base], x_(""), el_tempcluster);
1337 (void)allocstring(&portsizes[base], x_(""), el_tempcluster);
1338 (void)allocstring(&portangles[base], x_(""), el_tempcluster);
1339 }
1340 m++;
1341 base++;
1342 }
1343 if (m == 0) (void)allocstring(&connections[base++], x_("<NONE>"), el_tempcluster);
1344 }
1345 for( ; base < tot; base++)
1346 {
1347 (void)allocstring(&ports[base], x_(""), el_tempcluster);
1348 (void)allocstring(&portsizes[base], x_(""), el_tempcluster);
1349 (void)allocstring(&portangles[base], x_(""), el_tempcluster);
1350 (void)allocstring(&connections[base], x_(""), el_tempcluster);
1351 }
1352 for( ; tot < base; tot++)
1353 {
1354 (void)allocstring(&names[tot], x_(""), el_tempcluster);
1355 (void)allocstring(&funcs[tot], x_(""), el_tempcluster);
1356 (void)allocstring(&layers[tot], x_(""), el_tempcluster);
1357 (void)allocstring(&layersizes[tot], x_(""), el_tempcluster);
1358 }
1359 }
1360
1361 /* write the node information */
1362 fields[0] = names; fields[1] = funcs; fields[2] = layers;
1363 fields[3] = layersizes; fields[4] = ports; fields[5] = portsizes;
1364 fields[6] = portangles; fields[7] = connections;
1365 us_dumpfields(fields, 8, tot, f, x_("NODES"));
1366 for(i=0; i<tot; i++)
1367 {
1368 efree(names[i]);
1369 efree(funcs[i]);
1370 efree(layers[i]);
1371 efree(layersizes[i]);
1372 efree(ports[i]);
1373 efree(portsizes[i]);
1374 efree(portangles[i]);
1375 efree(connections[i]);
1376 }
1377 efree((CHAR *)names);
1378 efree((CHAR *)funcs);
1379 efree((CHAR *)layers);
1380 efree((CHAR *)layersizes);
1381 efree((CHAR *)ports);
1382 efree((CHAR *)portsizes);
1383 efree((CHAR *)portangles);
1384 efree((CHAR *)connections);
1385
1386 xclose(f);
1387 }
1388
us_dumpfields(CHAR *** fields,INTBIG count,INTBIG length,FILE * f,CHAR * title)1389 void us_dumpfields(CHAR ***fields, INTBIG count, INTBIG length, FILE *f, CHAR *title)
1390 {
1391 INTBIG widths[MAXCOLS];
1392 REGISTER INTBIG len, i, j, k, totwid, stars;
1393
1394 totwid = 0;
1395 for(i=0; i<count; i++)
1396 {
1397 widths[i] = 8;
1398 for(j=0; j<length; j++)
1399 {
1400 len = estrlen(fields[i][j]);
1401 if (len > widths[i]) widths[i] = len;
1402 }
1403 widths[i]++;
1404 totwid += widths[i];
1405 }
1406
1407 stars = (totwid - estrlen(title) - 2) / 2;
1408 for(i=0; i<stars; i++) xprintf(f, x_("*"));
1409 xprintf(f, x_(" %s "), title);
1410 for(i=0; i<stars; i++) xprintf(f, x_("*"));
1411 xprintf(f, x_("\n"));
1412
1413 for(j=0; j<length; j++)
1414 {
1415 for(i=0; i<count; i++)
1416 {
1417 xprintf(f, x_("%s"), fields[i][j]);
1418 if (i == count-1) continue;
1419 for(k=estrlen(fields[i][j]); k<widths[i]; k++) xprintf(f, x_(" "));
1420 }
1421 xprintf(f, x_("\n"));
1422 }
1423 xprintf(f, x_("\n"));
1424 }
1425