1
2 #ifndef lint
3 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResRex.c,v 1.3 2010/03/08 13:33:33 tim Exp $";
4 #endif /* not lint */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include <math.h>
11 #include <float.h>
12
13 #include "tcltk/tclmagic.h"
14 #include "utils/magic.h"
15 #include "utils/geometry.h"
16 #include "utils/geofast.h"
17 #include "tiles/tile.h"
18 #include "utils/hash.h"
19 #include "utils/undo.h"
20 #include "utils/signals.h"
21 #include "database/database.h"
22 #include "utils/malloc.h"
23 #include "textio/textio.h"
24 #include "extract/extract.h"
25 #include "extract/extractInt.h"
26 #include "extflat/extflat.h"
27 #include "windows/windows.h"
28 #include "dbwind/dbwind.h"
29 #include "utils/utils.h"
30 #include "utils/tech.h"
31 #include "textio/txcommands.h"
32 #include "resis/resis.h"
33 #ifdef LAPLACE
34 #include "laplace.h"
35 #endif
36
37 #define INITFLATSIZE 1024
38 #define MAXNAME 1000
39
40 /* Time constants are produced by multiplying attofarads by milliohms, */
41 /* giving zeptoseconds (yes, really. Look it up). This constant */
42 /* converts zeptoseconds to picoseconds. */
43
44 #define Z_TO_P 1e9
45
46 /* Table of nodes to ignore (manually specified) */
47
48 HashTable ResIgnoreTable; /* Hash table of nodes to ignore */
49
50 /* Table of nodes to include (manually specified) */
51
52 HashTable ResIncludeTable; /* Hash table of nodes to include */
53
54 /* Table of cells that have been processed */
55
56 HashTable ResProcessedTable;
57
58 /* ResSimNode is a node read in from a sim file */
59
60 HashTable ResNodeTable; /* Hash table of sim file nodes */
61 RDev *ResRDevList; /* Linked list of Sim devices */
62 ResGlobalParams gparams; /* Junk passed between */
63 /* ResCheckSimNodes and */
64 /* ResExtractNet. */
65 extern ResSimNode *ResOriginalNodes; /*Linked List of Nodes */
66 int resNodeNum;
67
68 #ifdef LAPLACE
69 int ResOptionsFlags = ResOpt_Simplify | ResOpt_Tdi | ResOpt_DoExtFile
70 | ResOpt_CacheLaplace;
71 #else
72 int ResOptionsFlags = ResOpt_Simplify | ResOpt_Tdi | ResOpt_DoExtFile;
73 #endif
74 char *ResCurrentNode;
75
76 FILE *ResExtFile;
77 FILE *ResLumpFile;
78 FILE *ResFHFile;
79
80 int ResPortIndex; /* Port ordering to backannotate into magic */
81
82 /* external declarations */
83 extern ResSimNode *ResInitializeNode();
84 extern CellUse *CmdGetSelectedCell();
85
86 /* Structure stores information required to be sent to ExtResisForDef() */
87 typedef struct
88 {
89 float tolerance;
90 float tdiTolerance;
91 float frequency;
92 CellDef *mainDef;
93 } ResisData;
94
95 /*
96 *-------------------------------------------------------------------------
97 *
98 * ExtResisForDef --
99 *
100 * Do resistance network extraction for the indicated CellDef.
101 *
102 *-------------------------------------------------------------------------
103 */
104
105 void
ExtResisForDef(celldef,resisdata)106 ExtResisForDef(celldef, resisdata)
107 CellDef *celldef;
108 ResisData *resisdata;
109 {
110 RDev *oldRDev;
111 HashSearch hs;
112 HashEntry *entry;
113 devPtr *tptr, *oldtptr;
114 ResSimNode *node;
115 int result, idx;
116 char *devname;
117
118 ResRDevList = NULL;
119 ResOriginalNodes = NULL;
120
121 /* Check if this cell has been processed */
122 if (HashLookOnly(&ResProcessedTable, celldef->cd_name)) return;
123 HashFind(&ResProcessedTable, celldef->cd_name);
124
125 /* Get device information from the current extraction style */
126 idx = 0;
127 while (ExtGetDevInfo(idx++, &devname, NULL, NULL, NULL, NULL, NULL))
128 {
129 if (idx == TT_MAXTYPES)
130 {
131 TxError("Error: Ran out of space for device types!\n");
132 break;
133 }
134 efBuildAddStr(EFDevTypes, &EFDevNumTypes, TT_MAXTYPES, devname);
135 }
136
137 HashInit(&ResNodeTable, INITFLATSIZE, HT_STRINGKEYS);
138 /* read in .sim file */
139 result = (ResReadSim(celldef->cd_name,
140 ResSimDevice, ResSimCapacitor, ResSimResistor,
141 ResSimAttribute, ResSimMerge, ResSimSubckt) == 0);
142
143 /* Clean up the EFDevTypes table */
144 for (idx = 0; idx < EFDevNumTypes; idx++) freeMagic(EFDevTypes[idx]);
145 EFDevNumTypes = 0;
146
147 if (result)
148 /* read in .nodes file */
149 result = (ResReadNode(celldef->cd_name) == 0);
150
151 if (result)
152 {
153 /* Check for subcircuit ports */
154 if (ResOptionsFlags & ResOpt_Blackbox)
155 ResCheckBlackbox(celldef);
156 else
157 ResCheckPorts(celldef);
158
159 /* Extract networks for nets that require it. */
160 if (!(ResOptionsFlags & ResOpt_FastHenry) ||
161 DBIsSubcircuit(celldef))
162 ResCheckSimNodes(celldef, resisdata);
163
164 if (ResOptionsFlags & ResOpt_Stat)
165 ResPrintStats((ResGlobalParams *)NULL, "");
166 }
167
168 /* Clean up */
169
170 HashStartSearch(&hs);
171 while((entry = HashNext(&ResNodeTable, &hs)) != NULL)
172 {
173 node=(ResSimNode *) HashGetValue(entry);
174 tptr = node->firstDev;
175 if (node == NULL)
176 {
177 TxError("Error: NULL Hash entry!\n");
178 TxFlushErr();
179 }
180 while (tptr != NULL)
181 {
182 oldtptr = tptr;
183 tptr = tptr->nextDev;
184 freeMagic((char *)oldtptr);
185 }
186 freeMagic((char *) node);
187 }
188 HashKill(&ResNodeTable);
189 while (ResRDevList != NULL)
190 {
191 oldRDev = ResRDevList;
192 ResRDevList = ResRDevList->nextDev;
193 if (oldRDev->layout != NULL)
194 {
195 freeMagic((char *)oldRDev->layout);
196 oldRDev->layout = NULL;
197 }
198 freeMagic((char *)oldRDev);
199 }
200 }
201
202
203 /*
204 *-------------------------------------------------------------------------
205 *
206 * CmdExtResis-- reads in sim file and layout, and produces patches to the
207 * .ext files and .sim files that include resistors.
208 *
209 * Results:
210 * None.
211 *
212 * Side Effects: Produces .res.sim file and .res.ext file for all nets that
213 * require resistors.
214 *
215 *-------------------------------------------------------------------------
216 */
217
218 void
CmdExtResis(win,cmd)219 CmdExtResis(win, cmd)
220 MagWindow *win;
221 TxCommand *cmd;
222 {
223 int i, j, k, option, value, saveFlags;
224 static int init = 1;
225 static float tolerance, tdiTolerance, fhFrequency;
226 CellDef *mainDef;
227 CellUse *selectedUse;
228 ResisData resisdata;
229 char *endptr; /* for use with strtod() */
230
231 extern int resSubcircuitFunc(); /* Forward declaration */
232
233 static char *onOff[] =
234 {
235 "off",
236 "on",
237 NULL
238 };
239
240 static char *cmdExtresisCmd[] =
241 {
242 "tolerance [value] set ratio between resistor and device tol.",
243 "all extract all the nets",
244 "simplify [on/off] turn on/off simplification of resistor nets",
245 "extout [on/off] turn on/off writing of .res.ext file",
246 "lumped [on/off] turn on/off writing of updated lumped resistances",
247 "silent [on/off] turn on/off printing of net statistics",
248 "skip mask don't extract these types",
249 "ignore names don't extract these nets",
250 "include names extract only these nets",
251 "box type extract the signal under the box on layer type",
252 "cell cellname extract the network for the cell named cellname",
253 "blackbox [on/off] treat subcircuits with ports as black boxes",
254 "fasthenry [freq] extract subcircuit network geometry into .fh file",
255 "geometry extract network centerline geometry (experimental)",
256 "help print this message",
257 #ifdef LAPLACE
258 "laplace [on/off] solve Laplace's equation using FEM",
259 #endif
260 NULL
261 };
262
263 typedef enum {
264 RES_BAD=-2, RES_AMBIG, RES_TOL,
265 RES_ALL, RES_SIMP, RES_EXTOUT, RES_LUMPED, RES_SILENT,
266 RES_SKIP, RES_IGNORE, RES_INCLUDE, RES_BOX, RES_CELL,
267 RES_BLACKBOX, RES_FASTHENRY, RES_GEOMETRY, RES_HELP,
268 #ifdef LAPLACE
269 RES_LAPLACE,
270 #endif
271 RES_RUN
272 } ResOptions;
273
274 if (init)
275 {
276 for (i = 0; i < NT; i++)
277 {
278 TTMaskZero(&(ResCopyMask[i]));
279 TTMaskSetMask(&ResCopyMask[i], &DBConnectTbl[i]);
280 }
281 tolerance = 1;
282 tdiTolerance = 1;
283 fhFrequency = 10e6; /* 10 MHz default */
284 HashInit(&ResIgnoreTable, INITFLATSIZE, HT_STRINGKEYS);
285 HashInit(&ResIncludeTable, INITFLATSIZE, HT_STRINGKEYS);
286 init = 0;
287 }
288
289 /* Initialize ResGlobalParams */
290 gparams.rg_ttype = TT_SPACE;
291 gparams.rg_Tdi = 0.0;
292 gparams.rg_nodecap = 0.0;
293 gparams.rg_maxres = 0.0;
294 gparams.rg_bigdevres = 0;
295 gparams.rg_tilecount = 0;
296 gparams.rg_status = 0;
297 gparams.rg_devloc = NULL;
298 gparams.rg_name = NULL;
299
300 option = (cmd->tx_argc > 1) ? Lookup(cmd->tx_argv[1], cmdExtresisCmd)
301 : RES_RUN;
302
303 switch (option)
304 {
305 case RES_SIMP:
306 case RES_EXTOUT:
307 case RES_LUMPED:
308 case RES_SILENT:
309 case RES_BLACKBOX:
310 if (cmd->tx_argc > 2)
311 {
312 value = Lookup(cmd->tx_argv[2], onOff);
313 if (value < 0)
314 {
315 TxError("Value must be either \"on\" or \"off\".\n");
316 return;
317 }
318 }
319 break;
320 }
321
322 switch (option)
323 {
324 case RES_TOL:
325 ResOptionsFlags |= ResOpt_ExplicitRtol;
326 if (cmd->tx_argc > 2)
327 {
328 tolerance = MagAtof(cmd->tx_argv[2]);
329 if (tolerance <= 0)
330 {
331 TxError("Usage: %s tolerance [value]\n", cmd->tx_argv[0]);
332 return;
333 }
334 tdiTolerance = tolerance;
335 }
336 else
337 {
338 #ifdef MAGIC_WRAPPER
339 Tcl_SetObjResult(magicinterp, Tcl_NewDoubleObj((double)tdiTolerance));
340 #else
341 TxPrintf("Tolerance ratio is %g.\n", tdiTolerance);
342 #endif
343 }
344 return;
345
346 case RES_ALL:
347 ResOptionsFlags |= ResOpt_ExtractAll;
348 break;
349
350 case RES_GEOMETRY:
351 saveFlags = ResOptionsFlags;
352 ResOptionsFlags |= ResOpt_Geometry | ResOpt_ExtractAll;
353 ResOptionsFlags &= ~(ResOpt_DoExtFile | ResOpt_DoLumpFile
354 | ResOpt_Simplify | ResOpt_Tdi);
355 break;
356
357 case RES_FASTHENRY:
358 if (cmd->tx_argc == 3)
359 {
360 double tmpf = strtod(cmd->tx_argv[2], &endptr);
361 if (endptr == cmd->tx_argv[2])
362 {
363 TxError("Cannot parse frequency value. Assuming default\n");
364 TxError("Frequency = %2.1f Hz\n", fhFrequency);
365 }
366 else
367 fhFrequency = (float)tmpf;
368 }
369 saveFlags = ResOptionsFlags;
370 ResOptionsFlags |= ResOpt_FastHenry | ResOpt_ExtractAll;
371 ResOptionsFlags &= ~(ResOpt_DoExtFile | ResOpt_DoLumpFile
372 | ResOpt_Simplify | ResOpt_Tdi);
373 break;
374
375 case RES_BLACKBOX:
376 if (cmd->tx_argc == 2)
377 {
378 value = (ResOptionsFlags & ResOpt_Blackbox) ?
379 TRUE : FALSE;
380 TxPrintf("%s\n", onOff[value]);
381 }
382 else
383 {
384 value = Lookup(cmd->tx_argv[2], onOff);
385
386 if (value)
387 ResOptionsFlags |= ResOpt_Blackbox;
388 else
389 ResOptionsFlags &= ~ResOpt_Blackbox;
390 }
391 return;
392 case RES_SIMP:
393 if (cmd->tx_argc == 2)
394 {
395 value = (ResOptionsFlags & (ResOpt_Simplify | ResOpt_Tdi)) ?
396 TRUE : FALSE;
397 TxPrintf("%s\n", onOff[value]);
398 }
399 else
400 {
401 value = Lookup(cmd->tx_argv[2], onOff);
402
403 if (value)
404 ResOptionsFlags |= ResOpt_Simplify | ResOpt_Tdi;
405 else
406 ResOptionsFlags &= ~(ResOpt_Simplify | ResOpt_Tdi);
407 }
408 return;
409 case RES_EXTOUT:
410 if (cmd->tx_argc == 2)
411 {
412 value = (ResOptionsFlags & ResOpt_DoExtFile) ?
413 TRUE : FALSE;
414 TxPrintf("%s\n", onOff[value]);
415 }
416 else
417 {
418 value = Lookup(cmd->tx_argv[2], onOff);
419 if (value)
420 ResOptionsFlags |= ResOpt_DoExtFile;
421 else
422 ResOptionsFlags &= ~ResOpt_DoExtFile;
423 }
424 return;
425 case RES_LUMPED:
426 if (cmd->tx_argc == 2)
427 {
428 value = (ResOptionsFlags & ResOpt_DoLumpFile) ?
429 TRUE : FALSE;
430 TxPrintf("%s\n", onOff[value]);
431 }
432 else
433 {
434 value = Lookup(cmd->tx_argv[2], onOff);
435 if (value)
436 ResOptionsFlags |= ResOpt_DoLumpFile;
437 else
438 ResOptionsFlags &= ~ResOpt_DoLumpFile;
439 }
440 return;
441 case RES_SILENT:
442 if (cmd->tx_argc == 2)
443 {
444 value = (ResOptionsFlags & ResOpt_RunSilent) ?
445 TRUE : FALSE;
446 TxPrintf("%s\n", onOff[value]);
447 }
448 else
449 {
450 value = Lookup(cmd->tx_argv[2], onOff);
451 if (value)
452 ResOptionsFlags |= ResOpt_RunSilent;
453 else
454 ResOptionsFlags &= ~ResOpt_RunSilent;
455 }
456 return;
457
458 case RES_SKIP:
459 if (cmd->tx_argc > 2)
460 {
461 j = DBTechNoisyNameType(cmd->tx_argv[2]);
462 if (j >= 0)
463 for (k = TT_TECHDEPBASE; k < TT_MAXTYPES; k++)
464 TTMaskClearType(&ResCopyMask[k], j);
465 TTMaskZero(&(ResCopyMask[j]));
466 }
467 else
468 {
469 for (i = 0; i != NT; i++)
470 {
471 TTMaskZero(&(ResCopyMask[i]));
472 TTMaskSetMask(&ResCopyMask[i], &DBConnectTbl[i]);
473 }
474 }
475 return;
476
477 case RES_IGNORE:
478 if (cmd->tx_argc > 2)
479 {
480 if (!strcasecmp(cmd->tx_argv[2], "none"))
481 {
482 /* Kill and reinitialize the table of ignored nets */
483 HashKill(&ResIgnoreTable);
484 HashInit(&ResIgnoreTable, INITFLATSIZE, HT_STRINGKEYS);
485 }
486 else
487 HashFind(&ResIgnoreTable, cmd->tx_argv[2]);
488 }
489 else
490 {
491 HashSearch hs;
492 HashEntry *entry;
493
494 /* List all net names that are being ignored */
495 HashStartSearch(&hs);
496 while((entry = HashNext(&ResIgnoreTable, &hs)) != NULL)
497 TxPrintf("%s ", (char *)entry->h_key.h_name);
498 TxPrintf("\n");
499 }
500 return;
501
502 case RES_INCLUDE:
503 if (cmd->tx_argc > 2)
504 {
505 if (!strcasecmp(cmd->tx_argv[2], "all"))
506 {
507 /* Kill and reinitialize the table of ignored nets */
508 HashKill(&ResIncludeTable);
509 HashInit(&ResIncludeTable, INITFLATSIZE, HT_STRINGKEYS);
510 }
511 else
512 HashFind(&ResIncludeTable, cmd->tx_argv[2]);
513 }
514 else
515 {
516 HashSearch hs;
517 HashEntry *entry;
518
519 /* List all net names that are being included */
520 HashStartSearch(&hs);
521 while((entry = HashNext(&ResIncludeTable, &hs)) != NULL)
522 TxPrintf("%s ", (char *)entry->h_key.h_name);
523 TxPrintf("\n");
524 }
525 return;
526
527 case RES_HELP:
528 for (i = 0; cmdExtresisCmd[i] != NULL; i++)
529 TxPrintf("%s\n", cmdExtresisCmd[i]);
530 return;
531
532 case RES_BOX:
533 {
534 TileType tt;
535 CellDef *def;
536 Rect rect;
537 int oldoptions;
538 ResSimNode lnode;
539
540 if (ToolGetBoxWindow((Rect *) NULL, (int *) NULL) == NULL)
541 {
542 TxError("Sorry, the box must appear in one of the windows.\n");
543 return;
544 }
545
546 if (cmd->tx_argc != 3) return;
547 tt = DBTechNoisyNameType(cmd->tx_argv[2]);
548 if (tt <= 0 || ToolGetBox(&def, &rect)== FALSE) return;
549 gparams.rg_devloc = &rect.r_ll;
550 gparams.rg_ttype = tt;
551 gparams.rg_status = DRIVEONLY;
552 oldoptions = ResOptionsFlags;
553 ResOptionsFlags = ResOpt_DoSubstrate | ResOpt_Signal | ResOpt_Box;
554 #ifdef LAPLACE
555 ResOptionsFlags |= (oldoptions &
556 (ResOpt_CacheLaplace | ResOpt_DoLaplace));
557 LaplaceMatchCount = 0;
558 LaplaceMissCount = 0;
559 #endif
560 lnode.location = rect.r_ll;
561 lnode.type = tt;
562 if (ResExtractNet(&lnode, &gparams, NULL) != 0) return;
563 ResPrintResistorList(stdout, ResResList);
564 ResPrintDeviceList(stdout, ResRDevList);
565 #ifdef LAPLACE
566 if (ResOptionsFlags & ResOpt_DoLaplace)
567 {
568 TxPrintf("Laplace solved: %d matched %d\n",
569 LaplaceMissCount, LaplaceMatchCount);
570 }
571 #endif
572
573 ResOptionsFlags = oldoptions;
574 return;
575 }
576 case RES_CELL:
577 selectedUse = CmdGetSelectedCell((Transform *) NULL);
578 if (selectedUse == NULL)
579 {
580 TxError("No cell selected\n");
581 return;
582 }
583 mainDef = selectedUse->cu_def;
584 ResOptionsFlags &= ~ResOpt_ExtractAll;
585 break;
586
587 case RES_RUN:
588 ResOptionsFlags &= ~ResOpt_ExtractAll;
589 break;
590 #ifdef LAPLACE
591 case RES_LAPLACE:
592 LaplaceParseString(cmd);
593 return;
594 #endif
595 case RES_AMBIG:
596 TxPrintf("Ambiguous option: %s\n", cmd->tx_argv[1]);
597 TxFlushOut();
598 return;
599 case RES_BAD:
600 TxPrintf("Unknown option: %s\n", cmd->tx_argv[1]);
601 TxFlushOut();
602 return;
603 default:
604 return;
605 }
606
607 #ifdef LAPLACE
608 LaplaceMatchCount = 0;
609 LaplaceMissCount = 0;
610 #endif
611 /* turn off undo stuff */
612 UndoDisable();
613
614 if (!ToolGetBox(&mainDef,(Rect *) NULL))
615 {
616 TxError("Couldn't find def corresponding to box\n");
617 if ((option == RES_FASTHENRY) || (option == RES_GEOMETRY))
618 ResOptionsFlags = saveFlags;
619 return;
620 }
621 ResOptionsFlags |= ResOpt_Signal;
622 #ifdef ARIEL
623 ResOptionsFlags &= ~ResOpt_Power;
624 #endif
625
626 resisdata.tolerance = tolerance;
627 resisdata.tdiTolerance = tdiTolerance;
628 resisdata.frequency = fhFrequency;
629 resisdata.mainDef = mainDef;
630
631 /* Do subcircuits (if any) first */
632 HashInit(&ResProcessedTable, INITFLATSIZE, HT_STRINGKEYS);
633 if (!(ResOptionsFlags & ResOpt_Blackbox))
634 DBCellEnum(mainDef, resSubcircuitFunc, (ClientData) &resisdata);
635
636 ExtResisForDef(mainDef, &resisdata);
637 HashKill(&ResProcessedTable);
638
639 /* turn back on undo stuff */
640 UndoEnable();
641 #ifdef LAPLACE
642 if (ResOptionsFlags & ResOpt_DoLaplace)
643 {
644 TxPrintf("Laplace solved: %d matched %d\n",
645 LaplaceMissCount, LaplaceMatchCount);
646 }
647 #endif
648
649 /* Revert to the original flags in the case of FastHenry or */
650 /* geometry centerline extraction. */
651
652 if ((option == RES_FASTHENRY) || (option == RES_GEOMETRY))
653 ResOptionsFlags = saveFlags;
654
655 return;
656 }
657
658 /*
659 *-------------------------------------------------------------------------
660 *
661 * resSubcircuitFunc --
662 * For each encountered cell, call the resistance extractor,
663 * then recursively call resSubcircuitFunc on all children
664 * of the cell.
665 *
666 * Results:
667 * Always return 0 to keep search alive.
668 *
669 * Side Effects:
670 * Does resistance extraction for an entire cell.
671 *
672 *-------------------------------------------------------------------------
673 */
674
675 int
resSubcircuitFunc(cellUse,rdata)676 resSubcircuitFunc(cellUse, rdata)
677 CellUse *cellUse;
678 ResisData *rdata;
679 {
680 CellDef *cellDef = cellUse->cu_def;
681
682 if (DBIsSubcircuit(cellDef))
683 {
684 ExtResisForDef(cellDef, rdata);
685 DBCellEnum(cellDef, resSubcircuitFunc, (ClientData)rdata);
686 }
687 return 0;
688 }
689
690 /*
691 *-------------------------------------------------------------------------
692 *
693 * Callback routine for ResCheckBlackBox. For each label found in a
694 * subcell, transform the label position back to the top level and
695 * add to the list of nodes for extresis.
696 *
697 *-------------------------------------------------------------------------
698 */
699
700 int
resPortFunc(scx,lab,tpath,result)701 resPortFunc(scx, lab, tpath, result)
702 SearchContext *scx;
703 Label *lab;
704 TerminalPath *tpath;
705 int *result;
706 {
707 Rect r;
708 int pclass, puse;
709 Point portloc;
710 HashEntry *entry;
711 ResSimNode *node;
712
713 GeoTransRect(&scx->scx_trans, &lab->lab_rect, &r);
714
715 // To be expanded. Currently this handles digital signal inputs
716 // and outputs, for standard cells.
717
718 if (lab->lab_flags & PORT_DIR_MASK) {
719 pclass = lab->lab_flags & PORT_CLASS_MASK;
720 puse = lab->lab_flags & PORT_USE_MASK;
721
722 // Ad hoc rule: If port use is not declared, but port
723 // direction is either INPUT or OUTPUT, then use SIGNAL is implied.
724
725 if ((puse == 0) && ((pclass == PORT_CLASS_INPUT)
726 || (pclass == PORT_CLASS_OUTPUT)))
727 puse = PORT_USE_SIGNAL;
728
729 if (puse == PORT_USE_SIGNAL || puse == PORT_USE_CLOCK) {
730
731 if (lab->lab_flags & (PORT_DIR_NORTH | PORT_DIR_SOUTH))
732 portloc.p_x = (r.r_xbot + r.r_xtop) >> 1;
733 else if (lab->lab_flags & (PORT_DIR_EAST | PORT_DIR_WEST))
734 portloc.p_y = (r.r_ybot + r.r_ytop) >> 1;
735
736 if (lab->lab_flags & PORT_DIR_NORTH)
737 portloc.p_y = r.r_ytop;
738 if (lab->lab_flags & PORT_DIR_SOUTH)
739 portloc.p_y = r.r_ybot;
740 if (lab->lab_flags & PORT_DIR_EAST)
741 portloc.p_x = r.r_xtop;
742 if (lab->lab_flags & PORT_DIR_WEST)
743 portloc.p_x = r.r_xbot;
744
745 if ((pclass == PORT_CLASS_INPUT) || (pclass == PORT_CLASS_OUTPUT)) {
746 int len;
747 char *nodename;
748
749 // Port name is the instance name / pin name
750 // To do: Make use of tpath
751 len = strlen(scx->scx_use->cu_id) + strlen(lab->lab_text) + 2;
752 nodename = (char *) mallocMagic((unsigned) len);
753 sprintf(nodename, "%s/%s", scx->scx_use->cu_id, lab->lab_text);
754
755 entry = HashFind(&ResNodeTable, nodename);
756 node = ResInitializeNode(entry);
757
758 /* Digital outputs are drivers */
759 if (pclass == PORT_CLASS_OUTPUT) node->status |= FORCE;
760
761 node->drivepoint = portloc;
762 node->status |= DRIVELOC | PORTNODE;
763 node->rs_bbox = r;
764 node->location = portloc;
765 node->rs_ttype = lab->lab_type;
766 node->type = lab->lab_type;
767
768 *result = 0;
769 freeMagic(nodename);
770 }
771 }
772 }
773 return 0; /* Keep the search going */
774 }
775
776 /*
777 *-------------------------------------------------------------------------
778 *
779 * ResCheckBlackbox--
780 *
781 * For standard cell parasitic extraction, search all children
782 * of cellDef for ports, and add each port to the list of nodes
783 * for extresist to process. If the port use is "ground" or
784 * "power", then don't process the node. If the port class is
785 * "output", then make this node a (forced) driver.
786 *
787 * Results: 0 if one or more nodes was created, 1 otherwise
788 *
789 * Side Effects: Adds driving nodes to the extresis network database.
790 *
791 *-------------------------------------------------------------------------
792 */
793
794 int
ResCheckBlackbox(cellDef)795 ResCheckBlackbox(cellDef)
796 CellDef *cellDef;
797 {
798 int result = 1;
799 SearchContext scx;
800 CellUse dummy;
801
802 dummy.cu_expandMask = 0;
803 dummy.cu_transform = GeoIdentityTransform;
804 dummy.cu_def = cellDef;
805 dummy.cu_id = NULL;
806
807 scx.scx_area = cellDef->cd_bbox;
808 scx.scx_trans = GeoIdentityTransform;
809 scx.scx_use = (CellUse *)&dummy;
810
811 /* Do a search on all children */
812
813 DBTreeSrLabels(&scx, &DBAllButSpaceAndDRCBits, 0, NULL,
814 TF_LABEL_ATTACH, resPortFunc, (ClientData)&result);
815
816 return result;
817 }
818
819 /*
820 *-------------------------------------------------------------------------
821 *
822 * ResCheckPorts--
823 *
824 * Subcircuit boundaries mark an area which is to be checked
825 * explicitly for geometry information. Because there may be
826 * no devices in the subcircuit cell, we must find the ports
827 * into the subcircuit and declare them to be "driving" nodes so
828 * the extresis algorithm will treat them as being part of valid
829 * networks.
830 *
831 * Results: 0 if one or more nodes was created, 1 otherwise
832 *
833 * Side Effects: Adds driving nodes to the extresis network database.
834 *
835 *-------------------------------------------------------------------------
836 */
837
838 int
ResCheckPorts(cellDef)839 ResCheckPorts(cellDef)
840 CellDef *cellDef;
841 {
842 Point portloc;
843 Label *lab;
844 HashEntry *entry;
845 ResSimNode *node;
846 int result = 1;
847
848 for (lab = cellDef->cd_labels; lab; lab = lab->lab_next)
849 {
850 if (lab->lab_flags & PORT_DIR_MASK)
851 {
852 /* Get drivepoint from the port connection direction(s) */
853 /* NOTE: This is not rigorous! */
854
855 if (lab->lab_flags & (PORT_DIR_NORTH | PORT_DIR_SOUTH))
856 portloc.p_x = (lab->lab_rect.r_xbot + lab->lab_rect.r_xtop) >> 1;
857 else if (lab->lab_flags & (PORT_DIR_EAST | PORT_DIR_WEST))
858 portloc.p_y = (lab->lab_rect.r_ybot + lab->lab_rect.r_ytop) >> 1;
859
860 if (lab->lab_flags & PORT_DIR_NORTH)
861 portloc.p_y = lab->lab_rect.r_ytop;
862 if (lab->lab_flags & PORT_DIR_SOUTH)
863 portloc.p_y = lab->lab_rect.r_ybot;
864 if (lab->lab_flags & PORT_DIR_EAST)
865 portloc.p_x = lab->lab_rect.r_xtop;
866 if (lab->lab_flags & PORT_DIR_WEST)
867 portloc.p_x = lab->lab_rect.r_xbot;
868
869 entry = HashFind(&ResNodeTable, lab->lab_text);
870 result = 0;
871 if ((node = (ResSimNode *) HashGetValue(entry)) != NULL)
872 {
873 TxPrintf("Port: name = %s exists, forcing drivepoint\n",
874 lab->lab_text);
875 TxPrintf("Location is (%d, %d); drivepoint (%d, %d)\n",
876 node->location.p_x, node->location.p_y,
877 portloc.p_x, portloc.p_y);
878 TxFlush();
879 node->drivepoint = portloc;
880 node->status |= FORCE;
881 }
882 else
883 {
884 /* This is a port, but it's merged with another node. */
885 /* We have to make sure it's listed as a separate node */
886 /* and a drivepoint. */
887
888 node = ResInitializeNode(entry);
889 TxPrintf("Port: name = %s is new node 0x%x\n",
890 lab->lab_text, node);
891 TxPrintf("Location is (%d, %d); drivepoint (%d, %d)\n",
892 portloc.p_x, portloc.p_y,
893 portloc.p_x, portloc.p_y);
894 node->location = portloc;
895 node->drivepoint = node->location;
896 }
897 node->status |= DRIVELOC | PORTNODE;
898 node->rs_bbox = lab->lab_rect;
899 node->rs_ttype = lab->lab_type;
900 node->type = lab->lab_type;
901 }
902 }
903 return result;
904 }
905
906 /*
907 *-------------------------------------------------------------------------
908 *
909 * ResCheckSimNodes-- check to see if lumped resistance is greater than the
910 * device resistance; if it is, Extract the net
911 * resistance. If the maximum point to point resistance
912 * in the extracted net is still creater than the
913 * tolerance, then output the extracted net.
914 *
915 * Results: none
916 *
917 * Side Effects: Writes networks to .res.ext and .res.sim files.
918 *
919 *-------------------------------------------------------------------------
920 */
921
922 void
ResCheckSimNodes(celldef,resisdata)923 ResCheckSimNodes(celldef, resisdata)
924 CellDef *celldef;
925 ResisData *resisdata;
926 {
927 ResSimNode *node;
928 devPtr *ptr;
929 float ftolerance, rctolerance, minRes, cumRes;
930 int failed1=0;
931 int failed3=0;
932 int total =0;
933 char *outfile = celldef->cd_name;
934 float tol = resisdata->tolerance;
935 float rctol = resisdata->tdiTolerance;
936 int nidx = 1, eidx = 1; /* node & segment counters for geom. */
937
938 if (ResOptionsFlags & ResOpt_DoExtFile)
939 {
940 ResExtFile = PaOpen(outfile,"w",".res.ext",".",(char *) NULL, (char **) NULL);
941 }
942 else
943 {
944 ResExtFile = NULL;
945 }
946 if (ResOptionsFlags & ResOpt_DoLumpFile)
947 {
948 ResLumpFile = PaOpen(outfile, "w", ".res.lump", ".", (char *)NULL, (char **)NULL);
949 }
950 else
951 {
952 ResLumpFile = NULL;
953 }
954 if (ResOptionsFlags & ResOpt_FastHenry)
955 {
956 char *geofilename;
957 ResFHFile = PaOpen(outfile, "w", ".fh", ".", (char *)NULL, &geofilename);
958 TxPrintf("Writing FastHenry-format geometry file \"%s\"\n", geofilename);
959 ResPortIndex = 0;
960 }
961 else
962 {
963 ResFHFile = NULL;
964 }
965
966 if (ResExtFile == NULL && (ResOptionsFlags & ResOpt_DoExtFile)
967 || (ResOptionsFlags & ResOpt_DoLumpFile) && ResLumpFile == NULL
968 || (ResOptionsFlags & ResOpt_FastHenry) && ResFHFile == NULL)
969 {
970 TxError("Couldn't open output file\n");
971 return;
972 }
973
974 /*
975 * Write a scale line at the top of the .res.ext file, as the
976 * scale may be different from the original .ext file.
977 */
978
979 if (ResExtFile != NULL)
980 {
981 fprintf(ResExtFile, "scale %d %d %g\n",
982 ExtCurStyle->exts_resistScale,
983 ExtCurStyle->exts_capScale,
984 ExtCurStyle->exts_unitsPerLambda);
985 }
986
987 /*
988 * Write reference plane (substrate) definition and end statement
989 * to the FastHenry geometry file.
990 */
991 if (ResOptionsFlags & ResOpt_FastHenry)
992 {
993 ResPrintReference(ResFHFile, ResRDevList, celldef);
994 }
995
996 for (node = ResOriginalNodes; node != NULL; node=node->nextnode)
997 {
998 HashEntry *he;
999
1000 if (SigInterruptPending) break;
1001
1002 /* Ignore or include specified nodes */
1003
1004 if (ResIncludeTable.ht_nEntries > 0)
1005 {
1006 he = HashLookOnly(&ResIncludeTable, node->name);
1007 if (he == NULL) continue;
1008 }
1009 else
1010 {
1011 he = HashLookOnly(&ResIgnoreTable, node->name);
1012 if (he != NULL) continue;
1013 }
1014
1015 /* Has this node been merged away or is it marked as skipped? */
1016 /* If so, skip it */
1017 if ((node->status & (FORWARD | REDUNDANT)) ||
1018 ((node->status & SKIP) &&
1019 (ResOptionsFlags & ResOpt_ExtractAll) == 0))
1020 continue;
1021
1022 ResCurrentNode = node->name;
1023 total++;
1024
1025 ResSortByGate(&node->firstDev);
1026
1027 /* Find largest SD device connected to node. */
1028
1029 minRes = FLT_MAX;
1030 gparams.rg_devloc = (Point *) NULL;
1031 gparams.rg_status = FALSE;
1032 gparams.rg_nodecap = node->capacitance;
1033
1034 /* The following is only used if there is a drivepoint */
1035 /* to identify which tile the drivepoint is on. */
1036
1037 gparams.rg_ttype = node->rs_ttype;
1038
1039 for (ptr = node->firstDev; ptr != NULL; ptr = ptr->nextDev)
1040 {
1041 RDev *t1;
1042 RDev *t2;
1043
1044 if (ptr->terminal == GATE)
1045 {
1046 break;
1047 }
1048 else
1049 {
1050 /* Get cumulative resistance of all devices */
1051 /* with same connections. */
1052
1053 cumRes = ptr->thisDev->resistance;
1054 t1 = ptr->thisDev;
1055 for (; ptr->nextDev != NULL; ptr = ptr->nextDev)
1056 {
1057 t1 = ptr->thisDev;
1058 t2 = ptr->nextDev->thisDev;
1059 if (t1->gate != t2->gate) break;
1060 if ((t1->source != t2->source ||
1061 t1->drain != t2->drain) &&
1062 (t1->source != t2->drain ||
1063 t1->drain != t2->source)) break;
1064
1065 /* Do parallel combination */
1066 if ((cumRes != 0.0) && (t2->resistance != 0.0))
1067 {
1068 cumRes = (cumRes * t2->resistance) /
1069 (cumRes + t2->resistance);
1070 }
1071 else
1072 {
1073 cumRes = 0;
1074 }
1075 }
1076 if (minRes > cumRes)
1077 {
1078 minRes = cumRes;
1079 gparams.rg_devloc = &t1->location;
1080 gparams.rg_ttype = t1->rs_ttype;
1081 }
1082 }
1083 }
1084
1085 /* special handling for FORCE and DRIVELOC labels: */
1086 /* set minRes = node->minsizeres if it exists, 0 otherwise */
1087
1088 if (node->status & (FORCE|DRIVELOC))
1089 {
1090 if (node->status & MINSIZE)
1091 {
1092 minRes = node->minsizeres;
1093 }
1094 else
1095 {
1096 minRes = 0;
1097 }
1098 if (node->status & DRIVELOC)
1099 {
1100 gparams.rg_devloc = &node->drivepoint;
1101 gparams.rg_status |= DRIVEONLY;
1102 }
1103 if (node->status & PORTNODE)
1104 {
1105 /* The node is a port, not a device, so make */
1106 /* sure rg_ttype is set accordingly. */
1107 gparams.rg_ttype = node->rs_ttype;
1108 }
1109 }
1110 if ((gparams.rg_devloc == NULL) && (node->status & FORCE))
1111 {
1112 TxError("Node %s has force label but no drive point or "
1113 "driving device\n", node->name);
1114 }
1115 if ((minRes == FLT_MAX) || (gparams.rg_devloc == NULL))
1116 {
1117 continue;
1118 }
1119 gparams.rg_bigdevres = (int)minRes * OHMSTOMILLIOHMS;
1120 if ((rctol == 0.0) || (tol == 0.0))
1121 {
1122 ftolerance = 0.0;
1123 rctolerance = 0.0;
1124 }
1125 else
1126 {
1127 ftolerance = minRes / tol;
1128 rctolerance = minRes / rctol;
1129 }
1130
1131 /*
1132 * Is the device resistance greater than the lumped node
1133 * resistance? If so, extract net.
1134 */
1135
1136 if ((node->resistance > ftolerance) || (node->status & FORCE) ||
1137 (ResOpt_ExtractAll & ResOptionsFlags))
1138 {
1139 ResFixPoint fp;
1140
1141 failed1++;
1142 if (ResExtractNet(node, &gparams, outfile) != 0)
1143 {
1144 /* On error, don't output this net, but keep going */
1145 TxError("Error in extracting node %s\n", node->name);
1146 }
1147 else
1148 {
1149 ResDoSimplify(ftolerance,rctol,&gparams);
1150 if (ResOptionsFlags & ResOpt_DoLumpFile)
1151 {
1152 ResWriteLumpFile(node);
1153 }
1154 if (gparams.rg_maxres >= ftolerance ||
1155 gparams.rg_maxres >= rctolerance ||
1156 (ResOptionsFlags & ResOpt_ExtractAll))
1157 {
1158 resNodeNum = 0;
1159 failed3 += ResWriteExtFile(celldef, node, tol, rctol,
1160 &nidx, &eidx);
1161 }
1162 }
1163 #ifdef PARANOID
1164 ResSanityChecks(node->name, ResResList, ResNodeList, ResDevList);
1165 #endif
1166 ResCleanUpEverything();
1167 }
1168 }
1169
1170 /*
1171 * Print out all device which have had at least one terminal changed
1172 * by resistance extraction.
1173 */
1174
1175 if (ResOptionsFlags & ResOpt_DoExtFile)
1176 {
1177 ResPrintExtDev(ResExtFile, ResRDevList);
1178 }
1179
1180 /*
1181 * Write end statement to the FastHenry geometry file.
1182 * (Frequency range should be user-specified. . .)
1183 */
1184
1185 if (ResOptionsFlags & ResOpt_FastHenry)
1186 {
1187 Label *lab;
1188
1189 fprintf(ResFHFile, "\n.freq fmin=%2.1g fmax=%2.1g\n",
1190 resisdata->frequency, resisdata->frequency);
1191
1192 /*----------------------------------------------------------------------*/
1193 /* Write (in comment lines) the order in which arguments are written */
1194 /* to a SPICE subcircuit call when Magic runs ext2spice (exttospice). */
1195 /* At present, it is the responsibility of the program that generates */
1196 /* SPICE from FastHenry output to use this information to appropriately */
1197 /* order the arguments in the ".subckt" definition. */
1198 /*----------------------------------------------------------------------*/
1199
1200 fprintf(ResFHFile, "\n* Order of arguments to SPICE subcircuit call:\n");
1201 for (lab = celldef->cd_labels; lab != NULL; lab = lab->lab_next)
1202 if (lab->lab_flags & PORT_DIR_MASK)
1203 fprintf(ResFHFile, "* %d %s\n", lab->lab_port, lab->lab_text);
1204
1205 fprintf(ResFHFile, "\n.end\n");
1206 }
1207
1208 /* Output statistics about extraction */
1209
1210 if (total)
1211 {
1212 TxPrintf("Total Nets: %d\nNets extracted: "
1213 "%d (%f)\nNets output: %d (%f)\n", total, failed1,
1214 (float)failed1 / (float)total, failed3,
1215 (float)failed3 / (float)total);
1216 }
1217 else
1218 {
1219 TxPrintf("Total Nodes: %d\n",total);
1220 }
1221
1222 /* close output files */
1223
1224 if (ResExtFile != NULL)
1225 (void) fclose(ResExtFile);
1226
1227 if (ResLumpFile != NULL)
1228 (void) fclose(ResLumpFile);
1229
1230 if (ResFHFile != NULL)
1231 (void) fclose(ResFHFile);
1232 }
1233
1234
1235 /*
1236 *-------------------------------------------------------------------------
1237 *
1238 * ResFixUpConnections-- Changes the connection to a terminal of the sim
1239 * device. The new name is formed by appending .t# to the old name.
1240 * The new name is added to the hash table of node names.
1241 *
1242 * Results:none
1243 *
1244 * Side Effects: Allocates new ResSimNodes. Modifies the terminal connections
1245 * of sim Devices.
1246 *
1247 *-------------------------------------------------------------------------
1248 */
1249
1250 void
ResFixUpConnections(simDev,layoutDev,simNode,nodename)1251 ResFixUpConnections(simDev, layoutDev, simNode, nodename)
1252 RDev *simDev;
1253 resDevice *layoutDev;
1254 ResSimNode *simNode;
1255 char *nodename;
1256
1257 {
1258 static char newname[MAXNAME], oldnodename[MAXNAME];
1259 int notdecremented;
1260 resNode *gate, *source, *drain, *subs;
1261
1262 /* If we aren't doing output (i.e. this is just a statistical run) */
1263 /* don't patch up networks. This cuts down on memory use. */
1264
1265 if ((ResOptionsFlags & (ResOpt_DoRsmFile | ResOpt_DoExtFile)) == 0)
1266 return;
1267
1268 if (simDev->layout == NULL)
1269 {
1270 layoutDev->rd_status |= RES_DEV_SAVE;
1271 simDev->layout = layoutDev;
1272 }
1273 simDev->status |= TRUE;
1274 if (strcmp(nodename, oldnodename) != 0)
1275 {
1276 strcpy(oldnodename, nodename);
1277 }
1278 sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
1279 notdecremented = TRUE;
1280
1281 if (simDev->gate == simNode)
1282 {
1283 if ((gate = layoutDev->rd_fet_gate) != NULL)
1284 {
1285 /* Cosmetic addition: If the layout device already has a */
1286 /* name, the new one won't be used, so we decrement resNodeNum */
1287 if (gate->rn_name != NULL)
1288 {
1289 resNodeNum--;
1290 notdecremented = FALSE;
1291 }
1292
1293 ResFixDevName(newname, GATE, simDev, gate);
1294 gate->rn_name = simDev->gate->name;
1295 sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
1296 }
1297 else
1298 TxError("Missing gate connection of device at (%d %d) on net %s\n",
1299 layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
1300 nodename);
1301 }
1302 if (simDev->subs == simNode)
1303 {
1304 if ((subs = layoutDev->rd_fet_subs) != NULL)
1305 {
1306 if (subs->rn_name != NULL && notdecremented)
1307 {
1308 resNodeNum--;
1309 notdecremented = FALSE;
1310 }
1311 ResFixDevName(newname, SUBS, simDev, subs);
1312 subs->rn_name = simDev->subs->name;
1313 sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
1314 }
1315 else
1316 TxError("Missing substrate connection of device at (%d %d) on net %s\n",
1317 layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
1318 nodename);
1319 }
1320 if (simDev->source == simNode)
1321 {
1322 if (simDev->drain == simNode)
1323 {
1324 if (((source = layoutDev->rd_fet_source) != NULL) &&
1325 ((drain = layoutDev->rd_fet_drain) != NULL))
1326 {
1327 if (source->rn_name != NULL && notdecremented)
1328 {
1329 resNodeNum--;
1330 notdecremented = FALSE;
1331 }
1332 ResFixDevName(newname, SOURCE, simDev, source);
1333 source->rn_name = simDev->source->name;
1334 (void)sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++);
1335 if (drain->rn_name != NULL) resNodeNum--;
1336 ResFixDevName(newname, DRAIN, simDev, drain);
1337 drain->rn_name = simDev->drain->name;
1338 /* one to each */
1339 }
1340 else
1341 TxError("Missing terminal connection of device at (%d %d) on net %s\n",
1342 layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
1343 nodename);
1344 }
1345 else
1346 {
1347 if ((source = layoutDev->rd_fet_source) != NULL)
1348 {
1349 if ((drain = layoutDev->rd_fet_drain) != NULL)
1350 {
1351 if (source != drain)
1352 {
1353 if (drain->rn_why & RES_NODE_ORIGIN)
1354 {
1355 ResMergeNodes(drain, source, &ResNodeQueue,
1356 &ResNodeList);
1357 ResDoneWithNode(drain);
1358 source = drain;
1359 }
1360 else
1361 {
1362 ResMergeNodes(source, drain, &ResNodeQueue,
1363 &ResNodeList);
1364 ResDoneWithNode(source);
1365 drain = source;
1366 }
1367 }
1368 layoutDev->rd_fet_drain = (resNode *)NULL;
1369 if (source->rn_name != NULL) resNodeNum--;
1370 ResFixDevName(newname, SOURCE, simDev, source);
1371 source->rn_name = simDev->source->name;
1372 }
1373 else
1374 {
1375 if (source->rn_name != NULL && notdecremented)
1376 {
1377 resNodeNum--;
1378 notdecremented = FALSE;
1379 }
1380 ResFixDevName(newname, SOURCE, simDev, source);
1381 source->rn_name = simDev->source->name;
1382 }
1383
1384 }
1385 else
1386 TxError("Missing terminal connection of device at (%d %d) on net %s\n",
1387 layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
1388 nodename);
1389 }
1390 }
1391 else if (simDev->drain == simNode)
1392 {
1393 if ((source = layoutDev->rd_fet_source) != NULL)
1394 {
1395 if ((drain = layoutDev->rd_fet_drain) != NULL)
1396 {
1397 if (drain != source)
1398 {
1399 if (drain->rn_why & ORIGIN)
1400 {
1401 ResMergeNodes(drain, source, &ResNodeQueue,
1402 &ResNodeList);
1403 ResDoneWithNode(drain);
1404 source = drain;
1405 }
1406 else
1407 {
1408 ResMergeNodes(source, drain, &ResNodeQueue,
1409 &ResNodeList);
1410 ResDoneWithNode(source);
1411 drain = source;
1412 }
1413 }
1414 layoutDev->rd_fet_source = (resNode *) NULL;
1415 if (drain->rn_name != NULL)
1416 {
1417 resNodeNum--;
1418 notdecremented = FALSE;
1419 }
1420 ResFixDevName(newname, DRAIN, simDev, drain);
1421 drain->rn_name = simDev->drain->name;
1422 }
1423 else
1424 {
1425 if (source->rn_name != NULL && notdecremented)
1426 {
1427 resNodeNum--;
1428 notdecremented = FALSE;
1429 }
1430 ResFixDevName(newname,DRAIN,simDev,source);
1431 source->rn_name = simDev->drain->name;
1432 }
1433 }
1434 else
1435 TxError("Missing terminal connection of device at (%d %d) on net %s\n",
1436 layoutDev->rd_inside.r_xbot, layoutDev->rd_inside.r_ybot,
1437 nodename);
1438 }
1439 else
1440 resNodeNum--;
1441 }
1442
1443
1444 /*
1445 *-------------------------------------------------------------------------
1446 *
1447 * ResFixDevName-- Moves device connection to new node.
1448 *
1449 * Results:
1450 * None.
1451 *
1452 * Side Effects: May create a new node. Creates a new device pointer.
1453 *
1454 *-------------------------------------------------------------------------
1455 */
1456
1457 void
ResFixDevName(line,type,device,layoutnode)1458 ResFixDevName(line, type, device, layoutnode)
1459 char line[];
1460 int type;
1461 RDev *device;
1462 resNode *layoutnode;
1463
1464 {
1465 HashEntry *entry;
1466 ResSimNode *node;
1467 devPtr *tptr;
1468
1469 if (layoutnode->rn_name != NULL)
1470 {
1471 entry = HashFind(&ResNodeTable, layoutnode->rn_name);
1472 node = ResInitializeNode(entry);
1473
1474 }
1475 else
1476 {
1477 entry = HashFind(&ResNodeTable, line);
1478 node = ResInitializeNode(entry);
1479 }
1480 tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr)));
1481 tptr->thisDev = device;
1482 tptr->nextDev = node->firstDev;
1483 node->firstDev = tptr;
1484 tptr->terminal = type;
1485 switch(type)
1486 {
1487 case GATE:
1488 node->oldname = device->gate->name;
1489 device->gate = node;
1490 break;
1491 case SOURCE:
1492 node->oldname = device->source->name;
1493 device->source = node;
1494 break;
1495 case DRAIN:
1496 node->oldname = device->drain->name;
1497 device->drain = node;
1498 break;
1499 case SUBS:
1500 node->oldname = device->subs->name;
1501 device->subs = node;
1502 break;
1503 default:
1504 TxError("Bad Terminal Specifier\n");
1505 break;
1506 }
1507 }
1508
1509 /*
1510 *-------------------------------------------------------------------------
1511 *
1512 * devSortFunc ---
1513 *
1514 * qsort() sorting function for gates. See description in
1515 * ResSortByGate() below.
1516 *
1517 * Returns:
1518 * 1 or -1 depending on comparison result. The devices are sorted
1519 * by gate first, then source or drain.
1520 *
1521 * Side effects:
1522 * qsort() reorders the indexed list of which dev1 and dev2 are
1523 * components.
1524 *
1525 *-------------------------------------------------------------------------
1526 */
1527
1528 int
devSortFunc(rec1,rec2)1529 devSortFunc(rec1, rec2)
1530 devPtr **rec1, **rec2;
1531 {
1532 devPtr *dev1 = *rec1;
1533 devPtr *dev2 = *rec2;
1534 RDev *rd1 = dev1->thisDev;
1535 RDev *rd2 = dev2->thisDev;
1536
1537 if (dev1->terminal == GATE)
1538 return 1;
1539 else if (dev2->terminal == GATE)
1540 return -1;
1541 else if (rd1->gate > rd2->gate)
1542 return 1;
1543 else if (rd1->gate == rd2->gate)
1544 {
1545 if ((dev1->terminal == SOURCE &&
1546 dev2->terminal == SOURCE &&
1547 rd1->drain > rd2->drain) ||
1548 (dev1->terminal == SOURCE &&
1549 dev2->terminal == DRAIN &&
1550 rd1->drain > rd2->source) ||
1551 (dev1->terminal == DRAIN &&
1552 dev2->terminal == SOURCE &&
1553 rd1->source > rd2->drain) ||
1554 (dev1->terminal == DRAIN &&
1555 dev2->terminal == DRAIN &&
1556 rd1->source > rd2->source))
1557 {
1558 return 1;
1559 }
1560 }
1561 return -1;
1562 }
1563
1564 /*
1565 *-------------------------------------------------------------------------
1566 *
1567 * ResSortByGate -- sorts device pointers whose terminal field is either
1568 * drain or source by gate node number, then by drain (source) number.
1569 * This places devices with identical connections next to one
1570 * another.
1571 *
1572 * Results: none
1573 *
1574 * Side Effects: modifies order of devices
1575 *
1576 *-------------------------------------------------------------------------
1577 */
1578
1579 void
ResSortByGate(DevpointerList)1580 ResSortByGate(DevpointerList)
1581 devPtr **DevpointerList;
1582 {
1583 devPtr *working, **Devindexed;
1584 int listlen, listidx;
1585
1586 /* Linked lists are very slow to sort. Create an indexed list */
1587 /* and run qsort() to sort, then regenerate the links. */
1588
1589 listlen = 0;
1590 for (working = *DevpointerList; working; working = working->nextDev) listlen++;
1591 if (listlen == 0) return;
1592
1593 Devindexed = (devPtr **)mallocMagic(listlen * sizeof(devPtr *));
1594 listidx = 0;
1595 for (working = *DevpointerList; working; working = working->nextDev)
1596 Devindexed[listidx++] = working;
1597
1598 qsort(Devindexed, (size_t)listlen, (size_t)sizeof(devPtr *), devSortFunc);
1599
1600 for (listidx = 0; listidx < listlen - 1; listidx++)
1601 Devindexed[listidx]->nextDev = Devindexed[listidx + 1];
1602 Devindexed[listidx]->nextDev = NULL;
1603
1604 *DevpointerList = Devindexed[0];
1605 freeMagic(Devindexed);
1606 }
1607
1608 /*
1609 *-------------------------------------------------------------------------
1610 *
1611 * ResWriteLumpFile
1612 *
1613 * Results: none
1614 *
1615 * Side Effects:
1616 *
1617 *-------------------------------------------------------------------------
1618 */
1619
1620 void
ResWriteLumpFile(node)1621 ResWriteLumpFile(node)
1622 ResSimNode *node;
1623 {
1624 int lumpedres;
1625
1626 if (ResOptionsFlags & ResOpt_Tdi)
1627 {
1628 if (gparams.rg_nodecap != 0)
1629 {
1630 lumpedres = (int)((gparams.rg_Tdi / gparams.rg_nodecap
1631 - (float)(gparams.rg_bigdevres)) / OHMSTOMILLIOHMS);
1632 }
1633 else
1634 lumpedres = 0;
1635 }
1636 else
1637 {
1638 lumpedres = gparams.rg_maxres;
1639 }
1640 fprintf(ResLumpFile, "R %s %d\n", node->name, lumpedres);
1641 }
1642
1643
1644 /*
1645 *-------------------------------------------------------------------------
1646 *
1647 * ResAlignNodes --
1648 * Attempt to put nodes onto a Manhattan grid.
1649 * At the same time, assign height values to nodes and thickness
1650 * values to resistors.
1651 *
1652 *-------------------------------------------------------------------------
1653 */
1654
1655 void
ResAlignNodes(nodelist,reslist)1656 ResAlignNodes(nodelist, reslist)
1657 resNode *nodelist;
1658 resResistor *reslist;
1659 {
1660 resResistor *resistor;
1661 resNode *node1;
1662 short i;
1663
1664 for (resistor = reslist; resistor->rr_nextResistor != NULL;
1665 resistor = resistor->rr_nextResistor)
1666 {
1667 /* Don't try to align nodes which came from split */
1668 /* tiles; we assume that the geometry there is */
1669 /* supposed to be non-Manhattan. */
1670
1671 if (resistor->rr_status & RES_DIAGONAL) continue;
1672
1673 for (i = 0; i < 2; i++)
1674 {
1675 node1 = resistor->rr_node[i];
1676 if (resistor->rr_status & RES_EW)
1677 {
1678 if (node1->rn_loc.p_y != resistor->rr_cl)
1679 {
1680 if (node1->rn_status & RES_NODE_YADJ)
1681 TxError("Warning: contention over node Y position\n");
1682 node1->rn_loc.p_y = resistor->rr_cl;
1683 node1->rn_status |= RES_NODE_YADJ;
1684 }
1685 }
1686 else if (resistor->rr_status & RES_NS)
1687 {
1688 if (node1->rn_loc.p_x != resistor->rr_cl)
1689 {
1690 if (node1->rn_status & RES_NODE_XADJ)
1691 TxError("Warning: contention over node X position\n");
1692 node1->rn_loc.p_x = resistor->rr_cl;
1693 node1->rn_status |= RES_NODE_XADJ;
1694 }
1695 }
1696 }
1697 }
1698 }
1699
1700 /*
1701 *-------------------------------------------------------------------------
1702 *
1703 * ResWriteExtFile --
1704 *
1705 * Results:
1706 * 1 if output was generated
1707 * 0 if no output was generated
1708 *
1709 * Side Effects:
1710 *
1711 *-------------------------------------------------------------------------
1712 */
1713
1714 int
ResWriteExtFile(celldef,node,tol,rctol,nidx,eidx)1715 ResWriteExtFile(celldef, node, tol, rctol, nidx, eidx)
1716 CellDef *celldef;
1717 ResSimNode *node;
1718 float tol, rctol;
1719 int *nidx, *eidx;
1720 {
1721 float RCdev;
1722 char *cp, newname[MAXNAME];
1723 devPtr *ptr;
1724 resDevice *layoutDev, *ResGetDevice();
1725
1726 RCdev = gparams.rg_bigdevres * gparams.rg_nodecap;
1727
1728 if (tol == 0.0 || (node->status & FORCE) ||
1729 (ResOptionsFlags & ResOpt_ExtractAll) ||
1730 (ResOptionsFlags & ResOpt_Simplify) == 0 ||
1731 (rctol + 1) * RCdev < rctol * gparams.rg_Tdi)
1732 {
1733 ASSERT(gparams.rg_Tdi != -1, "ResWriteExtFile");
1734 (void)sprintf(newname,"%s", node->name);
1735 cp = newname + strlen(newname)-1;
1736 if (*cp == '!' || *cp == '#') *cp = '\0';
1737 if ((rctol + 1) * RCdev < rctol * gparams.rg_Tdi ||
1738 (ResOptionsFlags & ResOpt_Tdi) == 0)
1739 {
1740 if ((ResOptionsFlags & (ResOpt_RunSilent | ResOpt_Tdi)) == ResOpt_Tdi)
1741 {
1742 TxPrintf("Adding %s; Tnew = %.2fns, Told = %.2fns\n",
1743 node->name, gparams.rg_Tdi / Z_TO_P, RCdev / Z_TO_P);
1744 }
1745 }
1746 for (ptr = node->firstDev; ptr != NULL; ptr=ptr->nextDev)
1747 {
1748 if (layoutDev = ResGetDevice(&ptr->thisDev->location, ptr->thisDev->rs_ttype))
1749 {
1750 ResFixUpConnections(ptr->thisDev, layoutDev, node, newname);
1751 }
1752 }
1753 if (ResOptionsFlags & ResOpt_DoExtFile)
1754 {
1755 ResPrintExtNode(ResExtFile, ResNodeList, node->name);
1756 ResPrintExtRes(ResExtFile, ResResList, newname);
1757 }
1758 if (ResOptionsFlags & ResOpt_FastHenry)
1759 {
1760 if (ResResList)
1761 ResAlignNodes(ResNodeList, ResResList);
1762 ResPrintFHNodes(ResFHFile, ResNodeList, node->name, nidx, celldef);
1763 ResPrintFHRects(ResFHFile, ResResList, newname, eidx);
1764 }
1765 if (ResOptionsFlags & ResOpt_Geometry)
1766 {
1767 if (ResResList)
1768 ResAlignNodes(ResNodeList, ResResList);
1769 if (ResCreateCenterlines(ResResList, nidx, celldef) < 0)
1770 return 0;
1771 }
1772 return 1;
1773 }
1774 else return 0;
1775 }
1776
1777