1 /*
2 * Electric(tm) VLSI Design System
3 *
4 * File: logeffort.cpp
5 * Logical effort timing and sizing tool
6 * Written by: Steven M. Rubin
7 *
8 * Copyright (c) 2000 Static Free Software.
9 *
10 * Electric(tm) is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * Electric(tm) is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Electric(tm); see the file COPYING. If not, write to
22 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23 * Boston, Mass 02111-1307, USA.
24 *
25 * Static Free Software
26 * 4119 Alpine Road
27 * Portola Valley, California 94028
28 * info@staticfreesoft.com
29 *
30 * This module is inspired by the book "Logical Effort"
31 * by Ivan Sutherland, Bob Sproull, and David Harris
32 * Morgan Kaufmann, San Francisco, 1999.
33 */
34
35 #include "config.h"
36 #if LOGEFFTOOL
37
38 #include "global.h"
39 #include "efunction.h"
40 #include "egraphics.h"
41 #include "edialogs.h"
42 #include "logeffort.h"
43 #include "network.h"
44 #include "usr.h"
45 #include <math.h>
46
47 /* the LOGICAL EFFORT tool table */
48 static KEYWORD leopt[] =
49 {
50 {x_("analyze-path"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
51 {x_("analyze-cell"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
52 {x_("analyze-network"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
53 {x_("show-loads"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
54 {x_("estimate-delay"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
55 {x_("set-options"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
56 {x_("set-capacitance"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
57 {x_("set-node-effort"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
58 TERMKEY
59 };
60 extern "C" {
61 COMCOMP le_tablep = {leopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
62 0, x_(" \t"), M_("Logical effort action"), M_("show defaults")};
63 }
64
65 #define MAXITERATIONS 10
66 #define MAXSTAGEEFFORT 3.0
67
68 /* the meaning of LENODE->type */
69 #define LEUNKNOWN 0
70 #define LETERMINAL 1
71 #define LEINVERTER 2
72 #define LENAND 3
73 #define LENOR 4
74 #define LEXOR 5
75 #define LEXNOR 6
76 #define LENMOS 7
77 #define LEPMOS 8
78 #define LEPOWER 9
79 #define LEGROUND 10
80
81 #define NOLENODE ((LENODE *)-1)
82
83 typedef struct Ilenode
84 {
85 NODEINST *ni; /* node in database */
86 PORTARCINST *piin, *piout; /* input and output ports on that NODEINST */
87 double cin, cout; /* input and output capacitances */
88 double logeffort; /* logical effort of the node (g) */
89 double parasitics; /* parasitics on the node (p) */
90 double branching; /* branching effort of the node (b) */
91 INTBIG type; /* node type (see above) */
92 INTBIG inputs; /* number of inputs */
93 struct Ilenode *nextlenode; /* next in linked list */
94 struct Ilenode *prevlenode; /* previous in linked list */
95
96 struct Ilenode **inputnodes; /* array of input nodes */
97 PORTARCINST **inputports; /* array of input ports on nodes */
98 struct Ilenode **outputnodes; /* array of output nodes */
99 PORTARCINST **outputports; /* array of output ports on nodes */
100 INTBIG numinputnodes; /* size of array of input nodes */
101 INTBIG numoutputnodes; /* size of array of output nodes */
102 } LENODE;
103
104 TOOL *le_tool; /* this tool */
105 static INTBIG le_attrcapacitance_key; /* variable key for "ATTR_Capacitance" */
106 static INTBIG le_nodeeffort_key; /* variable key for "LE_node_effort" */
107 static INTBIG le_fanout_key; /* variable key for "LE_fanout" */
108 static INTBIG le_state_key; /* variable key for "LE_state" */
109 INTBIG le_wire_ratio_key; /* variable key for "LE_wire_ratio" */
110 static INTBIG le_maximumstageeffort_key; /* variable key for "LE_maximum_stage_effort" */
111 static LENODE *le_lastlenode; /* for propagating capacitance values */
112 static double le_lastcapacitance; /* for propagating capacitance values */
113 static LENODE *le_firstlenode; /* first in list of LE nodes in the path */
114 static LENODE *le_lenodefree; /* list of free LE nodes */
115
116 /* prototypes for local routines */
117 static void le_addlinkage(LENODE *out, PORTARCINST *outpi, LENODE *in, PORTARCINST *inpi);
118 static LENODE *le_alloclenode(void);
119 static void le_analyzecell(void);
120 static void le_analyzenetwork(void);
121 static void le_analyzepath(void);
122 static CHAR *le_describenode(LENODE *le);
123 static void le_estimatedelay(NODEPROTO *cell);
124 static void le_figurebranching(void);
125 static void le_freealllenodes(void);
126 static void le_freelenode(LENODE *le);
127 static void le_gathercell(INTBIG show);
128 static void le_gatherpath(INTBIG show);
129 static double le_getcapacitance(NETWORK *net);
130 static INTBIG le_getgatetype(NODEINST *ni, INTBIG *inputs);
131 static double le_getlogeffort(LENODE *le);
132 static double le_getparasitics(LENODE *le);
133 static CHAR *le_nextarcs(void);
134 static NODEINST *le_propagate(NODEPROTO *cell, INTBIG edge);
135 static void le_propagatebranch(PORTARCINST *tpi, LENODE *final, double capacitance,
136 double *onpath, double *offpath);
137 static void le_setarccapacitance(ARCINST *ai, double c);
138 static void le_setlogicaleffort(void);
139 static void le_setoptions(void);
140 static void le_showloads(void);
141 static int le_sortbyproductsize(const void *e1, const void *e2);
142 static BOOLEAN le_topofarcs(CHAR **c);
143 static void le_unwind(NODEINST *start, NODEINST *prev);
144
145 /************************ CONTROL ***********************/
146
147 /*
148 * tool initialization
149 */
le_init(INTBIG * argc,CHAR1 * argv[],TOOL * thistool)150 void le_init(INTBIG *argc, CHAR1 *argv[], TOOL *thistool)
151 {
152 /* ignore pass 3 initialization */
153 if (thistool == 0) return;
154
155 /* ignore pass 2 initialization */
156 if (thistool == NOTOOL)
157 {
158 le_attrcapacitance_key = makekey(x_("ATTR_Capacitance"));
159 le_nodeeffort_key = makekey(x_("LE_node_effort"));
160 le_fanout_key = makekey(x_("LE_fanout"));
161 le_state_key = makekey(x_("LE_state"));
162 le_wire_ratio_key = makekey(x_("LE_wire_ratio"));
163 le_maximumstageeffort_key = makekey(x_("LE_maximum_stage_effort"));
164 le_firstlenode = NOLENODE;
165 le_lenodefree = NOLENODE;
166 nextchangequiet();
167 setvalkey((INTBIG)le_tool, VTOOL, le_state_key, DEFAULTSTATE, VINTEGER|VDONTSAVE);
168 return;
169 }
170
171 /* copy tool pointer during pass 1 */
172 le_tool = thistool;
173 }
174
le_done(void)175 void le_done(void)
176 {
177 #ifdef DEBUGMEMORY
178 LENODE *le;
179
180 le_freealllenodes();
181
182 while (le_lenodefree != NOLENODE)
183 {
184 le = le_lenodefree;
185 le_lenodefree = le_lenodefree->nextlenode;
186 efree((CHAR *)le);
187 }
188 #endif
189 }
190
191 /*
192 * Handle commands to the tool from the user.
193 */
le_set(INTBIG count,CHAR * par[])194 void le_set(INTBIG count, CHAR *par[])
195 {
196 REGISTER INTBIG l;
197 REGISTER VARIABLE *var;
198 REGISTER NODEPROTO *np;
199 REGISTER INTBIG state;
200 REGISTER CHAR *pp;
201
202 if (count == 0)
203 {
204 ttyputusage(x_("telltool logeffort (analyze-path | analyze-cell | analyze-network | show-loads | set-options | set-capacitance | set-node-effort)"));
205 return;
206 }
207
208 l = estrlen(pp = par[0]);
209 if (namesamen(pp, x_("analyze-cell"), l) == 0 && l >= 9)
210 {
211 var = getvalkey((INTBIG)le_tool, VTOOL, VINTEGER, le_state_key);
212 if (var == NOVARIABLE) state = DEFAULTSTATE; else
213 state = var->addr;
214 le_gathercell(state & HIGHLIGHTCOMPONENTS);
215 if (le_firstlenode == NOLENODE) return;
216 le_analyzecell();
217 return;
218 }
219 if (namesamen(pp, x_("analyze-path"), l) == 0 && l >= 9)
220 {
221 var = getvalkey((INTBIG)le_tool, VTOOL, VINTEGER, le_state_key);
222 if (var == NOVARIABLE) state = DEFAULTSTATE; else
223 state = var->addr;
224 le_gatherpath(state & HIGHLIGHTCOMPONENTS);
225 if (le_firstlenode == NOLENODE) return;
226 le_analyzepath();
227 return;
228 }
229 if (namesamen(pp, x_("estimate-delay"), l) == 0)
230 {
231 /* analyze cell */
232 np = getcurcell();
233 if (np == NONODEPROTO) return;
234 le_estimatedelay(np);
235 return;
236 }
237 if (namesamen(pp, x_("show-loads"), l) == 0 && l >= 2)
238 {
239 le_showloads();
240 return;
241 }
242 if (namesamen(pp, x_("analyze-network"), l) == 0 && l >= 2)
243 {
244 le_analyzenetwork();
245 return;
246 }
247 if (namesamen(pp, x_("set-options"), l) == 0 && l >= 5)
248 {
249 le_setoptions();
250 return;
251 }
252 if (namesamen(pp, x_("set-node-effort"), l) == 0 && l >= 5)
253 {
254 le_setlogicaleffort();
255 return;
256 }
257
258 ttyputbadusage(x_("telltool logeffort"));
259 }
260
261 /* Logical Effort Options dialog */
262 static DIALOGITEM le_leoptionsdialogitems[] =
263 {
264 /* 1 */ {0, {196,204,220,268}, BUTTON, N_("OK")},
265 /* 2 */ {0, {132,204,156,268}, BUTTON, N_("Cancel")},
266 /* 3 */ {0, {8,8,24,160}, MESSAGE, N_("Maximum Stage Gain")},
267 /* 4 */ {0, {8,168,24,220}, EDITTEXT, x_("")},
268 /* 5 */ {0, {36,8,52,244}, CHECK, N_("Display intermediate capacitances")},
269 /* 6 */ {0, {64,8,80,192}, CHECK, N_("Highlight components")},
270 /* 7 */ {0, {112,8,220,180}, SCROLL, x_("")},
271 /* 8 */ {0, {224,8,240,92}, MESSAGE, N_("Wire ratio:")},
272 /* 9 */ {0, {224,96,240,180}, EDITTEXT, x_("")},
273 /* 10 */ {0, {92,8,108,180}, MESSAGE, N_("Wire ratio for each layer:")}
274 };
275 static DIALOG le_leoptionsdialog = {{75,75,324,352}, N_("Logical Effort Options"), 0, 10, le_leoptionsdialogitems, 0, 0};
276
277 /* special items for the "Logical Effort Options" dialog: */
278 #define DLEO_MAXGAIN 4 /* Maximum Stage Gain (edit text) */
279 #define DLEO_INTERCAP 5 /* Show intermediate capacitances (check) */
280 #define DLEO_HIGHCOMP 6 /* Highlight components (check) */
281 #define DLEO_ARCLIST 7 /* List of arcs (scroll) */
282 #define DLEO_WIRERATIO 9 /* Arc wire ratio (edit text) */
283
284 static ARCPROTO *le_posarcs;
le_topofarcs(CHAR ** c)285 BOOLEAN le_topofarcs(CHAR **c)
286 {
287 le_posarcs = el_curtech->firstarcproto;
288 return(TRUE);
289 }
290
le_nextarcs(void)291 CHAR *le_nextarcs(void)
292 {
293 REGISTER ARCPROTO *ap;
294 REGISTER void *infstr;
295
296 ap = le_posarcs;
297 if (ap != NOARCPROTO)
298 {
299 le_posarcs = ap->nextarcproto;
300 infstr = initinfstr();
301 formatinfstr(infstr, x_("%s (%ld)"), describearcproto(ap), ap->temp1);
302 return(returninfstr(infstr));
303 }
304 return(0);
305 }
306
307 /*
308 * Routine to interactively set the logical effort options.
309 */
le_setoptions(void)310 void le_setoptions(void)
311 {
312 INTBIG itemHit;
313 INTBIG state, newstate, i, lineno;
314 float maxstageeffort, newmaxstageeffort;
315 REGISTER VARIABLE *var;
316 REGISTER ARCPROTO *ap;
317 CHAR line[200], *pt;
318 REGISTER void *infstr, *dia;
319
320 dia = DiaInitDialog(&le_leoptionsdialog);
321 if (dia == 0) return;
322 var = getvalkey((INTBIG)le_tool, VTOOL, VINTEGER, le_state_key);
323 if (var == NOVARIABLE) state = DEFAULTSTATE; else
324 state = var->addr;
325 if ((state&DISPLAYCAPACITANCE) != 0) DiaSetControl(dia, DLEO_INTERCAP, 1);
326 if ((state&HIGHLIGHTCOMPONENTS) != 0) DiaSetControl(dia, DLEO_HIGHCOMP, 1);
327 var = getvalkey((INTBIG)le_tool, VTOOL, VFLOAT, le_maximumstageeffort_key);
328 if (var == NOVARIABLE) maxstageeffort = MAXSTAGEEFFORT; else
329 maxstageeffort = castfloat(var->addr);
330
331 /* handle wire ratios */
332 for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
333 {
334 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, le_wire_ratio_key);
335 if (var != NOVARIABLE) ap->temp1 = var->addr; else
336 ap->temp1 = DEFWIRERATIO;
337 }
338 DiaInitTextDialog(dia, DLEO_ARCLIST, le_topofarcs, le_nextarcs,
339 DiaNullDlogDone, 0, SCSELMOUSE|SCREPORT);
340
341 esnprintf(line, 200, x_("%g"), maxstageeffort);
342 DiaSetText(dia, -DLEO_MAXGAIN, line);
343 for(;;)
344 {
345 itemHit = DiaNextHit(dia);
346 if (itemHit == OK || itemHit == CANCEL) break;
347 if (itemHit == DLEO_INTERCAP || itemHit == DLEO_HIGHCOMP)
348 {
349 DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
350 continue;
351 }
352 if (itemHit == DLEO_ARCLIST)
353 {
354 lineno = DiaGetCurLine(dia, DLEO_ARCLIST);
355 if (lineno < 0) continue;
356 estrcpy(line, DiaGetScrollLine(dia, DLEO_ARCLIST, lineno));
357 for(pt = line; *pt != 0; pt++) if (*pt == ' ') break;
358 *pt = 0;
359 ap = getarcproto(line);
360 if (ap == NOARCPROTO) continue;
361 esnprintf(line, 200, x_("%ld"), ap->temp1);
362 DiaSetText(dia, DLEO_WIRERATIO, line);
363 continue;
364 }
365 if (itemHit == DLEO_WIRERATIO)
366 {
367 lineno = DiaGetCurLine(dia, DLEO_ARCLIST);
368 if (lineno < 0) continue;
369 estrcpy(line, DiaGetScrollLine(dia, DLEO_ARCLIST, lineno));
370 for(pt = line; *pt != 0; pt++) if (*pt == ' ') break;
371 *pt = 0;
372 ap = getarcproto(line);
373 if (ap == NOARCPROTO) continue;
374 i = eatoi(DiaGetText(dia, DLEO_WIRERATIO));
375 if (i == ap->temp1) continue;
376 ap->temp1 = i;
377 infstr = initinfstr();
378 formatinfstr(infstr, x_("%s (%ld)"), describearcproto(ap), ap->temp1);
379 DiaSetScrollLine(dia, DLEO_ARCLIST, lineno, returninfstr(infstr));
380 continue;
381 }
382 }
383 if (itemHit == OK)
384 {
385 newstate = 0;
386 if (DiaGetControl(dia, DLEO_INTERCAP) != 0) newstate |= DISPLAYCAPACITANCE;
387 if (DiaGetControl(dia, DLEO_HIGHCOMP) != 0) newstate |= HIGHLIGHTCOMPONENTS;
388 if (newstate != state)
389 (void)setvalkey((INTBIG)le_tool, VTOOL, le_state_key, newstate, VINTEGER);
390 newmaxstageeffort = (float)eatof(DiaGetText(dia, DLEO_MAXGAIN));
391 if (newmaxstageeffort != maxstageeffort)
392 (void)setvalkey((INTBIG)le_tool, VTOOL, le_maximumstageeffort_key,
393 castint(newmaxstageeffort), VFLOAT);
394 for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
395 {
396 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, le_wire_ratio_key);
397 if (var != NOVARIABLE) i = var->addr; else
398 i = DEFWIRERATIO;
399 if (i == ap->temp1) continue;
400 if (ap->temp1 == DEFWIRERATIO)
401 {
402 delvalkey((INTBIG)ap, VARCPROTO, le_wire_ratio_key);
403 } else
404 {
405 setvalkey((INTBIG)ap, VARCPROTO, le_wire_ratio_key, ap->temp1, VINTEGER);
406 }
407 }
408 }
409 DiaDoneDialog(dia);
410 }
411
412 /* Logical Effort effort dialog */
413 static DIALOGITEM le_logeffortdialogitems[] =
414 {
415 /* 1 */ {0, {40,128,64,192}, BUTTON, N_("OK")},
416 /* 2 */ {0, {40,12,64,76}, BUTTON, N_("Cancel")},
417 /* 3 */ {0, {8,8,24,116}, MESSAGE, N_("Logical Effort:")},
418 /* 4 */ {0, {8,128,24,192}, EDITTEXT, x_("")}
419 };
420 static DIALOG le_logeffortdialog = {{75,75,149,281}, N_("Logical Effort"), 0, 4, le_logeffortdialogitems, 0, 0};
421
422 /* special items for the "Logical Effort effort" dialog: */
423 #define DLEE_EFFVALUE 4 /* Effort (edit text) */
424
425 /*
426 * Routine to interactively set the logical effort value on the selected node.
427 */
le_setlogicaleffort(void)428 void le_setlogicaleffort(void)
429 {
430 INTBIG itemHit;
431 INTBIG inputs;
432 REGISTER NODEINST *ni;
433 REGISTER INTBIG type;
434 double e;
435 CHAR line[50], *pt;
436 LENODE statle;
437 REGISTER void *dia;
438
439 ni = (NODEINST *)asktool(us_tool, x_("get-node"));
440 if (ni == NONODEINST) return;
441 type = le_getgatetype(ni, &inputs);
442 if (type == LEUNKNOWN) return;
443 statle.type = type;
444 statle.ni = ni;
445 statle.inputs = inputs;
446 e = le_getlogeffort(&statle);
447 dia = DiaInitDialog(&le_logeffortdialog);
448 if (dia == 0) return;
449
450 esnprintf(line, 50, x_("%g"), e);
451 DiaSetText(dia, -DLEE_EFFVALUE, line);
452 for(;;)
453 {
454 itemHit = DiaNextHit(dia);
455 if (itemHit == OK || itemHit == CANCEL) break;
456 }
457 if (itemHit == OK)
458 {
459 pt = DiaGetText(dia, DLEE_EFFVALUE);
460 startobjectchange((INTBIG)ni, VNODEINST);
461 esnprintf(line, 50, x_("g=%s"), pt);
462 setvalkey((INTBIG)ni, VNODEINST, le_nodeeffort_key, (INTBIG)line, VSTRING|VDISPLAY);
463 endobjectchange((INTBIG)ni, VNODEINST);
464 }
465 DiaDoneDialog(dia);
466 }
467
468 /*
469 * Routine to set the capacitance on arc "ai" to "c". This is displayed on the arc.
470 */
le_setarccapacitance(ARCINST * ai,double c)471 void le_setarccapacitance(ARCINST *ai, double c)
472 {
473 REGISTER VARIABLE *var;
474
475 startobjectchange((INTBIG)ai, VARCINST);
476 var = setvalkey((INTBIG)ai, VARCINST, le_attrcapacitance_key, castint((float)c),
477 VFLOAT|VDISPLAY);
478 if (var != NOVARIABLE)
479 {
480 TDSETDISPPART(var->textdescript, VTDISPLAYNAMEVALUE);
481 TDSETUNITS(var->textdescript, VTUNITSCAP);
482 TDSETSIZE(var->textdescript, TXTSETQLAMBDA(3));
483 if (ai->end[0].ypos == ai->end[1].ypos)
484 {
485 /* horizontal arc: push text to top */
486 TDSETPOS(var->textdescript, VTPOSUP);
487 }
488 if (ai->end[0].xpos == ai->end[1].xpos)
489 {
490 /* vertical arc: push text to right */
491 TDSETPOS(var->textdescript, VTPOSRIGHT);
492 }
493 }
494 endobjectchange((INTBIG)ai, VARCINST);
495 }
496
497 /******************** ANALYSIS ********************/
498
499 /*
500 * Routine to analyze a path in "le_firstlenode".
501 */
le_analyzepath(void)502 void le_analyzepath(void)
503 {
504 LENODE *le, *pathend;
505 REGISTER VARIABLE *var;
506 REGISTER INTBIG displaycapacitance, state;
507 CHAR line[50];
508 double g, G, B, h, H, F, P, N, fhat, Dhat, Cin, Cout, CinI, CoutI;
509
510 /* find the end of the path */
511 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode) pathend = le;
512
513 /* determine the number of stages of logic in the path */
514 N = 0.0;
515 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode) N++;
516 if (N == 0.0) return;
517
518 /* compute the path logical effort by multiplying the individual ones */
519 G = 1.0;
520 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
521 {
522 g = le->logeffort;
523 if (g == 0.0) return;
524 G = G * g;
525 }
526
527 /* compute the branching effort along the path */
528 B = 1.0;
529 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
530 B = B * le->branching;
531
532 /* compute the electrical effort along the path */
533 Cin = le_firstlenode->cin;
534 Cout = pathend->cout;
535 ttyputmsg(_("Capacitance starts at %g, ends at %g"), Cin, Cout);
536 if (Cin == 0.0) return;
537 H = Cout / Cin;
538
539 /* compute the overall path effort */
540 F = G * B * H;
541
542 /* determine the total parasitic effect */
543 P = 0.0;
544 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
545 P = P + le->parasitics;
546
547 /* compute the stage effort */
548 fhat = pow(F, 1/N);
549 ttyputmsg(_("Optimum stage effort is %g"), fhat);
550 if (fhat == 0.0) return;
551
552 /* compute the minimum path delay */
553 Dhat = N * fhat + P;
554 ttyputmsg(_("Minimum path delay is %g"), Dhat);
555
556 /* determine whether or not to set capacitance values */
557 var = getvalkey((INTBIG)le_tool, VTOOL, VINTEGER, le_state_key);
558 if (var == NOVARIABLE) state = DEFAULTSTATE; else
559 state = var->addr;
560 displaycapacitance = state & DISPLAYCAPACITANCE;
561
562 /* work backwards through the path, computing electrical effort of each gate */
563 CoutI = Cout;
564 for(le = pathend; le != NOLENODE; le = le->prevlenode)
565 {
566 /* determine input capacitance to this node */
567 CinI = le->logeffort * CoutI / fhat;
568 if (le->prevlenode != NOLENODE && displaycapacitance != 0)
569 le_setarccapacitance(le->piin->conarcinst, CinI);
570 if (CinI == 0.0) break;
571
572 /* set fanout (h) on this node */
573 h = CoutI / CinI;
574 esnprintf(line, 50, x_("h=%g"), h);
575 startobjectchange((INTBIG)le->ni, VNODEINST);
576 setvalkey((INTBIG)le->ni, VNODEINST, le_fanout_key, (INTBIG)line, VSTRING|VDISPLAY);
577 endobjectchange((INTBIG)le->ni, VNODEINST);
578
579 /* shift input capacitance to the output of the previous node */
580 CoutI = CinI;
581 }
582 }
583
584 /******************** DELAY ESTIMATION ********************/
585
586 #define NONETDELAY ((NETDELAY *)-1)
587
588 typedef struct Inetdelay
589 {
590 float numerator;
591 float pdenominator;
592 float ndenominator;
593 NETWORK *net;
594 struct Inetdelay *nextnetdelay;
595 } NETDELAY;
596
597 /*
598 * Routine to analyze cell "cell" and build a list of ERC errors.
599 */
le_estimatedelay(NODEPROTO * cell)600 void le_estimatedelay(NODEPROTO *cell)
601 {
602 REGISTER NETWORK *net;
603 TRANSISTORINFO *p_gate, *n_gate, *p_active, *n_active;
604 REGISTER AREAPERIM *ap, *aplist, *nextap;
605 REGISTER INTBIG fun;
606 REGISTER NETDELAY *nd, *firstnd;
607 float numerator, coefficient, flambda;
608
609 firstnd = NONETDELAY;
610 flambda = (float)lambdaofcell(cell);
611 for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
612 {
613 aplist = net_gathergeometry(net, &p_gate, &n_gate, &p_active, &n_active, TRUE);
614
615 /* numerator has the area of all transistors connected by their gate */
616 numerator = (float)(p_gate->area + n_gate->area);
617 ttyputmsg(x_("Network %s has numerator:"), describenetwork(net));
618 ttyputmsg(x_(" N Gates = %g, P Gates = %g"), n_gate->area/flambda/flambda, p_gate->area/flambda/flambda);
619
620 /* numerator also sums area of each layer */
621 for(ap = aplist; ap != NOAREAPERIM; ap = nextap)
622 {
623 nextap = ap->nextareaperim;
624 fun = layerfunction(ap->tech, ap->layer);
625 if ((fun&LFTYPE) != LFDIFF && !layerismetal(fun) && !layerispoly(fun)) continue;
626 coefficient = 1.0f;
627 if (layerismetal(fun)) coefficient = 0.1f;
628 if (layerispoly(fun)) coefficient = 0.1f;
629 ttyputmsg(x_(" Layer %s has %g x %g = %g"), layername(ap->tech, ap->layer),
630 ap->area/flambda/flambda, coefficient, ap->area*coefficient/flambda/flambda);
631 numerator += (float)ap->area * coefficient;
632 efree((CHAR *)ap);
633 }
634
635 /* save the results */
636 nd = (NETDELAY *)emalloc(sizeof (NETDELAY), le_tool->cluster);
637 if (nd == 0) break;
638 nd->pdenominator = (float)p_active->width / flambda;
639 nd->ndenominator = (float)n_active->width / flambda;
640 nd->numerator = numerator / flambda / flambda;
641 if (n_active->width == 0) ttyputmsg(x_(" N denominator undefined")); else
642 ttyputmsg(x_(" N denominator = %g, ratio = %g"), nd->ndenominator, nd->numerator/nd->ndenominator);
643 if (p_active->width == 0) ttyputmsg(x_(" P denominator undefined")); else
644 ttyputmsg(x_(" P denominator = %g, ratio = %g"), nd->pdenominator, nd->numerator/nd->pdenominator);
645 if (n_active->width+p_active->width == 0) ttyputmsg(x_(" Denominator undefined")); else
646 ttyputmsg(x_(" Denominator = %g, ratio = %g"), nd->ndenominator+nd->pdenominator,
647 nd->numerator/(nd->ndenominator+nd->pdenominator));
648 nd->net = net;
649 nd->nextnetdelay = firstnd;
650 firstnd = nd;
651 }
652
653 /* now sort by delay size */
654
655 #if 0 /* code to show the results */
656 for(nd = firstnd; nd != NONETDELAY; nd = nd->nextnetdelay)
657 {
658 REGISTER void *infstr;
659
660 ttyputmsg(M_("Network %s:"), describenetwork(nd->net));
661 infstr = initinfstr();
662 formatinfstr(infstr, M_("Network %s has N delay "), describenetwork(nd->net));
663 if (nd->ndenominator == 0.0)
664 {
665 ttyputmsg(M_(" N delay UNDEFINED"));
666 } else
667 {
668 ttyputmsg(M_(" N delay is %g/%g = %g"), nd->numerator, nd->ndenominator,
669 nd->numerator / nd->ndenominator);
670 }
671 if (nd->pdenominator == 0.0)
672 {
673 ttyputmsg(M_(" P delay UNDEFINED"));
674 } else
675 {
676 ttyputmsg(M_(" P delay is %g/%g = %g"), nd->numerator, nd->pdenominator,
677 nd->numerator / nd->pdenominator);
678 }
679 }
680 #endif
681 }
682
683 /******************** LOAD CALCULATION ********************/
684
le_showloads(void)685 void le_showloads(void)
686 {
687 REGISTER NODEPROTO *np;
688 REGISTER NETWORK *net, **netlist, **selnets;
689 REGISTER ARCPROTO *ap;
690 REGISTER VARIABLE *var;
691 REGISTER INTBIG lambda, gwidth, gtotal, atotal, wirelen, fun, load, wireratio, thisload, thiswl,
692 total, i;
693 float areatotal;
694 REGISTER CHAR *lname;
695 REGISTER AREAPERIM *arpe, *firstarpe, *nextarpe;
696 TRANSISTORINFO *p_gate, *n_gate, *p_active, *n_active;
697 REGISTER void *infstr;
698
699 /* get the current cell */
700 np = getcurcell();
701 if (np == NONODEPROTO)
702 {
703 ttyputerr(_("No current cell"));
704 return;
705 }
706 lambda = lambdaofcell(np);
707 selnets = net_gethighlightednets(FALSE);
708
709 /* gather product information for all nets in the cell */
710 for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
711 {
712 net->temp2 = 0;
713
714 /* if some nets were selected, ignore all others */
715 if (selnets[0] != NONETWORK)
716 {
717 for(i=0; selnets[i] != NONETWORK; i++)
718 if (selnets[i] == net) break;
719 if (selnets[i] == NONETWORK) continue;
720 }
721
722 /* gather geometry on this network */
723 firstarpe = net_gathergeometry(net, &p_gate, &n_gate, &p_active, &n_active, TRUE);
724
725 /* see if there are gates on the network */
726 gtotal = net_transistor_p_gate.count + net_transistor_n_gate.count;
727 if (gtotal > 0)
728 {
729 /* sum the metal half-perimeters on the network */
730 wirelen = 0;
731 for(arpe = firstarpe; arpe != NOAREAPERIM; arpe = arpe->nextareaperim)
732 {
733 fun = layerfunction(arpe->tech, arpe->layer);
734 if (!layerismetal(fun)) continue;
735 wirelen += arpe->perimeter / 2;
736 }
737 gwidth = net_transistor_p_gate.width + net_transistor_n_gate.width;
738 net->temp2 = muldiv(wirelen, gwidth, lambda);
739 }
740
741 /* free the area/perimeter information */
742 for(arpe = firstarpe; arpe != NOAREAPERIM; arpe = nextarpe)
743 {
744 nextarpe = arpe->nextareaperim;
745 efree((CHAR *)arpe);
746 }
747 }
748
749 /* now sort the networks by this product number in "temp2" */
750 total = 0;
751 for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
752 if (net->temp2 != 0) total++;
753 if (total == 0)
754 {
755 ttyputmsg(_("There are no networks with load information"));
756 return;
757 }
758 netlist = (NETWORK **)emalloc(total * (sizeof (NETWORK *)), le_tool->cluster);
759 if (netlist == 0) return;
760 total = 0;
761 for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
762 if (net->temp2 != 0) netlist[total++] = net;
763
764 /* sort by product number */
765 esort(netlist, total, sizeof (NETWORK *), le_sortbyproductsize);
766
767 /* now report the results */
768 for(i=0; i<total; i++)
769 {
770 /* gather geometry on this network */
771 net = netlist[i];
772 ttyputmsg(_("For network %s:"), describenetwork(net));
773 firstarpe = net_gathergeometry(net, &p_gate, &n_gate, &p_active, &n_active, TRUE);
774
775 /* determine the wire length */
776 load = wirelen = 0;
777 areatotal = 0.0;
778 for(arpe = firstarpe; arpe != NOAREAPERIM; arpe = arpe->nextareaperim)
779 {
780 lname = layername(arpe->tech, arpe->layer);
781 fun = layerfunction(arpe->tech, arpe->layer);
782 if (!layerismetal(fun)) continue;
783 ap = getarconlayer(arpe->layer, arpe->tech);
784 wireratio = DEFWIRERATIO;
785 if (ap != NOARCPROTO)
786 {
787 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, le_wire_ratio_key);
788 if (var != NOVARIABLE) wireratio = var->addr;
789 }
790 lname = layername(arpe->tech, arpe->layer);
791 thiswl = arpe->perimeter / 2;
792 thisload = thiswl / wireratio;
793 ttyputmsg(x_(" Layer %s wire-length (%s) / wire ratio (%ld) = load (%s)"),
794 lname, latoa(thiswl, 0), wireratio, latoa(thisload, 0));
795 load += thisload;
796 wirelen += thiswl;
797 areatotal += arpe->area;
798 }
799
800 gwidth = net_transistor_p_gate.width + net_transistor_n_gate.width;
801 ttyputmsg(_(" Total wire-length (%s) x gate-widths (%s) = product (%s); average wire-width = %g"),
802 latoa(wirelen, 0), latoa(gwidth, 0), latoa(muldiv(wirelen, gwidth, lambda), 0),
803 areatotal / (float)wirelen / (float)lambda);
804
805 atotal = net_transistor_p_active.count + net_transistor_n_active.count;
806 if (atotal > 0)
807 {
808 infstr = initinfstr();
809 formatinfstr(infstr, _(" Load = %s"), latoa(load, 0));
810 if (net_transistor_p_active.width != 0)
811 formatinfstr(infstr, x_("; load / P-active-width (%s) = %g"), latoa(net_transistor_p_active.width, 0),
812 (float)load / (float)net_transistor_p_active.width);
813 if (net_transistor_n_active.width != 0)
814 formatinfstr(infstr, x_("; load / N-active-width (%s) = %g"), latoa(net_transistor_n_active.width, 0),
815 (float)load / (float)net_transistor_n_active.width);
816 ttyputmsg(x_("%s"), returninfstr(infstr));
817 }
818
819 for(arpe = firstarpe; arpe != NOAREAPERIM; arpe = nextarpe)
820 {
821 nextarpe = arpe->nextareaperim;
822 efree((CHAR *)arpe);
823 }
824 }
825 efree((CHAR *)netlist);
826 }
827
828 /*
829 * Helper routine for to sort NETWORK objects by product in "temp2"
830 */
le_sortbyproductsize(const void * e1,const void * e2)831 int le_sortbyproductsize(const void *e1, const void *e2)
832 {
833 REGISTER NETWORK *net1, *net2;
834
835 net1 = *((NETWORK **)e1);
836 net2 = *((NETWORK **)e2);
837 return(net1->temp2 - net2->temp2);
838 }
839
le_analyzenetwork(void)840 void le_analyzenetwork(void)
841 {
842 REGISTER NETWORK **netlist, *net;
843 REGISTER NODEPROTO *np;
844 REGISTER ARCPROTO *ap;
845 REGISTER INTBIG i, j, k, widest, len, lambda, total, gtotal, atotal,
846 fun, metpolhalfperim, load, wireratio, additionalload;
847 REGISTER CHAR *lname, *pad;
848 REGISTER VARIABLE *var;
849 REGISTER AREAPERIM *arpe, *firstarpe, **arpelist;
850 TRANSISTORINFO *p_gate, *n_gate, *p_active, *n_active;
851 float ratio;
852 REGISTER void *infstr;
853
854 netlist = net_gethighlightednets(0);
855 if (netlist[0] == NONETWORK) return;
856 for(k=0; netlist[k] != NONETWORK; k++)
857 {
858 net = netlist[k];
859
860 /* gather geometry on this network */
861 np = net->parent;
862 firstarpe = net_gathergeometry(net, &p_gate, &n_gate, &p_active, &n_active, TRUE);
863
864 /* copy the linked list to an array for sorting */
865 total = 0;
866 for(arpe = firstarpe; arpe != NOAREAPERIM; arpe = arpe->nextareaperim)
867 if (arpe->layer >= 0) total++;
868 if (total == 0)
869 {
870 ttyputmsg(_("No geometry on network '%s' in cell %s"), describenetwork(net),
871 describenodeproto(np));
872 continue;
873 }
874 arpelist = (AREAPERIM **)emalloc(total * (sizeof (AREAPERIM *)), net_tool->cluster);
875 if (arpelist == 0) return;
876 i = 0;
877 for(arpe = firstarpe; arpe != NOAREAPERIM; arpe = arpe->nextareaperim)
878 if (arpe->layer >= 0) arpelist[i++] = arpe;
879
880 /* sort the layers */
881 esort(arpelist, total, sizeof (AREAPERIM *), net_areaperimdepthascending);
882
883 ttyputmsg(_("For network '%s' in cell %s:"), describenetwork(net),
884 describenodeproto(np));
885 lambda = lambdaofcell(np);
886 widest = 0;
887 for(i=0; i<total; i++)
888 {
889 arpe = arpelist[i];
890 lname = layername(arpe->tech, arpe->layer);
891 len = estrlen(lname);
892 if (len > widest) widest = len;
893 }
894 metpolhalfperim = 0;
895 for(i=0; i<total; i++)
896 {
897 arpe = arpelist[i];
898 lname = layername(arpe->tech, arpe->layer);
899 infstr = initinfstr();
900 for(j=estrlen(lname); j<widest; j++) addtoinfstr(infstr, ' ');
901 pad = returninfstr(infstr);
902 infstr = initinfstr();
903 formatinfstr(infstr, _("Layer %s:%s area=%7g half-perimeter=%s"), lname, pad,
904 arpe->area/(float)lambda/(float)lambda, latoa(arpe->perimeter/2, 0));
905 fun = layerfunction(arpe->tech, arpe->layer);
906 if (layerispoly(fun) != 0 || layerismetal(fun) != 0)
907 {
908 ap = getarconlayer(arpe->layer, arpe->tech);
909 wireratio = DEFWIRERATIO;
910 if (ap != NOARCPROTO)
911 {
912 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, le_wire_ratio_key);
913 if (var != NOVARIABLE) wireratio = var->addr;
914 }
915 additionalload = arpe->perimeter / 2 / wireratio;
916 metpolhalfperim += additionalload;
917 formatinfstr(infstr, _(" / wire-ratio (%ld) = %s"), wireratio,
918 latoa(additionalload, 0));
919 }
920 if (arpe->perimeter != 0)
921 {
922 ratio = (arpe->area / (float)lambda) / (float)(arpe->perimeter/2);
923 formatinfstr(infstr, _("; area/half-perimeter = %g"), ratio);
924 }
925 ttyputmsg(x_("%s"), returninfstr(infstr));
926 efree((CHAR *)arpe);
927 }
928 efree((CHAR *)arpelist);
929 gtotal = net_transistor_p_gate.count + net_transistor_n_gate.count;
930 if (gtotal > 0)
931 {
932 infstr = initinfstr();
933 formatinfstr(infstr, _("Connects to the gate of %ld %s (total width %s, average length %s)"),
934 gtotal, makeplural(_("transistor"), gtotal),
935 latoa(net_transistor_p_gate.width+net_transistor_n_gate.width, 0),
936 latoa((net_transistor_p_gate.length+net_transistor_n_gate.length)/gtotal, 0));
937 ttyputmsg(x_("%s"), returninfstr(infstr));
938 }
939 atotal = net_transistor_p_active.count + net_transistor_n_active.count;
940 if (atotal > 0)
941 {
942 infstr = initinfstr();
943 formatinfstr(infstr, _("Connects to the active of %ld %s (total width %s, average length %s)"),
944 atotal, makeplural(_("transistor"), atotal),
945 latoa(net_transistor_p_active.width+net_transistor_n_active.width, 0),
946 latoa((net_transistor_p_active.length+net_transistor_n_active.length)/atotal, 0));
947 ttyputmsg(x_("%s"), returninfstr(infstr));
948 }
949 if (metpolhalfperim > 0 && gtotal > 0 && atotal > 0)
950 {
951 ttyputmsg(x_("---------- Load Calculations:"));
952 ttyputmsg(x_("Sum of Metal and Poly half-perimeters / wire-ratio = %s"), latoa(metpolhalfperim, 0));
953 load = metpolhalfperim + net_transistor_p_gate.width+net_transistor_n_gate.width;
954 ttyputmsg(x_(" Sum + gate-width (%s) = %s (Load)"),
955 latoa(net_transistor_p_gate.width+net_transistor_n_gate.width, 0), latoa(load, 0));
956 if (net_transistor_p_active.width != 0)
957 ttyputmsg(x_(" Load / P-active-width (%s) = %g"), latoa(net_transistor_p_active.width, 0),
958 (float)load / (float)net_transistor_p_active.width);
959 if (net_transistor_n_active.width != 0)
960 ttyputmsg(x_(" Load / N-active-width (%s) = %g"), latoa(net_transistor_n_active.width, 0),
961 (float)load / (float)net_transistor_n_active.width);
962 }
963 }
964 }
965
966 /******************** CELL EXTRACTION ********************/
967
968 /*
969 * Routine to gather all relevant nodes in the current cell and build the structure
970 * headed by "le_firstlenode".
971 */
le_gathercell(INTBIG show)972 void le_gathercell(INTBIG show)
973 {
974 REGISTER INTBIG inport, oinport, which;
975 REGISTER BOOLEAN first;
976 REGISTER INTBIG arrowsize, x, y, i, type;
977 INTBIG inputs;
978 REGISTER NODEINST *ni;
979 REGISTER ARCINST *ai, *oai;
980 REGISTER NODEPROTO *np;
981 REGISTER NETWORK *net;
982 REGISTER VARIABLE *var;
983 REGISTER PORTARCINST *pi, *opi;
984 LENODE *le, *ole;
985 double cap;
986 REGISTER void *infstr;
987
988 /* make sure there is a current cell */
989 le_freealllenodes();
990 np = getcurcell();
991 if (np == NONODEPROTO) return;
992
993 /* reset to find power and ground nets */
994 for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
995 net->temp1 = 0;
996
997 /* gather all relevant nodes in the cell */
998 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
999 {
1000 type = le_getgatetype(ni, &inputs);
1001 switch (type)
1002 {
1003 case LEUNKNOWN:
1004 case LETERMINAL:
1005 break;
1006 case LEPOWER:
1007 case LEGROUND:
1008 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1009 if (pi->conarcinst->network != NONETWORK)
1010 pi->conarcinst->network->temp1 = 1;
1011 break;
1012 default:
1013 le = le_alloclenode();
1014 if (le == NOLENODE) break;
1015 le->ni = ni;
1016 le->piin = le->piout = NOPORTARCINST;
1017 le->cin = 0.0;
1018 le->cout = 0.0;
1019 le->type = type;
1020 le->inputs = inputs;
1021 le->logeffort = le_getlogeffort(le);
1022 le->parasitics = le_getparasitics(le);
1023 le->numinputnodes = 0;
1024 le->numoutputnodes = 0;
1025 le->nextlenode = le_firstlenode;
1026 le_firstlenode = le;
1027 break;
1028 }
1029 }
1030
1031 /* add input capacitances to the LENODEs */
1032 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1033 ai->temp1 = 0;
1034 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
1035 {
1036 for(pi = le->ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1037 {
1038 ai = pi->conarcinst;
1039 if (ai->network == NONETWORK) continue;
1040 if ((pi->proto->userbits & STATEBITS) != INPORT) continue;
1041
1042 /* see if there is a capacitance specification on the input to this node */
1043 cap = le_getcapacitance(ai->network);
1044 if (cap == 0.0) continue;
1045 le->cin = cap;
1046 ai->temp1 = 1;
1047 }
1048 }
1049
1050 /* create additional LENODEs for those nodes with input capacitances */
1051 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1052 {
1053 /* see if there is capacitance on this node */
1054 var = getvalkey((INTBIG)ni, VNODEINST, -1, le_attrcapacitance_key);
1055 if (var == NOVARIABLE) continue;
1056
1057 cap = eatof(describesimplevariable(var));
1058 le = le_alloclenode();
1059 if (le == NOLENODE) continue;
1060 le->ni = ni;
1061 le->piin = le->piout = NOPORTARCINST;
1062 le->cin = cap;
1063 le->cout = 0.0;
1064 le->type = LETERMINAL;
1065 le->logeffort = 1.0;
1066 le->parasitics = 0.0;
1067 le->numinputnodes = 0;
1068 le->numoutputnodes = 0;
1069 le->nextlenode = le_firstlenode;
1070 le_firstlenode = le;
1071 }
1072
1073 /* add linkage between the nodes */
1074 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
1075 {
1076 for(pi = le->ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1077 {
1078 ai = pi->conarcinst;
1079 if (ai->network == NONETWORK) continue;
1080 if (ai->network->temp1 != 0) continue;
1081 switch (pi->proto->userbits & STATEBITS)
1082 {
1083 case INPORT: inport = 1; break;
1084 case BIDIRPORT:
1085 case OUTPORT: inport = 0; break;
1086 default: inport = -1; break;
1087 }
1088 if (le->type == LETERMINAL) inport = 1;
1089 if (inport < 0) continue;
1090
1091 /* find other LENODE that connects to this */
1092 for(ole = le->nextlenode; ole != NOLENODE; ole = ole->nextlenode)
1093 {
1094 for(opi = ole->ni->firstportarcinst; opi != NOPORTARCINST; opi = opi->nextportarcinst)
1095 {
1096 oai = opi->conarcinst;
1097 if (oai->network != ai->network) continue;
1098 if (oai->network->temp1 != 0) continue;
1099
1100 /* LENODEs connect, check directionality of ports */
1101 switch (opi->proto->userbits & STATEBITS)
1102 {
1103 case INPORT: oinport = 1; break;
1104 case BIDIRPORT:
1105 case OUTPORT: oinport = 0; break;
1106 default: oinport = -1; break;
1107 }
1108 if (ole->type == LETERMINAL) oinport = 1;
1109 if (oinport < 0) continue;
1110
1111 /* figure out how to connect them */
1112 if (inport != 0)
1113 {
1114 /* configure input on node "le" */
1115 if (oinport != 0) continue;
1116 le_addlinkage(ole, opi, le, pi);
1117 } else
1118 {
1119 /* configure output on node "le" */
1120 if (oinport == 0)
1121 {
1122 ttyputerr(_("Node %s and %s drive the same network"),
1123 le_describenode(le), le_describenode(ole));
1124 continue;
1125 }
1126 le_addlinkage(le, pi, ole, opi);
1127 }
1128 }
1129 }
1130 }
1131 }
1132
1133 /* stop now if display is not requested */
1134 if (show == 0) return;
1135
1136 /* display the nodes */
1137 infstr = initinfstr();
1138 first = FALSE;
1139 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
1140 {
1141 if (first) addtoinfstr(infstr, '\n');
1142 first = TRUE;
1143 formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0"),
1144 describenodeproto(np), (INTBIG)le->ni->geom);
1145 }
1146 (void)asktool(us_tool, x_("show-multiple"), (INTBIG)returninfstr(infstr));
1147
1148 /* display the connection sites */
1149 arrowsize = lambdaofcell(np) * 2;
1150 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
1151 {
1152 if (le->piin != NOPORTARCINST)
1153 {
1154 ai = le->piin->conarcinst;
1155 if (ai->end[0].portarcinst == le->piin) which = 0; else which = 1;
1156 x = ai->end[which].xpos;
1157 y = ai->end[which].ypos;
1158 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize, y-arrowsize, ai->parent);
1159 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize/2, y-arrowsize/5, ai->parent);
1160 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize/5, y-arrowsize/2, ai->parent);
1161 }
1162 for(i=0; i<le->numoutputnodes; i++)
1163 {
1164 ai = le->outputports[i]->conarcinst;
1165 if (ai->end[0].portarcinst == le->outputports[i]) which = 0; else which = 1;
1166 x = ai->end[which].xpos+arrowsize;
1167 y = ai->end[which].ypos+arrowsize;
1168 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize, y-arrowsize, ai->parent);
1169 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize/2, y-arrowsize/5, ai->parent);
1170 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize/5, y-arrowsize/2, ai->parent);
1171 }
1172 }
1173 }
1174
1175 /*
1176 * Routine to add a connection that runs out of LENODE "out", port "outpi" into
1177 * LENODE "in", port "inpi".
1178 */
le_addlinkage(LENODE * out,PORTARCINST * outpi,LENODE * in,PORTARCINST * inpi)1179 void le_addlinkage(LENODE *out, PORTARCINST *outpi, LENODE *in, PORTARCINST *inpi)
1180 {
1181 LENODE **newinputnodelist, **newoutputnodelist;
1182 PORTARCINST **newinputportlist, **newoutputportlist;
1183 REGISTER INTBIG i;
1184
1185 /* add input node to list of outputs */
1186 newoutputnodelist = (LENODE **)emalloc((out->numoutputnodes+1) * (sizeof (LENODE *)), le_tool->cluster);
1187 newoutputportlist = (PORTARCINST **)emalloc((out->numoutputnodes+1) * (sizeof (PORTARCINST *)), le_tool->cluster);
1188 for(i=0; i<out->numoutputnodes; i++)
1189 {
1190 newoutputnodelist[i] = out->outputnodes[i];
1191 newoutputportlist[i] = out->outputports[i];
1192 }
1193 newoutputnodelist[out->numoutputnodes] = in;
1194 newoutputportlist[out->numoutputnodes] = outpi;
1195 if (out->numoutputnodes > 0)
1196 {
1197 efree((CHAR *)out->outputnodes);
1198 efree((CHAR *)out->outputports);
1199 }
1200 out->outputnodes = newoutputnodelist;
1201 out->outputports = newoutputportlist;
1202 out->numoutputnodes++;
1203
1204 /* add output node to list of inputs */
1205 newinputnodelist = (LENODE **)emalloc((in->numinputnodes+1) * (sizeof (LENODE *)), le_tool->cluster);
1206 newinputportlist = (PORTARCINST **)emalloc((in->numinputnodes+1) * (sizeof (PORTARCINST *)), le_tool->cluster);
1207 for(i=0; i<in->numinputnodes; i++)
1208 {
1209 newinputnodelist[i] = in->inputnodes[i];
1210 newinputportlist[i] = in->inputports[i];
1211 }
1212 newinputnodelist[in->numinputnodes] = out;
1213 newinputportlist[in->numinputnodes] = inpi;
1214 if (in->numinputnodes > 0)
1215 {
1216 efree((CHAR *)in->inputnodes);
1217 efree((CHAR *)in->inputports);
1218 }
1219 in->inputnodes = newinputnodelist;
1220 in->inputports = newinputportlist;
1221 in->numinputnodes++;
1222 }
1223
le_analyzecell(void)1224 void le_analyzecell(void)
1225 {
1226 REGISTER LENODE *le;
1227 REGISTER PORTARCINST *pi;
1228 REGISTER INTBIG iteration, changeneeded, changemade, i, displaycapacitance, state;
1229 REGISTER VARIABLE *var;
1230 CHAR line[50];
1231 double h, needed, maxstageeffort;
1232
1233 /* determine maximum stage effort */
1234 var = getvalkey((INTBIG)le_tool, VTOOL, VFLOAT, le_maximumstageeffort_key);
1235 if (var == NOVARIABLE) maxstageeffort = MAXSTAGEEFFORT; else
1236 maxstageeffort = (double)castfloat(var->addr);
1237 ttyputmsg(_("Maximum stage effort is %g"), maxstageeffort);
1238
1239 /* now iterate */
1240 for(iteration=0; iteration<MAXITERATIONS; iteration++)
1241 {
1242 changeneeded = changemade = 0;
1243 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
1244 {
1245 /* propagate this node */
1246 if (le->numoutputnodes == 0) continue;
1247
1248 /* sum up all of the capacitances that this node generates */
1249 le->cout = 0.0;
1250 for(i=0; i<le->numoutputnodes; i++)
1251 {
1252 le->cout += le->outputnodes[i]->cin;
1253 }
1254
1255 /* see if this node can generate that much capacitance */
1256 needed = le->cout / maxstageeffort * le->logeffort;
1257 if (le->cin < needed)
1258 {
1259 changeneeded = 1;
1260 if (le->cin != needed) changemade = 1;
1261 le->cin = needed;
1262 }
1263 }
1264 if (changemade == 0) break;
1265 }
1266 if (changemade != 0)
1267 {
1268 ttyputerr(_("WARNING: After %d iterations, analysis is still not stable"), MAXITERATIONS);
1269 } else if (changeneeded != 0)
1270 {
1271 ttyputerr(_("WARNING: Unable to find solution with maximum stage effort of %g"), maxstageeffort);
1272 }
1273
1274 /* determine whether or not to set capacitance values */
1275 var = getvalkey((INTBIG)le_tool, VTOOL, VINTEGER, le_state_key);
1276 if (var == NOVARIABLE) state = DEFAULTSTATE; else
1277 state = var->addr;
1278 displaycapacitance = state & DISPLAYCAPACITANCE;
1279
1280 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
1281 {
1282 if (le->numoutputnodes == 0) continue;
1283 if (displaycapacitance != 0)
1284 {
1285 for(pi = le->ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1286 {
1287 if ((pi->proto->userbits & STATEBITS) != INPORT) continue;
1288 le_setarccapacitance(pi->conarcinst, le->cin);
1289 }
1290 }
1291 h = le->cout / le->cin;
1292 esnprintf(line, 50, x_("h=%g"), h);
1293 startobjectchange((INTBIG)le->ni, VNODEINST);
1294 setvalkey((INTBIG)le->ni, VNODEINST, le_fanout_key, (INTBIG)line, VSTRING|VDISPLAY);
1295 endobjectchange((INTBIG)le->ni, VNODEINST);
1296 }
1297 }
1298
1299 /******************** PATH EXTRACTION ********************/
1300
1301 /*
1302 * Routine to gather a path, given that two nodes at the ends of the path
1303 * are highlighted. Fills the list of LENODEs pointed to by "le_firstlenode".
1304 */
le_gatherpath(INTBIG show)1305 void le_gatherpath(INTBIG show)
1306 {
1307 REGISTER BOOLEAN first;
1308 REGISTER INTBIG edge, x, y, arrowsize, agree, disagree, which;
1309 REGISTER NODEINST *ret, *ni;
1310 REGISTER ARCINST *ai;
1311 REGISTER NODEPROTO *np;
1312 REGISTER PORTARCINST *pi;
1313 double c, cstart, cend;
1314 GEOM **list;
1315 LENODE *le, *newle, *nextle, *lastle;
1316 REGISTER void *infstr;
1317
1318 /* make sure there is a current cell */
1319 le_freealllenodes();
1320 np = getcurcell();
1321 if (np == NONODEPROTO) return;
1322
1323 /* get all selected objects (must be 2 nodes) */
1324 list = (GEOM **)asktool(us_tool, x_("get-all-objects"));
1325 if (list[0] == NOGEOM || list[1] == NOGEOM || list[2] != NOGEOM)
1326 {
1327 ttyputerr(_("Select two objects at the ends of a path"));
1328 return;
1329 }
1330
1331 /* find a path from one node to the other (wavefront propagation) */
1332 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1333 ni->temp1 = ni->temp2 = 0;
1334 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1335 ai->temp1 = ai->temp2 = 0;
1336 if (list[0]->entryisnode)
1337 {
1338 ni = list[0]->entryaddr.ni;
1339 ni->temp1 = 1;
1340 cstart = 0.0;
1341 } else
1342 {
1343 ai = list[0]->entryaddr.ai;
1344 ai->temp2 = 1;
1345 ai->end[0].nodeinst->temp1 = 1;
1346 ai->end[1].nodeinst->temp1 = 1;
1347 cstart = le_getcapacitance(ai->network);
1348 }
1349 if (list[1]->entryisnode)
1350 {
1351 ni = list[1]->entryaddr.ni;
1352 ni->temp1 = -1;
1353 cend = 0.0;
1354 } else
1355 {
1356 ai = list[1]->entryaddr.ai;
1357 ai->temp2 = 1;
1358 ai->end[0].nodeinst->temp1 = -1;
1359 ai->end[1].nodeinst->temp1 = -1;
1360 cend = le_getcapacitance(ai->network);
1361 }
1362 for(edge = 1; ; edge++)
1363 {
1364 ret = le_propagate(np, edge);
1365 if (ret != 0) break;
1366 }
1367 if (ret == NONODEINST)
1368 {
1369 ttyputerr(_("No path exists between these nodes"));
1370 return;
1371 }
1372
1373 /* unwind the path and create a chain of LENODEs */
1374 le_lastlenode = NOLENODE;
1375 le_lastcapacitance = 1.0;
1376 le_unwind(ret, NONODEINST);
1377 if (le_firstlenode != NOLENODE)
1378 {
1379 if (cstart != 0.0) le_firstlenode->cin = cstart;
1380 if (cend != 0.0)
1381 {
1382 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode) lastle = le;
1383 lastle->cout = cend;
1384 }
1385 }
1386
1387 /* reverse the path if the ports indicate it */
1388 agree = disagree = 0;
1389 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
1390 {
1391 if (le->piin != NOPORTARCINST)
1392 {
1393 switch (le->piin->proto->userbits & STATEBITS)
1394 {
1395 case INPORT: agree++; break;
1396 case OUTPORT: disagree++; break;
1397 }
1398 }
1399 if (le->piout != NOPORTARCINST)
1400 {
1401 switch (le->piout->proto->userbits & STATEBITS)
1402 {
1403 case INPORT: disagree++; break;
1404 case OUTPORT: agree++; break;
1405 }
1406 }
1407 }
1408 if (agree != 0 && disagree != 0)
1409 ttyputmsg(_("Directionality of path is conflicting"));
1410 if (agree == 0 && disagree == 0)
1411 ttyputmsg(_("Directionality of path is unknown"));
1412 if (disagree != 0)
1413 {
1414 /* reverse the path */
1415 newle = NOLENODE;
1416 for(le = le_firstlenode; le != NOLENODE; le = nextle)
1417 {
1418 nextle = le->nextlenode;
1419 le->nextlenode = newle;
1420 newle = le;
1421 pi = le->piin; le->piin = le->piout; le->piout = pi;
1422 c = le->cin; le->cin = le->cout; le->cout = c;
1423 }
1424 le_firstlenode = newle;
1425 }
1426
1427 /* add back-pointers to path */
1428 lastle = NOLENODE;
1429 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
1430 {
1431 le->prevlenode = lastle;
1432 lastle = le;
1433 }
1434
1435 /* determine branching */
1436 le_figurebranching();
1437
1438 /* stop now if display is not requested */
1439 if (show == 0) return;
1440
1441 /* describe the nodes in the path */
1442 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
1443 {
1444 ttyputmsg(_("%s: LogEffort=%g Parasitics=%g Cin=%g Cout=%g Branching=%g"),
1445 le_describenode(le), le->logeffort, le->parasitics, le->cin, le->cout,
1446 le->branching);
1447 }
1448
1449 /* display the path between the nodes */
1450 (void)asktool(us_tool, x_("clear"));
1451 infstr = initinfstr();
1452 first = FALSE;
1453 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1454 {
1455 if (ni->temp2 == 0) continue;
1456 if (first) addtoinfstr(infstr, '\n');
1457 first = TRUE;
1458 formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0"),
1459 describenodeproto(np), (INTBIG)ni->geom);
1460 }
1461 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1462 {
1463 if (ai->temp2 == 0) continue;
1464 addtoinfstr(infstr, '\n');
1465 formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0"),
1466 describenodeproto(np), (INTBIG)ai->geom);
1467 }
1468 (void)asktool(us_tool, x_("show-multiple"), (INTBIG)returninfstr(infstr));
1469
1470 arrowsize = lambdaofcell(np) * 2;
1471 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
1472 {
1473 if (le->piin != NOPORTARCINST)
1474 {
1475 ai = le->piin->conarcinst;
1476 if (ai->end[0].portarcinst == le->piin) which = 0; else which = 1;
1477 x = ai->end[which].xpos;
1478 y = ai->end[which].ypos;
1479 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize, y-arrowsize, ai->parent);
1480 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize/2, y-arrowsize/5, ai->parent);
1481 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize/5, y-arrowsize/2, ai->parent);
1482 }
1483 if (le->piout != NOPORTARCINST)
1484 {
1485 ai = le->piout->conarcinst;
1486 if (ai->end[0].portarcinst == le->piout) which = 0; else which = 1;
1487 x = ai->end[which].xpos+arrowsize;
1488 y = ai->end[which].ypos+arrowsize;
1489 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize, y-arrowsize, ai->parent);
1490 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize/2, y-arrowsize/5, ai->parent);
1491 (void)asktool(us_tool, x_("show-line"), x, y, x-arrowsize/5, y-arrowsize/2, ai->parent);
1492 }
1493 }
1494 }
1495
1496 /*
1497 * helper function for "le_gatherpath" which propagates a wave of connectivity
1498 * through the circuit to find a path between the end nodes.
1499 * Returns NONODEINST if the propagation has failed to advance.
1500 * Returns zero if the propagation must run more.
1501 * Returns a NODEINST if it has found that node at then end of the path
1502 */
le_propagate(NODEPROTO * cell,INTBIG edge)1503 NODEINST *le_propagate(NODEPROTO *cell, INTBIG edge)
1504 {
1505 REGISTER NODEINST *ni, *oni;
1506 REGISTER PORTARCINST *pi;
1507 REGISTER ARCINST *ai;
1508 REGISTER INTBIG otherend, moved;
1509
1510 moved = 0;
1511 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1512 {
1513 if (ni->temp1 != edge) continue;
1514
1515 /* propagate from here */
1516 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1517 {
1518 ai = pi->conarcinst;
1519 if (ai->end[0].portarcinst == pi) otherend = 1; else otherend = 0;
1520 oni = ai->end[otherend].nodeinst;
1521 if (oni->temp1 == -1)
1522 {
1523 ai->temp1 = edge;
1524 oni->temp1 = edge+1;
1525 return(oni);
1526 }
1527 if (oni->temp1 == 0)
1528 {
1529 ai->temp1 = edge;
1530 oni->temp1 = edge+1;
1531 moved++;
1532 }
1533 }
1534 }
1535 if (moved == 0) return(NONODEINST);
1536 return(0);
1537 }
1538
1539 /*
1540 * helper function for "le_gatherpath" which retraces the wave information
1541 * to construct the minimum path between two nodes.
1542 */
le_unwind(NODEINST * start,NODEINST * prev)1543 void le_unwind(NODEINST *start, NODEINST *prev)
1544 {
1545 REGISTER NODEINST *oni;
1546 REGISTER PORTARCINST *pi;
1547 REGISTER ARCINST *ai;
1548 REGISTER INTBIG otherend;
1549 double capacitance;
1550 REGISTER INTBIG func;
1551 LENODE *le;
1552
1553 /* add this node to the chain, if it can be analyzed */
1554 le = NOLENODE;
1555 func = nodefunction(start);
1556 switch (func)
1557 {
1558 case NPPIN:
1559 case NPCONTACT:
1560 case NPNODE:
1561 case NPCONNECT:
1562 case NPCONPOWER:
1563 case NPCONGROUND:
1564 break;
1565 case NPBUFFER:
1566 case NPGATEAND:
1567 case NPGATEOR:
1568 case NPGATEXOR:
1569 le = le_alloclenode();
1570 if (le == NOLENODE) break;
1571 le->ni = start;
1572 le->piin = le->piout = NOPORTARCINST;
1573 le->cin = 0.0;
1574 le->cout = le_lastcapacitance;
1575 le->type = le_getgatetype(start, &le->inputs);
1576 le->logeffort = le_getlogeffort(le);
1577 le->parasitics = le_getparasitics(le);
1578 le->numinputnodes = 0;
1579 le->numoutputnodes = 0;
1580 le_lastcapacitance = 1.0;
1581 le->nextlenode = le_firstlenode;
1582 le_firstlenode = le;
1583 le_lastlenode = le;
1584 break;
1585 default:
1586 ttyputmsg(_("Sorry, cannot analyze %s nodes"), nodefunctionname(func, start));
1587 break;
1588 }
1589 if (le != NOLENODE)
1590 {
1591 for(pi = start->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1592 {
1593 ai = pi->conarcinst;
1594 if (ai->temp1 == 0) continue;
1595 if (ai->end[0].portarcinst == pi) otherend = 1; else otherend = 0;
1596 oni = ai->end[otherend].nodeinst;
1597 if (oni == prev) le->piout = pi;
1598 if (ai->temp1 == start->temp1 - 1 && oni->temp1 == start->temp1 - 1)
1599 le->piin = pi;
1600 }
1601 }
1602
1603 /* mark and trace the path */
1604 start->temp2 = 1;
1605 if (start->temp1 == 1) return;
1606 for(pi = start->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1607 {
1608 ai = pi->conarcinst;
1609 if (ai->temp1 == 0) continue;
1610 if (ai->end[0].portarcinst == pi) otherend = 1; else otherend = 0;
1611 oni = ai->end[otherend].nodeinst;
1612 if (ai->temp1 == start->temp1 - 1 && oni->temp1 == start->temp1 - 1)
1613 {
1614 ai->temp2 = 1;
1615 capacitance = le_getcapacitance(ai->network);
1616 if (capacitance != 0.0)
1617 {
1618 if (le_lastlenode != NOLENODE) le_lastlenode->cin = capacitance;
1619 le_lastcapacitance = capacitance;
1620 }
1621 le_unwind(oni, start);
1622 break;
1623 }
1624 }
1625 }
1626
1627 /*
1628 * Routine to figure out the branching for the chain of LENODEs pointed to by
1629 * "le_firstlenode". Loads the "branching" field of each LENODE.
1630 */
le_figurebranching(void)1631 void le_figurebranching(void)
1632 {
1633 REGISTER LENODE *le, *nextle;
1634 REGISTER ARCINST *ai;
1635 REGISTER PORTARCINST *pi;
1636 double onpath, offpath;
1637
1638 for(le = le_firstlenode; le != NOLENODE; le = le->nextlenode)
1639 {
1640 nextle = le->nextlenode;
1641 le->branching = 1.0;
1642 if (nextle == NOLENODE) continue;
1643 if (le->piout == NOPORTARCINST) continue;
1644
1645 /* reset indication of arcs that have been examined */
1646 for(ai = le->ni->parent->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1647 ai->temp1 = 0;
1648
1649 /* find useful and stray capacitance in network coming from this LE node */
1650 onpath = 0.0;
1651 offpath = 0.0;
1652 for(pi = le->ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1653 {
1654 if (pi->proto != le->piout->proto) continue;
1655 le_propagatebranch(pi, nextle, 1.0, &onpath, &offpath);
1656 }
1657
1658 /* determine branching factor */
1659 if (onpath == 0.0) le->branching = 1.0; else
1660 le->branching = (onpath + offpath) / onpath;
1661 }
1662 }
1663
1664 /*
1665 * Helper routine for "le_figurebranching" to propagate through the circuit, starting at
1666 * port "tpi" and gather capacitances into either "onpath" (if the path ends at the
1667 * desired "final" LENODE) or "offpath". "capacitance" is the capacitance value seen
1668 * so far while following the path.
1669 */
le_propagatebranch(PORTARCINST * tpi,LENODE * final,double capacitance,double * onpath,double * offpath)1670 void le_propagatebranch(PORTARCINST *tpi, LENODE *final, double capacitance,
1671 double *onpath, double *offpath)
1672 {
1673 REGISTER ARCINST *ai;
1674 REGISTER PORTARCINST *pi;
1675 REGISTER INTBIG otherend;
1676 REGISTER INTBIG func;
1677 double cap;
1678 REGISTER NODEINST *oni;
1679
1680 /* see if this arc has been examined */
1681 ai = tpi->conarcinst;
1682 if (ai->temp1 != 0) return;
1683 ai->temp1 = 1;
1684
1685 /* gather any capacitance specification on this arc */
1686 cap = le_getcapacitance(ai->network);
1687 if (cap != 0.0) capacitance = cap;
1688
1689 /* see if the other end of the arc is a terminal point */
1690 if (ai->end[0].portarcinst == tpi) otherend = 1; else otherend = 0;
1691 oni = ai->end[otherend].nodeinst;
1692 func = nodefunction(oni);
1693 if (func != NPPIN && func != NPCONTACT && func != NPNODE && func != NPCONNECT)
1694 {
1695 /* end of this chain: add capacitance into one of the path accumulators */
1696 if (oni == final->ni) *onpath += capacitance; else
1697 *offpath += capacitance;
1698 return;
1699 }
1700
1701 /* propagate further */
1702 for(pi = oni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1703 {
1704 le_propagatebranch(pi, final, capacitance, onpath, offpath);
1705 }
1706 }
1707
1708 /******************** SUPPORT ********************/
1709
1710 /*
1711 * Routine to determine the type of object at "ni", returning the type and the number
1712 * of inputs.
1713 */
le_getgatetype(NODEINST * ni,INTBIG * inputs)1714 INTBIG le_getgatetype(NODEINST *ni, INTBIG *inputs)
1715 {
1716 REGISTER INTBIG inputnegates, outputnegates, thisend, isinput, gatetype, func;
1717 CHAR *inputport, *outputport1, *outputport2;
1718 REGISTER ARCINST *ai;
1719 REGISTER PORTARCINST *pi;
1720 REGISTER VARIABLE *var;
1721
1722 /* determine the number of inputs to the gate */
1723 *inputs = 0;
1724 inputnegates = outputnegates = 0;
1725 func = nodefunction(ni);
1726 if (func == NPUNKNOWN)
1727 {
1728 /* ignore if it is a capacitance element */
1729 var = getvalkey((INTBIG)ni, VNODEINST, -1, le_attrcapacitance_key);
1730 if (var == NOVARIABLE)
1731 ttyputmsg(_("Sorry, Logical Effort cannot handle cells"));
1732 return(NPUNKNOWN);
1733 }
1734
1735 inputport = x_("a"); outputport1 = outputport2 = x_("y");
1736 if (func == NPTRANMOS || func == NPTRAPMOS)
1737 {
1738 inputport = x_("g"); outputport1 = x_("s"); outputport2 = x_("d");
1739 }
1740 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1741 {
1742 isinput = 0;
1743 if (estrcmp(pi->proto->protoname, inputport) == 0)
1744 {
1745 isinput = 1;
1746 (*inputs)++;
1747 }
1748 if (estrcmp(pi->proto->protoname, inputport) == 0 ||
1749 estrcmp(pi->proto->protoname, outputport1) == 0 ||
1750 estrcmp(pi->proto->protoname, outputport2) == 0)
1751 {
1752 if ((pi->conarcinst->userbits&ISNEGATED) != 0)
1753 {
1754 ai = pi->conarcinst;
1755 if (ai->end[0].portarcinst == pi) thisend = 0; else thisend = 1;
1756 if ((thisend == 0 && (ai->userbits&REVERSEEND) == 0) ||
1757 (thisend == 1 && (ai->userbits&REVERSEEND) != 0))
1758 {
1759 if (isinput != 0) inputnegates++; else outputnegates++;
1760 }
1761 }
1762 }
1763 }
1764
1765 /* determine the type of the gate */
1766 gatetype = LEUNKNOWN;
1767 switch (func)
1768 {
1769 case NPBUFFER:
1770 if (inputnegates+outputnegates == 0)
1771 {
1772 ttyputmsg(_("Cannot handle BUFFER gates, only INVERTER"));
1773 } else if (inputnegates+outputnegates != 1)
1774 {
1775 ttyputmsg(_("Cannot handle INVERTER gates that invert more than once"));
1776 } else gatetype = LEINVERTER;
1777 break;
1778
1779 case NPGATEAND:
1780 if (inputnegates != 0)
1781 {
1782 ttyputmsg(_("Cannot handle AND gates with inverted inputs"));
1783 } else if (outputnegates == 0)
1784 {
1785 ttyputmsg(_("Cannot handle AND gates, only NAND"));
1786 } else gatetype = LENAND;
1787 break;
1788
1789 case NPGATEOR:
1790 if (inputnegates != 0)
1791 {
1792 ttyputmsg(_("Cannot handle OR gates with inverted inputs"));
1793 } else if (outputnegates == 0)
1794 {
1795 ttyputmsg(_("Cannot handle OR gates, only NOR"));
1796 } else gatetype = LENOR;
1797 break;
1798
1799 case NPGATEXOR:
1800 if (inputnegates != 0)
1801 {
1802 ttyputmsg(_("Cannot handle XOR gates with inverted inputs"));
1803 } else
1804 {
1805 if (outputnegates != 0) gatetype = LEXNOR; else
1806 gatetype = LEXOR;
1807 }
1808 break;
1809
1810 case NPTRANMOS:
1811 if (inputnegates != 0 || outputnegates != 0)
1812 {
1813 ttyputmsg(_("Cannot negate inputs to transistors"));
1814 } else gatetype = LENMOS;
1815 break;
1816
1817 case NPTRAPMOS:
1818 if (inputnegates != 0 || outputnegates != 0)
1819 {
1820 ttyputmsg(_("Cannot negate inputs to transistors"));
1821 } else gatetype = LEPMOS;
1822 break;
1823
1824 case NPCONPOWER:
1825 if (inputnegates != 0 || outputnegates != 0)
1826 {
1827 ttyputmsg(_("Cannot negate inputs to power"));
1828 } else gatetype = LEPOWER;
1829 break;
1830
1831 case NPCONGROUND:
1832 if (inputnegates != 0 || outputnegates != 0)
1833 {
1834 ttyputmsg(_("Cannot negate inputs to ground"));
1835 } else gatetype = LEGROUND;
1836 break;
1837
1838 case NPPIN:
1839 case NPCONTACT:
1840 case NPNODE:
1841 case NPCONNECT:
1842 break;
1843
1844 default:
1845 ttyputmsg(_("Sorry, Logical Effort cannot handle %s nodes"), nodefunctionname(func, ni));
1846 break;
1847 }
1848
1849 return(gatetype);
1850 }
1851
1852 /*
1853 * Routine to return a string describing LENODE "le".
1854 */
le_describenode(LENODE * le)1855 CHAR *le_describenode(LENODE *le)
1856 {
1857 REGISTER VARIABLE *var;
1858 REGISTER void *infstr;
1859
1860 infstr = initinfstr();
1861 switch (le->type)
1862 {
1863 case LEINVERTER:
1864 addstringtoinfstr(infstr, _("inverter"));
1865 break;
1866 case LENAND:
1867 addstringtoinfstr(infstr, _("nand"));
1868 break;
1869 case LENOR:
1870 addstringtoinfstr(infstr, _("nor"));
1871 break;
1872 case LEXOR:
1873 addstringtoinfstr(infstr, _("xor"));
1874 break;
1875 case LEXNOR:
1876 addstringtoinfstr(infstr, _("xnor"));
1877 break;
1878 case LENMOS:
1879 addstringtoinfstr(infstr, _("nMOS"));
1880 break;
1881 case LEPMOS:
1882 addstringtoinfstr(infstr, _("pMOS"));
1883 break;
1884 default:
1885 addstringtoinfstr(infstr, describenodeproto(le->ni->proto));
1886 break;
1887 }
1888 var = getvalkey((INTBIG)le->ni, VNODEINST, VSTRING, el_node_name_key);
1889 if (var != NOVARIABLE)
1890 {
1891 addstringtoinfstr(infstr, x_("["));
1892 addstringtoinfstr(infstr, (CHAR *)var->addr);
1893 addstringtoinfstr(infstr, x_("]"));
1894 }
1895 return(returninfstr(infstr));
1896 }
1897
1898 /*
1899 * Routine to determine the logical effort of the gate in "le". Uses the table
1900 * from page 7 of Sutherland's book.
1901 */
le_getlogeffort(LENODE * le)1902 double le_getlogeffort(LENODE *le)
1903 {
1904 REGISTER VARIABLE *var;
1905 REGISTER CHAR *pt;
1906
1907 /* see if there is an override on the node */
1908 var = getvalkey((INTBIG)le->ni, VNODEINST, VSTRING, le_nodeeffort_key);
1909 if (var != NOVARIABLE)
1910 {
1911 pt = (CHAR *)var->addr;
1912 while (*pt == ' ' || *pt == '\t') pt++;
1913 if (*pt == 'g' || *pt == 'G')
1914 {
1915 pt++;
1916 while (*pt == ' ' || *pt == '\t') pt++;
1917 }
1918 if (*pt == '=')
1919 {
1920 pt++;
1921 while (*pt == ' ' || *pt == '\t') pt++;
1922 }
1923 return(eatof(pt));
1924 }
1925
1926 /* calculate the logical effort */
1927 switch (le->type)
1928 {
1929 case LEINVERTER: return(1.0);
1930 case LENAND: return((le->inputs+2.0) / 3.0);
1931 case LENOR: return((2.0*le->inputs+1.0) / 3.0);
1932 case LEXOR:
1933 case LEXNOR:
1934 switch (le->inputs)
1935 {
1936 case 2: return(4.0);
1937 case 3: return(12.0);
1938 case 4: return(32.0);
1939 }
1940 ttyputmsg(_("Cannot handle %ld-input XOR gates"), le->inputs);
1941 return(0.0);
1942 case LENMOS: return(1.0/3.0);
1943 case LEPMOS: return(2.0/3.0);
1944 }
1945 ttyputmsg(_("Sorry, node %s has unknown type"), describenodeinst(le->ni));
1946 return(0.0);
1947 }
1948
1949 /*
1950 * Routine to determine the parasitics of the gate in "le". Uses the table
1951 * from page 10 of Sutherland's book.
1952 */
le_getparasitics(LENODE * le)1953 double le_getparasitics(LENODE *le)
1954 {
1955 switch (le->type)
1956 {
1957 case LEINVERTER: return(1.0);
1958 case LENAND: return((double)le->inputs);
1959 case LENOR: return((double)le->inputs);
1960 case LEXOR: return(4.0);
1961 case LEXNOR: return(4.0);
1962 case LENMOS: return(1.0); /* probably not right!!! */
1963 case LEPMOS: return(1.0); /* probably not right!!! */
1964 }
1965 ttyputmsg(_("Sorry, node %s has unknown type"), describenodeinst(le->ni));
1966 return(0.0);
1967 }
1968
1969 /*
1970 * Routine to extract the capacitance value that is stored on network "net".
1971 * Returns zero if no value is stored there.
1972 */
le_getcapacitance(NETWORK * net)1973 double le_getcapacitance(NETWORK *net)
1974 {
1975 REGISTER VARIABLE *var;
1976 REGISTER NODEPROTO *np;
1977 REGISTER NODEINST *ni;
1978 REGISTER PORTARCINST *pi;
1979
1980 np = net->parent;
1981 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1982 {
1983 /* see if the node is connected to this arc */
1984 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1985 if (pi->conarcinst->network == net) break;
1986 if (pi == NOPORTARCINST) continue;
1987
1988 /* see if there is capacitance on this node */
1989 var = getvalkey((INTBIG)ni, VNODEINST, -1, le_attrcapacitance_key);
1990 if (var != NOVARIABLE)
1991 {
1992 return(eatof(describesimplevariable(var)));
1993 }
1994 }
1995 return(0.0);
1996 }
1997
1998 /*
1999 * Routine to free the global array of LE nodes (headed by "le_firstlenode").
2000 */
le_freealllenodes(void)2001 void le_freealllenodes(void)
2002 {
2003 LENODE *nextle, *le;
2004
2005 for(le = le_firstlenode; le != NOLENODE; le = nextle)
2006 {
2007 nextle = le->nextlenode;
2008 le_freelenode(le);
2009 }
2010 le_firstlenode = NOLENODE;
2011 }
2012
2013 /*
2014 * Routine to allocate a new LENODE (either from the pool of unused ones
2015 * or from memory).
2016 */
le_alloclenode(void)2017 LENODE *le_alloclenode(void)
2018 {
2019 LENODE *le;
2020
2021 if (le_lenodefree != NOLENODE)
2022 {
2023 le = le_lenodefree;
2024 le_lenodefree = le->nextlenode;
2025 } else
2026 {
2027 le = (LENODE *)emalloc(sizeof (LENODE), le_tool->cluster);
2028 if (le == 0) return(NOLENODE);
2029 }
2030 return(le);
2031 }
2032
2033 /*
2034 * Routine to return LENODE "le" to the pool of unused ones.
2035 */
le_freelenode(LENODE * le)2036 void le_freelenode(LENODE *le)
2037 {
2038 if (le->numinputnodes > 0)
2039 {
2040 efree((CHAR *)le->inputnodes);
2041 efree((CHAR *)le->inputports);
2042 }
2043 if (le->numoutputnodes > 0)
2044 {
2045 efree((CHAR *)le->outputnodes);
2046 efree((CHAR *)le->outputports);
2047 }
2048 le->nextlenode = le_lenodefree;
2049 le_lenodefree = le;
2050 }
2051
2052 #endif /* LOGEFFTOOL - at top */
2053