1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: netdiff.cpp
6 * Network tool: module for network comparison
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 *
31 * This module is inspired by the work of Carl Ebeling:
32 * Ebeling, Carl, "GeminiII: A Second Generation Layout Validation Program",
33 * Proceedings of ICCAD 1988, p322-325.
34 */
35
36 #include "global.h"
37 #include "network.h"
38 #include "efunction.h"
39 #include "egraphics.h"
40 #include "edialogs.h"
41 #include "tecschem.h"
42 #include "usr.h"
43 #include <math.h>
44
45 #define NEWNCC 1 /* comment out to remove last-minute changes */
46 #define STATIC
47
48 #define MAXITERATIONS 10
49 #define SYMGROUPCOMP 0
50 #define SYMGROUPNET 1
51
52 /* the meaning of errors returned by "net_analyzesymmetrygroups()" */
53 #define SIZEERRORS 1
54 #define EXPORTERRORS 2
55 #define STRUCTUREERRORS 4
56
57 static GRAPHICS net_cleardesc = {LAYERH, ALLOFF, SOLIDC, SOLIDC,
58 {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
59 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
60 static GRAPHICS net_msgdesc = {LAYERH, HIGHLIT, SOLIDC, SOLIDC,
61 {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
62 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
63
64 #define NOSYMGROUP ((SYMGROUP *)-1)
65
66 /* the meaning of "SYMGROUP->groupflags" */
67 #define GROUPACTIVENOW 1 /* set if this group is active now */
68 #define GROUPFRESH 2 /* set if this group is "fresh" (just split) */
69 #define GROUPPROMISING 4 /* set if this group is "promising" (refed from split group) */
70
71 typedef struct Isymgroup
72 {
73 HASHTYPE hashvalue; /* hash value of this symmetry group */
74 INTBIG grouptype; /* SYMGROUPCOMP (components) or SYMGROUPNET (nets) */
75 INTBIG groupflags; /* state of this group */
76 INTBIG groupindex; /* ordinal value of group */
77 INTBIG checksum; /* additional value for group to ensure hash codes don't clash */
78 INTBIG cellcount[2]; /* number of objects from cells */
79 INTBIG celltotal[2]; /* size of object list from cells */
80 void **celllist[2]; /* list of objects from cells */
81 struct Isymgroup *nextsymgroup; /* next in list */
82 struct Isymgroup *nexterrsymgroup; /* next in list of errors */
83 } SYMGROUP;
84
85 static SYMGROUP *net_firstsymgroup = NOSYMGROUP;
86 static SYMGROUP *net_firstmatchedsymgroup = NOSYMGROUP;
87 static SYMGROUP *net_symgroupfree = NOSYMGROUP;
88
89 static SYMGROUP **net_symgrouphashcomp; /* hash table for components */
90 static SYMGROUP **net_symgrouphashnet; /* hash table for nets */
91 static INTBIG *net_symgrouphashckcomp; /* hash table checksums for components */
92 static INTBIG *net_symgrouphashcknet; /* hash table checksums for nets */
93 static INTBIG net_symgrouphashcompsize = 0; /* size of component hash table */
94 static INTBIG net_symgrouphashnetsize = 0; /* size of net hash table */
95 static INTBIG net_symgrouplisttotal = 0;
96 static INTBIG net_symgroupnumber;
97 static SYMGROUP **net_symgrouplist;
98 static INTBIG net_nodeCountMultiplier = 0;
99 static INTBIG net_portFactorMultiplier;
100 static INTBIG net_portNetFactorMultiplier;
101 static INTBIG net_portHashFactorMultiplier;
102 static INTBIG net_functionMultiplier;
103 static PNET *net_nodelist1 = NOPNET, *net_nodelist2 = NOPNET;
104 static INTBIG net_ncc_tolerance; /* component value tolerance (%) */
105 static INTBIG net_ncc_tolerance_amt; /* component value tolerance (amt) */
106 static HASHTYPE net_uniquehashvalue;
107 static BOOLEAN net_nethashclashtold;
108 static BOOLEAN net_comphashclashtold;
109
110 static INTBIG net_debuggeminipasscount; /* number of passes through gemini renumbering */
111 static INTBIG net_debuggeminiexpandglobal; /* number of times entire set of groups considered */
112 static INTBIG net_debuggeminiexpandglobalworked; /* number of times entire group considereation worked */
113 static INTBIG net_debuggeminigroupsrenumbered;/* number of symmetry groups renumbered */
114 static INTBIG net_debuggeminigroupssplit; /* number of symmetry groups split */
115 static INTBIG net_debuggeminitotalgroups; /* total number of groups examined */
116 static INTBIG net_debuggeminitotalgroupsact; /* number of active groups examined */
117
118 /* structures for name matching */
119 typedef struct
120 {
121 CHAR *name;
122 INTBIG number;
123 NODEINST *original;
124 } NAMEMATCH;
125
126 static NAMEMATCH *net_namematch[2];
127 static INTBIG net_namematchtotal[2] = {0, 0};
128 static INTBIG *net_compmatch0list;
129 static INTBIG *net_compmatch1list;
130 static INTBIG net_compmatch0total = 0;
131 static INTBIG net_compmatch1total = 0;
132
133 static INTBIG net_foundsymgrouptotal = 0;
134 static INTBIG net_foundsymgroupcount;
135 static SYMGROUP **net_foundsymgroups;
136
137 /* structures for size matching */
138 typedef struct
139 {
140 float length, width;
141 } NODESIZE;
142
143 static INTBIG net_sizearraytotal[2] = {0, 0};
144 static NODESIZE *net_sizearray[2];
145
146 /* used by "netanalyze.c" */
147 #if defined(__cplusplus) && !defined(ALLCPLUSPLUS)
148 extern "C" {
149 #endif
150 PCOMP *net_pcomp1 = NOPCOMP, *net_pcomp2 = NOPCOMP;
151 INTBIG net_timestamp;
152 NODEPROTO *net_cell[2];
153 INTBIG net_ncc_options; /* options to use in NCC */
154 extern GRAPHICS us_hbox;
155 #if defined(__cplusplus) && !defined(ALLCPLUSPLUS)
156 }
157 #endif
158
159 /* prototypes for local routines */
160 STATIC void net_addcomptoerror(void *err, PCOMP *pc);
161 STATIC void net_addnettoerror(void *err, PNET *pn);
162 STATIC void net_addsymgrouptoerror(void *err, SYMGROUP *sg);
163 STATIC void net_addtonamematch(NAMEMATCH **match, INTBIG *total, INTBIG *count, CHAR *name,
164 INTBIG number, NODEINST *orig);
165 STATIC BOOLEAN net_addtosymgroup(SYMGROUP *sg, INTBIG cellno, void *obj);
166 STATIC INTBIG net_analyzesymmetrygroups(BOOLEAN reporterrors, BOOLEAN checksize,
167 BOOLEAN checkexportnames, BOOLEAN ignorepwrgnd, INTBIG *errorcount);
168 STATIC INTBIG net_assignnewgrouphashvalues(SYMGROUP *sg, INTBIG verbose);
169 STATIC INTBIG net_assignnewhashvalues(INTBIG grouptype);
170 STATIC CHAR *net_describesizefactor(float sizew, float sizel);
171 STATIC INTBIG net_dogemini(PCOMP *pcomp1, PNET *nodelist1, PCOMP *pcomp2, PNET *nodelist2,
172 BOOLEAN checksize, BOOLEAN checkexportnames, BOOLEAN ignorepwrgnd);
173 STATIC INTBIG net_findamatch(INTBIG verbose, BOOLEAN ignorepwrgnd);
174 STATIC BOOLEAN net_findcommonsizefactor(SYMGROUP *sg, float *sizew, float *sizel);
175 STATIC BOOLEAN net_findcomponentnamematch(SYMGROUP *sg, BOOLEAN usenccmatches,
176 INTBIG verbose, BOOLEAN ignorepwrgnd, INTBIG total, INTBIG unmatchednets, INTBIG unmatchedcomps);
177 STATIC BOOLEAN net_findexportnamematch(SYMGROUP *sg, INTBIG verbose, BOOLEAN ignorepwrgnd,
178 INTBIG total, INTBIG unmatchednets, INTBIG unmatchedcomps);
179 STATIC SYMGROUP **net_findgeomsymmetrygroup(GEOM *obj);
180 STATIC SYMGROUP **net_findnetsymmetrygroup(NETWORK *net);
181 STATIC BOOLEAN net_findnetworknamematch(SYMGROUP *sg, BOOLEAN usenccmatches,
182 INTBIG verbose, BOOLEAN ignorepwrgnd, INTBIG total, INTBIG unmatchednets, INTBIG unmatchedcomps);
183 STATIC BOOLEAN net_findpowerandgroundmatch(SYMGROUP *sg, INTBIG verbose, INTBIG total, INTBIG unmatchednets, INTBIG unmatchedcomps);
184 STATIC SYMGROUP *net_findsymmetrygroup(INTBIG grouptype, HASHTYPE hashvalue, INTBIG checksum);
185 STATIC void net_forceamatch(SYMGROUP *sg, INTBIG c1, INTBIG *i1, INTBIG c2, INTBIG *i2,
186 float sizew, float sizel, INTBIG verbose, BOOLEAN ignorepwrgnd);
187 STATIC void net_freesymgroup(SYMGROUP *sg);
188 STATIC void net_initializeverbose(PCOMP *pcomplist, PNET *pnetlist);
189 STATIC BOOLEAN net_insertinhashtable(SYMGROUP *sg);
190 STATIC BOOLEAN net_isspice(PCOMP *pc);
191 STATIC INTBIG net_ncconelevel(NODEPROTO *cell1, NODEPROTO *cell2, BOOLEAN preanalyze,
192 BOOLEAN interactive);
193 STATIC SYMGROUP *net_newsymgroup(INTBIG type, HASHTYPE hashvalue, INTBIG checksum);
194 STATIC void net_preserveresults(NODEPROTO *np1, NODEPROTO *np2);
195 STATIC UINTBIG net_recursiverevisiondate(NODEPROTO *cell);
196 STATIC void net_rebuildhashtable(void);
197 STATIC void net_redeemzerogroups(SYMGROUP *sgnewc, SYMGROUP *sgnewn, INTBIG verbose, BOOLEAN ignorepwrgnd);
198 STATIC void net_removefromsymgroup(SYMGROUP *sg, INTBIG f, INTBIG index);
199 STATIC INTBIG net_reporterror(SYMGROUP *sg, CHAR *errmsg, BOOLEAN ignorepwrgnd);
200 STATIC void net_reportsizeerror(PCOMP *pc1, CHAR *size1, PCOMP *pc2, CHAR *size2, INTBIG pctdiff, SYMGROUP *sg);
201 STATIC BOOLEAN net_sameexportnames(PNET *pn1, PNET *pn2);
202 STATIC void net_showpreanalysis(NODEPROTO *cell1, PCOMP *pcomp1, PNET *nodelist1,
203 NODEPROTO *cell2, PCOMP *pcomp2, PNET *nodelist2, BOOLEAN ignorepwrgnd);
204 STATIC void net_showsymmetrygroups(INTBIG verbose, INTBIG type);
205 STATIC HASHTYPE net_uniquesymmetrygrouphash(INTBIG grouptype);
206 STATIC void net_unmatchedstatus(INTBIG *unmatchednets, INTBIG *unmatchedcomps, INTBIG *symgroupcount);
207 STATIC void net_showmatchedgroup(SYMGROUP *sg);
208 STATIC void net_addtofoundsymgroups(SYMGROUP *sg);
209 STATIC int net_sortbycelltype(const void *n1, const void *n2);
210 STATIC int net_sortbypnet(const void *n1, const void *n2);
211 STATIC int net_sortexportcodes(const void *e1, const void *e2);
212 STATIC void net_checkcomponenttypes(void *errorsa, BOOLEAN ignorepwrgnd, PCOMP *pcomp1, PCOMP *pcomp2,
213 PNET *pnetlist1, PNET *pnetlist2, NODEPROTO *cell1, NODEPROTO *cell2);
214 STATIC NETWORK **net_makeexternalnetlist(NODEINST *ni, INTBIG *size, BOOLEAN ignorepwrgnd);
215 STATIC void net_randomizehashcodes(INTBIG verbose);
216 STATIC void net_randomizesymgroup(SYMGROUP *sg, INTBIG verbose, INTBIG factor);
217 STATIC void net_cleanupsymmetrygroups(void);
218 STATIC void net_foundmismatch(NODEPROTO *cell, NETWORK *net, NODEPROTO *cellwithout, PCOMP **celllist,
219 INTBIG start, INTBIG end, PNET *pnetlist, BOOLEAN ignorepwrgnd, void *errorsa);
220 #if defined(__cplusplus) && !defined(ALLCPLUSPLUS)
221 extern "C"
222 {
223 #endif
224 STATIC int net_sortnamematches(const void *e1, const void *e2);
225 STATIC int net_sortpcomp(const void *e1, const void *e2);
226 STATIC int net_sortpnet(const void *e1, const void *e2);
227 STATIC int net_sortsizearray(const void *e1, const void *e2);
228 STATIC int net_sortsymgroups(const void *e1, const void *e2);
229 #if defined(__cplusplus) && !defined(ALLCPLUSPLUS)
230 }
231 #endif
232
233 /*
234 * Routine to free all memory associated with this module.
235 */
net_freediffmemory(void)236 void net_freediffmemory(void)
237 {
238 REGISTER SYMGROUP *sg;
239 REGISTER INTBIG f;
240
241 net_removeassociations();
242 while (net_firstsymgroup != NOSYMGROUP)
243 {
244 sg = net_firstsymgroup;
245 net_firstsymgroup = sg->nextsymgroup;
246 net_freesymgroup(sg);
247 }
248 while (net_firstmatchedsymgroup != NOSYMGROUP)
249 {
250 sg = net_firstmatchedsymgroup;
251 net_firstmatchedsymgroup = sg->nextsymgroup;
252 net_freesymgroup(sg);
253 }
254 if (net_symgrouphashcompsize != 0)
255 {
256 efree((CHAR *)net_symgrouphashcomp);
257 efree((CHAR *)net_symgrouphashckcomp);
258 }
259 if (net_symgrouphashnetsize != 0)
260 {
261 efree((CHAR *)net_symgrouphashnet);
262 efree((CHAR *)net_symgrouphashcknet);
263 }
264 while (net_symgroupfree != NOSYMGROUP)
265 {
266 sg = net_symgroupfree;
267 net_symgroupfree = sg->nextsymgroup;
268 for(f=0; f<2; f++)
269 if (sg->celltotal[f] > 0) efree((CHAR *)sg->celllist[f]);
270 efree((CHAR *)sg);
271 }
272 if (net_symgrouplisttotal > 0) efree((CHAR *)net_symgrouplist);
273 if (net_foundsymgrouptotal > 0) efree((CHAR *)net_foundsymgroups);
274
275 for(f=0; f<2; f++)
276 {
277 if (net_namematchtotal[f] > 0) efree((CHAR *)net_namematch[f]);
278 if (net_sizearraytotal[f] > 0) efree((CHAR *)net_sizearray[f]);
279 }
280 if (net_compmatch0total > 0) efree((CHAR *)net_compmatch0list);
281 if (net_compmatch1total > 0) efree((CHAR *)net_compmatch1list);
282 #ifdef FORCESUNTOOLS
283 net_freeexpdiffmemory();
284 #endif
285 }
286
net_removeassociations(void)287 void net_removeassociations(void)
288 {
289 if (net_pcomp1 != NOPCOMP)
290 {
291 net_freeallpcomp(net_pcomp1);
292 net_pcomp1 = NOPCOMP;
293 }
294 if (net_pcomp2 != NOPCOMP)
295 {
296 net_freeallpcomp(net_pcomp2);
297 net_pcomp2 = NOPCOMP;
298 }
299 if (net_nodelist1 != NOPNET)
300 {
301 net_freeallpnet(net_nodelist1);
302 net_nodelist1 = NOPNET;
303 }
304 if (net_nodelist2 != NOPNET)
305 {
306 net_freeallpnet(net_nodelist2);
307 net_nodelist2 = NOPNET;
308 }
309 }
310
311 /******************************** EQUATING COMPARED OBJECTS ********************************/
312
313 /*
314 * routine to identify the equivalent object associated with the currently
315 * highlighted one (comparison must have been done). If "noise" is true,
316 * report errors. Returns false if an equate was shown.
317 */
net_equate(BOOLEAN noise)318 BOOLEAN net_equate(BOOLEAN noise)
319 {
320 REGISTER NODEPROTO *np;
321 REGISTER PORTPROTO *pp;
322 REGISTER ARCINST *ai;
323 REGISTER NODEINST *ni;
324 REGISTER NETWORK *net, *anet;
325 REGISTER PCOMP *pc;
326 REGISTER PNET *pn;
327 REGISTER GEOM *obj;
328 REGISTER SYMGROUP *sg, **sglist;
329 REGISTER INTBIG i, j, f, k, fun;
330 REGISTER BOOLEAN first;
331 REGISTER void *infstr;
332
333 /* make sure an association has been done */
334 #ifdef NEWNCC
335 if (net_pcomp1 == NOPCOMP && net_pcomp2 == NOPCOMP && net_nodelist1 == NOPNET && net_nodelist2 == NOPNET)
336 #else
337 if (net_pcomp1 == NOPCOMP || net_pcomp2 == NOPCOMP)
338 #endif
339 {
340 if (noise) ttyputerr(_("First associate with '-telltool network compare'"));
341 return(TRUE);
342 }
343
344 /* get the highlighted object */
345 obj = (GEOM *)asktool(us_tool, x_("get-object"));
346 if (obj == NOGEOM)
347 {
348 if (noise) ttyputerr(_("Must select something to be equated"));
349 return(TRUE);
350 }
351
352 /* make sure this object is in one of the associated cells */
353 np = geomparent(obj);
354 if (np != net_cell[0] && np != net_cell[1])
355 {
356 if (!isachildof(np, net_cell[0]) && !isachildof(np, net_cell[1]))
357 {
358 if (noise)
359 ttyputerr(_("This object is not in one of the two associated cells"));
360 return(TRUE);
361 }
362 }
363
364 /* highlight the associated object */
365 sglist = net_findgeomsymmetrygroup(obj);
366 if (sglist[0] == NOSYMGROUP)
367 {
368 #ifdef FORCESUNTOOLS
369 return(net_equateexp(noise));
370 #endif
371 ttyputmsg(_("This object is not associated with anything else"));
372 return(TRUE);
373 }
374 if (sglist[1] == NOSYMGROUP && sglist[0]->hashvalue == 0)
375 {
376 ttyputmsg(_("This object was not matched successfully"));
377 return(TRUE);
378 }
379
380 (void)asktool(us_tool, x_("clear"));
381 infstr = initinfstr();
382 first = FALSE;
383 for(k=0; sglist[k] != NOSYMGROUP; k++)
384 {
385 sg = sglist[k];
386 switch (sg->grouptype)
387 {
388 case SYMGROUPCOMP:
389 for(f=0; f<2; f++)
390 {
391 for(i=0; i<sg->cellcount[f]; i++)
392 {
393 pc = (PCOMP *)sg->celllist[f][i];
394 for(j=0; j<pc->numactual; j++)
395 {
396 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
397 ni = ((NODEINST **)pc->actuallist)[j];
398 if (first) addtoinfstr(infstr, '\n');
399 first = TRUE;
400 formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0"),
401 describenodeproto(geomparent(ni->geom)), (INTBIG)ni->geom);
402 }
403 }
404 }
405 break;
406 case SYMGROUPNET:
407 for(f=0; f<2; f++)
408 {
409 for(i=0; i<sg->cellcount[f]; i++)
410 {
411 pn = (PNET *)sg->celllist[f][i];
412 net = pn->network;
413 if (net == NONETWORK) continue;
414 np = net->parent;
415 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
416 {
417 anet = ai->network;
418 if (ai->proto == sch_busarc)
419 {
420 if (anet->buswidth > 1)
421 {
422 #ifdef NEWNCC
423 for(j=0; j<anet->buswidth; j++)
424 if (anet->networklist[j] == net) break;
425 if (j >= anet->buswidth) continue;
426 #else
427 for(i=0; i<anet->buswidth; i++)
428 if (anet->networklist[i] == net) break;
429 if (i >= anet->buswidth) continue;
430 #endif
431 } else
432 {
433 if (anet != net) continue;
434 }
435 } else
436 {
437 if (anet != net) continue;
438 }
439 if (first) addtoinfstr(infstr, '\n');
440 first = TRUE;
441 formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0"),
442 describenodeproto(np), (INTBIG)ai->geom);
443 }
444 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
445 {
446 if (ni->proto->primindex == 0) continue;
447 fun = nodefunction(ni);
448 if (fun != NPPIN && fun != NPCONTACT && fun != NPNODE && fun != NPCONNECT)
449 continue;
450 if (ni->firstportarcinst == NOPORTARCINST) continue;
451 if (ni->firstportarcinst->conarcinst->network != net) continue;
452 if (first) addtoinfstr(infstr, '\n');
453 first = TRUE;
454 formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0"),
455 describenodeproto(np), (INTBIG)ni->geom);
456 }
457 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
458 {
459 if (pp->network != net) continue;
460 if (first) addtoinfstr(infstr, '\n');
461 first = TRUE;
462 formatinfstr(infstr, x_("CELL=%s TEXT=0%lo;0%lo;-"),
463 describenodeproto(np), (INTBIG)pp->subnodeinst->geom, (INTBIG)pp);
464 }
465 }
466 }
467 }
468 }
469 (void)asktool(us_tool, x_("show-multiple"), (INTBIG)returninfstr(infstr));
470 return(FALSE);
471 }
472
473 /*
474 * Routine to return equivalent network(s) associated with passed net
475 * (comparison must have been done). Returns 0 if no equivalent net
476 * could be found. Any equivalent networks found are put in **equiv, with array
477 * size *numequiv, and returns 1. Returns -1 if no NCC data.
478 */
net_getequivalentnet(NETWORK * net,NETWORK *** equiv,INTBIG * numequiv,BOOLEAN allowchild)479 INTBIG net_getequivalentnet(NETWORK *net, NETWORK ***equiv, INTBIG *numequiv, BOOLEAN allowchild)
480 {
481 REGISTER SYMGROUP *sg, **sglist;
482 REGISTER PNET *pn;
483 REGISTER NETWORK **newequiv;
484 REGISTER INTBIG f, i, k;
485 REGISTER BOOLEAN done;
486
487 if (net == NONETWORK) return(0);
488
489 /* make sure an association has been done */
490 #ifdef NEWNCC
491 if (net_pcomp1 == NOPCOMP && net_pcomp2 == NOPCOMP && net_nodelist1 == NOPNET && net_nodelist2 == NOPNET)
492 return(-1);
493 #else
494 if (net_pcomp1 == NOPCOMP || net_pcomp2 == NOPCOMP) return(-1);
495 #endif
496
497 /* make sure ni is in one of the associated cells */
498 if (net->parent != net_cell[0] && net->parent != net_cell[1])
499 {
500 if (!allowchild) return(-1);
501 if (!isachildof(net->parent, net_cell[0]) && !isachildof(net->parent, net_cell[1]))
502 return(-1);
503 }
504
505 sglist = net_findnetsymmetrygroup(net);
506 sg = sglist[0];
507 if (sg == NOSYMGROUP) return(0);
508 if (sglist[1] != NOSYMGROUP) return(0);
509 if (sg->hashvalue == 0) return(0);
510 if (sg->grouptype != SYMGROUPNET) return(0);
511
512 /* find group for net */
513 done = FALSE;
514 for (f=0; f<2; f++)
515 {
516 for (i=0; i<sg->cellcount[f]; i++)
517 {
518 pn = (PNET *)sg->celllist[f][i];
519 if( net == pn->network) done = TRUE;
520 if(done) break;
521 }
522 if(done) break;
523 }
524 if (f==2) return(0);
525 if (f==1) f = 0; else f = 1;
526
527 /* build equivalent nodeinst list */
528 *numequiv = 0;
529 for (i=0; i<sg->cellcount[f]; i++)
530 {
531 pn = (PNET *)sg->celllist[f][i];
532 newequiv = (NETWORK **)emalloc((*numequiv + 1)*(sizeof(NETWORK *)), el_tempcluster);
533 for (k=0; k<(*numequiv); k++)
534 newequiv[k] = (*equiv)[k];
535 newequiv[*numequiv] = pn->network;
536 if( *numequiv > 0) efree((CHAR *)(*equiv));
537 *equiv = newequiv;
538 (*numequiv)++;
539 }
540 return(TRUE);
541 }
542
543 /*
544 * Routine to find the symmetry groups associated with object "obj".
545 * Returns an array of symmetry groups. The first element is NOSYMGROUP
546 * if there are no associated objects.
547 */
net_findgeomsymmetrygroup(GEOM * obj)548 SYMGROUP **net_findgeomsymmetrygroup(GEOM *obj)
549 {
550 REGISTER SYMGROUP *sg;
551 REGISTER INTBIG f, i, j, fun;
552 REGISTER PCOMP *pc;
553 REGISTER NODEINST *ni, *wantni;
554 REGISTER ARCINST *ai;
555
556 if (obj->entryisnode)
557 {
558 /* look for a node */
559 wantni = obj->entryaddr.ni;
560 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
561 {
562 if (sg->grouptype != SYMGROUPCOMP) continue;
563 for(f=0; f<2; f++)
564 {
565 for(i=0; i<sg->cellcount[f]; i++)
566 {
567 pc = (PCOMP *)sg->celllist[f][i];
568 for(j=0; j<pc->numactual; j++)
569 {
570 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
571 ni = ((NODEINST **)pc->actuallist)[j];
572 if (ni == wantni)
573 {
574 net_foundsymgroupcount = 0;
575 net_addtofoundsymgroups(sg);
576 net_addtofoundsymgroups(NOSYMGROUP);
577 return(net_foundsymgroups);
578 }
579 }
580 }
581 }
582 }
583
584 /* node not found, try network coming out of it */
585 fun = nodefunction(wantni);
586 if (fun == NPPIN || fun == NPCONTACT || fun == NPCONNECT)
587 {
588 if (wantni->firstportarcinst != NOPORTARCINST)
589 obj = wantni->firstportarcinst->conarcinst->geom;
590 }
591 if (obj->entryisnode)
592 {
593 /* return a null list */
594 net_foundsymgroupcount = 0;
595 net_addtofoundsymgroups(NOSYMGROUP);
596 return(net_foundsymgroups);
597 }
598 }
599
600 /* look for an arc */
601 ai = obj->entryaddr.ai;
602 return(net_findnetsymmetrygroup(ai->network));
603 }
604
605 /*
606 * Routine to find the symmetry groups associated with network "net".
607 * Returns an array of symmetry groups. The first element is NOSYMGROUP
608 * if there are no associated objects.
609 */
net_findnetsymmetrygroup(NETWORK * net)610 SYMGROUP **net_findnetsymmetrygroup(NETWORK *net)
611 {
612 REGISTER SYMGROUP *sg;
613 REGISTER INTBIG f, i, k;
614 REGISTER PNET *pn;
615 REGISTER NETWORK *subnet;
616
617 net_foundsymgroupcount = 0;
618 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
619 {
620 if (sg->grouptype != SYMGROUPNET) continue;
621 for(f=0; f<2; f++)
622 {
623 for(i=0; i<sg->cellcount[f]; i++)
624 {
625 pn = (PNET *)sg->celllist[f][i];
626 if (pn->network == net)
627 {
628 net_addtofoundsymgroups(sg);
629 net_addtofoundsymgroups(NOSYMGROUP);
630 return(net_foundsymgroups);
631 }
632 }
633 }
634 }
635
636 /* if this is a bus, load up all signals on it */
637 if (net->buswidth > 1)
638 {
639 for(k=0; k<net->buswidth; k++)
640 {
641 subnet = net->networklist[k];
642 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
643 {
644 if (sg->grouptype != SYMGROUPNET) continue;
645 for(f=0; f<2; f++)
646 {
647 for(i=0; i<sg->cellcount[f]; i++)
648 {
649 pn = (PNET *)sg->celllist[f][i];
650 if (pn->network == subnet)
651 {
652 net_addtofoundsymgroups(sg);
653 break;
654 }
655 }
656 if (i < sg->cellcount[f]) break;
657 }
658 if (f < 2) break;
659 }
660 }
661 }
662 net_addtofoundsymgroups(NOSYMGROUP);
663 return(net_foundsymgroups);
664 }
665
666 /*
667 * Routine to add symmetry group "sg" to the global array "net_foundsymgroups".
668 */
net_addtofoundsymgroups(SYMGROUP * sg)669 void net_addtofoundsymgroups(SYMGROUP *sg)
670 {
671 REGISTER INTBIG newtotal, i;
672 REGISTER SYMGROUP **newlist;
673
674 if (net_foundsymgroupcount >= net_foundsymgrouptotal)
675 {
676 newtotal = net_foundsymgrouptotal * 2;
677 if (net_foundsymgroupcount >= newtotal) newtotal = net_foundsymgroupcount + 5;
678 newlist = (SYMGROUP **)emalloc(newtotal * (sizeof (SYMGROUP *)), net_tool->cluster);
679 if (newlist == 0) return;
680 for(i=0; i<net_foundsymgroupcount; i++)
681 newlist[i] = net_foundsymgroups[i];
682 if (net_foundsymgrouptotal > 0)
683 efree((CHAR *)net_foundsymgroups);
684 net_foundsymgroups = newlist;
685 net_foundsymgrouptotal = newtotal;
686 }
687 net_foundsymgroups[net_foundsymgroupcount++] = sg;
688 }
689
690 /******************************** COMPARISON ********************************/
691
692 /*
693 * routine to compare the two networks in "cell1" and "cell2" (if they are NONODEPROTO,
694 * use the two cells on the screen). If "preanalyze" is
695 * true, only do preanalysis and display results.
696 * Returns FALSE if the cells match.
697 */
net_compare(BOOLEAN preanalyze,BOOLEAN interactive,NODEPROTO * cell1,NODEPROTO * cell2)698 BOOLEAN net_compare(BOOLEAN preanalyze, BOOLEAN interactive, NODEPROTO *cell1, NODEPROTO *cell2)
699 {
700 REGISTER INTBIG ret, resignore;
701 REGISTER VARIABLE *var;
702 REGISTER NODEPROTO *np;
703 REGISTER LIBRARY *lib;
704 REGISTER BOOLEAN backannotate;
705 CHAR *respar[2];
706
707 backannotate = FALSE;
708
709 /* make sure network tool is on */
710 if ((net_tool->toolstate&TOOLON) == 0)
711 {
712 ttyputerr(_("Network tool must be running...turning it on for you"));
713 toolturnon(net_tool);
714 return(TRUE);
715 }
716
717 if (cell1 == NONODEPROTO || cell2 == NONODEPROTO)
718 {
719 if (net_getcells(&cell1, &cell2))
720 {
721 ttyputerr(_("Must have two windows with two different cells"));
722 return(TRUE);
723 }
724 }
725
726 /* if the top cells are already checked, stop now */
727 if (net_nccalreadydone(cell1, cell2))
728 {
729 ttyputmsg(_("Cells are already checked"));
730 return(FALSE);
731 }
732
733 /* get options to use during comparison */
734 var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
735 if (var == NOVARIABLE) net_ncc_options = 0; else
736 net_ncc_options = var->addr;
737
738 /* see if there are any resistors in this circuit */
739 if ((net_ncc_options&NCCRESISTINCLUSION) != NCCRESISTLEAVE)
740 {
741 resignore = asktech(sch_tech, x_("ignoring-resistor-topology"));
742 if (resignore != 0 && (net_ncc_options&NCCRESISTINCLUSION) == NCCRESISTINCLUDE)
743 {
744 /* must redo network topology to include resistors */
745 respar[0] = x_("resistors");
746 respar[1] = x_("include");
747 (void)telltool(net_tool, 2, respar);
748 } else if (resignore == 0 && (net_ncc_options&NCCRESISTINCLUSION) == NCCRESISTEXCLUDE)
749 {
750 /* must redo network topology to exclude resistors */
751 respar[0] = x_("resistors");
752 respar[1] = x_("ignore");
753 (void)telltool(net_tool, 2, respar);
754 }
755 }
756
757 starttimer();
758 if (preanalyze) ttyputmsg(_("Analyzing..."));
759
760 /* reset the random number generator so that the results are repeatable */
761 srand(1);
762 net_nethashclashtold = FALSE;
763 net_comphashclashtold = FALSE;
764
765 var = getvalkey((INTBIG)net_tool, VTOOL, -1, net_ncc_comptolerancekey);
766 if (var == NOVARIABLE) net_ncc_tolerance = 0; else
767 {
768 if ((var->type&VTYPE) == VINTEGER) net_ncc_tolerance = var->addr * WHOLE; else
769 if ((var->type&VTYPE) == VFRACT) net_ncc_tolerance = var->addr;
770 }
771 var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_comptoleranceamtkey);
772 if (var == NOVARIABLE) net_ncc_tolerance_amt = 0; else net_ncc_tolerance_amt = var->addr;
773
774 /* mark all cells as not-checked and name all nets */
775 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
776 {
777 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
778 {
779 np->temp1 = (np->temp1 & ~NETNCCCHECKSTATE) | NETNCCNOTCHECKED;
780 if (asktool(net_tool, x_("name-nets"), (INTBIG)np) != 0) backannotate = TRUE;
781 }
782 }
783
784 ret = net_ncconelevel(cell1, cell2, preanalyze, interactive);
785
786 if (backannotate)
787 ttyputmsg(_("Back-annotation information has been added (library must be saved)"));
788
789 return(ret!=0 ? TRUE : FALSE);
790 }
791
792 /* NCC warning */
793 static DIALOGITEM net_nccwarndialogitems[] =
794 {
795 /* 1 */ {0, {276,340,300,480}, BUTTON, N_("Show Preanalysis")},
796 /* 2 */ {0, {244,340,268,480}, BUTTON, N_("Stop Now")},
797 /* 3 */ {0, {308,340,332,480}, BUTTON, N_("Do Full NCC")},
798 /* 4 */ {0, {8,8,24,512}, MESSAGE, x_("")},
799 /* 5 */ {0, {28,8,236,512}, SCROLL, x_("")},
800 /* 6 */ {0, {248,56,264,332}, MESSAGE, N_("You may stop the NCC now:")},
801 /* 7 */ {0, {280,56,296,332}, MESSAGE, N_("You may request additional detail:")},
802 /* 8 */ {0, {312,56,328,332}, MESSAGE, N_("You may continue with NCC:")}
803 };
804 static DIALOG net_nccwarndialog = {{75,75,416,597}, N_("NCC Differences Have Been Found"), 0, 8, net_nccwarndialogitems, 0, 0};
805
806 /* special items for the "NCC warning" dialog: */
807 #define DNCW_DOPREANALYSIS 1 /* Do preanalysis (button) */
808 #define DNCW_STOPNOW 2 /* Stop now (button) */
809 #define DNCW_DONCC 3 /* Do NCC (button) */
810 #define DNCW_TITLE 4 /* Title line (stat text) */
811 #define DNCW_DIFFLIST 5 /* List of differences (scroll) */
812
813 /*
814 * Routine to compare "cell1" and "cell2".
815 * If "preanalyze" is TRUE, only do preanalysis.
816 * If "interactive" is TRUE, do interactive comparison.
817 * Returns 0 if they compare, 1 if they do not compare, -1 on error.
818 */
net_ncconelevel(NODEPROTO * cell1,NODEPROTO * cell2,BOOLEAN preanalyze,BOOLEAN interactive)819 INTBIG net_ncconelevel(NODEPROTO *cell1, NODEPROTO *cell2, BOOLEAN preanalyze, BOOLEAN interactive)
820 {
821 INTBIG comp1, comp2, power1, power2, ground1, ground2, netcount1, netcount2,
822 unmatchednets, unmatchedcomps, prevunmatchednets, prevunmatchedcomps, errors,
823 symgroupcount, net1remove, net2remove, errorcount;
824 REGISTER INTBIG i, f, ocomp1, ocomp2, verbose, buscount1, buscount2, ret, itemHit;
825 BOOLEAN hierarchical, ignorepwrgnd, mergeparallel, mergeseries, recurse,
826 checkexportnames, checksize, localmergeseries1, localmergeseries2,
827 localmergeparallel1, localmergeparallel2, subcellsbad,
828 localhierarchical1, localhierarchical2, figuresizes;
829 float elapsed;
830 REGISTER CHAR *errortype, **errorstrings;
831 REGISTER WINDOWPART *w, *savecurw;
832 REGISTER NODEINST *ni;
833 REGISTER NODEPROTO *subnp1, *subnp2;
834 REGISTER NETWORK *net;
835 REGISTER VARIABLE *var;
836 REGISTER PCOMP *pc, *opc;
837 REGISTER PNET *pn;
838 REGISTER SYMGROUP *sg;
839 REGISTER void *infstr, *dia, *errorsa;
840
841 /* make sure prime multipliers are computed */
842 net_initdiff();
843
844 /* stop if already checked */
845 if ((cell1->temp1&NETNCCCHECKSTATE) == NETNCCCHECKEDGOOD &&
846 (cell2->temp1&NETNCCCHECKSTATE) == NETNCCCHECKEDGOOD) return(0);
847 if ((cell1->temp1&NETNCCCHECKSTATE) != NETNCCNOTCHECKED ||
848 (cell2->temp1&NETNCCCHECKSTATE) != NETNCCNOTCHECKED) return(1);
849 if (net_nccalreadydone(cell1, cell2))
850 {
851 cell1->temp1 = (cell1->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDGOOD;
852 cell2->temp1 = (cell2->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDGOOD;
853 return(0);
854 }
855
856 verbose = net_ncc_options & (NCCVERBOSETEXT | NCCVERBOSEGRAPHICS);
857 if ((net_ncc_options&NCCRECURSE) != 0) recurse = TRUE; else
858 recurse = FALSE;
859 if ((net_ncc_options&NCCHIERARCHICAL) != 0) hierarchical = TRUE; else
860 hierarchical = FALSE;
861 if ((net_ncc_options&NCCIGNOREPWRGND) != 0) ignorepwrgnd = TRUE; else
862 ignorepwrgnd = FALSE;
863 if ((net_ncc_options&NCCNOMERGEPARALLEL) == 0) mergeparallel = TRUE; else
864 mergeparallel = FALSE;
865 if ((net_ncc_options&NCCMERGESERIES) != 0) mergeseries = TRUE; else
866 mergeseries = FALSE;
867 if ((net_ncc_options&NCCCHECKEXPORTNAMES) != 0) checkexportnames = TRUE; else
868 checkexportnames = FALSE;
869 if ((net_ncc_options&NCCCHECKSIZE) != 0) checksize = TRUE; else
870 checksize = FALSE;
871 figuresizes = TRUE;
872 if (preanalyze) figuresizes = FALSE;
873 if (!checksize) figuresizes = FALSE;
874
875 /* check for cell overrides */
876 localhierarchical1 = localhierarchical2 = hierarchical;
877 localmergeparallel1 = localmergeparallel2 = mergeparallel;
878 localmergeseries1 = localmergeseries2 = mergeseries;
879 var = getvalkey((INTBIG)cell1, VNODEPROTO, VINTEGER, net_ncc_optionskey);
880 if (var != NOVARIABLE)
881 {
882 if ((var->addr&NCCHIERARCHICALOVER) != 0)
883 {
884 if ((var->addr&NCCHIERARCHICAL) != 0) localhierarchical1 = TRUE; else
885 localhierarchical1 = FALSE;
886 }
887 if ((var->addr&NCCNOMERGEPARALLELOVER) != 0)
888 {
889 if ((var->addr&NCCNOMERGEPARALLEL) == 0) localmergeparallel1 = TRUE; else
890 localmergeparallel1 = FALSE;
891 }
892 if ((var->addr&NCCMERGESERIESOVER) != 0)
893 {
894 if ((var->addr&NCCMERGESERIES) != 0) localmergeseries1 = TRUE; else
895 localmergeseries1 = FALSE;
896 }
897 }
898 var = getvalkey((INTBIG)cell2, VNODEPROTO, VINTEGER, net_ncc_optionskey);
899 if (var != NOVARIABLE)
900 {
901 if ((var->addr&NCCHIERARCHICALOVER) != 0)
902 {
903 if ((var->addr&NCCHIERARCHICAL) != 0) localhierarchical2 = TRUE; else
904 localhierarchical2 = FALSE;
905 }
906 if ((var->addr&NCCNOMERGEPARALLELOVER) != 0)
907 {
908 if ((var->addr&NCCNOMERGEPARALLEL) == 0) localmergeparallel2 = TRUE; else
909 localmergeparallel2 = FALSE;
910 }
911 if ((var->addr&NCCMERGESERIESOVER) != 0)
912 {
913 if ((var->addr&NCCMERGESERIES) != 0) localmergeseries2 = TRUE; else
914 localmergeseries2 = FALSE;
915 }
916 }
917 if (localhierarchical1 || localhierarchical2) hierarchical = TRUE; else
918 hierarchical = FALSE;
919 if (localmergeparallel1 || localmergeparallel2) mergeparallel = TRUE; else
920 mergeparallel = FALSE;
921 if (localmergeseries1 || localmergeseries2) mergeseries = TRUE; else
922 mergeseries = FALSE;
923 if (hierarchical) recurse = FALSE;
924
925 /* if recursing, look at subcells first */
926 subcellsbad = FALSE;
927 if (recurse)
928 {
929 for(ni = cell1->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
930 {
931 subnp1 = ni->proto;
932 if (subnp1->primindex != 0) continue;
933
934 /* ignore recursive references (showing icon in contents) */
935 if (isiconof(subnp1, cell1)) continue;
936 if (subnp1->cellview == el_iconview)
937 {
938 subnp1 = anyview(subnp1, cell1->cellview);
939 if (subnp1 == NONODEPROTO) continue;
940 }
941
942 /* find equivalent to this in the other view */
943 subnp2 = anyview(subnp1, cell2->cellview);
944 if (subnp2 == NONODEPROTO)
945 {
946 ttyputerr(_("Cannot find %s view of cell %s"), cell2->cellview->viewname,
947 describenodeproto(subnp1));
948 continue;
949 }
950 ret = net_ncconelevel(subnp1, subnp2, preanalyze, interactive);
951 if (ret < 0)
952 {
953 cell1->temp1 = (cell1->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDBAD;
954 cell2->temp1 = (cell2->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDBAD;
955 return(ret);
956 }
957 if (ret > 0) subcellsbad = TRUE;
958 }
959 for(ni = cell2->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
960 {
961 subnp2 = ni->proto;
962 if (subnp2->primindex != 0) continue;
963
964 /* ignore recursive references (showing icon in contents) */
965 if (isiconof(subnp2, cell2)) continue;
966 if (subnp2->cellview == el_iconview)
967 {
968 subnp2 = anyview(subnp2, cell2->cellview);
969 if (subnp2 == NONODEPROTO) continue;
970 }
971
972 /* find equivalent to this in the other view */
973 subnp1 = anyview(subnp2, cell1->cellview);
974 if (subnp1 == NONODEPROTO)
975 {
976 ttyputerr(_("Cannot find %s view of cell %s"), cell1->cellview->viewname,
977 describenodeproto(subnp2));
978 continue;
979 }
980 ret = net_ncconelevel(subnp1, subnp2, preanalyze, interactive);
981 if (ret < 0)
982 {
983 cell1->temp1 = (cell1->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDBAD;
984 cell2->temp1 = (cell2->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDBAD;
985 return(ret);
986 }
987 if (ret > 0) subcellsbad = TRUE;
988 }
989 }
990
991 /* free any previous data structures */
992 net_removeassociations();
993
994 /* announce what is happening */
995 ttyputmsg(_("Comparing cell %s with cell %s"),
996 describenodeproto(cell1), describenodeproto(cell2));
997
998 infstr = initinfstr();
999 if ((net_ncc_options&NCCHIERARCHICAL) != 0) addstringtoinfstr(infstr, _("Flattening hierarchy")); else
1000 {
1001 if (recurse) addstringtoinfstr(infstr, _("Checking cells recursively")); else
1002 addstringtoinfstr(infstr, _("Checking this cell only"));
1003 }
1004 if (ignorepwrgnd) addstringtoinfstr(infstr, _("; Ignoring Power and Ground nets")); else
1005 addstringtoinfstr(infstr, _("; Considering Power and Ground nets"));
1006 ttyputmsg(x_("- %s"), returninfstr(infstr));
1007
1008 infstr = initinfstr();
1009 if (!mergeparallel) addstringtoinfstr(infstr, _("Parallel components not merged")); else
1010 addstringtoinfstr(infstr, _("Parallel components merged"));
1011 if (!mergeseries) addstringtoinfstr(infstr, _("; Series transistors not merged")); else
1012 addstringtoinfstr(infstr, _("; Series transistors merged"));
1013 ttyputmsg(x_("- %s"), returninfstr(infstr));
1014
1015 if (checkexportnames && checksize)
1016 {
1017 ttyputmsg(_("- Checking export names and component sizes"));
1018 } else if (!checkexportnames && !checksize)
1019 {
1020 ttyputmsg(_("- Ignoring export names and component sizes"));
1021 } else
1022 {
1023 if (checkexportnames)
1024 ttyputmsg(_("- Checking export names; Ignoring component sizes")); else
1025 ttyputmsg(_("- Ignoring export names; Checking component sizes"));
1026 }
1027 net_listnccoverrides(FALSE);
1028
1029 /* precompute network topology */
1030 ttyputmsg(_("Preparing circuit for extraction..."));
1031 net_initnetflattening();
1032 ttyputmsg(_("--- Done preparing (%s so far)"), explainduration(endtimer()));
1033
1034 /* build network of pseudocomponents */
1035 ttyputmsg(_("Extracting networks from %s..."), describenodeproto(cell1));
1036 savecurw = el_curwindowpart;
1037 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1038 if (w->curnodeproto == cell1) break;
1039 if (w != NOWINDOWPART) el_curwindowpart = w;
1040 net_pcomp1 = net_makepseudo(cell1, &comp1, &netcount1, &power1, &ground1,
1041 &net_nodelist1, hierarchical, mergeparallel, mergeseries, TRUE, figuresizes);
1042 el_curwindowpart = savecurw;
1043 ttyputmsg(_("--- Done extracting %s (%s so far)"), describenodeproto(cell1),
1044 explainduration(endtimer()));
1045 if (net_pcomp1 == NOPCOMP && comp1 < 0)
1046 {
1047 cell1->temp1 = (cell1->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDBAD;
1048 cell2->temp1 = (cell2->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDBAD;
1049 return(-1);
1050 }
1051 ttyputmsg(_("Extracting networks from %s..."), describenodeproto(cell2));
1052 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1053 if (w->curnodeproto == cell2) break;
1054 if (w != NOWINDOWPART) el_curwindowpart = w;
1055 net_pcomp2 = net_makepseudo(cell2, &comp2, &netcount2, &power2, &ground2,
1056 &net_nodelist2, hierarchical, mergeparallel, mergeseries, TRUE, figuresizes);
1057 el_curwindowpart = savecurw;
1058 ttyputmsg(_("--- Done extracting %s (%s so far)"), describenodeproto(cell2),
1059 explainduration(endtimer()));
1060 if (net_pcomp2 == NOPCOMP && comp2 < 0)
1061 {
1062 cell1->temp1 = (cell1->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDBAD;
1063 cell2->temp1 = (cell2->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDBAD;
1064 return(-1);
1065 }
1066 net_cell[0] = cell1; net_cell[1] = cell2;
1067 net1remove = net2remove = 0;
1068 if (ignorepwrgnd)
1069 {
1070 net1remove = power1 + ground1;
1071 net2remove = power2 + ground2;
1072 }
1073
1074 /* separate nets into plain and busses */
1075 buscount1 = 0;
1076 for(pn = net_nodelist1; pn != NOPNET; pn = pn->nextpnet)
1077 {
1078 net = pn->network;
1079 if (net == NONETWORK) continue;
1080 if (net->buswidth > 1) buscount1++;
1081 }
1082 netcount1 -= buscount1;
1083 buscount2 = 0;
1084 for(pn = net_nodelist2; pn != NOPNET; pn = pn->nextpnet)
1085 {
1086 net = pn->network;
1087 if (net == NONETWORK) continue;
1088 if (net->buswidth > 1) buscount2++;
1089 }
1090 netcount2 -= buscount2;
1091
1092 /* remove extraneous information */
1093 net_removeextraneous(&net_pcomp1, &net_nodelist1, &comp1);
1094 net_removeextraneous(&net_pcomp2, &net_nodelist2, &comp2);
1095
1096 if (!mergeparallel && comp1 != comp2)
1097 {
1098 /* see if merging parallel components makes them match */
1099 ocomp1 = comp1; ocomp2 = comp2;
1100 if (comp1 < comp2)
1101 {
1102 /* try merging parallel components in cell 2 */
1103 ttyputmsg(_("--- Cell %s has %ld components and cell %s has %ld: merging parallel components in cell %s..."),
1104 describenodeproto(cell1), comp1, describenodeproto(cell2), comp2,
1105 describenodeproto(cell2));
1106 (void)net_mergeparallel(&net_pcomp2, net_nodelist2, &comp2);
1107 if (comp1 > comp2)
1108 {
1109 ttyputmsg(_("--- Merging parallel components in cell %s..."),
1110 describenodeproto(cell1));
1111 (void)net_mergeparallel(&net_pcomp1, net_nodelist1, &comp1);
1112 }
1113 } else
1114 {
1115 /* try merging parallel components in cell 1 */
1116 ttyputmsg(_("--- Cell %s has %ld components and cell %s has %ld: merging parallel components in cell %s..."),
1117 describenodeproto(cell1), comp1, describenodeproto(cell2), comp2,
1118 describenodeproto(cell1));
1119 (void)net_mergeparallel(&net_pcomp1, net_nodelist1, &comp1);
1120 if (comp2 > comp1)
1121 {
1122 ttyputmsg(_("--- Merging parallel components in cell %s..."),
1123 describenodeproto(cell2));
1124 (void)net_mergeparallel(&net_pcomp2, net_nodelist2, &comp2);
1125 }
1126 }
1127 }
1128
1129 /* make sure network pointers are correct */
1130 net_fillinnetpointers(net_pcomp1, net_nodelist1);
1131 net_fillinnetpointers(net_pcomp2, net_nodelist2);
1132
1133 /* announce results of extraction */
1134 errorsa = newstringarray(net_tool->cluster);
1135 if (comp1 == comp2)
1136 ttyputmsg(_("Both cells have %ld components"), comp1); else
1137 {
1138 infstr = initinfstr();
1139 formatinfstr(infstr, _("Cell %s has %ld components but cell %s has %ld"),
1140 describenodeproto(cell1), comp1, describenodeproto(cell2), comp2);
1141 addtostringarray(errorsa, returninfstr(infstr));
1142 }
1143 if (netcount1-net1remove == netcount2-net2remove)
1144 ttyputmsg(_("Both cells have %ld nets"), netcount1-net1remove); else
1145 {
1146 infstr = initinfstr();
1147 formatinfstr(infstr, _("Cell %s has %ld nets but cell %s has %ld"),
1148 describenodeproto(cell1), netcount1-net1remove, describenodeproto(cell2), netcount2-net2remove);
1149 addtostringarray(errorsa, returninfstr(infstr));
1150 }
1151 if (buscount1 == buscount2)
1152 {
1153 if (buscount1 != 0)
1154 ttyputmsg(_("Both cells have %ld busses"), netcount1-net1remove);
1155 } else
1156 {
1157 ttyputmsg(_("Note: cell %s has %ld busses but cell %s has %ld"),
1158 describenodeproto(cell1), buscount1, describenodeproto(cell2), buscount2);
1159 }
1160 if (!ignorepwrgnd)
1161 {
1162 if (power1 != power2)
1163 {
1164 infstr = initinfstr();
1165 formatinfstr(infstr, _("Cell %s has %ld power nets but cell %s has %ld"),
1166 describenodeproto(cell1), power1, describenodeproto(cell2), power2);
1167 addtostringarray(errorsa, returninfstr(infstr));
1168 infstr = initinfstr();
1169 formatinfstr(infstr, _(" Number of components on power nets in cell %s:"),
1170 describenodeproto(cell1));
1171 for(pn = net_nodelist1; pn != NOPNET; pn = pn->nextpnet)
1172 if ((pn->flags&POWERNET) != 0)
1173 formatinfstr(infstr, x_(" %ld"), pn->nodecount);
1174 addtostringarray(errorsa, returninfstr(infstr));
1175 infstr = initinfstr();
1176 formatinfstr(infstr, _(" Number of components on power nets in cell %s:"),
1177 describenodeproto(cell2));
1178 for(pn = net_nodelist2; pn != NOPNET; pn = pn->nextpnet)
1179 if ((pn->flags&POWERNET) != 0)
1180 formatinfstr(infstr, x_(" %ld"), pn->nodecount);
1181 addtostringarray(errorsa, returninfstr(infstr));
1182 }
1183 if (ground1 != ground2)
1184 {
1185 infstr = initinfstr();
1186 formatinfstr(infstr, _("Cell %s has %ld ground nets but cell %s has %ld"),
1187 describenodeproto(cell1), ground1, describenodeproto(cell2), ground2);
1188 addtostringarray(errorsa, returninfstr(infstr));
1189 infstr = initinfstr();
1190 formatinfstr(infstr, _(" Number of components on ground nets in cell %s:"),
1191 describenodeproto(cell1));
1192 for(pn = net_nodelist1; pn != NOPNET; pn = pn->nextpnet)
1193 if ((pn->flags&GROUNDNET) != 0)
1194 formatinfstr(infstr, x_(" %ld"), pn->nodecount);
1195 addtostringarray(errorsa, returninfstr(infstr));
1196 infstr = initinfstr();
1197 formatinfstr(infstr, _(" Number of components on ground nets in cell %s:"),
1198 describenodeproto(cell2));
1199 for(pn = net_nodelist2; pn != NOPNET; pn = pn->nextpnet)
1200 if ((pn->flags&GROUNDNET) != 0)
1201 formatinfstr(infstr, x_(" %ld"), pn->nodecount);
1202 addtostringarray(errorsa, returninfstr(infstr));
1203 }
1204 }
1205
1206 /* if there are no problems found, look deeper */
1207 (void)getstringarray(errorsa, &errorcount);
1208 if (errorcount == 0)
1209 {
1210 /* check to be sure the component types match */
1211 net_checkcomponenttypes(errorsa, ignorepwrgnd, net_pcomp1, net_pcomp2,
1212 net_nodelist1, net_nodelist2, cell1, cell2);
1213 }
1214
1215 /* check for duplicate names */
1216 #if 0 /* why does this crash? */
1217 net_checkforduplicatenames(net_nodelist1);
1218 net_checkforduplicatenames(net_nodelist2);
1219 #endif
1220
1221 /* if there are possible problems, report them now */
1222 errorstrings = getstringarray(errorsa, &errorcount);
1223 for(i=0; i<errorcount; i++)
1224 ttyputmsg(_("Note: %s"), errorstrings[i]);
1225 if (!preanalyze && errorcount > 0 && interactive)
1226 {
1227 dia = DiaInitDialog(&net_nccwarndialog);
1228 if (dia == 0) return(-1);
1229 DiaInitTextDialog(dia, DNCW_DIFFLIST, DiaNullDlogList, DiaNullDlogItem,
1230 DiaNullDlogDone, -1, SCHORIZBAR);
1231 infstr = initinfstr();
1232 formatinfstr(infstr, _("Differences between cells %s and %s:"),
1233 describenodeproto(cell1), describenodeproto(cell2));
1234 DiaSetText(dia, DNCW_TITLE, returninfstr(infstr));
1235 for(i=0; i<errorcount; i++)
1236 DiaStuffLine(dia, DNCW_DIFFLIST, errorstrings[i]);
1237 DiaSelectLine(dia, DNCW_DIFFLIST, -1);
1238
1239 for(;;)
1240 {
1241 itemHit = DiaNextHit(dia);
1242 if (itemHit == DNCW_DOPREANALYSIS || itemHit == DNCW_STOPNOW ||
1243 itemHit == DNCW_DONCC) break;
1244 }
1245 DiaDoneDialog(dia);
1246 if (itemHit == DNCW_STOPNOW)
1247 {
1248 killstringarray(errorsa);
1249 return(-1);
1250 }
1251 if (itemHit == DNCW_DOPREANALYSIS) preanalyze = TRUE;
1252 }
1253 killstringarray(errorsa);
1254
1255 /* build list of PNODEs and wires on each net */
1256 if (preanalyze) verbose = 0;
1257 net_timestamp = 0;
1258 if (verbose != 0)
1259 {
1260 net_initializeverbose(net_pcomp1, net_nodelist1);
1261 net_initializeverbose(net_pcomp2, net_nodelist2);
1262 }
1263
1264 if (preanalyze)
1265 {
1266 /* dump the networks and stop */
1267 net_showpreanalysis(cell1, net_pcomp1, net_nodelist1,
1268 cell2, net_pcomp2, net_nodelist2, ignorepwrgnd);
1269 cell1->temp1 = (cell1->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDGOOD;
1270 cell2->temp1 = (cell2->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDGOOD;
1271 return(0);
1272 }
1273
1274 /* try to find network symmetry with existing switches */
1275 net_debuggeminipasscount = 0;
1276 net_debuggeminiexpandglobal = net_debuggeminiexpandglobalworked = 0;
1277 net_debuggeminigroupsrenumbered = net_debuggeminigroupssplit = 0;
1278 net_debuggeminitotalgroups = net_debuggeminitotalgroupsact = 0;
1279 ret = net_dogemini(net_pcomp1, net_nodelist1, net_pcomp2, net_nodelist2,
1280 checksize, checkexportnames, ignorepwrgnd);
1281 if (ret < 0) return(-1);
1282
1283 /* if match failed, see if unmerged parallel components are ambiguous */
1284 if (ret != 0 && !mergeparallel)
1285 {
1286 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
1287 {
1288 if (sg->grouptype != SYMGROUPCOMP) continue;
1289 if (sg->cellcount[0] <= 1 || sg->cellcount[1] <= 1) continue;
1290 for(f=0; f<2; f++)
1291 {
1292 for(i=1; i<sg->cellcount[f]; i++)
1293 {
1294 opc = (PCOMP *)sg->celllist[f][i-1];
1295 pc = (PCOMP *)sg->celllist[f][i];
1296 if (net_comparewirelist(pc, opc, FALSE)) continue;
1297 mergeparallel = TRUE;
1298 break;
1299 }
1300 if (mergeparallel) break;
1301 }
1302 if (mergeparallel) break;
1303 }
1304 if (mergeparallel)
1305 {
1306 /* might work if parallel components are merged */
1307 ttyputmsg(_("--- No match: trying again with parallel components merged"));
1308 net_unmatchedstatus(&prevunmatchednets, &prevunmatchedcomps, &symgroupcount);
1309 (void)net_mergeparallel(&net_pcomp1, net_nodelist1, &comp1);
1310 (void)net_mergeparallel(&net_pcomp2, net_nodelist2, &comp2);
1311 net_debuggeminipasscount = 0;
1312 net_debuggeminiexpandglobal = net_debuggeminiexpandglobalworked = 0;
1313 net_debuggeminigroupsrenumbered = net_debuggeminigroupssplit = 0;
1314 net_debuggeminitotalgroups = net_debuggeminitotalgroupsact = 0;
1315 ret = net_dogemini(net_pcomp1, net_nodelist1, net_pcomp2, net_nodelist2,
1316 checksize, checkexportnames, ignorepwrgnd);
1317 if (ret < 0) return(-1);
1318 if (ret != 0)
1319 {
1320 net_unmatchedstatus(&unmatchednets, &unmatchedcomps, &symgroupcount);
1321 if (unmatchednets + unmatchedcomps < prevunmatchednets + prevunmatchedcomps)
1322 {
1323 /* this improved things but didn't solve them, use it */
1324 ttyputmsg(_("------ Merge of parallel components improved match"));
1325 } else if (unmatchednets + unmatchedcomps == prevunmatchednets + prevunmatchedcomps)
1326 ttyputmsg(_("------ Merge of parallel components make no change")); else
1327 ttyputmsg(_("------ Merge of parallel components make things worse"));
1328 }
1329 }
1330 }
1331
1332 /* free reason information */
1333 if (verbose != 0)
1334 {
1335 for(pn = net_nodelist1; pn != NOPNET; pn = pn->nextpnet)
1336 {
1337 efree((CHAR *)pn->hashreason);
1338 pn->hashreason = 0;
1339 }
1340 for(pn = net_nodelist2; pn != NOPNET; pn = pn->nextpnet)
1341 {
1342 efree((CHAR *)pn->hashreason);
1343 pn->hashreason = 0;
1344 }
1345 for(pc = net_pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
1346 {
1347 efree((CHAR *)pc->hashreason);
1348 pc->hashreason = 0;
1349 }
1350 for(pc = net_pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
1351 {
1352 efree((CHAR *)pc->hashreason);
1353 pc->hashreason = 0;
1354 }
1355 }
1356 if ((net_ncc_options&NCCENASTATISTICS) != 0)
1357 {
1358 ttyputmsg(x_("--- Made %ld iterations of Gemini"), net_debuggeminipasscount);
1359 if (net_debuggeminiexpandglobal != 0)
1360 {
1361 ttyputmsg(x_("--- Of those %ld iterations considered all groups"), net_debuggeminiexpandglobal);
1362 ttyputmsg(x_("--- And %ld of the all-group examinations found new splits"), net_debuggeminiexpandglobalworked);
1363 }
1364 ttyputmsg(x_("--- Renumbered %ld symmetry groups"), net_debuggeminigroupsrenumbered);
1365 if (net_debuggeminigroupssplit != net_debuggeminigroupsrenumbered)
1366 ttyputmsg(x_("--- Of these, %ld split"), net_debuggeminigroupssplit);
1367 if (net_debuggeminitotalgroups != net_debuggeminitotalgroupsact)
1368 {
1369 if (net_debuggeminitotalgroups == 0) net_debuggeminitotalgroups= 1;
1370 ttyputmsg(x_("--- On average, %ld%% of groups are active"),
1371 net_debuggeminitotalgroupsact*100/net_debuggeminitotalgroups);
1372 }
1373 }
1374
1375 /* see if errors were found */
1376 initerrorlogging(_("NCC"));
1377
1378 #ifdef FORCESUNTOOLS
1379 if ((net_ncc_options&NCCEXPERIMENTAL) != 0)
1380 {
1381 errors = net_expanalyzesymmetrygroups(TRUE, checksize, checkexportnames, ignorepwrgnd, &errorcount);
1382 } else
1383 #endif
1384 errors = net_analyzesymmetrygroups(TRUE, checksize, checkexportnames, ignorepwrgnd, &errorcount);
1385
1386 /* write summary of NCC */
1387 elapsed = endtimer();
1388 if (elapsed > 60.0 && (us_useroptions&BEEPAFTERLONGJOB) != 0)
1389 ttybeep(SOUNDBEEP, TRUE);
1390 if (errors != 0)
1391 {
1392 switch (errors)
1393 {
1394 case SIZEERRORS:
1395 errortype = N_("Size"); break;
1396 case EXPORTERRORS:
1397 errortype = N_("Export"); break;
1398 case STRUCTUREERRORS:
1399 errortype = N_("Structural"); break;
1400 case SIZEERRORS|EXPORTERRORS:
1401 errortype = N_("Size and Export"); break;
1402 case SIZEERRORS|STRUCTUREERRORS:
1403 errortype = N_("Size and Structural"); break;
1404 case EXPORTERRORS|STRUCTUREERRORS:
1405 errortype = N_("Export and Structural"); break;
1406 case SIZEERRORS|EXPORTERRORS|STRUCTUREERRORS:
1407 errortype = N_("Size, Export and Structural"); break;
1408 default:
1409 errortype = 0;
1410 }
1411 ttyputmsg(_("******* Found %ld %s differences! (%s)"), errorcount,
1412 errortype, explainduration(elapsed));
1413 ret = 1;
1414 } else
1415 {
1416 ttyputmsg(_("Cells %s and %s are equivalent (%s)"), describenodeproto(net_cell[0]),
1417 describenodeproto(net_cell[1]), explainduration(elapsed));
1418 if (subcellsbad)
1419 {
1420 ttyputmsg(_("******* But some subcells are not equivalent"));
1421 } else
1422 {
1423 #ifndef NEWNCC
1424 net_preserveresults(cell1, cell2);
1425 net_preserveresults(cell2, cell1);
1426 #endif
1427 }
1428 ret = subcellsbad ? 1 : 0;
1429 }
1430 termerrorlogging(TRUE);
1431 #ifdef NEWNCC
1432 net_preserveresults(cell1, cell2);
1433 net_preserveresults(cell2, cell1);
1434 #endif
1435 if (ret == 0)
1436 {
1437 cell1->temp1 = (cell1->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDGOOD;
1438 cell2->temp1 = (cell2->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDGOOD;
1439 } else
1440 {
1441 cell1->temp1 = (cell1->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDBAD;
1442 cell2->temp1 = (cell2->temp1 & ~NETNCCCHECKSTATE) | NETNCCCHECKEDBAD;
1443 }
1444 return(ret);
1445 }
1446
1447 /*
1448 * Routine to run the Gemini algorithm to match components/nets "pcomp1/pnet1" with
1449 * components/nets "pcomp2/pnet2". Use "checksize" to check sizes,
1450 * "checkexportnames" to check port names, and "ignorepwrgnd" to ignore power and ground.
1451 * The value of "mergeparallel" indicates whether parallel components are merged.
1452 * The routine returns:
1453 * -1 Hard error (memory allocation, etc.)
1454 * 0 Networks match
1455 * 1 No match, but association quiesced
1456 * 2 No match, and association did not quiesce
1457 */
net_dogemini(PCOMP * pcomp1,PNET * pnet1,PCOMP * pcomp2,PNET * pnet2,BOOLEAN checksize,BOOLEAN checkexportnames,BOOLEAN ignorepwrgnd)1458 INTBIG net_dogemini(PCOMP *pcomp1, PNET *pnet1, PCOMP *pcomp2, PNET *pnet2,
1459 BOOLEAN checksize, BOOLEAN checkexportnames, BOOLEAN ignorepwrgnd)
1460 {
1461 REGISTER SYMGROUP *sgc, *sgn, *sgnz, *sg, *lastsg;
1462 REGISTER PCOMP *pc;
1463 REGISTER PNET *pn;
1464 REGISTER INTBIG i, changesc, changesn, verbose, redeemcount, unmatched,
1465 prevunmatched, prevsymgroupcount, splittype, assigncompfirst, renumber,
1466 changes, reassignnow, pass;
1467 INTBIG unmatchednets, unmatchedcomps, symgroupcount, errors, errorcount;
1468 CHAR prompt[100];
1469 static BOOLEAN toldtohitreturn = FALSE;
1470
1471 #ifdef FORCESUNTOOLS
1472 if ((net_ncc_options&NCCEXPERIMENTAL) != 0)
1473 {
1474 return(net_doexpgemini(pcomp1, pnet1, pcomp2, pnet2,
1475 checksize, checkexportnames, ignorepwrgnd));
1476 }
1477 #endif
1478
1479 verbose = net_ncc_options & (NCCVERBOSETEXT | NCCVERBOSEGRAPHICS);
1480
1481 /* clear old symmetry group list */
1482 while (net_firstsymgroup != NOSYMGROUP)
1483 {
1484 sg = net_firstsymgroup;
1485 net_firstsymgroup = sg->nextsymgroup;
1486 net_freesymgroup(sg);
1487 }
1488 while (net_firstmatchedsymgroup != NOSYMGROUP)
1489 {
1490 sg = net_firstmatchedsymgroup;
1491 net_firstmatchedsymgroup = sg->nextsymgroup;
1492 net_freesymgroup(sg);
1493 }
1494 if (net_symgrouphashcompsize != 0)
1495 {
1496 efree((CHAR *)net_symgrouphashcomp);
1497 efree((CHAR *)net_symgrouphashckcomp);
1498 }
1499 if (net_symgrouphashnetsize != 0)
1500 {
1501 efree((CHAR *)net_symgrouphashnet);
1502 efree((CHAR *)net_symgrouphashcknet);
1503 }
1504 net_uniquehashvalue = -1;
1505 net_symgroupnumber = 1;
1506
1507 /* determine size of hash tables */
1508 net_symgrouphashnetsize = net_symgrouphashcompsize = 0;
1509 for(pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp) net_symgrouphashcompsize++;
1510 for(pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp) net_symgrouphashcompsize++;
1511 if (net_symgrouphashcompsize <= 0) net_symgrouphashcompsize = 2;
1512 for(pn = pnet1; pn != NOPNET; pn = pn->nextpnet) net_symgrouphashnetsize++;
1513 for(pn = pnet2; pn != NOPNET; pn = pn->nextpnet) net_symgrouphashnetsize++;
1514 if (net_symgrouphashnetsize <= 0) net_symgrouphashnetsize = 2;
1515 net_symgrouphashcompsize = pickprime(net_symgrouphashcompsize * 2);
1516 net_symgrouphashnetsize = pickprime(net_symgrouphashnetsize * 2);
1517 net_symgrouphashcomp = (SYMGROUP **)emalloc(net_symgrouphashcompsize * (sizeof (SYMGROUP *)),
1518 net_tool->cluster);
1519 if (net_symgrouphashcomp == 0) return(-1);
1520 net_symgrouphashckcomp = (INTBIG *)emalloc(net_symgrouphashcompsize * SIZEOFINTBIG,
1521 net_tool->cluster);
1522 if (net_symgrouphashckcomp == 0) return(-1);
1523 net_symgrouphashnet = (SYMGROUP **)emalloc(net_symgrouphashnetsize * (sizeof (SYMGROUP *)),
1524 net_tool->cluster);
1525 if (net_symgrouphashnet == 0) return(-1);
1526 net_symgrouphashcknet = (INTBIG *)emalloc(net_symgrouphashnetsize * SIZEOFINTBIG,
1527 net_tool->cluster);
1528 if (net_symgrouphashcknet == 0) return(-1);
1529 for(i=0; i<net_symgrouphashcompsize; i++) net_symgrouphashcomp[i] = NOSYMGROUP;
1530 for(i=0; i<net_symgrouphashnetsize; i++) net_symgrouphashnet[i] = NOSYMGROUP;
1531
1532 /* reset hash explanations */
1533 if (verbose != 0)
1534 {
1535 for(pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
1536 (void)reallocstring(&pc->hashreason, x_("initial"), net_tool->cluster);
1537 for(pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
1538 (void)reallocstring(&pc->hashreason, x_("initial"), net_tool->cluster);
1539 for(pn = pnet1; pn != NOPNET; pn = pn->nextpnet)
1540 (void)reallocstring(&pn->hashreason, x_("initial"), net_tool->cluster);
1541 for(pn = pnet2; pn != NOPNET; pn = pn->nextpnet)
1542 (void)reallocstring(&pn->hashreason, x_("initial"), net_tool->cluster);
1543 }
1544
1545 /* new time stamp for initial entry into symmetry groups */
1546 net_timestamp++;
1547
1548 /* initially assign all components to the same symmetry group (ignore SPICE) */
1549 sgc = net_newsymgroup(SYMGROUPCOMP, 1, 0);
1550 if (sgc == NOSYMGROUP) return(-1);
1551 for(pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
1552 {
1553 pc->hashvalue = sgc->hashvalue;
1554 if (net_addtosymgroup(sgc, 0, (void *)pc)) return(-1);
1555 pc->symgroup = sgc;
1556 }
1557 for(pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
1558 {
1559 pc->hashvalue = sgc->hashvalue;
1560 if (net_addtosymgroup(sgc, 1, (void *)pc)) return(-1);
1561 pc->symgroup = sgc;
1562 }
1563
1564 /* initially assign all nets to the same symmetry group (with ignored pwr/gnd in zero group) */
1565 sgn = net_newsymgroup(SYMGROUPNET, 1, 0);
1566 if (sgn == NOSYMGROUP) return(-1);
1567 sgnz = net_newsymgroup(SYMGROUPNET, 0, 0);
1568 if (sgnz == NOSYMGROUP) return(-1);
1569 for(pn = pnet1; pn != NOPNET; pn = pn->nextpnet)
1570 {
1571 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0)
1572 {
1573 pn->hashvalue = sgnz->hashvalue;
1574 if (net_addtosymgroup(sgnz, 0, (void *)pn)) return(-1);
1575 pn->symgroup = sgnz;
1576 } else
1577 {
1578 pn->hashvalue = sgn->hashvalue;
1579 if (net_addtosymgroup(sgn, 0, (void *)pn)) return(-1);
1580 pn->symgroup = sgn;
1581 }
1582 }
1583 for(pn = pnet2; pn != NOPNET; pn = pn->nextpnet)
1584 {
1585 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0)
1586 {
1587 pn->hashvalue = sgnz->hashvalue;
1588 if (net_addtosymgroup(sgnz, 0, (void *)pn)) return(-1);
1589 pn->symgroup = sgnz;
1590 } else
1591 {
1592 pn->hashvalue = sgn->hashvalue;
1593 if (net_addtosymgroup(sgn, 1, (void *)pn)) return(-1);
1594 pn->symgroup = sgn;
1595 }
1596 }
1597
1598 /* determine the true wirecount (considering ignored power and ground) */
1599 for(pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
1600 {
1601 pc->truewirecount = pc->wirecount;
1602 for(i=0; i<pc->wirecount; i++)
1603 if (pc->netnumbers[i]->hashvalue == 0) pc->truewirecount--;
1604 }
1605 for(pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
1606 {
1607 pc->truewirecount = pc->wirecount;
1608 for(i=0; i<pc->wirecount; i++)
1609 if (pc->netnumbers[i]->hashvalue == 0) pc->truewirecount--;
1610 }
1611
1612 /* now iteratively refine the symmetry groups */
1613 net_unmatchedstatus(&unmatchednets, &unmatchedcomps, &symgroupcount);
1614 prevsymgroupcount = symgroupcount;
1615 prevunmatched = unmatchednets + unmatchedcomps;
1616 redeemcount = 1;
1617 assigncompfirst = 1;
1618 changesc = changesn = 0;
1619 pass = 0;
1620 for(i=0; i<MAXITERATIONS; i++)
1621 {
1622 if (stopping(STOPREASONNCC)) break;
1623
1624 /* new time stamp for entry into symmetry groups */
1625 net_timestamp++;
1626 changes = 0;
1627 for(renumber=0; renumber<2; renumber++)
1628 {
1629 if ((renumber == 0 && assigncompfirst != 0) ||
1630 (renumber == 1 && assigncompfirst == 0))
1631 {
1632 /* assign new hash values to components */
1633 if ((verbose&NCCVERBOSETEXT) != 0)
1634 ttyputmsg(x_("***Computing component codes from networks:"));
1635 changes = changesc = net_assignnewhashvalues(reassignnow = SYMGROUPCOMP);
1636 if (changesc < 0) break;
1637 } else
1638 {
1639 /* assign new hash values to nets */
1640 if ((verbose&NCCVERBOSETEXT) != 0)
1641 ttyputmsg(x_("***Computing network codes from components:"));
1642 changes = changesn = net_assignnewhashvalues(reassignnow = SYMGROUPNET);
1643 if (changesn < 0) break;
1644 }
1645
1646 /* show the state of the world if requested */
1647 if (verbose != 0)
1648 {
1649 net_showsymmetrygroups(verbose, reassignnow);
1650 esnprintf(prompt, 100, x_("%ld changed, %ld symmetry groups:"), changes, symgroupcount);
1651 if (!toldtohitreturn)
1652 {
1653 estrcat(prompt, x_(" (hit return to continue) "));
1654 toldtohitreturn = TRUE;
1655 }
1656 (void)asktool(us_tool, x_("flush-changes"));
1657 if (*ttygetlinemessages(prompt) != 0) break;
1658 }
1659
1660 /* pull out matched objects */
1661 net_cleanupsymmetrygroups();
1662
1663 /* every 3rd time, randomize hash codes */
1664 if (((pass++) % 3) == 0)
1665 net_randomizehashcodes(verbose);
1666 }
1667 if (changes < 0) break;
1668
1669 /* if things are still improving, keep on */
1670 net_unmatchedstatus(&unmatchednets, &unmatchedcomps, &symgroupcount);
1671 unmatched = unmatchednets + unmatchedcomps;
1672 if (unmatched == 0) break;
1673 if (unmatched < prevunmatched)
1674 {
1675 prevunmatched = unmatched;
1676 i--;
1677 prevsymgroupcount = symgroupcount;
1678 continue;
1679 }
1680
1681 /* if nothing changed or about to stop the loop, look for ambiguity */
1682 if (changesc + changesn == 0 || symgroupcount == prevsymgroupcount || i == MAXITERATIONS-1)
1683 {
1684 /* new time stamp for entry into symmetry groups */
1685 net_timestamp++;
1686
1687 /* see if some incremental match can be applied */
1688 splittype = net_findamatch(verbose, ignorepwrgnd);
1689 if (splittype != 0)
1690 {
1691 if (splittype > 0)
1692 {
1693 /* if just split a component group, reassign networks first */
1694 assigncompfirst = 0;
1695 } else
1696 {
1697 /* if just split a network group, reassign components first */
1698 assigncompfirst = 1;
1699 }
1700 i = 0;
1701 prevsymgroupcount = symgroupcount;
1702 continue;
1703 }
1704 break;
1705 }
1706 prevsymgroupcount = symgroupcount;
1707 }
1708
1709 /* put matched symmetry groups back into the main list (place it at the end) */
1710 lastsg = NOSYMGROUP;
1711 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
1712 lastsg = sg;
1713 if (lastsg == NOSYMGROUP) net_firstsymgroup = net_firstmatchedsymgroup; else
1714 lastsg->nextsymgroup = net_firstmatchedsymgroup;
1715 net_firstmatchedsymgroup = NOSYMGROUP;
1716
1717 /* see if errors were found */
1718 errors = net_analyzesymmetrygroups(FALSE, checksize, checkexportnames, ignorepwrgnd, &errorcount);
1719 if (errors == 0) return(0);
1720 if (changesc + changesn != 0) return(2);
1721 return(1);
1722 }
1723
1724 /*
1725 * Routine to clean up the symmetry groups by deleting those with nothing in them
1726 * and pulling matched ones out of consideration.
1727 */
net_cleanupsymmetrygroups(void)1728 void net_cleanupsymmetrygroups(void)
1729 {
1730 REGISTER SYMGROUP *sg, *lastsg, *nextsg;
1731
1732 lastsg = NOSYMGROUP;
1733 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = nextsg)
1734 {
1735 nextsg = sg->nextsymgroup;
1736
1737 /* delete empty groups */
1738 if (sg->cellcount[0] == 0 && sg->cellcount[1] == 0)
1739 {
1740 if (lastsg == NOSYMGROUP) net_firstsymgroup = sg->nextsymgroup; else
1741 lastsg->nextsymgroup = sg->nextsymgroup;
1742 net_freesymgroup(sg);
1743 continue;
1744 }
1745
1746 /* pull matched groups into separate list */
1747 if (sg->cellcount[0] == 1 && sg->cellcount[1] == 1)
1748 {
1749 if (lastsg == NOSYMGROUP) net_firstsymgroup = sg->nextsymgroup; else
1750 lastsg->nextsymgroup = sg->nextsymgroup;
1751 sg->nextsymgroup = net_firstmatchedsymgroup;
1752 net_firstmatchedsymgroup = sg;
1753 if ((net_ncc_options&NCCGRAPHICPROGRESS) != 0)
1754 net_showmatchedgroup(sg);
1755 continue;
1756 }
1757 lastsg = sg;
1758 }
1759 }
1760
1761 #define RANDOMIZEBYMULTIPLYING 1
1762
net_randomizehashcodes(INTBIG verbose)1763 void net_randomizehashcodes(INTBIG verbose)
1764 {
1765 #ifdef RANDOMIZEBYMULTIPLYING
1766 REGISTER SYMGROUP *sg;
1767 REGISTER INTBIG index, factor;
1768
1769 if ((verbose&NCCVERBOSETEXT) != 0)
1770 ttyputmsg(x_("***Renumbering hash codes:"));
1771 index = 0;
1772 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
1773 {
1774 factor = getprime(index++);
1775 net_randomizesymgroup(sg, verbose, factor);
1776 }
1777 for(sg = net_firstmatchedsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
1778 {
1779 factor = getprime(index++);
1780 net_randomizesymgroup(sg, verbose, factor);
1781 }
1782 #else
1783 REGISTER SYMGROUP *sg;
1784
1785 if ((verbose&NCCVERBOSETEXT) != 0)
1786 ttyputmsg(x_("***Renumbering hash codes:"));
1787 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
1788 net_randomizesymgroup(sg, verbose, 0);
1789 for(sg = net_firstmatchedsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
1790 net_randomizesymgroup(sg, verbose, 0);
1791 #endif
1792 net_rebuildhashtable();
1793 }
1794
net_randomizesymgroup(SYMGROUP * sg,INTBIG verbose,INTBIG factor)1795 void net_randomizesymgroup(SYMGROUP *sg, INTBIG verbose, INTBIG factor)
1796 {
1797 REGISTER INTBIG f, j;
1798 REGISTER PCOMP *pc;
1799 REGISTER PNET *pn;
1800 REGISTER NODEINST *ni;
1801 REGISTER NETWORK *net;
1802
1803 if (sg->hashvalue != 0)
1804 {
1805 #ifdef RANDOMIZEBYMULTIPLYING
1806 sg->hashvalue *= factor;
1807 #else
1808 sg->hashvalue = (HASHTYPE)rand();
1809 sg->hashvalue = (sg->hashvalue << 16) | (HASHTYPE)rand();
1810 sg->hashvalue = (sg->hashvalue << 16) | (HASHTYPE)rand();
1811 sg->hashvalue = (sg->hashvalue << 16) | (HASHTYPE)rand();
1812 #endif
1813 if (sg->grouptype == SYMGROUPCOMP)
1814 {
1815 for(f=0; f<2; f++)
1816 {
1817 for(j=0; j<sg->cellcount[f]; j++)
1818 {
1819 pc = (PCOMP *)sg->celllist[f][j];
1820 pc->hashvalue = sg->hashvalue;
1821 if ((verbose&NCCVERBOSETEXT) != 0)
1822 {
1823 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
1824 ni = ((NODEINST **)pc->actuallist)[0];
1825 if (sg->groupindex != 0)
1826 {
1827 ttyputmsg(x_(" COMPONENT %s: now %s (hash #%ld)"), describenodeinst(ni),
1828 hugeinttoa(sg->hashvalue), sg->groupindex);
1829 } else
1830 {
1831 ttyputmsg(x_(" COMPONENT %s: now %s (hash)"), describenodeinst(ni),
1832 hugeinttoa(sg->hashvalue));
1833 }
1834 }
1835 }
1836 }
1837 } else
1838 {
1839 for(f=0; f<2; f++)
1840 {
1841 for(j=0; j<sg->cellcount[f]; j++)
1842 {
1843 pn = (PNET *)sg->celllist[f][j];
1844 pn->hashvalue = sg->hashvalue;
1845 if ((verbose&NCCVERBOSETEXT) != 0)
1846 {
1847 net = pn->network;
1848 if (net != NONETWORK)
1849 {
1850 if (sg->groupindex != 0)
1851 {
1852 ttyputmsg(x_(" NETWORK %s:%s: now %s (hash #%ld)"), describenodeproto(net->parent),
1853 net_describepnet(pn), hugeinttoa(sg->hashvalue), sg->groupindex);
1854 } else
1855 {
1856 ttyputmsg(x_(" NETWORK %s:%s: now %s (hash)"), describenodeproto(net->parent),
1857 net_describepnet(pn), hugeinttoa(sg->hashvalue));
1858 }
1859 }
1860 }
1861 }
1862 }
1863 }
1864 }
1865 }
1866
1867 /*
1868 * Routine to assign new hash values to the components or nets (depending on the
1869 * value of "grouptype") in all symmetry groups. Returns the number of changes
1870 * that were made (negative on error).
1871 */
net_assignnewhashvalues(INTBIG grouptype)1872 INTBIG net_assignnewhashvalues(INTBIG grouptype)
1873 {
1874 REGISTER SYMGROUP *sg;
1875 REGISTER INTBIG changes, verbose;
1876 REGISTER INTBIG f, i, j, change, activemask;
1877 REGISTER BOOLEAN matched, focusonactivegroups;
1878 REGISTER SYMGROUP *lastsg, *nextsg;
1879 REGISTER PCOMP *pc;
1880 REGISTER PNET *pn;
1881
1882 /* pickup options */
1883 net_debuggeminipasscount++;
1884 verbose = net_ncc_options & (NCCVERBOSETEXT | NCCVERBOSEGRAPHICS);
1885 activemask = 0;
1886 if ((net_ncc_options & (NCCENAFOCSYMGRPFRE|NCCENAFOCSYMGRPPRO)) != 0)
1887 {
1888 if ((net_ncc_options&NCCENAFOCSYMGRPFRE) != 0) activemask |= GROUPFRESH;
1889 if ((net_ncc_options&NCCENAFOCSYMGRPPRO) != 0) activemask |= GROUPPROMISING;
1890 focusonactivegroups = TRUE;
1891 } else focusonactivegroups = FALSE;
1892
1893 /* setup for spreading active groups */
1894 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
1895 sg->groupflags &= ~activemask;
1896
1897 changes = 0;
1898 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
1899 {
1900 if (sg->hashvalue == 0) continue;
1901 if (sg->grouptype != grouptype) continue;
1902 net_debuggeminitotalgroups++;
1903 if (focusonactivegroups)
1904 {
1905 if ((sg->groupflags&GROUPACTIVENOW) == 0) continue;
1906 }
1907 net_debuggeminitotalgroupsact++;
1908 net_debuggeminigroupsrenumbered++;
1909 change = net_assignnewgrouphashvalues(sg, verbose);
1910 if (change != 0) net_debuggeminigroupssplit++;
1911 changes += change;
1912 }
1913
1914 if (changes == 0 && focusonactivegroups)
1915 {
1916 /* no changes found while examining the focus group: expand to the entire list */
1917 net_debuggeminiexpandglobal++;
1918 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
1919 {
1920 if (sg->hashvalue == 0) continue;
1921 if (sg->grouptype != grouptype) continue;
1922 if ((sg->groupflags&GROUPACTIVENOW) != 0) continue;
1923 net_debuggeminigroupsrenumbered++;
1924 change = net_assignnewgrouphashvalues(sg, verbose);
1925 if (change != 0) net_debuggeminigroupssplit++;
1926 changes += change;
1927 }
1928 if (changes != 0) net_debuggeminiexpandglobalworked++;
1929 }
1930
1931 /* propagate active groups */
1932 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
1933 {
1934 if (sg->grouptype != grouptype)
1935 {
1936 if ((sg->groupflags&activemask) != 0)
1937 sg->groupflags |= GROUPACTIVENOW;
1938 } else
1939 {
1940 if ((sg->groupflags&activemask) != 0)
1941 sg->groupflags |= GROUPACTIVENOW; else
1942 sg->groupflags &= ~GROUPACTIVENOW;
1943 }
1944 }
1945
1946 /* see if local processing after a match is requested */
1947 if ((net_ncc_options&NCCDISLOCAFTERMATCH) != 0) return(changes);
1948
1949 /* now look for newly created matches and keep working from there */
1950 for(;;)
1951 {
1952 /* clear all flags of locality */
1953 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
1954 {
1955 switch (sg->grouptype)
1956 {
1957 case SYMGROUPCOMP:
1958 for(f=0; f<2; f++)
1959 {
1960 for(i=0; i<sg->cellcount[f]; i++)
1961 {
1962 pc = (PCOMP *)sg->celllist[f][i];
1963 pc->flags &= ~COMPLOCALFLAG;
1964 }
1965 }
1966 break;
1967 case SYMGROUPNET:
1968 for(f=0; f<2; f++)
1969 {
1970 for(i=0; i<sg->cellcount[f]; i++)
1971 {
1972 pn = (PNET *)sg->celllist[f][i];
1973 pn->flags &= ~NETLOCALFLAG;
1974 }
1975 }
1976 break;
1977 }
1978 }
1979
1980 /* mark local flags and remove match groups */
1981 matched = FALSE;
1982 lastsg = NOSYMGROUP;
1983 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = nextsg)
1984 {
1985 nextsg = sg->nextsymgroup;
1986 if (sg->hashvalue != 0)
1987 {
1988 if (sg->cellcount[0] == 1 && sg->cellcount[1] == 1)
1989 {
1990 switch (sg->grouptype)
1991 {
1992 case SYMGROUPCOMP:
1993 /* mark all related nets for local reevaluation */
1994 for(f=0; f<2; f++)
1995 {
1996 pc = (PCOMP *)sg->celllist[f][0];
1997 for(j=0; j<pc->wirecount; j++)
1998 {
1999 pn = pc->netnumbers[j];
2000 pn->flags |= NETLOCALFLAG;
2001 }
2002 }
2003 break;
2004 case SYMGROUPNET:
2005 /* mark all related components for local reevaluation */
2006 for(f=0; f<2; f++)
2007 {
2008 pn = (PNET *)sg->celllist[f][0];
2009 for(j=0; j<pn->nodecount; j++)
2010 {
2011 pc = pn->nodelist[j];
2012 pc->flags |= COMPLOCALFLAG;
2013 }
2014 }
2015 break;
2016 }
2017
2018 /* pull the matched groups into separate list */
2019 if (lastsg == NOSYMGROUP) net_firstsymgroup = sg->nextsymgroup; else
2020 lastsg->nextsymgroup = sg->nextsymgroup;
2021 sg->nextsymgroup = net_firstmatchedsymgroup;
2022 net_firstmatchedsymgroup = sg;
2023 matched = TRUE;
2024 continue;
2025 }
2026 }
2027 lastsg = sg;
2028 }
2029
2030 /* if there are no new matches, stop now */
2031 if (!matched) break;
2032
2033 /* search for groups that need to be reevaluated */
2034 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
2035 {
2036 if (sg->hashvalue == 0) continue;
2037 switch (sg->grouptype)
2038 {
2039 case SYMGROUPCOMP:
2040 /* see if this group is marked as local */
2041 for(f=0; f<2; f++)
2042 {
2043 for(i=0; i<sg->cellcount[f]; i++)
2044 {
2045 pc = (PCOMP *)sg->celllist[f][i];
2046 if ((pc->flags&COMPLOCALFLAG) != 0) break;
2047 }
2048 if (i < sg->cellcount[f]) break;
2049 }
2050 if (f >= 2) break;
2051
2052 /* reevaluate this group */
2053 change = net_assignnewgrouphashvalues(sg, verbose);
2054 changes += change;
2055 break;
2056 case SYMGROUPNET:
2057 /* mark all related components for local reevaluation */
2058 for(f=0; f<2; f++)
2059 {
2060 for(i=0; i<sg->cellcount[f]; i++)
2061 {
2062 pn = (PNET *)sg->celllist[f][i];
2063 if ((pn->flags&NETLOCALFLAG) != 0) break;
2064 }
2065 if (i < sg->cellcount[f]) break;
2066 }
2067 if (f >= 2) break;
2068
2069 /* reevaluate this group */
2070 change = net_assignnewgrouphashvalues(sg, verbose);
2071 changes += change;
2072 break;
2073 }
2074 }
2075 }
2076 return(changes);
2077 }
2078
net_assignnewgrouphashvalues(SYMGROUP * sg,INTBIG verbose)2079 INTBIG net_assignnewgrouphashvalues(SYMGROUP *sg, INTBIG verbose)
2080 {
2081 REGISTER INTBIG f, i, j;
2082 REGISTER PCOMP *pc;
2083 REGISTER PNET *pn;
2084 REGISTER SYMGROUP *osg, *newgroup;
2085 REGISTER BOOLEAN groupsplits;
2086
2087 switch (sg->grouptype)
2088 {
2089 case SYMGROUPCOMP:
2090 for(f=0; f<2; f++)
2091 {
2092 for(i=0; i<sg->cellcount[f]; i++)
2093 {
2094 pc = (PCOMP *)sg->celllist[f][i];
2095
2096 /* if the group is properly matched, don't change its hash value */
2097 if (sg->cellcount[0] == 1 && sg->cellcount[1] == 1)
2098 {
2099 if (verbose != 0)
2100 (void)reallocstring(&pc->hashreason, x_("matched"), net_tool->cluster);
2101 continue;
2102 }
2103
2104 /* if the group is a singleton, set a zero hash value */
2105 if (sg->cellcount[0] <= 0 || sg->cellcount[1] <= 0)
2106 {
2107 if (verbose != 0)
2108 (void)reallocstring(&pc->hashreason, x_("unmatched"), net_tool->cluster);
2109 pc->hashvalue = 0;
2110 } else
2111 {
2112 /* compute a new hash value for the component */
2113 pc->hashvalue = net_getcomphash(pc, verbose);
2114 }
2115 }
2116 }
2117 newgroup = NOSYMGROUP;
2118 groupsplits = FALSE;
2119 for(f=0; f<2; f++)
2120 {
2121 for(i=0; i<sg->cellcount[f]; i++)
2122 {
2123 pc = (PCOMP *)sg->celllist[f][i];
2124 if (pc->hashvalue != sg->hashvalue)
2125 {
2126 /* reassign this component to a different symmetry group */
2127 osg = net_findsymmetrygroup(SYMGROUPCOMP, pc->hashvalue, pc->truewirecount);
2128 if (osg == NOSYMGROUP)
2129 {
2130 osg = net_newsymgroup(SYMGROUPCOMP, pc->hashvalue, pc->truewirecount);
2131 if (osg == NOSYMGROUP) return(-1);
2132 }
2133 net_removefromsymgroup(sg, f, i);
2134 i--;
2135 if (net_addtosymgroup(osg, f, (void *)pc)) return(-1);
2136 pc->symgroup = osg;
2137 if (groupsplits) osg->groupflags |= GROUPFRESH; else
2138 {
2139 if (newgroup == NOSYMGROUP) newgroup = osg; else
2140 {
2141 if (newgroup != osg)
2142 {
2143 groupsplits = TRUE;
2144 newgroup->groupflags |= GROUPFRESH;
2145 osg->groupflags |= GROUPFRESH;
2146 }
2147 }
2148 }
2149 } else
2150 {
2151 if (groupsplits) sg->groupflags |= GROUPFRESH; else
2152 {
2153 if (newgroup == NOSYMGROUP) newgroup = sg; else
2154 {
2155 if (newgroup != sg)
2156 {
2157 groupsplits = TRUE;
2158 newgroup->groupflags |= GROUPFRESH;
2159 sg->groupflags |= GROUPFRESH;
2160 }
2161 }
2162 }
2163 }
2164 }
2165 }
2166
2167 /* propagate promising groups */
2168 if (groupsplits && (net_ncc_options&NCCENAFOCSYMGRPPRO) != 0)
2169 {
2170 /* this group split into others: propagate this information for localism */
2171 for(f=0; f<2; f++)
2172 {
2173 for(i=0; i<sg->cellcount[f]; i++)
2174 {
2175 pc = (PCOMP *)sg->celllist[f][i];
2176 for(j=0; j<pc->wirecount; j++)
2177 {
2178 pn = pc->netnumbers[j];
2179 ((SYMGROUP *)pn->symgroup)->groupflags |= GROUPPROMISING;
2180 }
2181 }
2182 }
2183 }
2184 break;
2185
2186 case SYMGROUPNET:
2187 for(f=0; f<2; f++)
2188 {
2189 for(i=0; i<sg->cellcount[f]; i++)
2190 {
2191 pn = (PNET *)sg->celllist[f][i];
2192
2193 /* if the group is properly matched, don't change its hash value */
2194 if (sg->cellcount[0] == 1 && sg->cellcount[1] == 1)
2195 {
2196 if (verbose != 0)
2197 (void)reallocstring(&pn->hashreason, x_("matched"), net_tool->cluster);
2198 continue;
2199 }
2200
2201 /* if the group is a singleton, set a zero hash value */
2202 if (sg->cellcount[0] <= 0 || sg->cellcount[1] <= 0)
2203 {
2204 pn->hashvalue = 0;
2205 if (verbose != 0)
2206 (void)reallocstring(&pn->hashreason, x_("unmatched"), net_tool->cluster);
2207 } else
2208 {
2209 /* compute a new hash value for the net */
2210 pn->hashvalue = net_getnethash(pn, verbose);
2211 }
2212 }
2213 }
2214 newgroup = NOSYMGROUP;
2215 groupsplits = FALSE;
2216 for(f=0; f<2; f++)
2217 {
2218 for(i=0; i<sg->cellcount[f]; i++)
2219 {
2220 pn = (PNET *)sg->celllist[f][i];
2221 if (pn->hashvalue != sg->hashvalue)
2222 {
2223 /* reassign this component to a different symmetry group */
2224 osg = net_findsymmetrygroup(SYMGROUPNET, pn->hashvalue, pn->nodecount);
2225 if (osg == NOSYMGROUP)
2226 {
2227 osg = net_newsymgroup(SYMGROUPNET, pn->hashvalue, pn->nodecount);
2228 if (osg == NOSYMGROUP) return(-1);
2229 }
2230 net_removefromsymgroup(sg, f, i);
2231 i--;
2232 if (net_addtosymgroup(osg, f, (void *)pn)) return(-1);
2233 pn->symgroup = osg;
2234 if (groupsplits) osg->groupflags |= GROUPFRESH; else
2235 {
2236 if (newgroup == NOSYMGROUP) newgroup = osg; else
2237 {
2238 if (newgroup != osg)
2239 {
2240 groupsplits = TRUE;
2241 newgroup->groupflags |= GROUPFRESH;
2242 osg->groupflags |= GROUPFRESH;
2243 }
2244 }
2245 }
2246 } else
2247 {
2248 if (groupsplits) sg->groupflags |= GROUPFRESH; else
2249 {
2250 if (newgroup == NOSYMGROUP) newgroup = sg; else
2251 {
2252 if (newgroup != sg)
2253 {
2254 groupsplits = TRUE;
2255 newgroup->groupflags |= GROUPFRESH;
2256 sg->groupflags |= GROUPFRESH;
2257 }
2258 }
2259 }
2260 }
2261 }
2262 }
2263
2264 if (groupsplits && (net_ncc_options&NCCENAFOCSYMGRPPRO) != 0)
2265 {
2266 /* this group split into others: propagate this information for localism */
2267 for(f=0; f<2; f++)
2268 {
2269 for(i=0; i<sg->cellcount[f]; i++)
2270 {
2271 pn = (PNET *)sg->celllist[f][i];
2272 for(j=0; j<pn->nodecount; j++)
2273 {
2274 pc = pn->nodelist[j];
2275 ((SYMGROUP *)pc->symgroup)->groupflags |= GROUPPROMISING;
2276 }
2277 }
2278 }
2279 }
2280 break;
2281 }
2282 if (groupsplits) return(1);
2283 return(0);
2284 }
2285
2286 /*
2287 * Routine to fill out the "nodecount/nodelist/nodewire" fields of the PNET
2288 * list in "pnetlist", given that it points to "pcomplist". Returns true on error.
2289 */
net_initializeverbose(PCOMP * pcomplist,PNET * pnetlist)2290 void net_initializeverbose(PCOMP *pcomplist, PNET *pnetlist)
2291 {
2292 REGISTER PNET *pn;
2293 REGISTER PCOMP *pc;
2294
2295 for(pn = pnetlist; pn != NOPNET; pn = pn->nextpnet)
2296 {
2297 (void)allocstring(&pn->hashreason, x_("initial"), net_tool->cluster);
2298 }
2299
2300 for(pc = pcomplist; pc != NOPCOMP; pc = pc->nextpcomp)
2301 {
2302 (void)allocstring(&pc->hashreason, x_("initial"), net_tool->cluster);
2303 }
2304 }
2305
2306 /*
2307 * Routine to examine the unexpanded cell instances in lists "pcomp1" and "pcomp2"
2308 * and make sure there are matching numbers of each type.
2309 * Adds error messages to the string array "errorsa" if any problems are found.
2310 */
net_checkcomponenttypes(void * errorsa,BOOLEAN ignorepwrgnd,PCOMP * pcomp1,PCOMP * pcomp2,PNET * pnetlist1,PNET * pnetlist2,NODEPROTO * cell1,NODEPROTO * cell2)2311 void net_checkcomponenttypes(void *errorsa, BOOLEAN ignorepwrgnd, PCOMP *pcomp1, PCOMP *pcomp2,
2312 PNET *pnetlist1, PNET *pnetlist2, NODEPROTO *cell1, NODEPROTO *cell2)
2313 {
2314 REGISTER INTBIG cells1, cells2, cellnum, i, j, l, portcount1, portcount2, start;
2315 REGISTER NODEPROTO *thecell;
2316 REGISTER BOOLEAN found;
2317 REGISTER PCOMP **celllist1, **celllist2, *pc1, *pc2;
2318 REGISTER PNET *pn;
2319 REGISTER NODEINST *ni1, *ni2;
2320 REGISTER CHAR *pt;
2321 REGISTER void *infstr;
2322
2323 /* first count the number of cell instances that are primitives in each cell */
2324 cells1 = 0;
2325 for(pc1 = pcomp1; pc1 != NOPCOMP; pc1 = pc1->nextpcomp)
2326 {
2327 if (pc1->numactual == 1) ni1 = (NODEINST *)pc1->actuallist; else
2328 ni1 = ((NODEINST **)pc1->actuallist)[0];
2329 if (ni1->proto->primindex == 0 && pc1->function == NPUNKNOWN) cells1++;
2330 }
2331 cells2 = 0;
2332 for(pc2 = pcomp2; pc2 != NOPCOMP; pc2 = pc2->nextpcomp)
2333 {
2334 if (pc2->numactual == 1) ni2 = (NODEINST *)pc2->actuallist; else
2335 ni2 = ((NODEINST **)pc2->actuallist)[0];
2336 if (ni2->proto->primindex == 0 && pc2->function == NPUNKNOWN) cells2++;
2337 }
2338
2339 /* if they are different, report that error */
2340 if (cells1 != cells2)
2341 {
2342 infstr = initinfstr();
2343 formatinfstr(infstr, _("Cell %s has %ld instances but cell %s has %ld instances"),
2344 describenodeproto(cell1), cells1, describenodeproto(cell2), cells2);
2345 addtostringarray(errorsa, returninfstr(infstr));
2346 return;
2347 }
2348
2349 /* if there are no cells on either side, stop now */
2350 if (cells1 == 0) return;
2351
2352 /* make a list of each cell's "function" number */
2353 celllist1 = (PCOMP **)emalloc(cells1 * (sizeof (PCOMP *)), net_tool->cluster);
2354 if (celllist1 == 0) return;
2355 celllist2 = (PCOMP **)emalloc(cells2 * (sizeof (PCOMP *)), net_tool->cluster);
2356 if (celllist2 == 0) return;
2357 cells1 = 0;
2358 for(pc1 = pcomp1; pc1 != NOPCOMP; pc1 = pc1->nextpcomp)
2359 {
2360 if (pc1->numactual == 1) ni1 = (NODEINST *)pc1->actuallist; else
2361 ni1 = ((NODEINST **)pc1->actuallist)[0];
2362 if (ni1->proto->primindex != 0) continue;
2363 celllist1[cells1++] = pc1;
2364 portcount1 = 0;
2365 for(l=0; l<pc1->wirecount; l++)
2366 {
2367 pn = pc1->netnumbers[l];
2368 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0) continue;
2369 portcount1++;
2370 }
2371 pc1->truewirecount = (INTSML)portcount1;
2372 }
2373 cells2 = 0;
2374 for(pc2 = pcomp2; pc2 != NOPCOMP; pc2 = pc2->nextpcomp)
2375 {
2376 if (pc2->numactual == 1) ni2 = (NODEINST *)pc2->actuallist; else
2377 ni2 = ((NODEINST **)pc2->actuallist)[0];
2378 if (ni2->proto->primindex != 0) continue;
2379 celllist2[cells2++] = pc2;
2380 portcount2 = 0;
2381 for(l=0; l<pc2->wirecount; l++)
2382 {
2383 pn = pc2->netnumbers[l];
2384 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0) continue;
2385 portcount2++;
2386 }
2387 pc2->truewirecount = (INTSML)portcount2;
2388 }
2389 esort(celllist1, cells1, sizeof (PCOMP *), net_sortbycelltype);
2390 esort(celllist2, cells2, sizeof (PCOMP *), net_sortbycelltype);
2391
2392 /* see if the functions are the same */
2393 for(i=0; i<cells1; i++)
2394 {
2395 pc1 = celllist1[i];
2396 pc2 = celllist2[i];
2397 if (pc1->numactual == 1) ni1 = (NODEINST *)pc1->actuallist; else
2398 ni1 = ((NODEINST **)pc1->actuallist)[0];
2399 if (pc2->numactual == 1) ni2 = (NODEINST *)pc2->actuallist; else
2400 ni2 = ((NODEINST **)pc2->actuallist)[0];
2401 if ((ni1->proto->temp1&NETCELLCODE) != (ni2->proto->temp1&NETCELLCODE)) break;
2402 }
2403 if (i >= cells1)
2404 {
2405 /* cell functions are the same: make sure the exports match */
2406 for(i=0; i<cells1; i++)
2407 {
2408 start = i;
2409 pc1 = celllist1[i];
2410 if (pc1->numactual == 1) ni1 = (NODEINST *)pc1->actuallist; else
2411 ni1 = ((NODEINST **)pc1->actuallist)[0];
2412 thecell = ni1->proto;
2413 cellnum = thecell->temp1 & NETCELLCODE;
2414
2415 /* determine the end of the block of cells with the same instance number */
2416 while (i < cells1-1)
2417 {
2418 pc1 = celllist1[i+1];
2419 if (pc1->numactual == 1) ni1 = (NODEINST *)pc1->actuallist; else
2420 ni1 = ((NODEINST **)pc1->actuallist)[0];
2421 if (cellnum != (ni1->proto->temp1 & NETCELLCODE)) break;
2422 i++;
2423 }
2424
2425 /* make sure the prototype exports match */
2426 {
2427 NETWORK **list1, **list2;
2428 INTBIG size1, size2, pos1, pos2;
2429
2430 pc1 = celllist1[start];
2431 if (pc1->numactual == 1) ni1 = (NODEINST *)pc1->actuallist; else
2432 ni1 = ((NODEINST **)pc1->actuallist)[0];
2433 pc2 = celllist2[start];
2434 if (pc2->numactual == 1) ni2 = (NODEINST *)pc2->actuallist; else
2435 ni2 = ((NODEINST **)pc2->actuallist)[0];
2436 list1 = net_makeexternalnetlist(ni1, &size1, ignorepwrgnd);
2437 list2 = net_makeexternalnetlist(ni2, &size2, ignorepwrgnd);
2438 if (size1 > 0) esort(list1, size1, sizeof (NETWORK *), net_sortexportcodes);
2439 if (size2 > 0) esort(list2, size2, sizeof (NETWORK *), net_sortexportcodes);
2440 pos1 = pos2 = 0;
2441 while (pos1 < size1 || pos2 < size2)
2442 {
2443 if (pos1 < size1 && pos2 < size2 && list1[pos1]->temp2 == list2[pos2]->temp2)
2444 {
2445 pos1++; pos2++;
2446 while (pos1 < size1 && list1[pos1]->temp2 == list1[pos1-1]->temp2)
2447 pos1++;
2448 while (pos2 < size2 && list2[pos2]->temp2 == list2[pos2-1]->temp2)
2449 pos2++;
2450 continue;
2451 }
2452 if (pos2 >= size2 ||
2453 (pos1 < size1 && list1[pos1]->temp2 < list2[pos2]->temp2))
2454 {
2455 /* report or fix missing connection */
2456 net_foundmismatch(list1[pos1]->parent, list1[pos1], ni2->proto, celllist2, start, i,
2457 pnetlist2, ignorepwrgnd, errorsa);
2458 pos1++;
2459 while (pos1 < size1 && list1[pos1]->temp2 == list1[pos1-1]->temp2)
2460 pos1++;
2461 } else if (pos1 >= size1 ||
2462 (pos2 < size2 && list2[pos2]->temp2 < list1[pos1]->temp2))
2463 {
2464 /* report or fix missing connection */
2465 net_foundmismatch(list2[pos2]->parent, list2[pos2], ni1->proto, celllist1, start, i,
2466 pnetlist1, ignorepwrgnd, errorsa);
2467 pos2++;
2468 while (pos2 < size2 && list2[pos2]->temp2 == list2[pos2-1]->temp2)
2469 pos2++;
2470 }
2471 }
2472 if (size1 > 0) efree((CHAR *)list1);
2473 if (size2 > 0) efree((CHAR *)list2);
2474 }
2475
2476 /* check all cells for export similarity */
2477 for(j=start; j<=i; j++)
2478 {
2479 pc1 = celllist1[j];
2480 if (pc1->numactual == 1) ni1 = (NODEINST *)pc1->actuallist; else
2481 ni1 = ((NODEINST **)pc1->actuallist)[0];
2482
2483 pc2 = celllist2[j];
2484 if (pc2->numactual == 1) ni2 = (NODEINST *)pc2->actuallist; else
2485 ni2 = ((NODEINST **)pc2->actuallist)[0];
2486 if (ni1->proto == ni2->proto) continue;
2487
2488 /* make sure the export count matches */
2489 if (pc1->truewirecount != pc2->truewirecount)
2490 {
2491 infstr = initinfstr();
2492 formatinfstr(infstr, _("Instance %s has %ld wires in cell %s but has %ld wires in cell %s"),
2493 ni1->proto->protoname, pc1->truewirecount, describenodeproto(cell1),
2494 pc2->truewirecount, describenodeproto(cell2));
2495 addtostringarray(errorsa, returninfstr(infstr));
2496 }
2497 }
2498 }
2499 } else
2500 {
2501 /* cell functions are different: report the differences */
2502 infstr = initinfstr();
2503 formatinfstr(infstr, _("These instances exist only in cell %s:"),
2504 describenodeproto(cell1));
2505 found = FALSE;
2506 for(i=0; i<cells1; i++)
2507 {
2508 /* get the index of the next cell instance in the list */
2509 pc1 = celllist1[i];
2510 if (pc1->numactual == 1) ni1 = (NODEINST *)pc1->actuallist; else
2511 ni1 = ((NODEINST **)pc1->actuallist)[0];
2512 thecell = ni1->proto;
2513 cellnum = thecell->temp1 & NETCELLCODE;
2514
2515 /* advance to the end of the block of cells with the same instance number */
2516 while (i < cells1-1)
2517 {
2518 pc1 = celllist1[i+1];
2519 if (pc1->numactual == 1) ni1 = (NODEINST *)pc1->actuallist; else
2520 ni1 = ((NODEINST **)pc1->actuallist)[0];
2521 if (cellnum != (ni1->proto->temp1 & NETCELLCODE)) break;
2522 i++;
2523 }
2524
2525 /* make sure it exists in the other list */
2526 for(j=0; j<cells2; j++)
2527 {
2528 pc2 = celllist2[j];
2529 if (pc2->numactual == 1) ni2 = (NODEINST *)pc2->actuallist; else
2530 ni2 = ((NODEINST **)pc2->actuallist)[0];
2531 if (cellnum == (ni2->proto->temp1 & NETCELLCODE)) break;
2532 }
2533 if (j < cells2) continue;
2534
2535 formatinfstr(infstr, x_(" %s"), thecell->protoname);
2536 found = TRUE;
2537 }
2538 pt = returninfstr(infstr);
2539 if (found) addtostringarray(errorsa, pt);
2540
2541 infstr = initinfstr();
2542 formatinfstr(infstr, _("These instances exist only in cell %s:"),
2543 describenodeproto(cell2));
2544 found = FALSE;
2545 for(i=0; i<cells2; i++)
2546 {
2547 /* get the index of the next cell instance in the list */
2548 pc2 = celllist2[i];
2549 if (pc2->numactual == 1) ni2 = (NODEINST *)pc2->actuallist; else
2550 ni2 = ((NODEINST **)pc2->actuallist)[0];
2551 thecell = ni2->proto;
2552 cellnum = thecell->temp1 & NETCELLCODE;
2553
2554 /* advance to the end of the block of cells with the same instance number */
2555 while (i < cells2-1)
2556 {
2557 pc2 = celllist2[i+1];
2558 if (pc2->numactual == 1) ni2 = (NODEINST *)pc2->actuallist; else
2559 ni2 = ((NODEINST **)pc2->actuallist)[0];
2560 if (cellnum != (ni2->proto->temp1 & NETCELLCODE)) break;
2561 i++;
2562 }
2563
2564 /* make sure it exists in the other list */
2565 for(j=0; j<cells1; j++)
2566 {
2567 pc1 = celllist1[j];
2568 if (pc1->numactual == 1) ni1 = (NODEINST *)pc1->actuallist; else
2569 ni1 = ((NODEINST **)pc1->actuallist)[0];
2570 if (cellnum == (ni1->proto->temp1 & NETCELLCODE)) break;
2571 }
2572 if (j < cells1) continue;
2573
2574 formatinfstr(infstr, x_(" %s"), thecell->protoname);
2575 found = TRUE;
2576 }
2577 pt = returninfstr(infstr);
2578 if (found) addtostringarray(errorsa, pt);
2579 }
2580 efree((CHAR *)celllist1);
2581 efree((CHAR *)celllist2);
2582 }
2583
2584 /*
2585 * Routine to handle a missing network on an unexpanded icon in NCC.
2586 * Cell "cell" has network "net", but "cellwithout" has no corresponding network.
2587 * The routine reports the problem in the string array "errorsa".
2588 *
2589 * A special case is handled. If:
2590 * "cellwithout" is an icon
2591 * the network is of type power or ground
2592 * there is a global network of that type in the flattened circuit
2593 * then:
2594 * create a port on "cell" of that type
2595 * connect it to that global net.
2596 * To do this, modify the PCOMPs in entries "start" to "end" of "celllist".
2597 * If power and ground are being ignored, "ignorepwrgnd" is TRUE.
2598 * The list of PNETs in cell "cell" is in "pnetlist".
2599 */
net_foundmismatch(NODEPROTO * cell,NETWORK * net,NODEPROTO * cellwithout,PCOMP ** celllist,INTBIG start,INTBIG end,PNET * pnetlist,BOOLEAN ignorepwrgnd,void * errorsa)2600 void net_foundmismatch(NODEPROTO *cell, NETWORK *net, NODEPROTO *cellwithout, PCOMP **celllist,
2601 INTBIG start, INTBIG end, PNET *pnetlist, BOOLEAN ignorepwrgnd, void *errorsa)
2602 {
2603 REGISTER void *infstr;
2604 REGISTER PNET *pn, **newnetnumbers;
2605 REGISTER PCOMP *pc, **newnodelist;
2606 REGISTER PORTPROTO **newportlist, *pp;
2607 REGISTER INTBIG i, j, wantedflag, newnodecount, *newnodewire;
2608 REGISTER INTSML *newportindices, *newstate, newwirecount;
2609 REGISTER BOOLEAN fixed;
2610
2611 fixed = FALSE;
2612
2613 /* special case for icons with missing connections (and not ignoring power and ground) */
2614 if (cellwithout->cellview == el_iconview && !ignorepwrgnd)
2615 {
2616 /* see if the missing connection is power or ground */
2617 wantedflag = 0;
2618 if (net->globalnet == GLOBALNETPOWER) wantedflag = POWERNET; else
2619 if (net->globalnet == GLOBALNETGROUND) wantedflag = GROUNDNET; else
2620 {
2621 pc = celllist[start];
2622 for(j=0; j<pc->wirecount; j++)
2623 {
2624 pn = pc->netnumbers[j];
2625 if (pn->network == net) break;
2626 }
2627 if (j < pc->wirecount && (pn->flags&(POWERNET|GROUNDNET)) != 0)
2628 wantedflag = pn->flags&(POWERNET|GROUNDNET);
2629 if (wantedflag == 0 && net->portcount > 0)
2630 {
2631 for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2632 if (pp->network == net) break;
2633 if (pp != NOPORTPROTO)
2634 {
2635 if ((pp->userbits&STATEBITS) == PWRPORT) wantedflag = POWERNET; else
2636 if ((pp->userbits&STATEBITS) == GNDPORT) wantedflag = GROUNDNET;
2637 }
2638 }
2639 }
2640 if (wantedflag != 0)
2641 {
2642 /* missing power or ground on an icon: see if such a signal is in the list */
2643 for(pn = pnetlist; pn != NOPNET; pn = pn->nextpnet)
2644 if ((pn->flags&(POWERNET|GROUNDNET)) == wantedflag) break;
2645 if (pn != NOPNET)
2646 {
2647 /* signal found: add it to the components */
2648 ttyputmsg(_("Note: added %s port to Cell %s"),
2649 net_describepnet(pn), describenodeproto(cellwithout));
2650 for(i=start; i<=end; i++)
2651 {
2652 /* add the PNET to the PCOMP */
2653 pc = celllist[i];
2654 newwirecount = pc->wirecount + 1;
2655 newportindices = (INTSML *)emalloc(newwirecount * SIZEOFINTSML, net_tool->cluster);
2656 newportlist = (PORTPROTO **)emalloc(newwirecount * sizeof (PORTPROTO *), net_tool->cluster);
2657 newnetnumbers = (PNET **)emalloc(newwirecount * sizeof (PNET *), net_tool->cluster);
2658 newstate = (INTSML *)emalloc(newwirecount * SIZEOFINTSML, net_tool->cluster);
2659 if (newportindices == 0 || newportlist == 0 || newnetnumbers == 0 ||
2660 newstate == 0) return;
2661 for(j=0; j<pc->wirecount; j++)
2662 {
2663 newportindices[j] = pc->portindices[j];
2664 newportlist[j] = pc->portlist[j];
2665 newnetnumbers[j] = pc->netnumbers[j];
2666 newstate[j] = pc->state[j];
2667 }
2668 newportindices[pc->wirecount] = (INTSML)net->temp2;
2669 newportlist[pc->wirecount] = NOPORTPROTO;
2670 newnetnumbers[pc->wirecount] = pn;
2671 newstate[pc->wirecount] = 0;
2672 if (pc->wirecount > 0)
2673 {
2674 efree((CHAR *)pc->portindices);
2675 efree((CHAR *)pc->portlist);
2676 efree((CHAR *)pc->netnumbers);
2677 efree((CHAR *)pc->state);
2678 }
2679 pc->portindices = newportindices;
2680 pc->portlist = newportlist;
2681 pc->netnumbers = newnetnumbers;
2682 pc->state = newstate;
2683 pc->wirecount = newwirecount;
2684 pc->truewirecount++;
2685
2686 /* add the PCOMP to the PNET */
2687 newnodecount = pn->nodecount + 1;
2688 newnodelist = (PCOMP **)emalloc(newnodecount * sizeof (PCOMP *), net_tool->cluster);
2689 newnodewire = (INTBIG *)emalloc(newnodecount * SIZEOFINTBIG, net_tool->cluster);
2690 if (newnodelist == 0 || newnodewire == 0) return;
2691 for(j=0; j<pn->nodecount; j++)
2692 {
2693 newnodelist[j] = pn->nodelist[j];
2694 newnodewire[j] = pn->nodewire[j];
2695 }
2696 newnodelist[pn->nodecount] = pc;
2697 newnodewire[pn->nodecount] = pc->wirecount-1;
2698 if (pn->nodecount > 0)
2699 {
2700 efree((CHAR *)pn->nodelist);
2701 efree((CHAR *)pn->nodewire);
2702 }
2703 pn->nodelist = newnodelist;
2704 pn->nodewire = newnodewire;
2705 pn->nodecount = newnodecount;
2706 }
2707 fixed = TRUE;
2708 }
2709 }
2710 }
2711 if (!fixed)
2712 {
2713 /* can't fix it: report the error */
2714 infstr = initinfstr();
2715 formatinfstr(infstr, _("Cell %s has %s, which does not exist in cell %s"),
2716 describenodeproto(cell), describenetwork(net), describenodeproto(cellwithout));
2717 addtostringarray(errorsa, returninfstr(infstr));
2718 }
2719 }
2720
net_makeexternalnetlist(NODEINST * ni,INTBIG * size,BOOLEAN ignorepwrgnd)2721 NETWORK **net_makeexternalnetlist(NODEINST *ni, INTBIG *size, BOOLEAN ignorepwrgnd)
2722 {
2723 REGISTER NODEPROTO *np;
2724 REGISTER PORTPROTO *pp;
2725 REGISTER NETWORK *net, *subnet, **list;
2726 REGISTER INTBIG i, total;
2727
2728 np = contentsview(ni->proto);
2729 if (np == NONODEPROTO) np = ni->proto;
2730 total = 0;
2731 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2732 {
2733 if (ignorepwrgnd)
2734 {
2735 if (portispower(pp) || portisground(pp)) continue;
2736 }
2737 net = pp->network;
2738 if (net->buswidth > 1)
2739 {
2740 for(i=0; i<net->buswidth; i++) total++;
2741 } else total++;
2742 }
2743 *size = total;
2744 if (total > 0)
2745 {
2746 list = (NETWORK **)emalloc(total * (sizeof (NETWORK *)), el_tempcluster);
2747 total = 0;
2748 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2749 {
2750 if (ignorepwrgnd)
2751 {
2752 if (portispower(pp) || portisground(pp)) continue;
2753 }
2754 net = pp->network;
2755 if (net->buswidth > 1)
2756 {
2757 for(i=0; i<net->buswidth; i++)
2758 {
2759 subnet = net->networklist[i];
2760 list[total++] = subnet;
2761 }
2762 } else
2763 {
2764 list[total++] = net;
2765 }
2766 }
2767 }
2768 return(list);
2769 }
2770
net_sortexportcodes(const void * e1,const void * e2)2771 int net_sortexportcodes(const void *e1, const void *e2)
2772 {
2773 REGISTER NETWORK *pp1, *pp2;
2774
2775 pp1 = *((NETWORK **)e1);
2776 pp2 = *((NETWORK **)e2);
2777 return(pp1->temp2 - pp2->temp2);
2778 }
2779
net_sortbycelltype(const void * n1,const void * n2)2780 int net_sortbycelltype(const void *n1, const void *n2)
2781 {
2782 REGISTER PCOMP *pc1, *pc2;
2783 REGISTER NODEINST *ni1, *ni2;
2784 REGISTER INTBIG diff;
2785
2786 pc1 = *((PCOMP **)n1);
2787 pc2 = *((PCOMP **)n2);
2788 if (pc1->numactual == 1) ni1 = (NODEINST *)pc1->actuallist; else
2789 ni1 = ((NODEINST **)pc1->actuallist)[0];
2790 if (pc2->numactual == 1) ni2 = (NODEINST *)pc2->actuallist; else
2791 ni2 = ((NODEINST **)pc2->actuallist)[0];
2792 diff = (ni1->proto->temp1 & NETCELLCODE) - (ni2->proto->temp1 & NETCELLCODE);
2793 if (diff != 0) return(diff);
2794 return(pc1->truewirecount - pc2->truewirecount);
2795 }
2796
net_sortbypnet(const void * n1,const void * n2)2797 int net_sortbypnet(const void *n1, const void *n2)
2798 {
2799 REGISTER PNET *pn1, *pn2;
2800
2801 pn1 = *((PNET **)n1);
2802 pn2 = *((PNET **)n2);
2803 return(namesame(net_describepnet(pn1), net_describepnet(pn2)));
2804 }
2805
2806 /*
2807 * Routine to remove extraneous information. It removes busses from the
2808 * networks and it removes SPICE parts from the components.
2809 */
net_removeextraneous(PCOMP ** pcomplist,PNET ** pnetlist,INTBIG * comp)2810 void net_removeextraneous(PCOMP **pcomplist, PNET **pnetlist, INTBIG *comp)
2811 {
2812 REGISTER PNET *pn, *lastpn, *nextpn;
2813 REGISTER PCOMP *pc, *lastpc, *nextpc;
2814 REGISTER NETWORK *net;
2815
2816 /* initialize all networks */
2817 lastpn = NOPNET;
2818 for(pn = *pnetlist; pn != NOPNET; pn = nextpn)
2819 {
2820 nextpn = pn->nextpnet;
2821 net = pn->network;
2822
2823 /* remove networks that refer to busses (individual signals are compared) */
2824 if (net != NONETWORK && net->buswidth > 1)
2825 {
2826 if (lastpn == NOPNET)
2827 {
2828 *pnetlist = pn->nextpnet;
2829 } else
2830 {
2831 lastpn->nextpnet = pn->nextpnet;
2832 }
2833 net_freepnet(pn);
2834 continue;
2835 }
2836 lastpn = pn;
2837 }
2838
2839 lastpc = NOPCOMP;
2840 for(pc = *pcomplist; pc != NOPCOMP; pc = nextpc)
2841 {
2842 nextpc = pc->nextpcomp;
2843
2844 /* remove components that relate to SPICE simulation */
2845 if (net_isspice(pc))
2846 {
2847 if (lastpc == NOPCOMP)
2848 {
2849 *pcomplist = pc->nextpcomp;
2850 } else
2851 {
2852 lastpc->nextpcomp = pc->nextpcomp;
2853 }
2854 net_freepcomp(pc);
2855 (*comp)--;
2856 continue;
2857 }
2858 lastpc = pc;
2859 }
2860 }
2861
2862 #if 0
2863 /*
2864 * Routine to check for duplicate names in the netlist, which may cause problems later.
2865 */
2866 void net_checkforduplicatenames(PNET *pnetlist)
2867 {
2868 REGISTER PNET *pn, **pnlist, *lastpn;
2869 REGISTER INTBIG total, i;
2870 REGISTER NETWORK *net, *lastnet;
2871
2872 /* see how many PNETs there are */
2873 total = 0;
2874 for(pn = pnetlist; pn != NOPNET; pn = pn->nextpnet)
2875 {
2876 net = pn->network;
2877 if (net == NONETWORK || net->namecount == 0) continue;
2878 total++;
2879 }
2880 if (total == 0) return;
2881
2882 /* make a list of them */
2883 pnlist = (PNET **)emalloc(total * (sizeof (PNET *)), net_tool->cluster);
2884 if (pnlist == 0) return;
2885 i = 0;
2886 for(pn = pnetlist; pn != NOPNET; pn = pn->nextpnet)
2887 {
2888 net = pn->network;
2889 if (net == NONETWORK || net->namecount == 0) continue;
2890 pnlist[i++] = pn;
2891 }
2892
2893 /* sort by name within parent */
2894 esort(pnlist, total, sizeof (PNET *), net_sortpnetlist);
2895
2896 /* now look for duplicates */
2897 for(i=1; i<total; i++)
2898 {
2899 lastpn = pnlist[i-1];
2900 lastnet = lastpn->network;
2901 pn = pnlist[i];
2902 net = pn->network;
2903 if (lastnet == net) continue;
2904 if (net->parent != lastnet->parent) continue;
2905 if (namesame(networkname(net, 0), networkname(lastnet, 0)) != 0) continue;
2906 ttyputmsg(_("Warning: cell %s has multiple networks named %s"),
2907 describenodeproto(net->parent), networkname(net, 0));
2908 }
2909 efree((CHAR *)pnlist);
2910 }
2911
2912 int net_sortpnetlist(const void *n1, const void *n2)
2913 {
2914 REGISTER PNET *pn1, *pn2;
2915 REGISTER NETWORK *net1, *net2;
2916
2917 pn1 = *((PNET **)n1);
2918 pn2 = *((PNET **)n2);
2919 net1 = pn1->network;
2920 net2 = pn2->network;
2921 if (net1->parent != net2->parent) return((int)(net1->parent - net2->parent));
2922 return(namesame(networkname(net1, 0), networkname(net2, 0)));
2923 }
2924 #endif
2925
2926 /******************************** RESULTS ANALYSIS ********************************/
2927
2928 #ifdef NEWNCC
2929 typedef struct
2930 {
2931 PORTPROTO *pp;
2932 SYMGROUP *sg;
2933 } EXPORTSYMGROUP;
2934
2935 int net_sortexportsymgroup(const void *e1, const void *e2);
2936
net_sortexportsymgroup(const void * e1,const void * e2)2937 int net_sortexportsymgroup(const void *e1, const void *e2)
2938 {
2939 REGISTER EXPORTSYMGROUP *es1, *es2;
2940
2941 es1 = (EXPORTSYMGROUP *)e1;
2942 es2 = (EXPORTSYMGROUP *)e2;
2943 return(namesame(es1->pp->protoname, es2->pp->protoname));
2944 }
2945
2946 #endif
2947
2948 /*
2949 * Routine to look at the symmetry groups and return the number of hard errors and the number of
2950 * soft errors in "harderrors", and "softerrors". If "reporterrors" is nonzero, these errors are
2951 * logged for perusal by the user. If "checksize" is true, check sizes. If "checkexportnames" is
2952 * true, check export names. If "ignorepwrgnd" is true, ignore power and ground nets. The total
2953 * number of errors is put in "errorcount".
2954 */
net_analyzesymmetrygroups(BOOLEAN reporterrors,BOOLEAN checksize,BOOLEAN checkexportnames,BOOLEAN ignorepwrgnd,INTBIG * errorcount)2955 INTBIG net_analyzesymmetrygroups(BOOLEAN reporterrors, BOOLEAN checksize, BOOLEAN checkexportnames,
2956 BOOLEAN ignorepwrgnd, INTBIG *errorcount)
2957 {
2958 REGISTER INTBIG f, i, j, errors, pctdiff1, pctdiff2, pctdiff, worstpctdiff, i1, i2;
2959 float diff, largest;
2960 BOOLEAN valid, exportcomparison;
2961 REGISTER SYMGROUP *sg, *osg, *amblist, *unasslist;
2962 REGISTER PCOMP *pc1, *pc2;
2963 REGISTER void *err;
2964 REGISTER CHAR *net1name, *pt1, *pt2;
2965 CHAR size1[200], size2[200];
2966 REGISTER PNET *pn, *pn1, *pn2, *opn;
2967 PNET **pnlist[2];
2968 REGISTER PORTPROTO *pp1, *pp2;
2969 REGISTER NODEPROTO *par1, *par2;
2970 REGISTER ARCINST *ai;
2971 REGISTER NETWORK *net;
2972 INTBIG pnlisttotal[2];
2973 REGISTER void *infstr;
2974
2975 errors = 0;
2976 *errorcount = 0;
2977 worstpctdiff = 0;
2978 amblist = unasslist = NOSYMGROUP;
2979
2980 /* now evaluate the differences */
2981 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
2982 {
2983 /* if there is nothing in the group, ignore it */
2984 if (sg->cellcount[0] == 0 && sg->cellcount[1] == 0) continue;
2985
2986 /* if the group is a good match, make optional checks */
2987 if (sg->cellcount[0] == 1 && sg->cellcount[1] == 1)
2988 {
2989 if (checksize && sg->grouptype == SYMGROUPCOMP)
2990 {
2991 /* see if sizes match */
2992 pc1 = (PCOMP *)sg->celllist[0][0];
2993 pc2 = (PCOMP *)sg->celllist[1][0];
2994 if ((pc1->flags&COMPHASWIDLEN) != 0)
2995 {
2996 if (!net_componentequalvalue(pc1->width, pc2->width) ||
2997 !net_componentequalvalue(pc1->length, pc2->length))
2998 {
2999 if (reporterrors)
3000 {
3001 diff = (float)fabs(pc1->width - pc2->width);
3002 if (pc1->width > pc2->width) largest = pc1->width; else largest = pc2->width;
3003 pctdiff1 = roundfloat(diff * 100.0f / largest);
3004 diff = (float)fabs(pc1->length - pc2->length);
3005 if (pc1->length > pc2->length) largest = pc1->length; else largest = pc2->length;
3006 pctdiff2 = roundfloat(diff * 100.0f / largest);
3007 pctdiff = maxi(pctdiff1, pctdiff2);
3008 if (pctdiff > worstpctdiff) worstpctdiff = pctdiff;
3009 esnprintf(size1, 200, x_("%s/%s"), frtoa(roundfloat(pc1->width)), frtoa(roundfloat(pc1->length)));
3010 esnprintf(size2, 200, x_("%s/%s"), frtoa(roundfloat(pc2->width)), frtoa(roundfloat(pc2->length)));
3011 net_reportsizeerror(pc1, size1, pc2, size2, pctdiff, sg);
3012 (*errorcount)++;
3013 }
3014 errors |= SIZEERRORS;
3015 }
3016 } else if ((pc1->flags&COMPHASAREA) != 0)
3017 {
3018 if (!net_componentequalvalue(pc1->length, pc2->length))
3019 {
3020 if (reporterrors)
3021 {
3022 diff = (float)fabs(pc1->length - pc2->length);
3023 if (pc1->length > pc2->length) largest = pc1->length; else largest = pc2->length;
3024 pctdiff = roundfloat(diff * 100.0f / largest);
3025 if (pctdiff > worstpctdiff) worstpctdiff = pctdiff;
3026 if (pc1->function == NPRESIST)
3027 {
3028 /* not area: show the values as they are */
3029 esnprintf(size1, 200, x_("%g"), pc1->length);
3030 esnprintf(size2, 200, x_("%g"), pc2->length);
3031 net_reportsizeerror(pc1, size1, pc2, size2, pctdiff, sg);
3032 } else
3033 {
3034 /* area: make the values sensible */
3035 net_reportsizeerror(pc1, frtoa(roundfloat(pc1->length)), pc2,
3036 frtoa(roundfloat(pc2->length)), pctdiff, sg);
3037 }
3038 (*errorcount)++;
3039 }
3040 errors |= SIZEERRORS;
3041 }
3042 }
3043 }
3044 if (sg->grouptype == SYMGROUPNET)
3045 {
3046 /* see if names match */
3047 pn1 = (PNET *)sg->celllist[0][0];
3048 pn2 = (PNET *)sg->celllist[1][0];
3049
3050 /* ignore name match for power and ground nets */
3051 if ((pn1->flags&(POWERNET|GROUNDNET)) != 0 || (pn2->flags&(POWERNET|GROUNDNET)) != 0)
3052 {
3053 if ((pn1->flags&(POWERNET|GROUNDNET)) != (pn2->flags&(POWERNET|GROUNDNET)))
3054 {
3055 if (reporterrors)
3056 {
3057 infstr = initinfstr();
3058 formatinfstr(infstr, _("Network '%s' in cell %s is on different power/ground than network '%s' in cell %s"),
3059 net_describepnet(pn1), describenodeproto(net_cell[0]),
3060 net_describepnet(pn2), describenodeproto(net_cell[1]));
3061 err = logerror(returninfstr(infstr), NONODEPROTO, 0);
3062 net_addsymgrouptoerror(err, sg);
3063 (*errorcount)++;
3064 }
3065 errors |= EXPORTERRORS;
3066 }
3067 continue;
3068 }
3069
3070 if ((pn1->flags&EXPORTEDNET) != 0 &&
3071 (pn1->realportcount > 0 || (pn1->network != NONETWORK && pn1->network->namecount > 0)))
3072 {
3073 if ((pn2->flags&EXPORTEDNET) == 0)
3074 {
3075 if (checkexportnames)
3076 {
3077 /* net in cell 1 is exported, but net in cell 2 isn't */
3078 if (reporterrors)
3079 {
3080 infstr = initinfstr();
3081 formatinfstr(infstr, _("Network in cell %s is '%s' but network in cell %s is not exported"),
3082 describenodeproto(net_cell[0]), net_describepnet(pn1), describenodeproto(net_cell[1]));
3083 err = logerror(returninfstr(infstr), NONODEPROTO, 0);
3084 net_addsymgrouptoerror(err, sg);
3085 (*errorcount)++;
3086 }
3087 errors |= EXPORTERRORS;
3088 }
3089 } else
3090 {
3091 /* both networks exported: check names */
3092 if (checkexportnames)
3093 {
3094 exportcomparison = net_sameexportnames(pn1, pn2);
3095 if (!exportcomparison)
3096 {
3097 if (reporterrors)
3098 {
3099 infstr = initinfstr();
3100 addstringtoinfstr(infstr, net_describepnet(pn1));
3101 net1name = returninfstr(infstr);
3102 infstr = initinfstr();
3103 par1 = pn1->network->parent;
3104 par2 = pn2->network->parent;
3105 if ((par1 == net_cell[0] && par2 == net_cell[1]) ||
3106 (par1 == net_cell[1] && par2 == net_cell[0]) ||
3107 insamecellgrp(par1, par2))
3108 {
3109 formatinfstr(infstr, _("Export names '%s:%s' and '%s:%s' do not match"),
3110 describenodeproto(par1), net1name,
3111 describenodeproto(par2), net_describepnet(pn2));
3112 } else
3113 {
3114 formatinfstr(infstr, _("Export names '%s:%s' and '%s:%s' are not at the same level of hierarchy"),
3115 describenodeproto(par1), net1name,
3116 describenodeproto(par2), net_describepnet(pn2));
3117 }
3118 err = logerror(returninfstr(infstr), NONODEPROTO, 0);
3119 net_addsymgrouptoerror(err, sg);
3120 (*errorcount)++;
3121 }
3122 errors |= EXPORTERRORS;
3123 }
3124 }
3125
3126 /* check that the export characteristics match */
3127 if (pn2->realportcount > 0)
3128 {
3129 pp1 = NOPORTPROTO;
3130 for(i=0; i<pn1->realportcount; i++)
3131 {
3132 if (pn1->realportcount == 1) pp1 = (PORTPROTO *)pn1->realportlist; else
3133 pp1 = ((PORTPROTO **)pn1->realportlist)[i];
3134 for(j=0; j<pn2->realportcount; j++)
3135 {
3136 if (pn2->realportcount == 1) pp2 = (PORTPROTO *)pn2->realportlist; else
3137 pp2 = ((PORTPROTO **)pn2->realportlist)[j];
3138 if ((pp1->userbits&STATEBITS) == (pp2->userbits&STATEBITS)) break;
3139 }
3140 if (j < pn2->realportcount) break;
3141 }
3142 if (i >= pn1->realportcount)
3143 {
3144 if (reporterrors)
3145 {
3146 if (pn2->realportcount == 1) pp2 = (PORTPROTO *)pn2->realportlist; else
3147 pp2 = ((PORTPROTO **)pn2->realportlist)[0];
3148 infstr = initinfstr();
3149 formatinfstr(infstr, _("Exports have different characteristics (%s:%s is %s and %s:%s is %s)"),
3150 describenodeproto(net_cell[0]), pp1->protoname, describeportbits(pp1->userbits),
3151 describenodeproto(net_cell[1]), pp2->protoname, describeportbits(pp2->userbits));
3152 err = logerror(returninfstr(infstr), NONODEPROTO, 0);
3153 net_addsymgrouptoerror(err, sg);
3154 (*errorcount)++;
3155 }
3156 errors |= EXPORTERRORS;
3157 }
3158 }
3159 }
3160 } else
3161 {
3162 if ((pn2->flags&EXPORTEDNET) != 0 &&
3163 (pn2->realportcount > 0 || (pn2->network != NONETWORK && pn2->network->namecount > 0)))
3164 {
3165 if (checkexportnames)
3166 {
3167 /* net in cell 2 is exported, but net in cell 1 isn't */
3168 if (reporterrors)
3169 {
3170 infstr = initinfstr();
3171 formatinfstr(infstr, _("Network in cell %s is '%s' but network in cell %s is not exported"),
3172 describenodeproto(net_cell[1]), net_describepnet(pn2), describenodeproto(net_cell[0]));
3173 err = logerror(returninfstr(infstr), NONODEPROTO, 0);
3174 net_addsymgrouptoerror(err, sg);
3175 (*errorcount)++;
3176 }
3177 errors |= EXPORTERRORS;
3178 }
3179 }
3180 }
3181 }
3182 continue;
3183 }
3184
3185 if (sg->cellcount[0] <= 0 || sg->cellcount[1] <= 0 || sg->hashvalue == 0)
3186 {
3187 if (sg->grouptype == SYMGROUPNET)
3188 {
3189 /* network group: ignore if no real associated networks */
3190 valid = FALSE;
3191 pn = NOPNET;
3192 for(f=0; f<2; f++)
3193 {
3194 for(i=0; i<sg->cellcount[f]; i++)
3195 {
3196 pn = (PNET *)sg->celllist[f][i];
3197 if (pn->network != NONETWORK) valid = TRUE;
3198 }
3199 }
3200 if (!valid) continue;
3201
3202 /* network group: ignore if a bus */
3203 for(f=0; f<2; f++)
3204 {
3205 for(i=0; i<sg->cellcount[f]; i++)
3206 {
3207 pn = (PNET *)sg->celllist[f][i];
3208 net = pn->network;
3209 if (net == NONETWORK) continue;
3210 if (net->buswidth > 1) break;
3211 }
3212 if (i < sg->cellcount[f]) break;
3213 }
3214 if (f < 2) continue;
3215
3216 /* network group: ignore if all power and ground that is being ignored */
3217 if (ignorepwrgnd)
3218 {
3219 valid = FALSE;
3220 for(f=0; f<2; f++)
3221 {
3222 for(i=0; i<sg->cellcount[f]; i++)
3223 {
3224 pn = (PNET *)sg->celllist[f][i];
3225 if ((pn->flags&(POWERNET|GROUNDNET)) == 0)
3226 valid = TRUE;
3227 }
3228 }
3229 if (!valid) continue;
3230 }
3231
3232 /* network group: ignore if no components are on it (but warn) */
3233 if (sg->cellcount[0] == 0 || sg->cellcount[1] == 0)
3234 {
3235 for(f=0; f<2; f++)
3236 {
3237 if (sg->cellcount[f] == 0) continue;
3238 for(i=0; i<sg->cellcount[f]; i++)
3239 {
3240 pn = (PNET *)sg->celllist[f][i];
3241 if (pn->nodecount != 0) break;
3242 }
3243 if (i < sg->cellcount[f]) continue;
3244 if (reporterrors)
3245 {
3246 infstr = initinfstr();
3247 formatinfstr(infstr, _("Network %s in cell %s is unused"),
3248 net_describepnet(pn), describenodeproto(net_cell[f]));
3249 err = logerror(returninfstr(infstr), NONODEPROTO, 0);
3250 net_addsymgrouptoerror(err, sg);
3251 (*errorcount)++;
3252 }
3253 errors |= EXPORTERRORS;
3254 break;
3255 }
3256 if (f < 2) continue;
3257 }
3258 }
3259
3260 /* add to the list of unassociated groups */
3261 sg->nexterrsymgroup = unasslist;
3262 unasslist = sg;
3263 } else
3264 {
3265 /* add to the list of ambiguous groups */
3266 sg->nexterrsymgroup = amblist;
3267 amblist = sg;
3268 }
3269 }
3270
3271 #ifdef NEWNCC
3272 /* make more thorough check if checking export names */
3273 if (checkexportnames)
3274 {
3275 REGISTER INTBIG c1, c2, i1, i2, chdiff;
3276 REGISTER PORTPROTO *pp;
3277 EXPORTSYMGROUP *es1, *es2;
3278
3279 c1 = c2 = 0;
3280 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
3281 {
3282 /* only interested in matched network groups */
3283 if (sg->grouptype != SYMGROUPNET) continue;
3284 if (sg->cellcount[0] != 1 || sg->cellcount[1] != 1) continue;
3285 pn1 = (PNET *)sg->celllist[0][0];
3286 if ((pn1->flags&EXPORTEDNET) != 0)
3287 {
3288 for(i=0; i<pn1->realportcount; i++)
3289 {
3290 if (pn1->realportcount == 1) pp = (PORTPROTO *)pn1->realportlist; else
3291 pp = ((PORTPROTO **)pn1->realportlist)[i];
3292 if (pp->network->buswidth <= 1) c1++;
3293 }
3294 }
3295 pn2 = (PNET *)sg->celllist[1][0];
3296 if ((pn2->flags&EXPORTEDNET) != 0)
3297 {
3298 for(i=0; i<pn2->realportcount; i++)
3299 {
3300 if (pn2->realportcount == 1) pp = (PORTPROTO *)pn2->realportlist; else
3301 pp = ((PORTPROTO **)pn2->realportlist)[i];
3302 if (pp->network->buswidth <= 1) c2++;
3303 }
3304 }
3305 }
3306
3307 if (c1 != 0 && c2 != 0)
3308 {
3309 /* build array of export names */
3310 es1 = (EXPORTSYMGROUP *)emalloc(c1 * (sizeof (EXPORTSYMGROUP)), net_tool->cluster);
3311 if (es1 == 0) return(0);
3312 es2 = (EXPORTSYMGROUP *)emalloc(c2 * (sizeof (EXPORTSYMGROUP)), net_tool->cluster);
3313 if (es1 == 0) return(0);
3314
3315 /* load the export lists */
3316 c1 = c2 = 0;
3317 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
3318 {
3319 /* only interested in matched network groups */
3320 if (sg->grouptype != SYMGROUPNET) continue;
3321 if (sg->cellcount[0] != 1 || sg->cellcount[1] != 1) continue;
3322 pn1 = (PNET *)sg->celllist[0][0];
3323 if ((pn1->flags&EXPORTEDNET) != 0)
3324 {
3325 for(i=0; i<pn1->realportcount; i++)
3326 {
3327 if (pn1->realportcount == 1) pp = (PORTPROTO *)pn1->realportlist; else
3328 pp = ((PORTPROTO **)pn1->realportlist)[i];
3329 if (pp->network->buswidth > 1) continue;
3330 es1[c1].pp = pp;
3331 es1[c1].sg = sg;
3332 c1++;
3333 }
3334 }
3335 pn2 = (PNET *)sg->celllist[1][0];
3336 if ((pn2->flags&EXPORTEDNET) != 0)
3337 {
3338 for(i=0; i<pn2->realportcount; i++)
3339 {
3340 if (pn2->realportcount == 1) pp = (PORTPROTO *)pn2->realportlist; else
3341 pp = ((PORTPROTO **)pn2->realportlist)[i];
3342 if (pp->network->buswidth > 1) continue;
3343 es2[c2].pp = pp;
3344 es2[c2].sg = sg;
3345 c2++;
3346 }
3347 }
3348 }
3349
3350 /* analyze */
3351 esort(es1, c1, sizeof (EXPORTSYMGROUP), net_sortexportsymgroup);
3352 esort(es2, c2, sizeof (EXPORTSYMGROUP), net_sortexportsymgroup);
3353
3354 i1 = i2 = 0;
3355 for(;;)
3356 {
3357 if (i1 >= c1 || i2 >= c2) break;
3358 chdiff = namesame(es1[i1].pp->protoname, es2[i2].pp->protoname);
3359 if (chdiff == 0)
3360 {
3361 /* same name: make sure symgroups are the same */
3362 if (es1[i1].sg != es2[i2].sg)
3363 {
3364 if (reporterrors)
3365 {
3366 infstr = initinfstr();
3367 formatinfstr(infstr, _("Export %s not wired consistently"),
3368 es1[i1].pp->protoname);
3369 err = logerror(returninfstr(infstr), NONODEPROTO, 0);
3370 addexporttoerror(err, es1[i1].pp, TRUE);
3371 addexporttoerror(err, es2[i2].pp, TRUE);
3372 (*errorcount)++;
3373 }
3374 errors |= EXPORTERRORS;
3375 }
3376 i1++;
3377 i2++;
3378 continue;
3379 }
3380 if (chdiff < 0) i1++; else
3381 i2++;
3382 }
3383 efree((CHAR *)es1);
3384 efree((CHAR *)es2);
3385 }
3386 }
3387 #endif
3388
3389 if (unasslist != NOSYMGROUP || amblist != NOSYMGROUP)
3390 {
3391 if (reporterrors)
3392 {
3393 if (unasslist != NOSYMGROUP)
3394 *errorcount += net_reporterror(unasslist, _("Unassociated"), ignorepwrgnd);
3395 if (amblist != NOSYMGROUP)
3396 *errorcount += net_reporterror(amblist, _("Ambiguous"), ignorepwrgnd);
3397 }
3398 errors |= STRUCTUREERRORS;
3399 }
3400
3401 /* if reporting errors, look for groups with missing parts */
3402 if (reporterrors)
3403 {
3404 pnlisttotal[0] = pnlisttotal[1] = 0;
3405 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
3406 {
3407 if (sg->cellcount[0] <= 0 || sg->cellcount[1] <= 0) continue;
3408 if (sg->grouptype != SYMGROUPNET) continue;
3409 if (sg->cellcount[0] == 1 && sg->cellcount[1] == 1) continue;
3410
3411 /* first make a list of the networks in both cells */
3412 for(f=0; f<2; f++)
3413 {
3414 if (sg->cellcount[f] > pnlisttotal[f])
3415 {
3416 if (pnlisttotal[f] > 0) efree((CHAR *)pnlist[f]);
3417 pnlist[f] = (PNET **)emalloc(sg->cellcount[f] * (sizeof (PNET *)), el_tempcluster);
3418 if (pnlist[f] == 0) return(errors);
3419 pnlisttotal[f] = sg->cellcount[f];
3420 }
3421 for(i=0; i<sg->cellcount[f]; i++)
3422 pnlist[f][i] = (PNET *)sg->celllist[f][i];
3423 }
3424
3425 /* sort the names and look for matches */
3426 esort(pnlist[0], sg->cellcount[0], sizeof (PNET *), net_sortbypnet);
3427 esort(pnlist[1], sg->cellcount[1], sizeof (PNET *), net_sortbypnet);
3428 i1 = i2 = 0;
3429 for(;;)
3430 {
3431 if (i1 >= sg->cellcount[0] || i2 >= sg->cellcount[1]) break;
3432 pn1 = pnlist[0][i1];
3433 pn2 = pnlist[1][i2];
3434 if (pn1 == NOPNET || pn2 == NOPNET) break;
3435 pt1 = net_describepnet(pn1);
3436 pt2 = net_describepnet(pn2);
3437 i = namesame(pt1, pt2);
3438 if (i < 0)
3439 {
3440 i1++;
3441 continue;
3442 }
3443 if (i > 0)
3444 {
3445 i2++;
3446 continue;
3447 }
3448 pnlist[0][i1] = NOPNET;
3449 while (i1+1 < sg->cellcount[0])
3450 {
3451 pn = pnlist[0][i1+1];
3452 if (pn == NOPNET) break;
3453 if (namesame(net_describepnet(pn1), net_describepnet(pn)) != 0) break;
3454 i1++;
3455 pnlist[0][i1] = NOPNET;
3456 }
3457 pnlist[1][i2] = NOPNET;
3458 while (i2+1 < sg->cellcount[1])
3459 {
3460 pn = pnlist[1][i2+1];
3461 if (pn == NOPNET) break;
3462 if (namesame(net_describepnet(pn2), net_describepnet(pn)) != 0) break;
3463 i2++;
3464 pnlist[1][i2] = NOPNET;
3465 }
3466 }
3467
3468 /* see if one entire side is eliminated */
3469 for(f=0; f<2; f++)
3470 {
3471 for(i=0; i<sg->cellcount[f]; i++)
3472 if (pnlist[f][i] != NOPNET) break;
3473 if (i >= sg->cellcount[f]) break;
3474 }
3475 if (f < 2)
3476 {
3477 /* side "f" is eliminated: find name matches to those on side "1-f" */
3478 for(j=0; j<sg->cellcount[1-f]; j++)
3479 {
3480 opn = (PNET *)sg->celllist[1-f][j];
3481 if (opn == NOPNET) continue;
3482 if (opn->network == NONETWORK) continue;
3483 for(osg = net_firstsymgroup; osg != NOSYMGROUP; osg = osg->nextsymgroup)
3484 {
3485 if (osg->grouptype != SYMGROUPNET) continue;
3486 if (osg == sg) continue;
3487 for(i=0; i<osg->cellcount[f]; i++)
3488 {
3489 pn = (PNET *)osg->celllist[f][i];
3490 if (opn->nodecount == pn->nodecount) continue;
3491 if (pn->network == NONETWORK) continue;
3492 pt1 = net_describepnet(opn);
3493 pt2 = net_describepnet(pn);
3494 if (namesame(pt1, pt2) == 0)
3495 {
3496 /* found it! */
3497 infstr = initinfstr();
3498 formatinfstr(infstr, _("Networks %s may be wired differently"),
3499 net_describepnet(pn));
3500 err = logerror(returninfstr(infstr), NONODEPROTO, 0);
3501 for(ai = pn->network->parent->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3502 if (ai->network == pn->network)
3503 addgeomtoerror(err, ai->geom, TRUE, 0, 0);
3504 for(ai = opn->network->parent->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3505 if (ai->network == opn->network)
3506 addgeomtoerror(err, ai->geom, TRUE, 0, 0);
3507 (*errorcount)++;
3508 break;
3509 }
3510 }
3511 if (i < osg->cellcount[f]) break;
3512 }
3513 }
3514 }
3515 }
3516 for(f=0; f<2; f++) if (pnlisttotal[f] > 0)
3517 efree((CHAR *)pnlist[f]);
3518 }
3519 if (reporterrors && worstpctdiff != 0)
3520 ttyputmsg(_("Worst size difference is %ld%%"), worstpctdiff);
3521 return(errors);
3522 }
3523
3524 /*
3525 * Routine to report a size error between component "pc1" with size "size1" and component "pc2" with
3526 * size "size2". The error is "pctdiff" percent, and it comes from symmetry group "sg".
3527 */
net_reportsizeerror(PCOMP * pc1,CHAR * size1,PCOMP * pc2,CHAR * size2,INTBIG pctdiff,SYMGROUP * sg)3528 void net_reportsizeerror(PCOMP *pc1, CHAR *size1, PCOMP *pc2, CHAR *size2, INTBIG pctdiff, SYMGROUP *sg)
3529 {
3530 REGISTER void *infstr, *err;
3531
3532 infstr = initinfstr();
3533 formatinfstr(infstr, _("Node sizes differ by %ld%% ("), pctdiff);
3534 if (pc1->numactual > 1)
3535 {
3536 formatinfstr(infstr, _("cell %s has %s from %ld transistors"), describenodeproto(net_cell[0]),
3537 size1, pc1->numactual);
3538 } else
3539 {
3540 formatinfstr(infstr, _("cell %s has %s"), describenodeproto(net_cell[0]), size1);
3541 }
3542 addstringtoinfstr(infstr, _(", but "));
3543 if (pc2->numactual > 1)
3544 {
3545 formatinfstr(infstr, _("cell %s has %s from %ld transistors"), describenodeproto(net_cell[1]),
3546 size2, pc2->numactual);
3547 } else
3548 {
3549 formatinfstr(infstr, _("cell %s has %s"), describenodeproto(net_cell[1]), size2);
3550 }
3551 addstringtoinfstr(infstr, x_(")"));
3552 err = logerror(returninfstr(infstr), NONODEPROTO, 0);
3553 net_addsymgrouptoerror(err, sg);
3554 }
3555
3556 /*
3557 * Routine to report the list of groups starting at "sg" as errors of type "errmsg".
3558 * Returns the number of errors reported.
3559 */
net_reporterror(SYMGROUP * sg,CHAR * errmsg,BOOLEAN ignorepwrgnd)3560 INTBIG net_reporterror(SYMGROUP *sg, CHAR *errmsg, BOOLEAN ignorepwrgnd)
3561 {
3562 REGISTER INTBIG i, f, oi, of, errorsfound;
3563 REGISTER PCOMP *pc, *opc;
3564 REGISTER PNET *pn, *opn;
3565 REGISTER void *infstr, *err;
3566 REGISTER CHAR *segue;
3567 CHAR errormessage[200];
3568 REGISTER NODEPROTO *lastcell;
3569 REGISTER NETWORK *net;
3570
3571 errorsfound = 0;
3572 for( ; sg != NOSYMGROUP; sg = sg->nexterrsymgroup)
3573 {
3574 switch (sg->grouptype)
3575 {
3576 case SYMGROUPCOMP:
3577 for(f=0; f<2; f++)
3578 {
3579 for(i=0; i<sg->cellcount[f]; i++)
3580 {
3581 pc = (PCOMP *)sg->celllist[f][i];
3582 if (pc->timestamp <= 0) continue;
3583 esnprintf(errormessage, 200, _("%s nodes"), errmsg);
3584 err = logerror(errormessage, NONODEPROTO, 0);
3585 net_addcomptoerror(err, pc);
3586 for(of=0; of<2; of++)
3587 {
3588 for(oi=0; oi<sg->cellcount[of]; oi++)
3589 {
3590 opc = (PCOMP *)sg->celllist[of][oi];
3591 if (opc == pc) continue;
3592 if (opc->timestamp != pc->timestamp) continue;
3593 net_addcomptoerror(err, opc);
3594 opc->timestamp = -opc->timestamp;
3595 }
3596 }
3597 pc->timestamp = -pc->timestamp;
3598 errorsfound++;
3599 }
3600 }
3601 for(f=0; f<2; f++)
3602 {
3603 for(i=0; i<sg->cellcount[f]; i++)
3604 {
3605 pc = (PCOMP *)sg->celllist[f][i];
3606 pc->timestamp = -pc->timestamp;
3607 }
3608 }
3609 break;
3610 case SYMGROUPNET:
3611 for(f=0; f<2; f++)
3612 {
3613 for(i=0; i<sg->cellcount[f]; i++)
3614 {
3615 pn = (PNET *)sg->celllist[f][i];
3616 if (pn->timestamp <= 0) continue;
3617 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0)
3618 continue;
3619
3620 /* build the error message */
3621 infstr = initinfstr();
3622 formatinfstr(infstr, _("%s networks"), errmsg);
3623 segue = x_(": ");
3624 for(of=0; of<2; of++)
3625 {
3626 lastcell = NONODEPROTO;
3627 for(oi=0; oi<sg->cellcount[of]; oi++)
3628 {
3629 opn = (PNET *)sg->celllist[of][oi];
3630 if (opn->timestamp != pn->timestamp) continue;
3631 if (ignorepwrgnd && (opn->flags&(POWERNET|GROUNDNET)) != 0)
3632 continue;
3633 net = opn->network;
3634 if (net == NONETWORK) continue;
3635 if (lastcell != net->parent)
3636 {
3637 addstringtoinfstr(infstr, segue);
3638 segue = x_("; ");
3639 formatinfstr(infstr, _("from cell %s:"),
3640 describenodeproto(net->parent));
3641 } else addtoinfstr(infstr, ',');
3642 lastcell = net->parent;
3643 formatinfstr(infstr, x_(" %s (%ld connections)"), describenetwork(net), opn->nodecount);
3644 }
3645 }
3646
3647 /* report the error */
3648 err = logerror(returninfstr(infstr), NONODEPROTO, 0);
3649 net_addnettoerror(err, pn);
3650 for(of=0; of<2; of++)
3651 {
3652 for(oi=0; oi<sg->cellcount[of]; oi++)
3653 {
3654 opn = (PNET *)sg->celllist[of][oi];
3655 if (opn == pn) continue;
3656 if (opn->timestamp != pn->timestamp) continue;
3657 if (ignorepwrgnd && (opn->flags&(POWERNET|GROUNDNET)) != 0)
3658 continue;
3659 net_addnettoerror(err, opn);
3660 opn->timestamp = -opn->timestamp;
3661 }
3662 }
3663 pn->timestamp = -pn->timestamp;
3664 errorsfound++;
3665 }
3666 }
3667 for(f=0; f<2; f++)
3668 {
3669 for(i=0; i<sg->cellcount[f]; i++)
3670 {
3671 pn = (PNET *)sg->celllist[f][i];
3672 pn->timestamp = -pn->timestamp;
3673 }
3674 }
3675 break;
3676 }
3677 }
3678 return(errorsfound);
3679 }
3680
3681 #define PRECISEBUSMATCH 1
3682
3683 /*
3684 * Routine to return true if the exported ports on "pn1" and "pn2" match.
3685 */
net_sameexportnames(PNET * pn1,PNET * pn2)3686 BOOLEAN net_sameexportnames(PNET *pn1, PNET *pn2)
3687 {
3688 REGISTER INTBIG i, j, c1, c2, nc1, nc2, c1ind, c1sig, c2ind, c2sig;
3689 REGISTER CHAR *name1, *name2;
3690 REGISTER PORTPROTO *pp1, *pp2;
3691
3692 /* determine the number of signal names on net 1 */
3693 c1 = 0;
3694 for(i=0; i<pn1->realportcount; i++)
3695 {
3696 if (pn1->realportcount == 1) pp1 = (PORTPROTO *)pn1->realportlist; else
3697 pp1 = ((PORTPROTO **)pn1->realportlist)[i];
3698 if (pp1->network->buswidth <= 1) c1++;
3699 #ifndef PRECISEBUSMATCH
3700 else c1 += pp1->network->buswidth;
3701 #endif
3702 }
3703 if (pn1->network == NONETWORK) nc1 = 0; else
3704 nc1 = pn1->network->namecount;
3705
3706 /* determine the number of signal names on net 2 */
3707 c2 = 0;
3708 for(i=0; i<pn2->realportcount; i++)
3709 {
3710 if (pn2->realportcount == 1) pp2 = (PORTPROTO *)pn2->realportlist; else
3711 pp2 = ((PORTPROTO **)pn2->realportlist)[i];
3712 if (pp2->network->buswidth <= 1) c2++;
3713 #ifndef PRECISEBUSMATCH
3714 else c2 += pp2->network->buswidth;
3715 #endif
3716 }
3717 if (pn2->network == NONETWORK) nc2 = 0; else
3718 nc2 = pn2->network->namecount;
3719
3720 c1ind = c1sig = 0;
3721 for(i=0; i<nc1+c1; i++)
3722 {
3723 if (i < nc1)
3724 {
3725 name1 = networkname(pn1->network, i);
3726 } else
3727 {
3728 if (pn1->realportcount == 1) pp1 = (PORTPROTO *)pn1->realportlist; else
3729 pp1 = ((PORTPROTO **)pn1->realportlist)[c1ind];
3730 if (pp1->network->buswidth <= 1)
3731 {
3732 name1 = pp1->protoname;
3733 c1ind++;
3734 c1sig = 0;
3735 #ifndef PRECISEBUSMATCH
3736 } else
3737 {
3738 name1 = networkname(pp1->network->networklist[c1sig++], 0);
3739 if (c1sig >= pp1->network->buswidth)
3740 {
3741 c1ind++;
3742 c1sig = 0;
3743 }
3744 #endif
3745 }
3746 }
3747
3748 c2ind = c2sig = 0;
3749 for(j=0; j<nc2+c2; j++)
3750 {
3751 if (j < nc2)
3752 {
3753 name2 = networkname(pn2->network, j);
3754 } else
3755 {
3756 if (pn2->realportcount == 1) pp2 = (PORTPROTO *)pn2->realportlist; else
3757 pp2 = ((PORTPROTO **)pn2->realportlist)[c2ind];
3758 if (pp2->network->buswidth <= 1)
3759 {
3760 name2 = pp2->protoname;
3761 c2ind++;
3762 c2sig = 0;
3763 #ifndef PRECISEBUSMATCH
3764 } else
3765 {
3766 name2 = networkname(pp2->network->networklist[c2sig++], 0);
3767 if (c2sig >= pp2->network->buswidth)
3768 {
3769 c2ind++;
3770 c2sig = 0;
3771 }
3772 #endif
3773 }
3774 }
3775 if (namesame(name1, name2) == 0) return(TRUE);
3776 }
3777 }
3778 return(FALSE);
3779 }
3780
3781 /*
3782 * Routine to report the number of unmatched networks and components.
3783 */
net_unmatchedstatus(INTBIG * unmatchednets,INTBIG * unmatchedcomps,INTBIG * symgroupcount)3784 void net_unmatchedstatus(INTBIG *unmatchednets, INTBIG *unmatchedcomps, INTBIG *symgroupcount)
3785 {
3786 REGISTER INTBIG f;
3787 REGISTER SYMGROUP *sg;
3788
3789 *unmatchednets = *unmatchedcomps = *symgroupcount = 0;
3790 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
3791 {
3792 if (sg->cellcount[0] == 0 && sg->cellcount[1] == 0) continue;
3793 (*symgroupcount)++;
3794 if (sg->cellcount[0] == 1 && sg->cellcount[1] == 1) continue;
3795 for(f=0; f<2; f++)
3796 {
3797 if (sg->grouptype == SYMGROUPCOMP)
3798 {
3799 *unmatchedcomps += sg->cellcount[f];
3800 } else
3801 {
3802 *unmatchednets += sg->cellcount[f];
3803 }
3804 }
3805 }
3806 for(sg = net_firstmatchedsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
3807 (*symgroupcount)++;
3808 }
3809
net_addcomptoerror(void * err,PCOMP * pc)3810 void net_addcomptoerror(void *err, PCOMP *pc)
3811 {
3812 REGISTER NODEINST *ni;
3813 REGISTER INTBIG i;
3814
3815 for(i=0; i<pc->numactual; i++)
3816 {
3817 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
3818 ni = ((NODEINST **)pc->actuallist)[i];
3819 addgeomtoerror(err, ni->geom, TRUE, pc->hierpathcount, pc->hierpath);
3820 }
3821 }
3822
net_addnettoerror(void * err,PNET * pn)3823 void net_addnettoerror(void *err, PNET *pn)
3824 {
3825 REGISTER ARCINST *ai;
3826 REGISTER NETWORK *net, *anet;
3827 REGISTER PORTPROTO *pp;
3828 REGISTER NODEPROTO *np;
3829 REGISTER BOOLEAN found;
3830 REGISTER INTBIG i;
3831
3832 found = FALSE;
3833 net = pn->network;
3834 if (net == NONETWORK) return;
3835 np = net->parent;
3836 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3837 {
3838 anet = ai->network;
3839 if (ai->proto == sch_busarc)
3840 {
3841 if (anet->buswidth > 1)
3842 {
3843 for(i=0; i<anet->buswidth; i++)
3844 if (anet->networklist[i] == net) break;
3845 if (i >= anet->buswidth) continue;
3846 } else
3847 {
3848 if (anet != net) continue;
3849 }
3850 } else
3851 {
3852 if (anet != net) continue;
3853 }
3854 addgeomtoerror(err, ai->geom, TRUE, 0, 0);
3855 found = TRUE;
3856 }
3857 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
3858 {
3859 if (pp->network != net) continue;
3860 addexporttoerror(err, pp, TRUE);
3861 found = TRUE;
3862 }
3863 if (!found && net->namecount > 0)
3864 {
3865 if (np == net_cell[0]) np = net_cell[1]; else
3866 np = net_cell[0];
3867 net = getnetwork(networkname(net, 0), np);
3868 if (net == NONETWORK) return;
3869 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3870 {
3871 if (ai->network != net) continue;
3872 addgeomtoerror(err, ai->geom, TRUE, 0, 0);
3873 }
3874 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
3875 {
3876 if (pp->network != net) continue;
3877 addexporttoerror(err, pp, TRUE);
3878 }
3879 }
3880 }
3881
3882 /*
3883 * Routine to add all objects in symmetry group "sg" to the error report "err".
3884 */
net_addsymgrouptoerror(void * err,SYMGROUP * sg)3885 void net_addsymgrouptoerror(void *err, SYMGROUP *sg)
3886 {
3887 REGISTER INTBIG i, f;
3888 REGISTER PCOMP *pc;
3889 REGISTER PNET *pn;
3890
3891 switch (sg->grouptype)
3892 {
3893 case SYMGROUPCOMP:
3894 for(f=0; f<2; f++)
3895 {
3896 for(i=0; i<sg->cellcount[f]; i++)
3897 {
3898 pc = (PCOMP *)sg->celllist[f][i];
3899 net_addcomptoerror(err, pc);
3900 }
3901 }
3902 break;
3903 case SYMGROUPNET:
3904 for(f=0; f<2; f++)
3905 {
3906 for(i=0; i<sg->cellcount[f]; i++)
3907 {
3908 pn = (PNET *)sg->celllist[f][i];
3909 net_addnettoerror(err, pn);
3910 }
3911 }
3912 break;
3913 }
3914 }
3915
3916 /******************************** RESOLVING AMBIGUITY ********************************/
3917
3918 /*
3919 * Routine to look for matches in ambiguous symmetry groups.
3920 * Returns 1 if a component group is split; -1 if a network group is split;
3921 * zero if no split was found.
3922 */
net_findamatch(INTBIG verbose,BOOLEAN ignorepwrgnd)3923 INTBIG net_findamatch(INTBIG verbose, BOOLEAN ignorepwrgnd)
3924 {
3925 REGISTER SYMGROUP *sg, *osg;
3926 REGISTER PNET *pn;
3927 REGISTER PCOMP *pc;
3928 NETWORK *nets[2];
3929 REGISTER INTBIG i, f, u, any, total, newtype;
3930 INTBIG is[2], unmatchednets, unmatchedcomps, symgroupcount;
3931 CHAR uniquename[30];
3932 float sizew, sizel;
3933 REGISTER NODEINST *ni;
3934 NODEPROTO *localcell[2];
3935 REGISTER ARCINST *ai;
3936 NODEINST *nis[2];
3937 REGISTER VARIABLE *var, *var0, *var1;
3938
3939 /* determine the number of unmatched nets and components */
3940 net_unmatchedstatus(&unmatchednets, &unmatchedcomps, &symgroupcount);
3941
3942 /* prepare a list of ambiguous symmetry groups */
3943 total = 0;
3944 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
3945 {
3946 if (sg->hashvalue == 0) continue;
3947 #ifdef NEWNCC
3948 if (sg->cellcount[0] < 2 && sg->cellcount[1] < 2) continue;
3949 #else
3950 if (sg->cellcount[0] < 2 || sg->cellcount[1] < 2) continue;
3951 #endif
3952 total++;
3953 }
3954 if (total > net_symgrouplisttotal)
3955 {
3956 if (net_symgrouplisttotal > 0) efree((CHAR *)net_symgrouplist);
3957 net_symgrouplisttotal = 0;
3958 net_symgrouplist = (SYMGROUP **)emalloc(total * (sizeof (SYMGROUP *)),
3959 net_tool->cluster);
3960 if (net_symgrouplist == 0) return(0);
3961 net_symgrouplisttotal = total;
3962 }
3963 total = 0;
3964 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
3965 {
3966 if (sg->hashvalue == 0) continue;
3967 #ifdef NEWNCC
3968 if (sg->cellcount[0] < 2 && sg->cellcount[1] < 2) continue;
3969 #else
3970 if (sg->cellcount[0] < 2 || sg->cellcount[1] < 2) continue;
3971 #endif
3972 net_symgrouplist[total++] = sg;
3973 }
3974
3975 /* sort by size of ambiguity */
3976 esort(net_symgrouplist, total, sizeof (SYMGROUP *), net_sortsymgroups);
3977
3978 /* now look through the groups, starting with the smallest */
3979 for(i=0; i<total; i++)
3980 {
3981 sg = net_symgrouplist[i];
3982
3983 if (sg->grouptype == SYMGROUPNET)
3984 {
3985 /* look for export names that are the same */
3986 if (net_findexportnamematch(sg, verbose, ignorepwrgnd,
3987 symgroupcount, unmatchednets, unmatchedcomps)) return(-1);
3988
3989 /* look for network names that are the same */
3990 if (net_findnetworknamematch(sg, FALSE, verbose, ignorepwrgnd,
3991 symgroupcount, unmatchednets, unmatchedcomps)) return(-1);
3992 } else
3993 {
3994 /* look for nodes that are uniquely the same size */
3995 if (net_findcommonsizefactor(sg, &sizew, &sizel))
3996 {
3997 ttyputmsg(_("--- Forcing a match based on size %s nodes (%ld symmetry groups with %ld nets and %ld nodes unmatched)"),
3998 net_describesizefactor(sizew, sizel), symgroupcount, unmatchednets, unmatchedcomps);
3999 net_forceamatch(sg, 0, 0, 0, 0, sizew, sizel, verbose, ignorepwrgnd);
4000 return(1);
4001 }
4002
4003 /* look for node names that are the same */
4004 if (net_findcomponentnamematch(sg, FALSE, verbose, ignorepwrgnd,
4005 symgroupcount, unmatchednets, unmatchedcomps)) return(1);
4006 }
4007 }
4008
4009 /* now look for pseudo-matches with the "NCCMatch" tags */
4010 for(i=0; i<total; i++)
4011 {
4012 sg = net_symgrouplist[i];
4013
4014 if (sg->grouptype == SYMGROUPNET)
4015 {
4016 /* look for network names that are the same */
4017 if (net_findnetworknamematch(sg, TRUE, verbose, ignorepwrgnd,
4018 symgroupcount, unmatchednets, unmatchedcomps)) return(-1);
4019 } else
4020 {
4021 /* look for node names that are the same */
4022 if (net_findcomponentnamematch(sg, TRUE, verbose, ignorepwrgnd,
4023 symgroupcount, unmatchednets, unmatchedcomps)) return(1);
4024 }
4025 }
4026
4027 /* random match: look again through the groups, starting with the smallest */
4028 for(i=0; i<total; i++)
4029 {
4030 sg = net_symgrouplist[i];
4031 if (sg->cellcount[0] <= 0 || sg->cellcount[1] <= 0) continue;
4032
4033 if (sg->grouptype == SYMGROUPCOMP)
4034 {
4035 for(f=0; f<2; f++)
4036 {
4037 for(is[f]=0; is[f] < sg->cellcount[f]; is[f]++)
4038 {
4039 pc = (PCOMP *)sg->celllist[f][is[f]];
4040 if (pc->numactual == 1) nis[f] = (NODEINST *)pc->actuallist; else
4041 nis[f] = ((NODEINST **)pc->actuallist)[0];
4042 var = getvalkey((INTBIG)nis[f], VNODEINST, VSTRING, el_node_name_key);
4043 if (var == NOVARIABLE) break;
4044 if ((var->type&VDISPLAY) == 0) break;
4045 }
4046 if (is[f] >= sg->cellcount[f])
4047 {
4048 is[f] = 0;
4049 pc = (PCOMP *)sg->celllist[f][is[f]];
4050 if (pc->numactual == 1) nis[f] = (NODEINST *)pc->actuallist; else
4051 nis[f] = ((NODEINST **)pc->actuallist)[0];
4052 }
4053 }
4054
4055 /* copy "NCCMatch" information if possible */
4056 localcell[0] = nis[0]->parent;
4057 localcell[1] = nis[1]->parent;
4058 var0 = getvalkey((INTBIG)nis[0], VNODEINST, VSTRING, net_ncc_matchkey);
4059 var1 = getvalkey((INTBIG)nis[1], VNODEINST, VSTRING, net_ncc_matchkey);
4060 if (var0 != NOVARIABLE && var1 != NOVARIABLE)
4061 {
4062 /* both have a name: warn if different */
4063 if (namesame((CHAR *)var0->addr, (CHAR *)var1->addr) != 0)
4064 {
4065 ttyputmsg(x_("WARNING: want to match nodes %s:s and %s:%s but they are already tagged '%s' and '%s'"),
4066 describenodeproto(localcell[0]), describenodeinst(nis[0]),
4067 describenodeproto(localcell[1]), describenodeinst(nis[1]),
4068 (CHAR *)var0->addr, (CHAR *)var1->addr);
4069 }
4070 var0 = var1 = NOVARIABLE;
4071 }
4072 if (var0 == NOVARIABLE && var1 != NOVARIABLE)
4073 {
4074 /* node in cell 0 has no name, see if it can take the name from cell 1 */
4075 estrcpy(uniquename, (CHAR *)var1->addr);
4076 for(ni = localcell[0]->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
4077 {
4078 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, net_ncc_matchkey);
4079 if (var == NOVARIABLE) continue;
4080 if (namesame((CHAR *)var->addr, uniquename) == 0) break;
4081 }
4082 if (ni != NONODEINST) var1 = NOVARIABLE; else
4083 {
4084 /* copy from cell 1 to cell 0 */
4085 startobjectchange((INTBIG)nis[0], VNODEINST);
4086 newtype = VSTRING;
4087 if ((net_ncc_options&NCCHIDEMATCHTAGS) == 0) newtype |= VDISPLAY;
4088 var = setvalkey((INTBIG)nis[0], VNODEINST, net_ncc_matchkey,
4089 (INTBIG)uniquename, newtype);
4090 if (var != NOVARIABLE)
4091 defaulttextsize(3, var->textdescript);
4092 endobjectchange((INTBIG)nis[0], VNODEINST);
4093 }
4094 }
4095 if (var0 != NOVARIABLE && var1 == NOVARIABLE)
4096 {
4097 /* node in cell 1 has no name, see if it can take the name from cell 0 */
4098 estrcpy(uniquename, (CHAR *)var0->addr);
4099 for(ni = localcell[1]->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
4100 {
4101 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, net_ncc_matchkey);
4102 if (var == NOVARIABLE) continue;
4103 if (namesame((CHAR *)var->addr, uniquename) == 0) break;
4104 }
4105 if (ni != NONODEINST) var0 = NOVARIABLE; else
4106 {
4107 /* copy from cell 0 to cell 1 */
4108 startobjectchange((INTBIG)nis[1], VNODEINST);
4109 newtype = VSTRING;
4110 if ((net_ncc_options&NCCHIDEMATCHTAGS) == 0) newtype |= VDISPLAY;
4111 var = setvalkey((INTBIG)nis[1], VNODEINST, net_ncc_matchkey,
4112 (INTBIG)uniquename, newtype);
4113 if (var != NOVARIABLE)
4114 defaulttextsize(3, var->textdescript);
4115 endobjectchange((INTBIG)nis[1], VNODEINST);
4116 }
4117 }
4118 if (var0 == NOVARIABLE && var1 == NOVARIABLE)
4119 {
4120 /* neither has a name: find a unique name and tag the selected nodes */
4121 for(u=1; ; u++)
4122 {
4123 esnprintf(uniquename, 30, x_("NCCmatch%ld"), u);
4124 for(f=0; f<2; f++)
4125 {
4126 for(ni = localcell[f]->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
4127 {
4128 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, net_ncc_matchkey);
4129 if (var == NOVARIABLE) continue;
4130 if (namesame((CHAR *)var->addr, uniquename) == 0) break;
4131 }
4132 if (ni != NONODEINST) break;
4133 }
4134 if (f >= 2) break;
4135 }
4136 for(f=0; f<2; f++)
4137 {
4138 startobjectchange((INTBIG)nis[f], VNODEINST);
4139 newtype = VSTRING;
4140 if ((net_ncc_options&NCCHIDEMATCHTAGS) == 0) newtype |= VDISPLAY;
4141 var = setvalkey((INTBIG)nis[f], VNODEINST, net_ncc_matchkey,
4142 (INTBIG)uniquename, newtype);
4143 if (var != NOVARIABLE)
4144 defaulttextsize(3, var->textdescript);
4145 endobjectchange((INTBIG)nis[f], VNODEINST);
4146 }
4147 }
4148 if ((net_ncc_options&NCCSUPALLAMBREP) == 0)
4149 {
4150 ttyputmsg(_("--- Forcing a random match of nodes '%s:%s' and '%s:%s', called %s (%ld symmetry groups with %ld nets and %ld nodes unmatched)"),
4151 describenodeproto(localcell[0]), describenodeinst(nis[0]),
4152 describenodeproto(localcell[1]), describenodeinst(nis[1]),
4153 uniquename, symgroupcount, unmatchednets, unmatchedcomps);
4154 }
4155 net_forceamatch(sg, 1, &is[0], 1, &is[1], 0.0, 0.0, verbose, ignorepwrgnd);
4156 return(1);
4157 } else
4158 {
4159 /* look for any ambiguous networks and randomly match them */
4160 for(f=0; f<2; f++)
4161 {
4162 any = -1;
4163 for(is[f]=0; is[f] < sg->cellcount[f]; is[f]++)
4164 {
4165 pn = (PNET *)sg->celllist[f][is[f]];
4166 nets[f] = pn->network;
4167 if (nets[f] == NONETWORK) continue;
4168 any = is[f];
4169 if (nets[f]->namecount == 0 ||
4170 nets[f]->tempname != 0) break;
4171 }
4172 if (is[f] >= sg->cellcount[f])
4173 {
4174 if (any < 0) nets[f] = NONETWORK; else
4175 {
4176 is[f] = any;
4177 pn = (PNET *)sg->celllist[f][any];
4178 nets[f] = pn->network;
4179 }
4180 }
4181 }
4182 if (nets[0] != NONETWORK && nets[1] != NONETWORK)
4183 {
4184 /* find a unique name and tag the selected networks */
4185 for(u=1; ; u++)
4186 {
4187 esnprintf(uniquename, 30, x_("NCCmatch%ld"), u);
4188 for(f=0; f<2; f++)
4189 {
4190 for(ai = nets[f]->parent->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
4191 {
4192 var = getvalkey((INTBIG)ai, VARCINST, VSTRING, net_ncc_matchkey);
4193 if (var == NOVARIABLE) continue;
4194 if (namesame(uniquename, (CHAR *)var->addr) == 0) break;
4195 }
4196 if (ai != NOARCINST) break;
4197 }
4198 if (f >= 2) break;
4199 }
4200 for(f=0; f<2; f++)
4201 {
4202 for(ai = nets[f]->parent->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
4203 {
4204 if (ai->network != nets[f]) continue;
4205 startobjectchange((INTBIG)ai, VARCINST);
4206 newtype = VSTRING;
4207 if ((net_ncc_options&NCCHIDEMATCHTAGS) == 0) newtype |= VDISPLAY;
4208 var = setvalkey((INTBIG)ai, VARCINST, net_ncc_matchkey,
4209 (INTBIG)uniquename, newtype);
4210 if (var != NOVARIABLE)
4211 defaulttextsize(4, var->textdescript);
4212 endobjectchange((INTBIG)ai, VARCINST);
4213
4214 /* pickup new net number and remember it in the data structures */
4215 for(osg = net_firstsymgroup; osg != NOSYMGROUP; osg = osg->nextsymgroup)
4216 {
4217 if (osg->grouptype == SYMGROUPCOMP) continue;
4218 for(i=0; i<osg->cellcount[f]; i++)
4219 {
4220 pn = (PNET *)osg->celllist[f][i];
4221 if (pn->network == nets[f])
4222 pn->network = ai->network;
4223 }
4224 }
4225 nets[f] = ai->network;
4226 break;
4227 }
4228 }
4229
4230 if ((net_ncc_options&NCCSUPALLAMBREP) == 0)
4231 {
4232 ttyputmsg(_("--- Forcing a random match of networks '%s' in cells %s and %s (%ld symmetry groups with %ld nets and %ld nodes unmatched)"),
4233 uniquename, describenodeproto(nets[0]->parent), describenodeproto(nets[1]->parent),
4234 symgroupcount, unmatchednets, unmatchedcomps);
4235 }
4236 net_forceamatch(sg, 1, &is[0], 1, &is[1], 0.0, 0.0, verbose, ignorepwrgnd);
4237 return(-1);
4238 }
4239 }
4240 }
4241
4242 return(0);
4243 }
4244
4245 /*
4246 * Routine to look through ambiguous symmetry group "sg" for export names that cause a match.
4247 * If one is found, it is reported and matched and the routine returns true.
4248 * Flags "verbose" and "ignorepwrgnd" apply to the match. Tallys "total", "unmatchednets",
4249 * and "unmatchedcomps" are reported.
4250 */
net_findexportnamematch(SYMGROUP * sg,INTBIG verbose,BOOLEAN ignorepwrgnd,INTBIG total,INTBIG unmatchednets,INTBIG unmatchedcomps)4251 BOOLEAN net_findexportnamematch(SYMGROUP *sg, INTBIG verbose, BOOLEAN ignorepwrgnd,
4252 INTBIG total, INTBIG unmatchednets, INTBIG unmatchedcomps)
4253 {
4254 REGISTER INTBIG f, i0, i1, i, ip, i0base, i1base, comp;
4255 INTBIG count[2];
4256 REGISTER PNET *pn;
4257 REGISTER PORTPROTO *pp;
4258
4259 /* build a list of all export names */
4260 for(f=0; f<2; f++)
4261 {
4262 count[f] = 0;
4263 for(i=0; i<sg->cellcount[f]; i++)
4264 {
4265 pn = (PNET *)sg->celllist[f][i];
4266 for(ip=0; ip<pn->realportcount; ip++)
4267 {
4268 if (pn->realportcount == 1) pp = (PORTPROTO *)pn->realportlist; else
4269 pp = ((PORTPROTO **)pn->realportlist)[ip];
4270 net_addtonamematch(&net_namematch[f], &net_namematchtotal[f], &count[f],
4271 pp->protoname, i, NONODEINST);
4272 }
4273 }
4274 esort(net_namematch[f], count[f], sizeof(NAMEMATCH), net_sortnamematches);
4275 }
4276
4277 /* now look for unique matches */
4278 i0 = i1 = 0;
4279 for(;;)
4280 {
4281 if (i0 >= count[0] || i1 >= count[1]) break;
4282 comp = namesame(net_namematch[0][i0].name, net_namematch[1][i1].name);
4283 i0base = i0; i1base = i1;
4284 while (i0+1 < count[0] &&
4285 namesame(net_namematch[0][i0].name, net_namematch[0][i0+1].name) == 0)
4286 i0++;
4287 while (i1+1 < count[1] &&
4288 namesame(net_namematch[1][i1].name, net_namematch[1][i1+1].name) == 0)
4289 i1++;
4290 if (comp == 0)
4291 {
4292 if (i0 == i0base && i1 == i1base)
4293 {
4294 /* found a unique match */
4295 ttyputmsg(_("--- Forcing a match based on the export name '%s' (%ld symmetry groups with %ld nets and %ld nodes unmatched)"),
4296 net_namematch[0][i0].name, total, unmatchednets, unmatchedcomps);
4297 net_forceamatch(sg, 1, &net_namematch[0][i0].number, 1, &net_namematch[1][i1].number,
4298 0.0, 0.0, verbose, ignorepwrgnd);
4299 return(TRUE);
4300 }
4301 i0++; i1++;
4302 } else
4303 {
4304 if (comp < 0) i0++; else i1++;
4305 }
4306 }
4307 return(FALSE);
4308 }
4309
net_findpowerandgroundmatch(SYMGROUP * sg,INTBIG verbose,INTBIG total,INTBIG unmatchednets,INTBIG unmatchedcomps)4310 BOOLEAN net_findpowerandgroundmatch(SYMGROUP *sg, INTBIG verbose, INTBIG total, INTBIG unmatchednets, INTBIG unmatchedcomps)
4311 {
4312 REGISTER INTBIG f, i, power[2], ground[2];
4313 REGISTER PNET *pn;
4314
4315 power[0] = power[1] = ground[0] = ground[1] = -1;
4316 for(f=0; f<2; f++)
4317 {
4318 for(i=0; i<sg->cellcount[f]; i++)
4319 {
4320 pn = (PNET *)sg->celllist[f][i];
4321 if ((pn->flags&POWERNET) != 0)
4322 {
4323 if (power[f] == -1) power[f] = i; else power[f] = -2;
4324 }
4325 if ((pn->flags&GROUNDNET) != 0)
4326 {
4327 if (ground[f] == -1) ground[f] = i; else ground[f] = -2;
4328 }
4329 }
4330 }
4331
4332 /* if there is exactly 1 power net in each side, disambiguate it */
4333 if (power[0] >= 0 && power[1] >= 0)
4334 {
4335 /* found a unique match */
4336 ttyputmsg(_("--- Forcing a match based on the power characteristic (%ld symmetry groups with %ld nets and %ld nodes unmatched)"),
4337 total, unmatchednets, unmatchedcomps);
4338 net_forceamatch(sg, 1, &power[0], 1, &power[1], 0.0, 0.0, verbose, FALSE);
4339 return(TRUE);
4340 }
4341
4342 /* if there is exactly 1 ground net in each side, disambiguate it */
4343 if (ground[0] >= 0 && ground[1] >= 0)
4344 {
4345 /* found a unique match */
4346 ttyputmsg(_("--- Forcing a match based on the ground characteristic (%ld symmetry groups with %ld nets and %ld nodes unmatched)"),
4347 total, unmatchednets, unmatchedcomps);
4348 net_forceamatch(sg, 1, &ground[0], 1, &ground[1], 0.0, 0.0, verbose, FALSE);
4349 return(TRUE);
4350 }
4351 return(FALSE);
4352 }
4353
4354 /*
4355 * Routine to look through ambiguous symmetry group "sg" for network names that cause a match.
4356 * If one is found, it is reported and matched and the routine returns true.
4357 * If "usenccmatches" is true, allow "NCCMatch" tags.
4358 * If "allowpseudonames" is zero and such names are found, the routine returns true.
4359 * Flags "verbose" and "ignorepwrgnd" apply to the match. Tallys "total", "unmatchednets",
4360 * and "unmatchedcomps" are reported.
4361 */
net_findnetworknamematch(SYMGROUP * sg,BOOLEAN usenccmatches,INTBIG verbose,BOOLEAN ignorepwrgnd,INTBIG total,INTBIG unmatchednets,INTBIG unmatchedcomps)4362 BOOLEAN net_findnetworknamematch(SYMGROUP *sg, BOOLEAN usenccmatches, INTBIG verbose,
4363 BOOLEAN ignorepwrgnd, INTBIG total, INTBIG unmatchednets, INTBIG unmatchedcomps)
4364 {
4365 REGISTER INTBIG i0, i1, i, ip, f, comp, i0base, i1base;
4366 INTBIG count[2];
4367 REGISTER BOOLEAN foundexport;
4368 REGISTER PNET *pn;
4369 REGISTER VARIABLE *var;
4370 REGISTER ARCINST *ai;
4371 REGISTER NETWORK *net;
4372 REGISTER CHAR *netname;
4373
4374 /* build a list of all network names */
4375 foundexport = FALSE;
4376 for(f=0; f<2; f++)
4377 {
4378 count[f] = 0;
4379 for(i=0; i<sg->cellcount[f]; i++)
4380 {
4381 pn = (PNET *)sg->celllist[f][i];
4382 net = pn->network;
4383 if (net == NONETWORK) continue;
4384 if ((pn->flags&EXPORTEDNET) != 0) foundexport = TRUE;
4385 if (usenccmatches)
4386 {
4387 for(ai = net_cell[f]->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
4388 {
4389 if (ai->network != net) continue;
4390 var = getvalkey((INTBIG)ai, VARCINST, VSTRING, net_ncc_matchkey);
4391 if (var == NOVARIABLE) continue;
4392 net_addtonamematch(&net_namematch[f], &net_namematchtotal[f], &count[f],
4393 (CHAR *)var->addr, i, NONODEINST);
4394 }
4395 } else
4396 {
4397 if (net->namecount == 0 || net->tempname != 0) continue;
4398 for(ip=0; ip<net->namecount; ip++)
4399 {
4400 netname = networkname(net, ip);
4401 net_addtonamematch(&net_namematch[f], &net_namematchtotal[f], &count[f],
4402 netname, i, NONODEINST);
4403 }
4404 }
4405 }
4406 esort(net_namematch[f], count[f], sizeof(NAMEMATCH), net_sortnamematches);
4407 }
4408
4409 /* now look for unique matches */
4410 i0 = i1 = 0;
4411 for(;;)
4412 {
4413 if (i0 >= count[0] || i1 >= count[1]) break;
4414 comp = namesame(net_namematch[0][i0].name, net_namematch[1][i1].name);
4415 i0base = i0; i1base = i1;
4416 while (i0+1 < count[0] &&
4417 namesame(net_namematch[0][i0].name, net_namematch[0][i0+1].name) == 0)
4418 i0++;
4419 while (i1+1 < count[1] &&
4420 namesame(net_namematch[1][i1].name, net_namematch[1][i1+1].name) == 0)
4421 i1++;
4422 if (comp == 0)
4423 {
4424 if (i0 == i0base && i1 == i1base)
4425 {
4426 /* found a unique match */
4427 if ((net_ncc_options&NCCSUPALLAMBREP) == 0 || foundexport)
4428 {
4429 ttyputmsg(_("--- Forcing a match based on the network name '%s' (%ld symmetry groups with %ld nets and %ld nodes unmatched)"),
4430 net_namematch[0][i0].name, total, unmatchednets, unmatchedcomps);
4431 }
4432 net_forceamatch(sg, 1, &net_namematch[0][i0].number, 1, &net_namematch[1][i1].number,
4433 0.0, 0.0, verbose, ignorepwrgnd);
4434 return(TRUE);
4435 }
4436 i0++; i1++;
4437 } else
4438 {
4439 if (comp < 0) i0++; else i1++;
4440 }
4441 }
4442
4443 /* no unique name found */
4444 return(FALSE);
4445 }
4446
4447 /*
4448 * Routine to look through ambiguous symmetry group "sg" for component names that cause a match.
4449 * If one is found, it is reported and matched and the routine returns true.
4450 * If "usenccmatches" is true, use "NCCMatch" tags.
4451 * If "allowpseudonames" is zero and such names are found, the routine returns true.
4452 * Flags "verbose" and "ignorepwrgnd" apply to the match. Tallys "total", "unmatchednets",
4453 * and "unmatchedcomps" are reported.
4454 */
net_findcomponentnamematch(SYMGROUP * sg,BOOLEAN usenccmatches,INTBIG verbose,BOOLEAN ignorepwrgnd,INTBIG total,INTBIG unmatchednets,INTBIG unmatchedcomps)4455 BOOLEAN net_findcomponentnamematch(SYMGROUP *sg, BOOLEAN usenccmatches,
4456 INTBIG verbose, BOOLEAN ignorepwrgnd, INTBIG total, INTBIG unmatchednets, INTBIG unmatchedcomps)
4457 {
4458 REGISTER INTBIG i0, i1, i0base, i1base, i, j, f, comp, i0ptr, i1ptr;
4459 INTBIG count[2];
4460 REGISTER PCOMP *pc;
4461 REGISTER NODEINST *ni;
4462 REGISTER VARIABLE *var;
4463
4464 /* build a list of all component names */
4465 for(f=0; f<2; f++)
4466 {
4467 count[f] = 0;
4468 for(i=0; i<sg->cellcount[f]; i++)
4469 {
4470 pc = (PCOMP *)sg->celllist[f][i];
4471 if (pc->numactual != 1) continue;
4472 ni = (NODEINST *)pc->actuallist;
4473 if (usenccmatches)
4474 {
4475 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, net_ncc_matchkey);
4476 if (var == NOVARIABLE) continue;
4477 net_addtonamematch(&net_namematch[f], &net_namematchtotal[f], &count[f],
4478 (CHAR *)var->addr, i, ni);
4479 } else
4480 {
4481 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
4482 if (var != NOVARIABLE)
4483 {
4484 if ((var->type&VDISPLAY) != 0)
4485 {
4486 net_addtonamematch(&net_namematch[f], &net_namematchtotal[f], &count[f],
4487 (CHAR *)var->addr, i, ni);
4488 }
4489 }
4490 }
4491 }
4492 esort(net_namematch[f], count[f], sizeof(NAMEMATCH), net_sortnamematches);
4493 }
4494
4495 /* now look for unique matches */
4496 i0 = i1 = 0;
4497 i0ptr = i1ptr = 0;
4498 for(;;)
4499 {
4500 if (i0 >= count[0] || i1 >= count[1]) break;
4501 comp = namesame(net_namematch[0][i0].name, net_namematch[1][i1].name);
4502 if (comp == 0)
4503 {
4504 /* gather all with the same name */
4505 i0base = i0; i1base = i1;
4506 while (i0+1 < count[0] &&
4507 namesame(net_namematch[0][i0].name, net_namematch[0][i0+1].name) == 0)
4508 i0++;
4509 while (i1+1 < count[1] &&
4510 namesame(net_namematch[1][i1].name, net_namematch[1][i1+1].name) == 0)
4511 i1++;
4512
4513 /* make a list of entries from cell 0 */
4514 j = i0 - i0base + 1;
4515 if (j >= net_compmatch0total)
4516 {
4517 if (net_compmatch0total > 0) efree((CHAR *)net_compmatch0list);
4518 net_compmatch0total = 0;
4519 net_compmatch0list = (INTBIG *)emalloc(j * SIZEOFINTBIG, net_tool->cluster);
4520 if (net_compmatch0list == 0) return(FALSE);
4521 net_compmatch0total = j;
4522 }
4523 i0ptr = 0;
4524 for(i=i0base; i<=i0; i++)
4525 net_compmatch0list[i0ptr++] = net_namematch[0][i].number;
4526 esort(net_compmatch0list, i0ptr, SIZEOFINTBIG, sort_intbigdescending);
4527 j = 0; for(i=0; i<i0ptr; i++)
4528 {
4529 if (i == 0 || net_compmatch0list[i-1] != net_compmatch0list[i])
4530 net_compmatch0list[j++] = net_compmatch0list[i];
4531 }
4532 i0ptr = j;
4533
4534 /* make a list of entries from cell 1 */
4535 j = i1 - i1base + 1;
4536 if (j >= net_compmatch1total)
4537 {
4538 if (net_compmatch1total > 0) efree((CHAR *)net_compmatch1list);
4539 net_compmatch1total = 0;
4540 net_compmatch1list = (INTBIG *)emalloc(j * SIZEOFINTBIG, net_tool->cluster);
4541 if (net_compmatch1list == 0) return(FALSE);
4542 net_compmatch1total = j;
4543 }
4544 i1ptr = 0;
4545 for(i=i1base; i<=i1; i++)
4546 net_compmatch1list[i1ptr++] = net_namematch[1][i].number;
4547 esort(net_compmatch1list, i1ptr, SIZEOFINTBIG, sort_intbigdescending);
4548 j = 0; for(i=0; i<i1ptr; i++)
4549 {
4550 if (i == 0 || net_compmatch1list[i-1] != net_compmatch1list[i])
4551 net_compmatch1list[j++] = net_compmatch1list[i];
4552 }
4553 i1ptr = j;
4554 if (i0ptr != 0 && i1ptr != 0 && i0ptr != sg->cellcount[0] && i1ptr != sg->cellcount[1])
4555 {
4556 /* found a unique match */
4557 if ((net_ncc_options&NCCSUPALLAMBREP) == 0)
4558 {
4559 ttyputmsg(_("--- Forcing a match based on the nodes named '%s' in cells %s and %s (%ld symmetry groups with %ld nets and %ld nodes unmatched)"),
4560 net_namematch[0][i0].name, describenodeproto(net_namematch[0][i0].original->parent),
4561 describenodeproto(net_namematch[1][i1].original->parent), total,
4562 unmatchednets, unmatchedcomps);
4563 }
4564 net_forceamatch(sg, i0ptr, net_compmatch0list, i1ptr, net_compmatch1list,
4565 0.0, 0.0, verbose, ignorepwrgnd);
4566 return(TRUE);
4567 }
4568 i0++; i1++;
4569 } else
4570 {
4571 if (comp < 0) i0++; else i1++;
4572 }
4573 }
4574
4575 /* no unique name found */
4576 return(FALSE);
4577 }
4578
4579 /*
4580 * Helper routine to build the list of names.
4581 */
net_addtonamematch(NAMEMATCH ** match,INTBIG * total,INTBIG * count,CHAR * name,INTBIG number,NODEINST * orig)4582 void net_addtonamematch(NAMEMATCH **match, INTBIG *total, INTBIG *count,
4583 CHAR *name, INTBIG number, NODEINST *orig)
4584 {
4585 REGISTER INTBIG i, newtotal;
4586 REGISTER NAMEMATCH *newmatch;
4587
4588 if (*count >= *total)
4589 {
4590 newtotal = *total * 2;
4591 if (newtotal <= *count) newtotal = *count + 25;
4592 newmatch = (NAMEMATCH *)emalloc(newtotal * (sizeof (NAMEMATCH)), net_tool->cluster);
4593 if (newmatch == 0) return;
4594 for(i=0; i < *count; i++)
4595 {
4596 newmatch[i].name = (*match)[i].name;
4597 newmatch[i].number = (*match)[i].number;
4598 newmatch[i].original = (*match)[i].original;
4599 }
4600 if (*total > 0) efree((CHAR *)*match);
4601 *match = newmatch;
4602 *total = newtotal;
4603 }
4604 (*match)[*count].name = name;
4605 (*match)[*count].number = number;
4606 (*match)[*count].original = orig;
4607 (*count)++;
4608 }
4609
4610 /*
4611 * Helper routine to sort the list of names.
4612 */
net_sortnamematches(const void * e1,const void * e2)4613 int net_sortnamematches(const void *e1, const void *e2)
4614 {
4615 REGISTER NAMEMATCH *nm1, *nm2;
4616
4617 nm1 = (NAMEMATCH *)e1;
4618 nm2 = (NAMEMATCH *)e2;
4619 return(namesame(nm1->name, nm2->name));
4620 }
4621
net_sortsymgroups(const void * e1,const void * e2)4622 int net_sortsymgroups(const void *e1, const void *e2)
4623 {
4624 REGISTER SYMGROUP *sg1, *sg2;
4625 REGISTER INTBIG sg1size, sg2size;
4626
4627 sg1 = *((SYMGROUP **)e1);
4628 sg2 = *((SYMGROUP **)e2);
4629 sg1size = sg1->cellcount[0] + sg1->cellcount[1];
4630 sg2size = sg2->cellcount[0] + sg2->cellcount[1];
4631 #ifdef NEWNCC
4632 if (sg1->hashvalue == 0 || (sg1->cellcount[0] < 2 && sg1->cellcount[1] < 2)) sg1size = 0;
4633 if (sg2->hashvalue == 0 || (sg2->cellcount[0] < 2 && sg2->cellcount[1] < 2)) sg2size = 0;
4634 #else
4635 if (sg1->hashvalue == 0 || sg1->cellcount[0] < 2 || sg1->cellcount[1] < 2) sg1size = 0;
4636 if (sg2->hashvalue == 0 || sg2->cellcount[0] < 2 || sg2->cellcount[1] < 2) sg2size = 0;
4637 #endif
4638 return(sg1size - sg2size);
4639 }
4640
net_sortpcomp(const void * e1,const void * e2)4641 int net_sortpcomp(const void *e1, const void *e2)
4642 {
4643 REGISTER PCOMP *pc1, *pc2;
4644 REGISTER CHAR *pt1, *pt2;
4645
4646 pc1 = *((PCOMP **)e1);
4647 pc2 = *((PCOMP **)e2);
4648 if (pc2->wirecount != pc1->wirecount)
4649 return(pc2->wirecount - pc1->wirecount);
4650 pt1 = pc1->hashreason;
4651 pt2 = pc2->hashreason;
4652 return(namesame(pt1, pt2));
4653 }
4654
net_sortpnet(const void * e1,const void * e2)4655 int net_sortpnet(const void *e1, const void *e2)
4656 {
4657 REGISTER PNET *pn1, *pn2;
4658 REGISTER NETWORK *net1, *net2;
4659 REGISTER NODEPROTO *cell1, *cell2;
4660 REGISTER INTBIG un1, un2;
4661
4662 pn1 = *((PNET **)e1);
4663 pn2 = *((PNET **)e2);
4664 if (pn2->nodecount != pn1->nodecount)
4665 return(pn2->nodecount - pn1->nodecount);
4666 un1 = un2 = 0;
4667 if ((pn1->flags&(POWERNET|GROUNDNET|EXPORTEDNET)) == 0 &&
4668 (pn1->network == NONETWORK || pn1->network->namecount == 0)) un1 = 1;
4669 if ((pn2->flags&(POWERNET|GROUNDNET|EXPORTEDNET)) == 0 &&
4670 (pn2->network == NONETWORK || pn2->network->namecount == 0)) un2 = 1;
4671 if (un1 == 0 && un2 == 0)
4672 {
4673 return(namesame(net_describepnet(pn1), net_describepnet(pn2)));
4674 }
4675 if (un1 != 0 && un2 != 0)
4676 {
4677 net1 = pn1->network;
4678 net2 = pn2->network;
4679 if (net1 != NONETWORK && net2 != NONETWORK)
4680 {
4681 cell1 = net1->parent;
4682 cell2 = net2->parent;
4683 return(namesame(cell1->protoname, cell2->protoname));
4684 }
4685 return(0);
4686 }
4687 return(un1 - un2);
4688 }
4689
4690 /*
4691 * Routine to search symmetry group "sg" for a size factor that will distinguish part of
4692 * the group. Returns true if a distinguishing size is found (and places it in "sizew" and
4693 * "sizel").
4694 */
net_findcommonsizefactor(SYMGROUP * sg,float * sizew,float * sizel)4695 BOOLEAN net_findcommonsizefactor(SYMGROUP *sg, float *sizew, float *sizel)
4696 {
4697 REGISTER INTBIG i, j, f, newtotal, p0, p1, bestind0, bestind1;
4698 INTBIG sizearraycount[2];
4699 REGISTER PCOMP *pc;
4700 REGISTER NODESIZE *newnodesizes, *ns0, *ns1;
4701 REGISTER BOOLEAN firsttime;
4702 float diff, bestdiff, wantlength, wantwidth;
4703
4704 for(f=0; f<2; f++)
4705 {
4706 sizearraycount[f] = 0;
4707 for(i=0; i<sg->cellcount[f]; i++)
4708 {
4709 pc = (PCOMP *)sg->celllist[f][i];
4710 if ((pc->flags&(COMPHASWIDLEN|COMPHASAREA)) == 0) continue;
4711 if (sizearraycount[f] >= net_sizearraytotal[f])
4712 {
4713 newtotal = net_sizearraytotal[f] * 2;
4714 if (sizearraycount[f] >= newtotal) newtotal = sizearraycount[f] + 20;
4715 newnodesizes = (NODESIZE *)emalloc(newtotal * (sizeof (NODESIZE)), net_tool->cluster);
4716 if (newnodesizes == 0) return(FALSE);
4717 for(j=0; j<sizearraycount[f]; j++)
4718 newnodesizes[j] = net_sizearray[f][j];
4719 if (net_sizearraytotal[f] > 0) efree((CHAR *)net_sizearray[f]);
4720 net_sizearray[f] = newnodesizes;
4721 net_sizearraytotal[f] = newtotal;
4722 }
4723 j = sizearraycount[f]++;
4724 if ((pc->flags&COMPHASWIDLEN) != 0)
4725 {
4726 net_sizearray[f][j].length = pc->length;
4727 net_sizearray[f][j].width = pc->width;
4728 } else
4729 {
4730 net_sizearray[f][j].length = pc->length;
4731 net_sizearray[f][j].width = 0.0;
4732 }
4733 }
4734 if (sizearraycount[f] > 0)
4735 esort(net_sizearray[f], sizearraycount[f], sizeof (NODESIZE), net_sortsizearray);
4736 }
4737
4738 /* now find the two values that are closest */
4739 p0 = p1 = bestind0 = bestind1 = 0;
4740 firsttime = TRUE;
4741 for(;;)
4742 {
4743 if (p0 >= sizearraycount[0]) break;
4744 if (p1 >= sizearraycount[1]) break;
4745
4746 ns0 = &net_sizearray[0][p0];
4747 ns1 = &net_sizearray[1][p1];
4748 diff = (float)(fabs(ns0->length-ns1->length) + fabs(ns0->width-ns1->width));
4749 if (firsttime || diff < bestdiff)
4750 {
4751 bestdiff = diff;
4752 bestind0 = p0;
4753 bestind1 = p1;
4754 firsttime = FALSE;
4755 }
4756 if (ns0->length + ns0->width < ns1->length + ns1->width) p0++; else
4757 p1++;
4758 }
4759 if (firsttime) return(FALSE);
4760
4761 /* found the two closest values: see if they are indeed close */
4762 ns0 = &net_sizearray[0][bestind0];
4763 ns1 = &net_sizearray[1][bestind1];
4764 if (!net_componentequalvalue(ns0->length, ns1->length) ||
4765 !net_componentequalvalue(ns0->width, ns1->width)) return(FALSE);
4766 wantlength = (ns0->length + ns1->length) / 2.0f;
4767 wantwidth = (ns0->width + ns1->width) / 2.0f;
4768
4769 /* make sure these values distinguish */
4770 ns0 = &net_sizearray[0][0];
4771 ns1 = &net_sizearray[0][sizearraycount[0]-1];
4772 if (net_componentequalvalue(ns0->length, wantlength) &&
4773 net_componentequalvalue(ns1->length, wantlength) &&
4774 net_componentequalvalue(ns0->width, wantwidth) &&
4775 net_componentequalvalue(ns1->width, wantwidth)) return(FALSE);
4776 ns0 = &net_sizearray[1][0];
4777 ns1 = &net_sizearray[1][sizearraycount[1]-1];
4778 if (net_componentequalvalue(ns0->length, wantlength) &&
4779 net_componentequalvalue(ns1->length, wantlength) &&
4780 net_componentequalvalue(ns0->width, wantwidth) &&
4781 net_componentequalvalue(ns1->width, wantwidth)) return(FALSE);
4782
4783 /* return the size */
4784 *sizew = wantwidth;
4785 *sizel = wantlength;
4786 return(TRUE);
4787 }
4788
net_sortsizearray(const void * e1,const void * e2)4789 int net_sortsizearray(const void *e1, const void *e2)
4790 {
4791 REGISTER NODESIZE *ns1, *ns2;
4792 REGISTER float v1, v2;
4793
4794 ns1 = (NODESIZE *)e1;
4795 ns2 = (NODESIZE *)e2;
4796 v1 = ns1->length + ns1->width;
4797 v2 = ns2->length + ns2->width;
4798 if (floatsequal(v1, v2)) return(0);
4799 if (v1 < v2) return(-1);
4800 return(1);
4801 }
4802
4803 /*
4804 * Routine to force a match between parts of symmetry group "sg". If "sizefactorsplit" is
4805 * zero, then "c0" entries in "i0" in cell 0 and "c1" entries in "i1" in cell 1 are to be matched.
4806 * Otherwise, those components with size factor "sizew/sizel" are to be matched.
4807 */
net_forceamatch(SYMGROUP * sg,INTBIG c0,INTBIG * i0,INTBIG c1,INTBIG * i1,float sizew,float sizel,INTBIG verbose,BOOLEAN ignorepwrgnd)4808 void net_forceamatch(SYMGROUP *sg, INTBIG c0, INTBIG *i0, INTBIG c1, INTBIG *i1,
4809 float sizew, float sizel, INTBIG verbose, BOOLEAN ignorepwrgnd)
4810 {
4811 REGISTER SYMGROUP *sgnewc, *sgnewn;
4812 REGISTER HASHTYPE hashvalue;
4813 REGISTER BOOLEAN match;
4814 REGISTER PNET *pn, *pn0, *pn1;
4815 REGISTER PCOMP *pc, *pc0, *pc1;
4816 REGISTER INTBIG i, f, ind;
4817
4818 if (sg->grouptype == SYMGROUPCOMP)
4819 {
4820 hashvalue = net_uniquesymmetrygrouphash(SYMGROUPCOMP);
4821 sgnewc = net_newsymgroup(SYMGROUPCOMP, hashvalue, 0);
4822
4823 if (sizew == 0.0 && sizel == 0.0)
4824 {
4825 /* matching two like-named nodes */
4826 for(i=0; i<c0; i++)
4827 {
4828 ind = i0[i];
4829 pc0 = (PCOMP *)sg->celllist[0][ind];
4830 net_removefromsymgroup(sg, 0, ind);
4831 if (net_addtosymgroup(sgnewc, 0, (void *)pc0)) return;
4832 pc0->symgroup = sgnewc;
4833 pc0->hashvalue = hashvalue;
4834 if (verbose != 0)
4835 (void)reallocstring(&pc0->hashreason, x_("name matched"), net_tool->cluster);
4836 }
4837 for(i=0; i<c1; i++)
4838 {
4839 ind = i1[i];
4840 pc1 = (PCOMP *)sg->celllist[1][ind];
4841 net_removefromsymgroup(sg, 1, ind);
4842 if (net_addtosymgroup(sgnewc, 1, (void *)pc1)) return;
4843 pc1->symgroup = sgnewc;
4844 pc1->hashvalue = hashvalue;
4845 if (verbose != 0)
4846 (void)reallocstring(&pc1->hashreason, x_("name matched"), net_tool->cluster);
4847 }
4848 } else
4849 {
4850 /* matching nodes with size "sizefactor" */
4851 for(f=0; f<2; f++)
4852 {
4853 for(i=sg->cellcount[f]-1; i>=0; i--)
4854 {
4855 pc = (PCOMP *)sg->celllist[f][i];
4856 match = FALSE;
4857 if ((pc->flags&COMPHASWIDLEN) != 0)
4858 {
4859 if (net_componentequalvalue(sizew, pc->width) &&
4860 net_componentequalvalue(sizel, pc->length)) match = TRUE;
4861 } else
4862 {
4863 if (net_componentequalvalue(sizel, pc->length)) match = TRUE;
4864 }
4865 if (match)
4866 {
4867 net_removefromsymgroup(sg, f, i);
4868 if (net_addtosymgroup(sgnewc, f, (void *)pc)) return;
4869 pc->symgroup = sgnewc;
4870 pc->hashvalue = hashvalue;
4871 if (verbose != 0)
4872 (void)reallocstring(&pc->hashreason, x_("size matched"), net_tool->cluster);
4873 }
4874 }
4875 }
4876 }
4877
4878 /* set the remaining components in this symmetry group to a nonzero hash */
4879 hashvalue = net_uniquesymmetrygrouphash(SYMGROUPCOMP);
4880 sgnewc = net_newsymgroup(SYMGROUPCOMP, hashvalue, 0);
4881 for(f=0; f<2; f++)
4882 {
4883 for(i=sg->cellcount[f]-1; i>=0; i--)
4884 {
4885 pc = (PCOMP *)sg->celllist[f][i];
4886 net_removefromsymgroup(sg, f, i);
4887 if (net_addtosymgroup(sgnewc, f, (void *)pc)) return;
4888 pc->symgroup = sgnewc;
4889 pc->hashvalue = hashvalue;
4890 if (verbose != 0)
4891 (void)reallocstring(&pc->hashreason, x_("redeemed"), net_tool->cluster);
4892 }
4893 }
4894 sgnewn = NOSYMGROUP;
4895 } else
4896 {
4897 hashvalue = net_uniquesymmetrygrouphash(SYMGROUPNET);
4898 sgnewn = net_newsymgroup(SYMGROUPNET, hashvalue, 0);
4899
4900 for(i=0; i<c0; i++)
4901 {
4902 ind = i0[i];
4903 pn0 = (PNET *)sg->celllist[0][ind];
4904 net_removefromsymgroup(sg, 0, ind);
4905 if (net_addtosymgroup(sgnewn, 0, (void *)pn0)) return;
4906 pn0->symgroup = sgnewn;
4907 pn0->hashvalue = hashvalue;
4908 if (verbose != 0)
4909 (void)reallocstring(&pn0->hashreason, x_("export matched"), net_tool->cluster);
4910 }
4911 for(i=0; i<c1; i++)
4912 {
4913 ind = i1[i];
4914 pn1 = (PNET *)sg->celllist[1][ind];
4915 net_removefromsymgroup(sg, 1, ind);
4916 if (net_addtosymgroup(sgnewn, 1, (void *)pn1)) return;
4917 pn1->symgroup = sgnewn;
4918 pn1->hashvalue = hashvalue;
4919 if (verbose != 0)
4920 (void)reallocstring(&pn1->hashreason, x_("export matched"), net_tool->cluster);
4921 }
4922
4923 /* set the remaining nets in this symmetry group to a nonzero hash */
4924 hashvalue = net_uniquesymmetrygrouphash(SYMGROUPNET);
4925 sgnewn = net_newsymgroup(SYMGROUPNET, hashvalue, 0);
4926 for(f=0; f<2; f++)
4927 {
4928 for(i=sg->cellcount[f]-1; i>=0; i--)
4929 {
4930 pn = (PNET *)sg->celllist[f][i];
4931 net_removefromsymgroup(sg, f, i);
4932 if (net_addtosymgroup(sgnewn, f, (void *)pn)) return;
4933 pn->symgroup = sgnewn;
4934 pn->hashvalue = hashvalue;
4935 if (verbose != 0)
4936 (void)reallocstring(&pn->hashreason, x_("redeemed"), net_tool->cluster);
4937 }
4938 }
4939 sgnewc = NOSYMGROUP;
4940 }
4941
4942 net_redeemzerogroups(sgnewc, sgnewn, verbose, ignorepwrgnd);
4943 }
4944
net_redeemzerogroups(SYMGROUP * sgnewc,SYMGROUP * sgnewn,INTBIG verbose,BOOLEAN ignorepwrgnd)4945 void net_redeemzerogroups(SYMGROUP *sgnewc, SYMGROUP *sgnewn, INTBIG verbose, BOOLEAN ignorepwrgnd)
4946 {
4947 REGISTER SYMGROUP *sg;
4948 REGISTER HASHTYPE hashvalue;
4949 REGISTER PNET *pn;
4950 REGISTER PCOMP *pc;
4951 REGISTER INTBIG i, f;
4952
4953 /* redeem all zero-symmetry groups */
4954 sg = net_findsymmetrygroup(SYMGROUPNET, 0, 0);
4955 if (sg != NOSYMGROUP)
4956 {
4957 if (sgnewn == NOSYMGROUP)
4958 {
4959 hashvalue = net_uniquesymmetrygrouphash(SYMGROUPNET);
4960 sgnewn = net_newsymgroup(SYMGROUPNET, hashvalue, 0);
4961 }
4962 for(f=0; f<2; f++)
4963 {
4964 for(i=sg->cellcount[f]-1; i>=0; i--)
4965 {
4966 pn = (PNET *)sg->celllist[f][i];
4967 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0) continue;
4968 net_removefromsymgroup(sg, f, i);
4969 if (net_addtosymgroup(sgnewn, f, (void *)pn)) return;
4970 pn->symgroup = sgnewn;
4971 pn->hashvalue = sgnewn->hashvalue;
4972 if (verbose != 0)
4973 (void)reallocstring(&pn->hashreason, x_("redeemed"), net_tool->cluster);
4974 }
4975 }
4976 }
4977
4978 sg = net_findsymmetrygroup(SYMGROUPCOMP, 0, 0);
4979 if (sg != NOSYMGROUP)
4980 {
4981 if (sgnewc == NOSYMGROUP)
4982 {
4983 hashvalue = net_uniquesymmetrygrouphash(SYMGROUPCOMP);
4984 sgnewc = net_newsymgroup(SYMGROUPCOMP, hashvalue, 0);
4985 }
4986 for(f=0; f<2; f++)
4987 {
4988 for(i=sg->cellcount[f]-1; i>=0; i--)
4989 {
4990 pc = (PCOMP *)sg->celllist[f][i];
4991 net_removefromsymgroup(sg, f, i);
4992 if (net_addtosymgroup(sgnewc, f, (void *)pc)) return;
4993 pc->symgroup = sgnewc;
4994 pc->hashvalue = sgnewc->hashvalue;
4995 if (verbose != 0)
4996 (void)reallocstring(&pc->hashreason, x_("redeemed"), net_tool->cluster);
4997 }
4998 }
4999 }
5000 }
5001
5002 /*
5003 * Routine to return a string describing size factor "sizefactor".
5004 */
net_describesizefactor(float sizew,float sizel)5005 CHAR *net_describesizefactor(float sizew, float sizel)
5006 {
5007 static CHAR sizedesc[80];
5008
5009 if (sizew == 0)
5010 {
5011 esnprintf(sizedesc, 80, x_("%g"), sizel/WHOLE);
5012 } else
5013 {
5014 esnprintf(sizedesc, 80, x_("%gx%g"), sizew/WHOLE, sizel/WHOLE);
5015 }
5016 return(sizedesc);
5017 }
5018
5019 /******************************** HASH CODE EVALUATION ********************************/
5020
5021 /*
5022 * Routine to return a hash code for component "pc".
5023 */
net_getcomphash(PCOMP * pc,INTBIG verbose)5024 HASHTYPE net_getcomphash(PCOMP *pc, INTBIG verbose)
5025 {
5026 REGISTER INTBIG function, i, portfactor;
5027 REGISTER HASHTYPE hashvalue;
5028 REGISTER NODEINST *ni;
5029 REGISTER NETWORK *net;
5030 REGISTER PNET *pn;
5031 REGISTER PORTPROTO *pp;
5032 REGISTER void *infstr = 0;
5033
5034 /* get the node's function */
5035 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
5036 ni = ((NODEINST **)pc->actuallist)[0];
5037 if (ni->proto->primindex == 0)
5038 {
5039 /* if the function is overridden for the cell, use it */
5040 if (pc->function != NPUNKNOWN) function = pc->function; else
5041 {
5042 /* a cell instance: use the node's prototype address */
5043 function = (INTBIG)(ni->proto->temp1 & NETCELLCODE) >> NETCELLCODESH;
5044 }
5045 } else
5046 {
5047 /* a primitive: use the node's function */
5048 function = pc->function;
5049 }
5050
5051 /* initialize the hash factor */
5052 hashvalue = function * net_functionMultiplier + pc->forcedassociation;
5053
5054 if (verbose != 0)
5055 {
5056 /* compute new hash values and store an explanation */
5057 infstr = initinfstr();
5058 formatinfstr(infstr, x_("%ld(fun)"), function);
5059 if (pc->forcedassociation != 0)
5060 formatinfstr(infstr, x_("+%ld(force)"), pc->forcedassociation);
5061
5062 /* now add in all networks as a function of the port's network */
5063 for(i=0; i<pc->wirecount; i++)
5064 {
5065 pp = pc->portlist[i];
5066 pn = pc->netnumbers[i];
5067 portfactor = pc->portindices[i];
5068 hashvalue += (portfactor * net_portNetFactorMultiplier) *
5069 (pn->hashvalue * net_portHashFactorMultiplier);
5070 net = pn->network;
5071 if (net == NONETWORK)
5072 {
5073 formatinfstr(infstr, x_(" + %ld[%s]"), portfactor, pp->protoname);
5074 } else
5075 {
5076 formatinfstr(infstr, x_(" + %ld(%s)"), portfactor, describenetwork(net));
5077 }
5078 formatinfstr(infstr, x_("x%s(hash)"), hugeinttoa(pn->hashvalue));
5079 }
5080 (void)reallocstring(&pc->hashreason, returninfstr(infstr), net_tool->cluster);
5081 } else
5082 {
5083 /* now add in all networks as a function of the port's network */
5084 for(i=0; i<pc->wirecount; i++)
5085 {
5086 pn = pc->netnumbers[i];
5087 portfactor = pc->portindices[i];
5088 hashvalue += (portfactor * net_portNetFactorMultiplier) *
5089 (pn->hashvalue * net_portHashFactorMultiplier);
5090 }
5091 }
5092 return(hashvalue);
5093 }
5094
5095 /*
5096 * Routine to return a hash code for network "pn".
5097 */
net_getnethash(PNET * pn,INTBIG verbose)5098 HASHTYPE net_getnethash(PNET *pn, INTBIG verbose)
5099 {
5100 REGISTER INTBIG i, index, portfactor;
5101 REGISTER BOOLEAN validcomponents;
5102 REGISTER HASHTYPE hashvalue;
5103 REGISTER PCOMP *pc;
5104 REGISTER void *infstr=0;
5105
5106 /* initialize the hash factor */
5107 hashvalue = 0;
5108
5109 /* start with the number of components on this net */
5110 hashvalue += (pn->nodecount+1) * net_nodeCountMultiplier + pn->forcedassociation;
5111
5112 validcomponents = FALSE;
5113 if (verbose != 0)
5114 {
5115 infstr = initinfstr();
5116 formatinfstr(infstr, x_("%ld(cnt)"), pn->nodecount);
5117 if (pn->forcedassociation != 0)
5118 formatinfstr(infstr, x_("+%ld(force)"), pn->forcedassociation);
5119
5120 /* add in information for each component */
5121 for(i=0; i<pn->nodecount; i++)
5122 {
5123 pc = pn->nodelist[i];
5124 index = pn->nodewire[i];
5125 portfactor = pc->portindices[index];
5126 hashvalue += portfactor * net_portFactorMultiplier * pc->hashvalue;
5127 if (pc->hashvalue != 0) validcomponents = TRUE;
5128 formatinfstr(infstr, x_(" + %ld(port)x%s(hash)"), portfactor, hugeinttoa(pc->hashvalue));
5129 }
5130
5131 /* if no components had valid hash values, make this net zero */
5132 if (!validcomponents && pn->nodecount != 0) hashvalue = 0;
5133 (void)reallocstring(&pn->hashreason, returninfstr(infstr), net_tool->cluster);
5134 } else
5135 {
5136 for(i=0; i<pn->nodecount; i++)
5137 {
5138 pc = pn->nodelist[i];
5139 index = pn->nodewire[i];
5140 portfactor = pc->portindices[index];
5141 hashvalue += portfactor * net_portFactorMultiplier * pc->hashvalue;
5142 if (pc->hashvalue != 0) validcomponents = TRUE;
5143 }
5144
5145 /* if no components had valid hash values, make this net zero */
5146 if (!validcomponents && pn->nodecount != 0) hashvalue = 0;
5147 }
5148
5149 return(hashvalue);
5150 }
5151
5152 /******************************** DEBUGGING ********************************/
5153
5154 /*
5155 * Routine to show the components in group "sg" because they have been matched.
5156 */
net_showmatchedgroup(SYMGROUP * sg)5157 void net_showmatchedgroup(SYMGROUP *sg)
5158 {
5159 NODEPROTO *topcell;
5160 NODEINST *ni;
5161 XARRAY xf, xformtrans, temp;
5162 INTBIG xp1, yp1, xp2, yp2, xp3, yp3, xp4, yp4, plx, phx, ply, phy;
5163 REGISTER INTBIG f, j, lx, hx, ly, hy;
5164 REGISTER PCOMP *pc;
5165 REGISTER WINDOWPART *w;
5166
5167 us_hbox.col = HIGHLIT;
5168
5169 /* show the components in this group if requested */
5170 if (sg->grouptype == SYMGROUPCOMP)
5171 {
5172 for(f=0; f<2; f++)
5173 {
5174 pc = (PCOMP *)sg->celllist[f][0];
5175 transid(xf);
5176 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
5177 ni = ((NODEINST **)pc->actuallist)[0];
5178 topcell = ni->parent;
5179 for(j=pc->hierpathcount-1; j>=0; j--)
5180 {
5181 ni = pc->hierpath[j];
5182 if (ni->proto->cellview == el_iconview) break;
5183 topcell = ni->parent;
5184 maketrans(ni, xformtrans);
5185 transmult(xformtrans, xf, temp);
5186 makerot(ni, xformtrans);
5187 transmult(xformtrans, temp, xf);
5188 }
5189 if (j >= 0) continue;
5190 for(j=0; j<pc->numactual; j++)
5191 {
5192 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
5193 ni = ((NODEINST **)pc->actuallist)[j];
5194 makerot(ni, xformtrans);
5195 transmult(xformtrans, xf, temp);
5196 nodesizeoffset(ni, &plx, &ply, &phx, &phy);
5197 lx = ni->lowx+plx; hx = ni->highx-phx;
5198 ly = ni->lowy+ply; hy = ni->highy-phy;
5199 xform(lx, ly, &xp1, &yp1, temp);
5200 xform(hx, hy, &xp2, &yp2, temp);
5201 xform(lx, hy, &xp3, &yp3, temp);
5202 xform(hx, ly, &xp4, &yp4, temp);
5203 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
5204 {
5205 if (w->curnodeproto != topcell) continue;
5206 xp1 = applyxscale(w, xp1-w->screenlx) + w->uselx;
5207 yp1 = applyyscale(w, yp1-w->screenly) + w->usely;
5208 xp2 = applyxscale(w, xp2-w->screenlx) + w->uselx;
5209 yp2 = applyyscale(w, yp2-w->screenly) + w->usely;
5210 screendrawline(w, xp1, yp1, xp2, yp2, &us_hbox, 0);
5211 xp3 = applyxscale(w, xp3-w->screenlx) + w->uselx;
5212 yp3 = applyyscale(w, yp3-w->screenly) + w->usely;
5213 xp4 = applyxscale(w, xp4-w->screenlx) + w->uselx;
5214 yp4 = applyyscale(w, yp4-w->screenly) + w->usely;
5215 screendrawline(w, xp3, yp3, xp4, yp4, &us_hbox, 0);
5216 flushscreen();
5217 }
5218 }
5219 }
5220 }
5221 }
5222
5223 /*
5224 * Debugging routine to show the hash codes on all symmetry groups.
5225 */
net_showsymmetrygroups(INTBIG verbose,INTBIG type)5226 void net_showsymmetrygroups(INTBIG verbose, INTBIG type)
5227 {
5228 WINDOWPART *win[2];
5229 REGISTER WINDOWPART *w;
5230 REGISTER INTBIG i, f;
5231 UINTBIG descript[TEXTDESCRIPTSIZE];
5232 REGISTER SYMGROUP *sg;
5233 REGISTER PNET *pn;
5234 REGISTER PCOMP *pc;
5235
5236 if ((verbose&NCCVERBOSEGRAPHICS) != 0)
5237 {
5238 /* find the windows associated with the cells */
5239 win[0] = win[1] = NOWINDOWPART;
5240 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
5241 {
5242 for(f=0; f<2; f++)
5243 if (w->curnodeproto == net_cell[f]) win[f] = w;
5244 }
5245 if (win[0] == NOWINDOWPART || win[1] == NOWINDOWPART) return;
5246
5247 /* clear all highlighting */
5248 (void)asktool(us_tool, x_("clear"));
5249 for(f=0; f<2; f++)
5250 screendrawbox(win[f], win[f]->uselx, win[f]->usehx, win[f]->usely, win[f]->usehy,
5251 &net_cleardesc);
5252
5253 TDCLEAR(descript);
5254 TDSETSIZE(descript, TXTSETPOINTS(16));
5255 screensettextinfo(win[0], NOTECHNOLOGY, descript);
5256 screensettextinfo(win[1], NOTECHNOLOGY, descript);
5257 }
5258 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
5259 {
5260 if (sg->grouptype != type) continue;
5261 switch (sg->grouptype)
5262 {
5263 case SYMGROUPCOMP:
5264 for(f=0; f<2; f++)
5265 {
5266 for(i=0; i<sg->cellcount[f]; i++)
5267 {
5268 pc = (PCOMP *)sg->celllist[f][i];
5269 net_showcomphash(win[f], pc, pc->hashvalue, sg->groupindex, verbose);
5270 }
5271 }
5272 break;
5273 case SYMGROUPNET:
5274 for(f=0; f<2; f++)
5275 {
5276 for(i=0; i<sg->cellcount[f]; i++)
5277 {
5278 pn = (PNET *)sg->celllist[f][i];
5279 net_shownethash(win[f], pn, pn->hashvalue, sg->groupindex, verbose);
5280 }
5281 }
5282 break;
5283 }
5284 }
5285 for(sg = net_firstmatchedsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
5286 {
5287 if (sg->grouptype != type) continue;
5288 switch (sg->grouptype)
5289 {
5290 case SYMGROUPCOMP:
5291 for(f=0; f<2; f++)
5292 {
5293 for(i=0; i<sg->cellcount[f]; i++)
5294 {
5295 pc = (PCOMP *)sg->celllist[f][i];
5296 net_showcomphash(win[f], pc, pc->hashvalue, sg->groupindex, verbose);
5297 }
5298 }
5299 break;
5300 case SYMGROUPNET:
5301 for(f=0; f<2; f++)
5302 {
5303 for(i=0; i<sg->cellcount[f]; i++)
5304 {
5305 pn = (PNET *)sg->celllist[f][i];
5306 net_shownethash(win[f], pn, pn->hashvalue, sg->groupindex, verbose);
5307 }
5308 }
5309 break;
5310 }
5311 }
5312 }
5313
net_shownethash(WINDOWPART * win,PNET * pn,HASHTYPE hashvalue,INTBIG hashindex,INTBIG verbose)5314 void net_shownethash(WINDOWPART *win, PNET *pn, HASHTYPE hashvalue, INTBIG hashindex, INTBIG verbose)
5315 {
5316 REGISTER NETWORK *net;
5317 CHAR msg[50];
5318 REGISTER PORTPROTO *pp;
5319 REGISTER ARCINST *ai;
5320 INTBIG tsx, tsy, px, py;
5321 REGISTER INTBIG j;
5322 INTBIG xp, yp;
5323
5324 net = pn->network;
5325 if (net == NONETWORK) return;
5326 if ((verbose&NCCVERBOSEGRAPHICS) != 0)
5327 {
5328 if (hashindex != 0) esnprintf(msg, 50, x_("%ld"), hashindex); else
5329 estrcpy(msg, hugeinttoa(hashvalue));
5330 screengettextsize(win, msg, &tsx, &tsy);
5331 for(j=0; j<net->arccount; j++)
5332 {
5333 if (net->arctotal == 0) ai = (ARCINST *)net->arcaddr; else
5334 ai = ((ARCINST **)net->arcaddr)[j];
5335 if (ai->parent == win->curnodeproto)
5336 {
5337 xp = (ai->end[0].xpos + ai->end[1].xpos) / 2;
5338 yp = (ai->end[0].ypos + ai->end[1].ypos) / 2;
5339 if ((win->state&INPLACEEDIT) != 0)
5340 xform(xp, yp, &xp, &yp, win->outofcell);
5341 xp = applyxscale(win, xp-win->screenlx) + win->uselx;
5342 yp = applyyscale(win, yp-win->screenly) + win->usely;
5343 px = xp - tsx/2; py = yp - tsy/2;
5344 if (px < win->uselx) px = win->uselx;
5345 if (px+tsx > win->usehx) px = win->usehx - tsx;
5346 screendrawtext(win, px, py, msg, &net_msgdesc);
5347 }
5348 }
5349 if (net->portcount > 0)
5350 {
5351 for(pp = win->curnodeproto->firstportproto; pp != NOPORTPROTO;
5352 pp = pp->nextportproto)
5353 {
5354 if (pp->network != net) continue;
5355 portposition(pp->subnodeinst, pp->subportproto, &xp, &yp);
5356 if ((win->state&INPLACEEDIT) != 0)
5357 xform(xp, yp, &xp, &yp, win->outofcell);
5358 xp = applyxscale(win, xp-win->screenlx) + win->uselx;
5359 yp = applyyscale(win, yp-win->screenly) + win->usely;
5360 px = xp - tsx/2; py = yp - tsy/2;
5361 if (px < win->uselx) px = win->uselx;
5362 if (px+tsx > win->usehx) px = win->usehx - tsx;
5363 screendrawtext(win, px, py, msg, &net_msgdesc);
5364 }
5365 }
5366 }
5367 if ((verbose&NCCVERBOSETEXT) != 0)
5368 {
5369 if (hashindex != 0)
5370 {
5371 ttyputmsg(x_(" NETWORK %s:%s: %s (hash #%ld) = %s"), describenodeproto(net->parent),
5372 net_describepnet(pn), hugeinttoa(hashvalue), hashindex, pn->hashreason);
5373 } else
5374 {
5375 ttyputmsg(x_(" NETWORK %s:%s: %s (hash) = %s"), describenodeproto(net->parent),
5376 net_describepnet(pn), hugeinttoa(hashvalue), pn->hashreason);
5377 }
5378 }
5379 }
5380
net_showcomphash(WINDOWPART * win,PCOMP * pc,HASHTYPE hashvalue,INTBIG hashindex,INTBIG verbose)5381 void net_showcomphash(WINDOWPART *win, PCOMP *pc, HASHTYPE hashvalue, INTBIG hashindex, INTBIG verbose)
5382 {
5383 INTBIG xp, yp;
5384 INTBIG tsx, tsy, px, py;
5385 REGISTER NODEINST *ni;
5386 CHAR msg[50];
5387
5388 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
5389 ni = ((NODEINST **)pc->actuallist)[0];
5390 if ((verbose&NCCVERBOSEGRAPHICS) != 0)
5391 {
5392 if (ni->parent == win->curnodeproto)
5393 {
5394 xp = (ni->lowx + ni->highx) / 2;
5395 yp = (ni->lowy + ni->highy) / 2;
5396 if ((win->state&INPLACEEDIT) != 0)
5397 xform(xp, yp, &xp, &yp, win->outofcell);
5398 xp = applyxscale(win, xp-win->screenlx) + win->uselx;
5399 yp = applyyscale(win, yp-win->screenly) + win->usely;
5400 if (hashindex != 0) esnprintf(msg, 50, x_("%ld"), hashindex); else
5401 estrcpy(msg, hugeinttoa(hashvalue));
5402 screengettextsize(win, msg, &tsx, &tsy);
5403 px = xp - tsx/2; py = yp - tsy/2;
5404 if (px < win->uselx) px = win->uselx;
5405 if (px+tsx > win->usehx) px = win->usehx - tsx;
5406 screendrawtext(win, px, py, msg, &net_msgdesc);
5407 }
5408 }
5409 if ((verbose&NCCVERBOSETEXT) != 0)
5410 {
5411 if (hashindex != 0)
5412 {
5413 ttyputmsg(x_(" COMPONENT %s: %s (hash #%ld) = %s"), describenodeinst(ni),
5414 hugeinttoa(hashvalue), hashindex, pc->hashreason);
5415 } else
5416 {
5417 ttyputmsg(x_(" COMPONENT %s: %s (hash) = %s"), describenodeinst(ni),
5418 hugeinttoa(hashvalue), pc->hashreason);
5419 }
5420 }
5421 }
5422
net_dumpnetwork(PCOMP * pclist,PNET * pnlist)5423 void net_dumpnetwork(PCOMP *pclist, PNET *pnlist)
5424 {
5425 REGISTER PCOMP *pc;
5426 REGISTER PNET *pn;
5427 REGISTER INTBIG i;
5428 REGISTER NODEINST *ni;
5429 CHAR nettype[50];
5430 REGISTER void *infstr;
5431
5432 ttyputmsg(x_("Nodes:"));
5433 for(pc = pclist; pc != NOPCOMP; pc = pc->nextpcomp)
5434 {
5435 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
5436 ni = ((NODEINST **)pc->actuallist)[0];
5437 ttyputmsg(x_(" Node %s (fun=%d)"), describenodeinst(ni), pc->function);
5438 }
5439 ttyputmsg(x_("Nets:"));
5440 for(pn = pnlist; pn != NOPNET; pn = pn->nextpnet)
5441 {
5442 infstr = initinfstr();
5443 nettype[0] = 0;
5444 if ((pn->flags&(POWERNET|GROUNDNET)) != 0)
5445 {
5446 if ((pn->flags&POWERNET) != 0) estrcat(nettype, x_("POWER ")); else
5447 estrcat(nettype, x_("GROUND "));
5448 }
5449 formatinfstr(infstr, x_(" %sNet %s (%ld nodes):"), nettype, net_describepnet(pn), pn->nodecount);
5450 for(i=0; i<pn->nodecount; i++)
5451 {
5452 pc = pn->nodelist[i];
5453 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
5454 ni = ((NODEINST **)pc->actuallist)[0];
5455 formatinfstr(infstr, x_(" %s"), describenodeinst(ni));
5456 }
5457 ttyputmsg(x_("%s"), returninfstr(infstr));
5458 }
5459 }
5460
5461 /* NCC preanalysis */
5462 static DIALOGITEM net_nccpredialogitems[] =
5463 {
5464 /* 1 */ {0, {8,315,24,615}, MESSAGE, N_("Cell2")},
5465 /* 2 */ {0, {28,8,384,308}, SCROLL, x_("")},
5466 /* 3 */ {0, {8,8,24,308}, MESSAGE, N_("Cell1")},
5467 /* 4 */ {0, {28,315,384,615}, SCROLL, x_("")},
5468 /* 5 */ {0, {392,244,408,392}, RADIOA, N_("Components")},
5469 /* 6 */ {0, {416,20,432,212}, AUTOCHECK, N_("Tie lists vertically")},
5470 /* 7 */ {0, {416,244,432,392}, RADIOA, N_("Networks")},
5471 /* 8 */ {0, {392,20,408,212}, AUTOCHECK, N_("Show only differences")},
5472 /* 9 */ {0, {400,524,424,604}, DEFBUTTON, N_("Close")},
5473 /* 10 */ {0, {400,420,424,500}, BUTTON, N_("Compare")}
5474 };
5475 static DIALOG net_nccpredialog = {{75,75,516,700}, N_("NCC Preanalysis Results"), 0, 10, net_nccpredialogitems, x_("nccpre"), 0};
5476
5477 /* special items for the "nccpre" dialog: */
5478 #define DNCP_CELL2NAME 1 /* cell 2 name (message) */
5479 #define DNCP_CELL1LIST 2 /* cell 1 list (scroll) */
5480 #define DNCP_CELL1NAME 3 /* cell 1 name (message) */
5481 #define DNCP_CELL2LIST 4 /* cell 2 list (scroll) */
5482 #define DNCP_SHOWCOMPS 5 /* Show components (radioa) */
5483 #define DNCP_TIEVERTICALLY 6 /* Tie lists vertically (autocheck) */
5484 #define DNCP_SHOWNETS 7 /* Show networks (radioa) */
5485 #define DNCP_SHOWDIFFS 8 /* Show only differences (autocheck) */
5486 #define DNCP_CLOSE 9 /* Close (defbutton) */
5487 #define DNCP_COMPARE 10 /* Compare (button) */
5488
5489 class EDiaNetShowPreanalysis : public EDialogModeless
5490 {
5491 public:
5492 EDiaNetShowPreanalysis();
5493 void reset();
5494 void setCells(NODEPROTO *cell1, PCOMP *aPcomp1, PNET *aNodelist1,
5495 NODEPROTO *cell2, PCOMP *aPcomp2, PNET *aNodelist2, BOOLEAN aIgnorepwrgnd);
5496 static EDiaNetShowPreanalysis *dialog;
5497 private:
5498 void itemHitAction(INTBIG itemHit);
5499 void putNetIntoDialog();
5500 void putCompIntoDialog();
5501
5502 BOOLEAN vSynch;
5503 BOOLEAN showComps;
5504 BOOLEAN showAll;
5505 PCOMP *pcomp1, *pcomp2;
5506 PNET *nodelist1, *nodelist2;
5507 BOOLEAN ignorepwrgnd;
5508 };
5509
5510 EDiaNetShowPreanalysis *EDiaNetShowPreanalysis::dialog = 0;
5511
5512 /*
5513 * Routine to show preanalysis results for cells
5514 */
net_showpreanalysis(NODEPROTO * cell1,PCOMP * pcomp1,PNET * nodelist1,NODEPROTO * cell2,PCOMP * pcomp2,PNET * nodelist2,BOOLEAN ignorepwrgnd)5515 void net_showpreanalysis(NODEPROTO *cell1, PCOMP *pcomp1, PNET *nodelist1,
5516 NODEPROTO *cell2, PCOMP *pcomp2, PNET *nodelist2, BOOLEAN ignorepwrgnd)
5517 {
5518 if (EDiaNetShowPreanalysis::dialog == 0) EDiaNetShowPreanalysis::dialog = new EDiaNetShowPreanalysis();
5519 if (EDiaNetShowPreanalysis::dialog == 0) return;
5520 EDiaNetShowPreanalysis::dialog->setCells(cell1, pcomp1, nodelist1, cell2, pcomp2, nodelist2, ignorepwrgnd);
5521 }
5522
EDiaNetShowPreanalysis()5523 EDiaNetShowPreanalysis::EDiaNetShowPreanalysis()
5524 : EDialogModeless(&net_nccpredialog)
5525 {
5526 reset();
5527 }
5528
reset()5529 void EDiaNetShowPreanalysis::reset()
5530 {
5531 vSynch = TRUE;
5532 showComps = FALSE;
5533 showAll = FALSE;
5534 pcomp1 = pcomp2 = 0;
5535 nodelist1 = nodelist2 = 0;
5536 ignorepwrgnd = FALSE;
5537 }
5538
setCells(NODEPROTO * cell1,PCOMP * aPcomp1,PNET * aNodelist1,NODEPROTO * cell2,PCOMP * aPcomp2,PNET * aNodelist2,BOOLEAN aIgnorepwrgnd)5539 void EDiaNetShowPreanalysis::setCells(NODEPROTO *cell1, PCOMP *aPcomp1, PNET *aNodelist1,
5540 NODEPROTO *cell2, PCOMP *aPcomp2, PNET *aNodelist2, BOOLEAN aIgnorepwrgnd)
5541 {
5542 REGISTER PCOMP *pc;
5543
5544 show();
5545
5546 initTextDialog(DNCP_CELL1LIST, DiaNullDlogList, DiaNullDlogItem,
5547 DiaNullDlogDone, -1, SCSELMOUSE|SCREPORT|SCHORIZBAR|SCSMALLFONT);
5548 initTextDialog(DNCP_CELL2LIST, DiaNullDlogList, DiaNullDlogItem,
5549 DiaNullDlogDone, -1, SCSELMOUSE|SCREPORT|SCHORIZBAR|SCSMALLFONT);
5550
5551 /* make the horizontally-aligned lists scroll together */
5552 if (vSynch)
5553 {
5554 synchVScrolls(DNCP_CELL1LIST, DNCP_CELL2LIST, 0);
5555 setControl(DNCP_TIEVERTICALLY, 1);
5556 }
5557 if (showComps) setControl(DNCP_SHOWCOMPS, 1); else setControl(DNCP_SHOWNETS, 1);
5558 setControl(DNCP_SHOWDIFFS, !showAll);
5559
5560 setText(DNCP_CELL1NAME, describenodeproto(cell1));
5561 setText(DNCP_CELL2NAME, describenodeproto(cell2));
5562 pcomp1 = aPcomp1; nodelist1 = aNodelist1;
5563 pcomp2 = aPcomp2; nodelist2 = aNodelist2;
5564 ignorepwrgnd = aIgnorepwrgnd;
5565
5566 /* precache the component names */
5567 for(pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
5568 allocstring(&pc->hashreason, net_describepcomp(pc), net_tool->cluster);
5569 for(pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
5570 allocstring(&pc->hashreason, net_describepcomp(pc), net_tool->cluster);
5571
5572 if (showComps) putCompIntoDialog(); else putNetIntoDialog();
5573 }
5574
5575 typedef struct
5576 {
5577 INTBIG pcount;
5578 PORTPROTO *pp;
5579 NETWORK *net;
5580 } COMPPORT;
5581
itemHitAction(INTBIG itemHit)5582 void EDiaNetShowPreanalysis::itemHitAction(INTBIG itemHit)
5583 {
5584 REGISTER INTBIG i, j, total1, total2, pgcount1, pgcount2, i1, i2, maxlen, diff;
5585 REGISTER BOOLEAN first;
5586 REGISTER PCOMP *pc, *pc1, *pc2;
5587 REGISTER NETWORK *net;
5588 REGISTER PNET *pn;
5589 REGISTER void *infstr;
5590 REGISTER CHAR **netnames1, **netnames2, *pt1, *pt2;
5591 REGISTER NODEPROTO *np1, *np2, *np1orig, *np2orig;
5592 REGISTER PORTPROTO *pp1, *pp2;
5593 REGISTER NODEINST *ni, *ni1, *ni2;
5594 REGISTER ARCINST *ai;
5595 REGISTER COMPPORT *comportlist1, *comportlist2;
5596
5597 if (itemHit == DNCP_CLOSE)
5598 {
5599 for(pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
5600 {
5601 efree((CHAR *)pc->hashreason);
5602 pc->hashreason = 0;
5603 }
5604 for(pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
5605 {
5606 efree((CHAR *)pc->hashreason);
5607 pc->hashreason = 0;
5608 }
5609 hide();
5610 return;
5611 }
5612 if (itemHit == DNCP_COMPARE)
5613 {
5614 if (showComps)
5615 {
5616 i = getCurLine(DNCP_CELL1LIST);
5617 for(pc1 = pcomp1; pc1 != NOPCOMP; pc1 = pc1->nextpcomp)
5618 if (pc1->timestamp == i) break;
5619 i = getCurLine(DNCP_CELL2LIST);
5620 for(pc2 = pcomp2; pc2 != NOPCOMP; pc2 = pc2->nextpcomp)
5621 if (pc2->timestamp == i) break;
5622 if (pc1 == NOPCOMP || pc2 == NOPCOMP)
5623 {
5624 ttyputmsg(_("First select a component from each list"));
5625 return;
5626 }
5627
5628 /* compare components "pc1" and "pc2" */
5629 if (pc1->numactual == 1) ni1 = ((NODEINST *)pc1->actuallist); else
5630 ni1 = ((NODEINST **)pc1->actuallist)[0];
5631 np1orig = ni1->proto;
5632 np1 = contentsview(np1orig);
5633 if (np1 == NONODEPROTO) np1 = np1orig;
5634 if (pc2->numactual == 1) ni2 = ((NODEINST *)pc2->actuallist); else
5635 ni2 = ((NODEINST **)pc2->actuallist)[0];
5636 np2orig = ni2->proto;
5637 np2 = contentsview(np2orig);
5638 if (np2 == NONODEPROTO) np2 = np2orig;
5639 infstr = initinfstr();
5640 formatinfstr(infstr, _("Differences between component %s"), describenodeproto(np1));
5641 if (pc1->numactual > 1) formatinfstr(infstr, _(" (%ld merged nodes)"), pc1->numactual);
5642 formatinfstr(infstr, _(" and component %s"), describenodeproto(np2));
5643 if (pc2->numactual > 1) formatinfstr(infstr, _(" (%ld merged nodes)"), pc2->numactual);
5644 ttyputmsg(x_("%s"), returninfstr(infstr));
5645
5646 /* gather information about component "pc1" */
5647 total1 = pgcount1 = 0;
5648 comportlist1 = 0;
5649 for(pp1 = np1->firstportproto; pp1 != NOPORTPROTO; pp1 = pp1->nextportproto)
5650 {
5651 if (portispower(pp1) || portisground(pp1))
5652 {
5653 if (pp1->network->buswidth <= 1) pgcount1++; else
5654 pgcount1 += pp1->network->buswidth;
5655 if (ignorepwrgnd) continue;
5656 }
5657 if (pp1->network->buswidth > 1)
5658 total1 += pp1->network->buswidth;
5659 total1++;
5660 }
5661 if (total1 > 0)
5662 {
5663 comportlist1 = (COMPPORT *)emalloc(total1 * (sizeof (COMPPORT)), net_tool->cluster);
5664 if (comportlist1 == 0) return;
5665 total1 = 0;
5666 for(pp1 = np1->firstportproto; pp1 != NOPORTPROTO; pp1 = pp1->nextportproto)
5667 {
5668 if (ignorepwrgnd && (portispower(pp1) || portisground(pp1))) continue;
5669 comportlist1[total1].pp = equivalentport(np1, pp1, np1orig);
5670 comportlist1[total1++].net = pp1->network;
5671 if (pp1->network->buswidth > 1)
5672 {
5673 for(i=0; i<pp1->network->buswidth; i++)
5674 {
5675 comportlist1[total1].pp = NOPORTPROTO;
5676 comportlist1[total1++].net = pp1->network->networklist[i];
5677 }
5678 }
5679 }
5680 }
5681 for(i=0; i<total1; i++) comportlist1[i].pcount = 0;
5682 for(i=0; i<pc1->wirecount; i++)
5683 {
5684 pp1 = pc1->portlist[i];
5685 for(j=0; j<total1; j++)
5686 {
5687 if (comportlist1[j].pp == pp1) comportlist1[j].pcount++;
5688 }
5689 }
5690
5691 /* gather information about component "pc2" */
5692 total2 = pgcount2 = 0;
5693 comportlist2 = 0;
5694 for(pp2 = np2->firstportproto; pp2 != NOPORTPROTO; pp2 = pp2->nextportproto)
5695 {
5696 if (portispower(pp2) || portisground(pp2))
5697 {
5698 if (pp2->network->buswidth <= 1) pgcount2++; else
5699 pgcount2 += pp2->network->buswidth;
5700 if (ignorepwrgnd) continue;
5701 }
5702 total2++;
5703 if (pp2->network->buswidth > 1)
5704 total2 += pp2->network->buswidth;
5705 }
5706 if (total2 > 0)
5707 {
5708 comportlist2 = (COMPPORT *)emalloc(total2 * (sizeof (COMPPORT)), net_tool->cluster);
5709 if (comportlist2 == 0) return;
5710 total2 = 0;
5711 for(pp2 = np2->firstportproto; pp2 != NOPORTPROTO; pp2 = pp2->nextportproto)
5712 {
5713 if (ignorepwrgnd && (portispower(pp2) || portisground(pp2))) continue;
5714 comportlist2[total2].pp = equivalentport(np2, pp2, np2orig);
5715 comportlist2[total2++].net = pp2->network;
5716 if (pp2->network->buswidth > 1)
5717 {
5718 for(i=0; i<pp2->network->buswidth; i++)
5719 {
5720 comportlist2[total2].pp = NOPORTPROTO;
5721 comportlist2[total2++].net = pp2->network->networklist[i];
5722 }
5723 }
5724 }
5725 }
5726 for(i=0; i<total2; i++) comportlist2[i].pcount = 0;
5727 for(i=0; i<pc2->wirecount; i++)
5728 {
5729 pp2 = pc2->portlist[i];
5730 for(j=0; j<total2; j++)
5731 {
5732 if (comportlist2[j].pp == pp2) comportlist2[j].pcount++;
5733 }
5734 }
5735
5736 /* analyze results */
5737 if (pgcount1 != pgcount2)
5738 ttyputmsg(_(" Cells %s has %ld power-and-ground exports but cell %s has %ld"),
5739 describenodeproto(np1), pgcount1, describenodeproto(np2), pgcount2);
5740
5741 for(i=0; i<total1; i++)
5742 {
5743 if (comportlist1[i].net->buswidth > 1) continue;
5744 for(j=0; j<total2; j++)
5745 if (net_samenetworkname(comportlist1[i].net, comportlist2[j].net)) break;
5746 if (j < total2) continue;
5747 ttyputmsg(_(" Export %s exists only in %s"), describenetwork(comportlist1[i].net),
5748 describenodeproto(np1));
5749 }
5750 for(i=0; i<total2; i++)
5751 {
5752 if (comportlist2[i].net->buswidth > 1) continue;
5753 for(j=0; j<total1; j++)
5754 if (net_samenetworkname(comportlist2[i].net, comportlist1[j].net)) break;
5755 if (j < total1) continue;
5756 ttyputmsg(_(" Export %s exists only in %s"), describenetwork(comportlist2[i].net),
5757 describenodeproto(np2));
5758 }
5759 if (total1 > 0) efree((CHAR *)comportlist1);
5760 if (total2 > 0) efree((CHAR *)comportlist2);
5761 ttyputmsg(_("End of comparison"));
5762
5763
5764 /* now do another analysis */
5765 total1 = 0;
5766 netnames1 = 0;
5767 for(i=0; i<pc1->wirecount; i++)
5768 {
5769 pn = pc1->netnumbers[i];
5770 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0) continue;
5771 total1++;
5772 }
5773 if (total1 > 0)
5774 {
5775 netnames1 = (CHAR **)emalloc(total1 * (sizeof (CHAR *)), net_tool->cluster);
5776 if (netnames1 == 0) return;
5777 total1 = 0;
5778 for(i=0; i<pc1->wirecount; i++)
5779 {
5780 pn = pc1->netnumbers[i];
5781 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0) continue;
5782 netnames1[total1++] = pc1->portlist[i]->protoname;
5783 }
5784 }
5785 esort(netnames1, total1, sizeof (CHAR *), sort_stringascending);
5786
5787 total2 = 0;
5788 netnames2 = 0;
5789 for(i=0; i<pc2->wirecount; i++)
5790 {
5791 pn = pc2->netnumbers[i];
5792 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0) continue;
5793 total2++;
5794 }
5795 if (total2 > 0)
5796 {
5797 netnames2 = (CHAR **)emalloc(total2 * (sizeof (CHAR *)), net_tool->cluster);
5798 if (netnames2 == 0) return;
5799 total2 = 0;
5800 for(i=0; i<pc2->wirecount; i++)
5801 {
5802 pn = pc2->netnumbers[i];
5803 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0) continue;
5804 netnames2[total2++] = pc2->portlist[i]->protoname;
5805 }
5806 }
5807 esort(netnames2, total2, sizeof (CHAR *), sort_stringascending);
5808
5809 ttyputmsg(_("Comparison of wires on nodes %s and %s"), describenodeinst(ni1),
5810 describenodeinst(ni2));
5811 maxlen = estrlen(describenodeinst(ni1));
5812 for(i=0; i<total1; i++)
5813 maxlen = maxi(maxlen, estrlen(netnames1[i]));
5814 maxlen += 5;
5815 infstr = initinfstr();
5816 addstringtoinfstr(infstr, describenodeinst(ni1));
5817 for(i=estrlen(describenodeinst(ni1)); i<maxlen; i++) addtoinfstr(infstr, ' ');
5818 addstringtoinfstr(infstr, describenodeinst(ni2));
5819 ttyputmsg(x_("%s"), returninfstr(infstr));
5820
5821 i1 = i2 = 0;
5822 for(;;)
5823 {
5824 if (i1 >= total1 && i2 >= total2) break;
5825 if (i1 < total1) pt1 = netnames1[i1]; else
5826 pt1 = x_("");
5827 if (i2 < total2) pt2 = netnames2[i2]; else
5828 pt2 = x_("");
5829 infstr = initinfstr();
5830 diff = namesame(pt1, pt2);
5831 if (diff < 0 && i1 >= total1) diff = 1;
5832 if (diff > 0 && i2 >= total2) diff = -1;
5833 if (diff == 0)
5834 {
5835 addstringtoinfstr(infstr, pt1);
5836 for(i=estrlen(pt1); i<maxlen; i++) addtoinfstr(infstr, ' ');
5837 addstringtoinfstr(infstr, pt2);
5838 if (i1 < total1) i1++;
5839 if (i2 < total2) i2++;
5840 } else if (diff < 0)
5841 {
5842 addstringtoinfstr(infstr, pt1);
5843 i1++;
5844 } else
5845 {
5846 for(i=0; i<maxlen; i++) addtoinfstr(infstr, ' ');
5847 addstringtoinfstr(infstr, pt2);
5848 i2++;
5849 }
5850 ttyputmsg(x_("%s"), returninfstr(infstr));
5851 }
5852 if (total1 > 0) efree((CHAR *)netnames1);
5853 if (total2 > 0) efree((CHAR *)netnames2);
5854 } else
5855 {
5856 ttyputmsg(_("Can only compare components"));
5857 }
5858 return;
5859 }
5860 if (itemHit == DNCP_TIEVERTICALLY)
5861 {
5862 vSynch = getControl(DNCP_TIEVERTICALLY) != 0;
5863 if (vSynch) synchVScrolls(DNCP_CELL1LIST, DNCP_CELL2LIST, 0); else unSynchVScrolls();
5864 return;
5865 }
5866 if (itemHit == DNCP_SHOWCOMPS || itemHit == DNCP_SHOWNETS || itemHit == DNCP_SHOWDIFFS)
5867 {
5868 showComps = getControl(DNCP_SHOWCOMPS) != 0;
5869 showAll = !getControl(DNCP_SHOWDIFFS);
5870 if (showComps) putCompIntoDialog(); else putNetIntoDialog();
5871 return;
5872 }
5873 if (itemHit == DNCP_CELL1LIST || itemHit == DNCP_CELL2LIST)
5874 {
5875 (void)asktool(us_tool, x_("clear"));
5876 infstr = initinfstr();
5877 first = TRUE;
5878 i = getCurLine(itemHit);
5879 if (showComps)
5880 {
5881 for(pc = (itemHit == DNCP_CELL1LIST ? pcomp1 : pcomp2); pc != NOPCOMP; pc = pc->nextpcomp)
5882 {
5883 if (pc->timestamp != i) continue;
5884 for(j=0; j<pc->numactual; j++)
5885 {
5886 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
5887 ni = ((NODEINST **)pc->actuallist)[j];
5888 if (first) first = FALSE; else
5889 addtoinfstr(infstr, '\n');
5890 formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0;NOBBOX"),
5891 describenodeproto(ni->parent), (INTBIG)ni->geom);
5892 }
5893 }
5894 } else
5895 {
5896 for(pn = (itemHit == DNCP_CELL1LIST ? nodelist1 : nodelist2); pn != NOPNET; pn = pn->nextpnet)
5897 {
5898 if (pn->timestamp != i) continue;
5899 net = pn->network;
5900 if (net == NONETWORK) continue;
5901 for(ai = net->parent->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
5902 {
5903 if (ai->network != net)
5904 {
5905 if (ai->network->buswidth <= 1) continue;
5906 for(j=0; j<ai->network->buswidth; j++)
5907 if (ai->network->networklist[j] == net) break;
5908 if (j >= ai->network->buswidth) continue;
5909 }
5910 if (first) first = FALSE; else
5911 addtoinfstr(infstr, '\n');
5912 formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0;NOBBOX"),
5913 describenodeproto(ai->parent), (INTBIG)ai->geom);
5914 }
5915 }
5916 }
5917 (void)asktool(us_tool, x_("show-multiple"), (INTBIG)returninfstr(infstr));
5918 return;
5919 }
5920 }
5921
putNetIntoDialog()5922 void EDiaNetShowPreanalysis::putNetIntoDialog()
5923 {
5924 REGISTER INTBIG pn1total, pn2total, ind1, ind2, i, maxwirecount,
5925 reportedwid, curwid, line1, line2, *wirecountlist, numin1, numin2;
5926 CHAR *pt, line[200];
5927 REGISTER PNET **pn1list, **pn2list, *pn, *pn1, *pn2;
5928 REGISTER NETWORK *net1, *net2;
5929 REGISTER NODEPROTO *np1, *np2;
5930 REGISTER void *infstr;
5931
5932 /* clear the scroll areas */
5933 loadTextDialog(DNCP_CELL1LIST, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
5934 loadTextDialog(DNCP_CELL2LIST, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
5935
5936 /* show the networks */
5937 pn1total = 0;
5938 pn1list = 0;
5939 for(pn = nodelist1; pn != NOPNET; pn = pn->nextpnet)
5940 {
5941 pn->timestamp = -1;
5942 pn1total++;
5943 }
5944 if (pn1total > 0)
5945 {
5946 pn1list = (PNET **)emalloc(pn1total * (sizeof (PNET *)), net_tool->cluster);
5947 if (pn1list == 0) return;
5948 pn1total = 0;
5949 for(pn = nodelist1; pn != NOPNET; pn = pn->nextpnet)
5950 pn1list[pn1total++] = pn;
5951 esort(pn1list, pn1total, sizeof (PNET *), net_sortpnet);
5952 }
5953
5954 /* count the number of networks in the second cell */
5955 pn2total = 0;
5956 pn2list = 0;
5957 for(pn = nodelist2; pn != NOPNET; pn = pn->nextpnet)
5958 {
5959 pn->timestamp = -1;
5960 pn2total++;
5961 }
5962 if (pn2total > 0)
5963 {
5964 pn2list = (PNET **)emalloc(pn2total * (sizeof (PNET *)), net_tool->cluster);
5965 if (pn2list == 0) return;
5966 pn2total = 0;
5967 for(pn = nodelist2; pn != NOPNET; pn = pn->nextpnet)
5968 pn2list[pn2total++] = pn;
5969 esort(pn2list, pn2total, sizeof (PNET *), net_sortpnet);
5970 }
5971
5972 /* if reducing to the obvious differences, remove all with a nodecount if numbers match */
5973 if (!showAll)
5974 {
5975 maxwirecount = -1;
5976 for(pn = nodelist1; pn != NOPNET; pn = pn->nextpnet)
5977 if (pn->nodecount > maxwirecount) maxwirecount = pn->nodecount;
5978 for(pn = nodelist2; pn != NOPNET; pn = pn->nextpnet)
5979 if (pn->nodecount > maxwirecount) maxwirecount = pn->nodecount;
5980 if (maxwirecount > 0)
5981 {
5982 wirecountlist = (INTBIG *)emalloc((maxwirecount+1) * SIZEOFINTBIG, el_tempcluster);
5983 if (wirecountlist == 0) return;
5984 for(i=0; i<=maxwirecount; i++) wirecountlist[i] = 0;
5985 for(pn = nodelist1; pn != NOPNET; pn = pn->nextpnet)
5986 wirecountlist[pn->nodecount] = 1;
5987 for(pn = nodelist2; pn != NOPNET; pn = pn->nextpnet)
5988 wirecountlist[pn->nodecount] = 1;
5989 for(i=maxwirecount; i>=0; i--)
5990 {
5991 if (wirecountlist[i] == 0) continue;
5992 for(ind1 = 0, pn = nodelist1; pn != NOPNET; pn = pn->nextpnet)
5993 if (pn->nodecount == i) ind1++;
5994 for(ind2 = 0, pn = nodelist2; pn != NOPNET; pn = pn->nextpnet)
5995 if (pn->nodecount == i) ind2++;
5996 if (ind1 != ind2) continue;
5997 if (ind1 == 0) continue;
5998 for(pn = nodelist1; pn != NOPNET; pn = pn->nextpnet)
5999 if (pn->nodecount == i) pn->timestamp = 0;
6000 for(pn = nodelist2; pn != NOPNET; pn = pn->nextpnet)
6001 if (pn->nodecount == i) pn->timestamp = 0;
6002 }
6003 efree((CHAR *)wirecountlist);
6004 }
6005 }
6006
6007 ind1 = ind2 = 0;
6008 line1 = line2 = 0;
6009 reportedwid = -1;
6010 for(;;)
6011 {
6012 if (ind1 >= pn1total) pn1 = NOPNET; else
6013 {
6014 pn1 = pn1list[ind1];
6015 if (pn1->timestamp == 0)
6016 {
6017 ind1++;
6018 pn1->timestamp = -1;
6019 continue;
6020 }
6021 if (ignorepwrgnd && (pn1->flags&(POWERNET|GROUNDNET)) != 0)
6022 {
6023 ind1++;
6024 pn1->timestamp = -1;
6025 continue;
6026 }
6027 }
6028 if (ind2 >= pn2total) pn2 = NOPNET; else
6029 {
6030 pn2 = pn2list[ind2];
6031 if (pn2->timestamp == 0)
6032 {
6033 ind2++;
6034 pn2->timestamp = -1;
6035 continue;
6036 }
6037 if (ignorepwrgnd && (pn2->flags&(POWERNET|GROUNDNET)) != 0)
6038 {
6039 ind2++;
6040 pn2->timestamp = -1;
6041 continue;
6042 }
6043 }
6044 if (pn1 == NOPNET && pn2 == NOPNET) break;
6045 if (pn1 != NOPNET && pn2 != NOPNET)
6046 {
6047 if (pn1->nodecount < pn2->nodecount) pn1 = NOPNET; else
6048 if (pn1->nodecount > pn2->nodecount) pn2 = NOPNET;
6049 }
6050 if (pn1 != NOPNET) curwid = pn1->nodecount; else curwid = pn2->nodecount;
6051 if (curwid != reportedwid)
6052 {
6053 numin1 = 0;
6054 if (pn1 != NOPNET)
6055 {
6056 for(i=ind1; i<pn1total; i++)
6057 {
6058 pn = pn1list[i];
6059 if (pn->timestamp == 0) continue;
6060 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0) continue;
6061 if (pn->nodecount != pn1->nodecount) break;
6062 numin1++;
6063 }
6064 }
6065 numin2 = 0;
6066 if (pn2 != NOPNET)
6067 {
6068 for(i=ind2; i<pn2total; i++)
6069 {
6070 pn = pn2list[i];
6071 if (pn->timestamp == 0) continue;
6072 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0) continue;
6073 if (pn->nodecount != pn2->nodecount) break;
6074 numin2++;
6075 }
6076 }
6077 esnprintf(line, 200, _(":::::::: nets with %ld components (%ld) ::::::::"), curwid, numin1);
6078 stuffLine(DNCP_CELL1LIST, line);
6079 esnprintf(line, 200, _(":::::::: nets with %ld components (%ld) ::::::::"), curwid, numin2);
6080 stuffLine(DNCP_CELL2LIST, line);
6081 line1++; line2++;
6082 reportedwid = curwid;
6083 }
6084
6085 if (pn1 == NOPNET) stuffLine(DNCP_CELL1LIST, x_("")); else
6086 {
6087 pn1->timestamp = line1;
6088 if ((pn1->flags&(POWERNET|GROUNDNET|EXPORTEDNET)) == 0 &&
6089 (pn1->network == NONETWORK || pn1->network->namecount == 0))
6090 {
6091 /* unnamed internal network: merge with others like it */
6092 net1 = pn1->network;
6093 if (net1 != NONETWORK) np1 = net1->parent; else
6094 np1 = NONODEPROTO;
6095 i = 0;
6096 for(;;)
6097 {
6098 i++;
6099 ind1++;
6100 if (ind1 >= pn1total) break;
6101 pn = pn1list[ind1];
6102 if (pn->nodecount != pn1->nodecount) break;
6103 if ((pn->flags&(POWERNET|GROUNDNET|EXPORTEDNET)) != 0 ||
6104 (pn->network != NONETWORK && pn->network->namecount != 0)) break;
6105 net2 = pn->network;
6106 if (net2 != NONETWORK) np2 = net2->parent; else
6107 np2 = NONODEPROTO;
6108 if (np1 != np2) break;
6109 pn->timestamp = line1;
6110 }
6111 if (i == 1) estrcpy(line, _("Unnamed net")); else
6112 esnprintf(line, 200, _("Unnamed nets (%ld)"), i);
6113 if (np1 != NONODEPROTO)
6114 {
6115 estrcat(line, _(" in cell "));
6116 estrcat(line, describenodeproto(np1));
6117 }
6118 stuffLine(DNCP_CELL1LIST, line);
6119 } else
6120 {
6121 (void)allocstring(&pt, net_describepnet(pn1), el_tempcluster);
6122 infstr = initinfstr();
6123 addstringtoinfstr(infstr, pt);
6124 i = 0;
6125 for(;;)
6126 {
6127 i++;
6128 ind1++;
6129 if (ind1 >= pn1total) break;
6130 pn = pn1list[ind1];
6131 if (pn->nodecount != pn1->nodecount) break;
6132 if (namesame(pt, net_describepnet(pn)) != 0) break;
6133 pn->timestamp = line1;
6134 }
6135 efree(pt);
6136 if (i > 1)
6137 formatinfstr(infstr, x_(" (%ld)"), i);
6138 stuffLine(DNCP_CELL1LIST, returninfstr(infstr));
6139 }
6140 }
6141 line1++;
6142
6143 if (pn2 == NOPNET) stuffLine(DNCP_CELL2LIST, x_("")); else
6144 {
6145 pn2->timestamp = line2;
6146 if ((pn2->flags&(POWERNET|GROUNDNET|EXPORTEDNET)) == 0 &&
6147 (pn2->network == NONETWORK || pn2->network->namecount == 0))
6148 {
6149 /* unnamed internal network: merge with others like it */
6150 net2 = pn2->network;
6151 if (net2 != NONETWORK) np2 = net2->parent; else
6152 np2 = NONODEPROTO;
6153 i = 0;
6154 for(;;)
6155 {
6156 i++;
6157 ind2++;
6158 if (ind2 >= pn2total) break;
6159 pn = pn2list[ind2];
6160 if (pn->nodecount != pn2->nodecount) break;
6161 if ((pn->flags&(POWERNET|GROUNDNET|EXPORTEDNET)) != 0 ||
6162 (pn->network != NONETWORK && pn->network->namecount != 0)) break;
6163 net1 = pn->network;
6164 if (net1 != NONETWORK) np1 = net1->parent; else
6165 np1 = NONODEPROTO;
6166 if (np1 != np2) break;
6167 pn->timestamp = line2;
6168 }
6169 if (i == 1) estrcpy(line, _("Unnamed net")); else
6170 esnprintf(line, 200, _("Unnamed nets (%ld)"), i);
6171 if (np2 != NONODEPROTO)
6172 {
6173 estrcat(line, _(" in cell "));
6174 estrcat(line, describenodeproto(np2));
6175 }
6176 stuffLine(DNCP_CELL2LIST, line);
6177 } else
6178 {
6179 (void)allocstring(&pt, net_describepnet(pn2), el_tempcluster);
6180 infstr = initinfstr();
6181 addstringtoinfstr(infstr, pt);
6182 i = 0;
6183 for(;;)
6184 {
6185 i++;
6186 ind2++;
6187 if (ind2 >= pn2total) break;
6188 pn = pn2list[ind2];
6189 if (pn->nodecount != pn2->nodecount) break;
6190 if (namesame(pt, net_describepnet(pn)) != 0) break;
6191 pn->timestamp = line2;
6192 }
6193 efree(pt);
6194 if (i > 1)
6195 formatinfstr(infstr, x_(" (%ld)"), i);
6196 stuffLine(DNCP_CELL2LIST, returninfstr(infstr));
6197 }
6198 }
6199 line2++;
6200 }
6201 if (pn1total > 0) efree((CHAR *)pn1list);
6202 if (pn2total > 0) efree((CHAR *)pn2list);
6203 selectLine(DNCP_CELL1LIST, 0);
6204 selectLine(DNCP_CELL2LIST, 0);
6205 }
6206
putCompIntoDialog()6207 void EDiaNetShowPreanalysis::putCompIntoDialog()
6208 {
6209 REGISTER INTBIG ind1, ind2, i, maxwirecount, numin1, numin2,
6210 reportedwid, curwid, pc1total, pc2total, w, line1, line2;
6211 CHAR line[200];
6212 REGISTER PNET *pn;
6213 REGISTER PCOMP **pc1list, **pc2list, *pc, *pc1, *pc2;
6214 REGISTER void *infstr;
6215
6216 /* clear the scroll areas */
6217 loadTextDialog(DNCP_CELL1LIST, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
6218 loadTextDialog(DNCP_CELL2LIST, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
6219
6220 /* count the number of components in the first cell */
6221 pc1total = 0;
6222 pc1list = 0;
6223 for(pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
6224 {
6225 pc1total++;
6226 pc->timestamp = -1;
6227
6228 /* adjust the number of wires, removing ignored power and ground */
6229 w = 0;
6230 for(i=0; i<pc->wirecount; i++)
6231 {
6232 pn = pc->netnumbers[i];
6233 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0) continue;
6234 w++;
6235 }
6236 pc->hashvalue = pc->wirecount;
6237 pc->wirecount = (INTSML)w;
6238 }
6239
6240 /* make a sorted list of the components in the first cell */
6241 if (pc1total > 0)
6242 {
6243 pc1list = (PCOMP **)emalloc(pc1total * (sizeof (PCOMP *)), net_tool->cluster);
6244 if (pc1list == 0) return;
6245 pc1total = 0;
6246 for(pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
6247 pc1list[pc1total++] = pc;
6248 esort(pc1list, pc1total, sizeof (PCOMP *), net_sortpcomp);
6249 }
6250
6251 /* count the number of components in the second cell */
6252 pc2total = 0;
6253 pc2list = 0;
6254 for(pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
6255 {
6256 pc2total++;
6257 pc->timestamp = -1;
6258
6259 /* adjust the number of wires, removing ignored power and ground */
6260 w = 0;
6261 for(i=0; i<pc->wirecount; i++)
6262 {
6263 pn = pc->netnumbers[i];
6264 if (ignorepwrgnd && (pn->flags&(POWERNET|GROUNDNET)) != 0) continue;
6265 w++;
6266 }
6267 pc->hashvalue = pc->wirecount;
6268 pc->wirecount = (INTSML)w;
6269 }
6270
6271 /* make a sorted list of the components in the second cell */
6272 if (pc2total > 0)
6273 {
6274 pc2list = (PCOMP **)emalloc(pc2total * (sizeof (PCOMP *)), net_tool->cluster);
6275 if (pc2list == 0) return;
6276 pc2total = 0;
6277 for(pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
6278 pc2list[pc2total++] = pc;
6279 esort(pc2list, pc2total, sizeof (PCOMP *), net_sortpcomp);
6280 }
6281
6282 /* if reducing to the obvious differences, remove all with a wirecount if numbers match */
6283 if (!showAll)
6284 {
6285 maxwirecount = -1;
6286 for(pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
6287 if (pc->wirecount > maxwirecount) maxwirecount = pc->wirecount;
6288 for(pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
6289 if (pc->wirecount > maxwirecount) maxwirecount = pc->wirecount;
6290 for(i=maxwirecount; i>=0; i--)
6291 {
6292 for(ind1 = 0, pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
6293 if (pc->wirecount == i) ind1++;
6294 for(ind2 = 0, pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
6295 if (pc->wirecount == i) ind2++;
6296 if (ind1 != ind2) continue;
6297 if (ind1 == 0) continue;
6298 for(pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
6299 if (pc->wirecount == i) pc->timestamp = 0;
6300 for(pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
6301 if (pc->wirecount == i) pc->timestamp = 0;
6302 }
6303 }
6304
6305 ind1 = ind2 = 0;
6306 line1 = line2 = 0;
6307 reportedwid = -1;
6308 for(;;)
6309 {
6310 if (ind1 >= pc1total) pc1 = NOPCOMP; else
6311 {
6312 pc1 = pc1list[ind1];
6313 if (pc1->timestamp == 0)
6314 {
6315 ind1++;
6316 pc1->timestamp = -1;
6317 continue;
6318 }
6319 }
6320 if (ind2 >= pc2total) pc2 = NOPCOMP; else
6321 {
6322 pc2 = pc2list[ind2];
6323 if (pc2->timestamp == 0)
6324 {
6325 ind2++;
6326 pc2->timestamp = -1;
6327 continue;
6328 }
6329 }
6330 if (pc1 == NOPCOMP && pc2 == NOPCOMP) break;
6331 if (pc1 != NOPCOMP && pc2 != NOPCOMP)
6332 {
6333 if (pc1->wirecount < pc2->wirecount) pc1 = NOPCOMP; else
6334 if (pc1->wirecount > pc2->wirecount) pc2 = NOPCOMP;
6335 }
6336 if (pc1 != NOPCOMP) curwid = pc1->wirecount; else curwid = pc2->wirecount;
6337 if (curwid != reportedwid)
6338 {
6339 numin1 = 0;
6340 if (pc1 != NOPCOMP)
6341 {
6342 for(i=ind1; i<pc1total; i++)
6343 {
6344 if (pc1list[i]->wirecount == pc1->wirecount) numin1++; else break;
6345 }
6346 }
6347 numin2 = 0;
6348 if (pc2 != NOPCOMP)
6349 {
6350 for(i=ind2; i<pc2total; i++)
6351 {
6352 if (pc2list[i]->wirecount == pc2->wirecount) numin2++; else break;
6353 }
6354 }
6355 esnprintf(line, 200, _(":::::::: components with %ld nets (%ld) ::::::::"), curwid, numin1);
6356 stuffLine(DNCP_CELL1LIST, line);
6357 esnprintf(line, 200, _(":::::::: components with %ld nets (%ld) ::::::::"), curwid, numin2);
6358 stuffLine(DNCP_CELL2LIST, line);
6359 line1++; line2++;
6360 reportedwid = curwid;
6361 }
6362
6363 if (pc1 == NOPCOMP) stuffLine(DNCP_CELL1LIST, x_("")); else
6364 {
6365 pc1->timestamp = line1;
6366 i = 0;
6367 for(;;)
6368 {
6369 i++;
6370 ind1++;
6371 if (ind1 >= pc1total) break;
6372 if (pc1list[ind1]->timestamp == 0) break;
6373 if (namesame(pc1->hashreason, pc1list[ind1]->hashreason) != 0)
6374 break;
6375 pc1list[ind1]->timestamp = line1;
6376 }
6377 infstr = initinfstr();
6378 if (i > 1)
6379 formatinfstr(infstr, x_("(%ld) "), i);
6380 addstringtoinfstr(infstr, pc1->hashreason);
6381 stuffLine(DNCP_CELL1LIST, returninfstr(infstr));
6382 }
6383 line1++;
6384
6385 if (pc2 == NOPCOMP) stuffLine(DNCP_CELL2LIST, x_("")); else
6386 {
6387 pc2->timestamp = line2;
6388 i = 0;
6389 for(;;)
6390 {
6391 i++;
6392 ind2++;
6393 if (ind2 >= pc2total) break;
6394 if (pc2list[ind2]->timestamp == 0) break;
6395 if (namesame(pc2->hashreason, pc2list[ind2]->hashreason) != 0)
6396 break;
6397 pc2list[ind2]->timestamp = line2;
6398 }
6399 infstr = initinfstr();
6400 if (i > 1)
6401 formatinfstr(infstr, x_("(%ld) "), i);
6402 addstringtoinfstr(infstr, pc2->hashreason);
6403 stuffLine(DNCP_CELL2LIST, returninfstr(infstr));
6404 }
6405 line2++;
6406 }
6407 selectLine(DNCP_CELL1LIST, 0);
6408 selectLine(DNCP_CELL2LIST, 0);
6409
6410 /* restore true wire counts */
6411 for(pc = pcomp1; pc != NOPCOMP; pc = pc->nextpcomp)
6412 pc->wirecount = (INTSML)pc->hashvalue;
6413 for(pc = pcomp2; pc != NOPCOMP; pc = pc->nextpcomp)
6414 pc->wirecount = (INTSML)pc->hashvalue;
6415 if (pc1total > 0) efree((CHAR *)pc1list);
6416 if (pc2total > 0) efree((CHAR *)pc2list);
6417 }
6418
6419 /******************************** SYMMETRY GROUP SUPPORT ********************************/
6420
6421 /*
6422 * Routine to create a new symmetry group of type "grouptype" with hash value "hashvalue".
6423 * The group is linked into the global list of symmetry groups.
6424 * Returns NOSYMGROUP on error.
6425 */
net_newsymgroup(INTBIG grouptype,HASHTYPE hashvalue,INTBIG checksum)6426 SYMGROUP *net_newsymgroup(INTBIG grouptype, HASHTYPE hashvalue, INTBIG checksum)
6427 {
6428 REGISTER SYMGROUP *sg;
6429
6430 if (net_symgroupfree == NOSYMGROUP)
6431 {
6432 sg = (SYMGROUP *)emalloc(sizeof (SYMGROUP), net_tool->cluster);
6433 if (sg == 0) return(NOSYMGROUP);
6434 sg->celltotal[0] = sg->celltotal[1] = 0;
6435 } else
6436 {
6437 sg = net_symgroupfree;
6438 net_symgroupfree = sg->nextsymgroup;
6439 }
6440 sg->hashvalue = hashvalue;
6441 sg->grouptype = grouptype;
6442 sg->groupflags = 0;
6443 sg->groupindex = net_symgroupnumber++;
6444 sg->checksum = checksum;
6445 sg->cellcount[0] = sg->cellcount[1] = 0;
6446 sg->nextsymgroup = net_firstsymgroup;
6447 net_firstsymgroup = sg;
6448
6449 /* put it in the hash table */
6450 if (net_insertinhashtable(sg))
6451 net_rebuildhashtable();
6452 return(sg);
6453 }
6454
6455 /*
6456 * Routine to free symmetry group "sg" to the pool of unused ones.
6457 */
net_freesymgroup(SYMGROUP * sg)6458 void net_freesymgroup(SYMGROUP *sg)
6459 {
6460 sg->nextsymgroup = net_symgroupfree;
6461 net_symgroupfree = sg;
6462 }
6463
6464 /*
6465 * Routine to find a unique hash number for a new symmetry group.
6466 */
net_uniquesymmetrygrouphash(INTBIG grouptype)6467 HASHTYPE net_uniquesymmetrygrouphash(INTBIG grouptype)
6468 {
6469 REGISTER SYMGROUP *sg;
6470
6471 for( ; ; net_uniquehashvalue--)
6472 {
6473 sg = net_findsymmetrygroup(grouptype, net_uniquehashvalue, 0);
6474 if (sg == NOSYMGROUP) break;
6475 }
6476 return(net_uniquehashvalue);
6477 }
6478
6479 /*
6480 * Routine to find the symmetry group of type "grouptype" with hash value "hashvalue".
6481 * The "checksum" value is an additional piece of information about this hash value
6482 * to ensure that there are not clashes in the codes. Returns NOSYMGROUP if none is found.
6483 */
net_findsymmetrygroup(INTBIG grouptype,HASHTYPE hashvalue,INTBIG checksum)6484 SYMGROUP *net_findsymmetrygroup(INTBIG grouptype, HASHTYPE hashvalue, INTBIG checksum)
6485 {
6486 REGISTER SYMGROUP *sg;
6487 REGISTER INTBIG i, hashindex;
6488
6489 if (grouptype == SYMGROUPNET)
6490 {
6491 hashindex = abs((INTBIG)(hashvalue % net_symgrouphashnetsize));
6492 for(i=0; i<net_symgrouphashnetsize; i++)
6493 {
6494 sg = net_symgrouphashnet[hashindex];
6495 if (sg == NOSYMGROUP) break;
6496 if (sg->hashvalue == hashvalue)
6497 {
6498 if (sg->checksum != checksum && hashvalue != 0 && !net_nethashclashtold)
6499 {
6500 ttyputerr(_("-- POSSIBLE NETWORK HASH CLASH (%ld AND %ld)"),
6501 sg->checksum, checksum);
6502 net_nethashclashtold = TRUE;
6503 }
6504 return(sg);
6505 }
6506 hashindex++;
6507 if (hashindex >= net_symgrouphashnetsize) hashindex = 0;
6508 }
6509 } else
6510 {
6511 hashindex = abs((INTBIG)(hashvalue % net_symgrouphashcompsize));
6512 for(i=0; i<net_symgrouphashcompsize; i++)
6513 {
6514 sg = net_symgrouphashcomp[hashindex];
6515 if (sg == NOSYMGROUP) break;
6516 if (sg->hashvalue == hashvalue)
6517 {
6518 if (sg->checksum != checksum && hashvalue != 0 && !net_comphashclashtold)
6519 {
6520 ttyputerr(_("-- POSSIBLE COMPONENT HASH CLASH (%ld AND %ld)"),
6521 sg->checksum, checksum);
6522 net_comphashclashtold = TRUE;
6523 }
6524 return(sg);
6525 }
6526 hashindex++;
6527 if (hashindex >= net_symgrouphashcompsize) hashindex = 0;
6528 }
6529 }
6530 return(NOSYMGROUP);
6531 }
6532
net_rebuildhashtable(void)6533 void net_rebuildhashtable(void)
6534 {
6535 REGISTER INTBIG i;
6536 REGISTER BOOLEAN problems;
6537 REGISTER SYMGROUP *sg;
6538
6539 for(;;)
6540 {
6541 problems = FALSE;
6542 for(i=0; i<net_symgrouphashcompsize; i++) net_symgrouphashcomp[i] = NOSYMGROUP;
6543 for(i=0; i<net_symgrouphashnetsize; i++) net_symgrouphashnet[i] = NOSYMGROUP;
6544 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
6545 {
6546 problems = net_insertinhashtable(sg);
6547 if (problems) break;
6548 }
6549 for(sg = net_firstmatchedsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
6550 {
6551 problems = net_insertinhashtable(sg);
6552 if (problems) break;
6553 }
6554 if (!problems) break;
6555 }
6556 }
6557
6558 /*
6559 * Routine to insert symmetry group "sg" into a hash table. Returns true
6560 * if the hash table needed to be expanded (and is thus invalid now).
6561 */
net_insertinhashtable(SYMGROUP * sg)6562 BOOLEAN net_insertinhashtable(SYMGROUP *sg)
6563 {
6564 REGISTER INTBIG i, hashindex, newsize, *newhashtableck;
6565 REGISTER SYMGROUP **newhashtable;
6566
6567 if (sg->grouptype == SYMGROUPNET)
6568 {
6569 hashindex = abs((INTBIG)(sg->hashvalue % net_symgrouphashnetsize));
6570 for(i=0; i<net_symgrouphashnetsize; i++)
6571 {
6572 if (net_symgrouphashnet[hashindex] == NOSYMGROUP)
6573 {
6574 net_symgrouphashnet[hashindex] = sg;
6575 net_symgrouphashcknet[hashindex] = sg->checksum;
6576 break;
6577 }
6578 hashindex++;
6579 if (hashindex >= net_symgrouphashnetsize) hashindex = 0;
6580 }
6581 if (i >= net_symgrouphashnetsize)
6582 {
6583 newsize = pickprime(net_symgrouphashnetsize * 2);
6584 newhashtable = (SYMGROUP **)emalloc(newsize * (sizeof (SYMGROUP *)),
6585 net_tool->cluster);
6586 if (newhashtable == 0) return(FALSE);
6587 newhashtableck = (INTBIG *)emalloc(newsize * SIZEOFINTBIG,
6588 net_tool->cluster);
6589 if (newhashtableck == 0) return(FALSE);
6590 efree((CHAR *)net_symgrouphashnet);
6591 efree((CHAR *)net_symgrouphashcknet);
6592 net_symgrouphashnet = newhashtable;
6593 net_symgrouphashcknet = newhashtableck;
6594 net_symgrouphashnetsize = newsize;
6595 ttyputmsg(x_(" -- EXPANDING SIZE OF NETWORK HASH TABLE TO %ld ENTRIES"),
6596 newsize);
6597 return(TRUE);
6598 }
6599 } else
6600 {
6601 hashindex = abs((INTBIG)(sg->hashvalue % net_symgrouphashcompsize));
6602 for(i=0; i<net_symgrouphashcompsize; i++)
6603 {
6604 if (net_symgrouphashcomp[hashindex] == NOSYMGROUP)
6605 {
6606 net_symgrouphashcomp[hashindex] = sg;
6607 net_symgrouphashckcomp[hashindex] = sg->checksum;
6608 break;
6609 }
6610 hashindex++;
6611 if (hashindex >= net_symgrouphashcompsize) hashindex = 0;
6612 }
6613 if (i >= net_symgrouphashcompsize)
6614 {
6615 newsize = pickprime(net_symgrouphashcompsize * 2);
6616 newhashtable = (SYMGROUP **)emalloc(newsize * (sizeof (SYMGROUP *)),
6617 net_tool->cluster);
6618 if (newhashtable == 0) return(FALSE);
6619 newhashtableck = (INTBIG *)emalloc(newsize * SIZEOFINTBIG,
6620 net_tool->cluster);
6621 if (newhashtableck == 0) return(FALSE);
6622 efree((CHAR *)net_symgrouphashcomp);
6623 efree((CHAR *)net_symgrouphashckcomp);
6624 net_symgrouphashcomp = newhashtable;
6625 net_symgrouphashckcomp = newhashtableck;
6626 net_symgrouphashcompsize = newsize;
6627 ttyputmsg(x_(" -- EXPANDING SIZE OF COMPONENT HASH TABLE TO %ld ENTRIES"),
6628 newsize);
6629 return(TRUE);
6630 }
6631 }
6632 return(FALSE);
6633 }
6634
6635 /*
6636 * Routine to add object "obj" to cell "f" (0 or 1) of symmetry group "sg".
6637 * Returns true on error.
6638 */
net_addtosymgroup(SYMGROUP * sg,INTBIG f,void * obj)6639 BOOLEAN net_addtosymgroup(SYMGROUP *sg, INTBIG f, void *obj)
6640 {
6641 INTBIG newtotal, i, count;
6642 REGISTER PNET *pn;
6643 REGISTER PCOMP *pc;
6644 void **newlist;
6645
6646 count = sg->cellcount[f];
6647 if (count >= sg->celltotal[f])
6648 {
6649 newtotal = count + 10;
6650 newlist = (void **)emalloc(newtotal * (sizeof (void *)), net_tool->cluster);
6651 if (newlist == 0) return(TRUE);
6652 for(i=0; i < count; i++)
6653 newlist[i] = sg->celllist[f][i];
6654 if (sg->celltotal[f] > 0) efree((CHAR *)sg->celllist[f]);
6655 sg->celllist[f] = newlist;
6656 sg->celltotal[f] = newtotal;
6657 }
6658 sg->celllist[f][count] = obj;
6659 sg->cellcount[f]++;
6660 if (sg->grouptype == SYMGROUPNET)
6661 {
6662 pn = (PNET *)obj;
6663 pn->timestamp = net_timestamp;
6664 } else
6665 {
6666 pc = (PCOMP *)obj;
6667 pc->timestamp = net_timestamp;
6668 }
6669 return(FALSE);
6670 }
6671
6672 /*
6673 * Routine to remove entry "index" from cell "f" (0 or 1) of symmetry group "sg".
6674 */
net_removefromsymgroup(SYMGROUP * sg,INTBIG f,INTBIG index)6675 void net_removefromsymgroup(SYMGROUP *sg, INTBIG f, INTBIG index)
6676 {
6677 REGISTER INTBIG count;
6678
6679 count = sg->cellcount[f];
6680 sg->celllist[f][index] = sg->celllist[f][count-1];
6681 sg->cellcount[f]--;
6682 }
6683
6684 /*********************** NCC MATCH CACHING ***********************/
6685
6686 /*
6687 * Routine to preserve NCC results on cell "np1" (after being compared with "np2")
6688 */
net_preserveresults(NODEPROTO * np1,NODEPROTO * np2)6689 void net_preserveresults(NODEPROTO *np1, NODEPROTO *np2)
6690 {
6691 REGISTER time_t curtime;
6692 UINTBIG matchdate;
6693 NODEPROTO *othercell;
6694 INTBIG count;
6695 REGISTER INTBIG i, index, highestindex;
6696 REGISTER VARIABLE *var;
6697 REGISTER void *sa;
6698 REGISTER CHAR *name1, *name2, *pt;
6699 REGISTER PNET *pn1, *pn2;
6700 REGISTER SYMGROUP *sg;
6701 CHAR line[300], **stringarray;
6702
6703 sa = newstringarray(net_tool->cluster);
6704 curtime = getcurrenttime();
6705 esnprintf(line, 300, x_("TIME %lu"), curtime);
6706 addtostringarray(sa, line);
6707 esnprintf(line, 300, x_("MATCH %s:%s"), np2->lib->libname, nldescribenodeproto(np2));
6708 addtostringarray(sa, line);
6709 for(sg = net_firstsymgroup; sg != NOSYMGROUP; sg = sg->nextsymgroup)
6710 {
6711 if (sg->cellcount[0] == 1 && sg->cellcount[1] == 1 && sg->grouptype == SYMGROUPNET)
6712 {
6713 /* see if names match */
6714 if (np1 == net_cell[0])
6715 {
6716 pn1 = (PNET *)sg->celllist[0][0];
6717 pn2 = (PNET *)sg->celllist[1][0];
6718 } else
6719 {
6720 pn1 = (PNET *)sg->celllist[1][0];
6721 pn2 = (PNET *)sg->celllist[0][0];
6722 }
6723
6724 if ((pn1->flags&EXPORTEDNET) == 0 || (pn2->flags&EXPORTEDNET) == 0) continue;
6725 if (pn1->realportcount == 0 &&
6726 (pn1->network == NONETWORK || pn1->network->namecount == 0)) continue;
6727 if (pn2->realportcount == 0 &&
6728 (pn2->network == NONETWORK || pn2->network->namecount == 0)) continue;
6729
6730 if (pn1->realportcount == 0)
6731 {
6732 name1 = networkname(pn1->network, 0);
6733 } else if (pn1->realportcount == 1)
6734 {
6735 name1 = ((PORTPROTO *)pn1->realportlist)->protoname;
6736 } else
6737 {
6738 name1 = (((PORTPROTO **)pn1->realportlist)[0])->protoname;
6739 }
6740 if (pn2->realportcount == 0)
6741 {
6742 name2 = networkname(pn2->network, 0);
6743 } else if (pn2->realportcount == 1)
6744 {
6745 name2 = ((PORTPROTO *)pn2->realportlist)->protoname;
6746 } else
6747 {
6748 name2 = (((PORTPROTO **)pn2->realportlist)[0])->protoname;
6749 }
6750 esnprintf(line, 300, x_("EXPORT %s:%s"), name1, name2);
6751 addtostringarray(sa, line);
6752 }
6753 }
6754 stringarray = getstringarray(sa, &count);
6755
6756 /* find a place to store this information */
6757 highestindex = 0;
6758 for(i=0; i<np1->numvar; i++)
6759 {
6760 var = &np1->firstvar[i];
6761 pt = makename(var->key);
6762 if (namesamen(pt, x_("NET_ncc_last_result"), 19) != 0) continue;
6763 index = eatoi(&pt[19]);
6764 if (index > highestindex) highestindex = index;
6765
6766 /* if this information is intended for the other cell, overwrite it */
6767 net_parsenccresult(np1, var, &othercell, &matchdate);
6768 if (othercell == np2)
6769 {
6770 highestindex = index-1;
6771 break;
6772 }
6773 }
6774 esnprintf(line, 300, x_("NET_ncc_last_result%ld"), highestindex+1);
6775 (void)setval((INTBIG)np1, VNODEPROTO, line, (INTBIG)stringarray,
6776 VSTRING|VISARRAY|(count<<VLENGTHSH));
6777 killstringarray(sa);
6778 }
6779
6780 /*
6781 * Routine to return true if the cells "cell1" and "cell2" are already NCC'd.
6782 */
net_nccalreadydone(NODEPROTO * cell1,NODEPROTO * cell2)6783 BOOLEAN net_nccalreadydone(NODEPROTO *cell1, NODEPROTO *cell2)
6784 {
6785 REGISTER VARIABLE *var1, *var2;
6786 UINTBIG cell1matchdate, cell2matchdate, cell1changedate, cell2changedate;
6787
6788 /* see if cell 1 has match information with cell 2 */
6789 var1 = net_nccfindmatch(cell1, cell2, &cell1matchdate);
6790 if (var1 == NOVARIABLE) return(FALSE);
6791 cell1changedate = net_recursiverevisiondate(cell1);
6792 if (cell1changedate > cell1matchdate) return(FALSE);
6793
6794 /* see if cell 2 has match information with cell 1 */
6795 var2 = net_nccfindmatch(cell2, cell1, &cell2matchdate);
6796 if (var2 == NOVARIABLE) return(FALSE);
6797 cell2changedate = net_recursiverevisiondate(cell2);
6798 if (cell2changedate > cell2matchdate) return(FALSE);
6799
6800 /* the cells are already checked */
6801 return(TRUE);
6802 }
6803
6804 /*
6805 * Routine to recursively obtain the most recent revision date for cell "cell"
6806 * or any of its subcells.
6807 */
net_recursiverevisiondate(NODEPROTO * cell)6808 UINTBIG net_recursiverevisiondate(NODEPROTO *cell)
6809 {
6810 REGISTER UINTBIG latestrevision, instancerevision;
6811 REGISTER NODEINST *ni;
6812 REGISTER NODEPROTO *np, *cnp;
6813
6814 latestrevision = cell->revisiondate;
6815 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
6816 {
6817 np = ni->proto;
6818 if (np->primindex != 0) continue;
6819 cnp = contentsview(np);
6820 if (cnp == NONODEPROTO) cnp = np;
6821 if (cnp == cell) continue;
6822 instancerevision = net_recursiverevisiondate(cnp);
6823 if (instancerevision > latestrevision)
6824 latestrevision = instancerevision;
6825 }
6826 return(latestrevision);
6827 }
6828
6829 /*
6830 * Routine to scan cell "np" looking for an NCC match to cell "onp". If found,
6831 * the date of the match is returned in "matchdate" and the variable describing
6832 * the match information is returned. Returns NOVARIABLE if not found.
6833 */
net_nccfindmatch(NODEPROTO * np,NODEPROTO * onp,UINTBIG * matchdate)6834 VARIABLE *net_nccfindmatch(NODEPROTO *np, NODEPROTO *onp, UINTBIG *matchdate)
6835 {
6836 REGISTER INTBIG i;
6837 NODEPROTO *othernp;
6838 REGISTER VARIABLE *var;
6839 REGISTER CHAR *pt;
6840
6841 /* find a place to store this information */
6842 for(i=0; i<np->numvar; i++)
6843 {
6844 var = &np->firstvar[i];
6845 pt = makename(var->key);
6846 if (namesamen(pt, x_("NET_ncc_last_result"), 19) != 0) continue;
6847 net_parsenccresult(np, var, &othernp, matchdate);
6848 if (othernp == onp) return(var);
6849 }
6850 return(NOVARIABLE);
6851 }
6852
6853 /*
6854 * Routine to return nonzero if cell "np" has NCC match information that is
6855 * still current with any other cell.
6856 */
net_ncchasmatch(NODEPROTO * np)6857 INTBIG net_ncchasmatch(NODEPROTO *np)
6858 {
6859 REGISTER INTBIG i;
6860 UINTBIG matchdate, revisiondate;
6861 NODEPROTO *othernp;
6862 REGISTER VARIABLE *var;
6863 REGISTER CHAR *pt;
6864
6865 for(i=0; i<np->numvar; i++)
6866 {
6867 var = &np->firstvar[i];
6868 pt = makename(var->key);
6869 if (namesamen(pt, x_("NET_ncc_last_result"), 19) != 0) continue;
6870 net_parsenccresult(np, var, &othernp, &matchdate);
6871 revisiondate = net_recursiverevisiondate(np);
6872 if (revisiondate <= matchdate) return(1);
6873 }
6874 return(0);
6875 }
6876
6877 /*
6878 * Routine to remove all NCC match information on cell "np".
6879 */
net_nccremovematches(NODEPROTO * np)6880 void net_nccremovematches(NODEPROTO *np)
6881 {
6882 REGISTER INTBIG i;
6883 REGISTER VARIABLE *var;
6884 REGISTER CHAR *pt;
6885
6886 /* find a place to store this information */
6887 for(i=0; i<np->numvar; i++)
6888 {
6889 var = &np->firstvar[i];
6890 pt = makename(var->key);
6891 if (namesamen(pt, x_("NET_ncc_last_result"), 19) != 0) continue;
6892 (void)delvalkey((INTBIG)np, VNODEPROTO, var->key);
6893 i--;
6894 }
6895 }
6896
6897 /*
6898 * Routine to parse the NCC results on cell "np" and store the information in
6899 * "cellmatch" (the cell that was matched) and "celldate" (the time of the match)
6900 */
net_nccmatchinfo(NODEPROTO * np,NODEPROTO ** cellmatch,UINTBIG * celldate)6901 void net_nccmatchinfo(NODEPROTO *np, NODEPROTO **cellmatch, UINTBIG *celldate)
6902 {
6903 REGISTER VARIABLE *var;
6904 REGISTER INTBIG i;
6905 REGISTER CHAR *pt;
6906
6907 *cellmatch = NONODEPROTO;
6908 *celldate = 0;
6909 for(i=0; i<np->numvar; i++)
6910 {
6911 var = &np->firstvar[i];
6912 pt = makename(var->key);
6913 if (namesamen(pt, x_("NET_ncc_last_result"), 19) != 0) continue;
6914 net_parsenccresult(np, var, cellmatch, celldate);
6915 break;
6916 }
6917 }
6918
6919 /*
6920 * Routine to parse the NCC results on cell "np" in variable "var" and store the
6921 * information in "cellmatch" (the cell that was matched) and "celldate" (the
6922 * time of the match).
6923 */
net_parsenccresult(NODEPROTO * np,VARIABLE * var,NODEPROTO ** cellmatch,UINTBIG * celldate)6924 void net_parsenccresult(NODEPROTO *np, VARIABLE *var, NODEPROTO **cellmatch,
6925 UINTBIG *celldate)
6926 {
6927 REGISTER INTBIG len, i;
6928 REGISTER CHAR **strings, *pt;
6929 Q_UNUSED( np );
6930
6931 *cellmatch = NONODEPROTO;
6932 *celldate = 0;
6933 if (var == NOVARIABLE) return;
6934 len = getlength(var);
6935 strings = (CHAR **)var->addr;
6936 for(i=0; i<len; i++)
6937 {
6938 pt = strings[i];
6939 if (namesamen(pt, x_("TIME "), 5) == 0)
6940 {
6941 *celldate = eatoi(&pt[5]);
6942 continue;
6943 }
6944 if (namesamen(pt, x_("MATCH "), 6) == 0)
6945 {
6946 *cellmatch = getnodeproto(&pt[6]);
6947 continue;
6948 }
6949 }
6950 }
6951
6952 /*********************** HELPER ROUTINES ***********************/
6953
net_describepcomp(PCOMP * pc)6954 CHAR *net_describepcomp(PCOMP *pc)
6955 {
6956 REGISTER INTBIG i;
6957 REGISTER NODEINST *ni;
6958 REGISTER void *infstr;
6959
6960 infstr = initinfstr();
6961 for(i=0; i<pc->numactual; i++)
6962 {
6963 if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
6964 ni = ((NODEINST **)pc->actuallist)[i];
6965 if (i != 0) addtoinfstr(infstr, '/');
6966 addstringtoinfstr(infstr, ntdescribenodeinst(ni));
6967 }
6968 return(returninfstr(infstr));
6969 }
6970
net_describepnet(PNET * pn)6971 CHAR *net_describepnet(PNET *pn)
6972 {
6973 REGISTER PORTPROTO *pp;
6974 REGISTER INTBIG i;
6975 REGISTER NETWORK *net;
6976 REGISTER void *infstr;
6977
6978 net = pn->network;
6979 infstr = initinfstr();
6980 if ((pn->flags&POWERNET) != 0) addstringtoinfstr(infstr, _("POWER "));
6981 if ((pn->flags&GROUNDNET) != 0) addstringtoinfstr(infstr, _("GROUND "));
6982 if ((pn->flags&EXPORTEDNET) == 0)
6983 {
6984 if (net == NONETWORK) addstringtoinfstr(infstr, _("INTERNAL")); else
6985 {
6986 if (net->globalnet >= 0 && net->globalnet < net->parent->globalnetcount)
6987 {
6988 addstringtoinfstr(infstr, describenetwork(net));
6989 } else
6990 {
6991 formatinfstr(infstr, _("INTERNAL %s:%s"), describenodeproto(net->parent),
6992 describenetwork(net));
6993 }
6994 }
6995 } else
6996 {
6997 #ifdef PATHTOPNET
6998 if (pn->hierpathcount > 0)
6999 {
7000 for(i=0; i<pn->hierpathcount; i++)
7001 {
7002 addstringtoinfstr(infstr, describenodeinst(pn->hierpath[i]));
7003 if (pn->hierindex[i] != 0) formatinfstr(infstr, "[%ld]", pn->hierindex[i]);
7004 addstringtoinfstr(infstr, ".");
7005 }
7006 } else addstringtoinfstr(infstr, "TOP.");
7007 #endif
7008 if (pn->realportcount == 1)
7009 {
7010 pp = (PORTPROTO *)pn->realportlist;
7011 if (pp->network->buswidth > 1 && net != NONETWORK)
7012 addstringtoinfstr(infstr, describenetwork(net)); else
7013 addstringtoinfstr(infstr, pp->protoname);
7014 } else if (pn->realportcount > 1)
7015 {
7016 for(i=0; i<pn->realportcount; i++)
7017 {
7018 pp = ((PORTPROTO **)pn->realportlist)[i];
7019 if (i > 0) addtoinfstr(infstr, ',');
7020 if (i == 0 && pp->network->buswidth > 1 && net != NONETWORK)
7021 addstringtoinfstr(infstr, describenetwork(net)); else
7022 addstringtoinfstr(infstr, pp->protoname);
7023 }
7024 } else
7025 {
7026 net = pn->network;
7027 addstringtoinfstr(infstr, describenetwork(net));
7028 }
7029 }
7030 return(returninfstr(infstr));
7031 }
7032
7033 /*
7034 * Routine to see if the component values "v1" and "v2" are within the prescribed
7035 * tolerance (in "net_ncc_tolerance" and "net_ncc_tolerance_amt"). Returns true if so.
7036 */
net_componentequalvalue(float v1,float v2)7037 BOOLEAN net_componentequalvalue(float v1, float v2)
7038 {
7039 float tolerance, largest, diff;
7040
7041 /* first see if it is within tolerance amount */
7042 diff = (float)fabs(v1 - v2);
7043 if (diff <= net_ncc_tolerance_amt) return(TRUE);
7044
7045 /* now see if it is within tolerance percentage */
7046 if (v1 > v2) largest = v1; else largest = v2;
7047 tolerance = largest * net_ncc_tolerance / (WHOLE * 100.0f);
7048 if (diff <= tolerance) return(TRUE);
7049
7050 /* not within any tolerance */
7051 return(FALSE);
7052 }
7053
7054 /*
7055 * Routine to return true if component "pc" is a SPICE component.
7056 */
net_isspice(PCOMP * pc)7057 BOOLEAN net_isspice(PCOMP *pc)
7058 {
7059 REGISTER NODEINST *ni;
7060
7061 switch (pc->function)
7062 {
7063 case NPMETER:
7064 case NPSOURCE:
7065 return(TRUE);
7066 }
7067 if (pc->numactual == 1)
7068 {
7069 ni = (NODEINST *)pc->actuallist;
7070 if (ni->proto->primindex == 0 &&
7071 namesamen(ni->proto->lib->libname, x_("spiceparts"), 10) == 0)
7072 return(TRUE);
7073 }
7074 return(FALSE);
7075 }
7076
net_initdiff(void)7077 void net_initdiff(void)
7078 {
7079 REGISTER INTBIG i;
7080
7081 if (net_nodeCountMultiplier == 0)
7082 {
7083 i = 0;
7084 net_nodeCountMultiplier = getprime(i++);
7085 net_portFactorMultiplier = getprime(i++);
7086 net_functionMultiplier = getprime(i++);
7087 net_portNetFactorMultiplier = getprime(i++);
7088 net_portHashFactorMultiplier = getprime(i++);
7089 }
7090 }
7091