2
* Electric(tm) VLSI Design System
5
* Network tool: module for fully instantiating a hierarchical network
6
* Written by: Steven M. Rubin, Static Free Software
8
* Copyright (c) 2000 Static Free Software.
10
* Electric(tm) is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* Electric(tm) is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with Electric(tm); see the file COPYING. If not, write to
22
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23
* Boston, Mass 02111-1307, USA.
25
* Static Free Software
27
* Portola Valley, California 94028
28
* info@staticfreesoft.com
33
#include "efunction.h"
36
#define IGNOREFOURPORT 1 /* comment out to handle 4-port transistors properly */
38
static INTBIG net_pseudonode; /* net number for pseudonetworks */
39
static NODEINST *net_toplevelinst; /* actual top-instance associated with this node */
40
static PCOMP *net_seriesend1, *net_seriesend2; /* end component of series transistor chains */
41
static INTBIG net_seriescon1, net_seriescon2; /* end index of series transistor chains */
43
/* working memory for "net_comparewirelist()" */
44
static INTBIG net_comparelistsize = 0;
45
static BOOLEAN *net_comparelist;
47
/* working memory for "net_mergeseries()" */
48
static PCOMP **net_serieslist;
49
static INTBIG net_serieslistcount;
50
static INTBIG net_serieslisttotal = 0;
52
/* prototypes for local routines */
53
static BOOLEAN net_addtoserieslist(PCOMP *pc);
54
static PCOMP *net_allocpcomp(void);
55
static PNET *net_allocpnet(void);
56
static PCOMP *net_buildpseudo(NODEPROTO*, PCOMP*, INTBIG*, PNET**, BOOLEAN);
57
static void net_crawlforseries(PCOMP *pc);
58
static INTBIG net_findotherexporttopology(NODEPROTO *np, char *exportname);
59
static PCOMP **net_gatherseries(PCOMP *pc, INTBIG *seriescount);
60
static INTBIG net_getfunction(NODEINST*);
61
static float net_getpartvalue(NODEINST *ni);
62
static BOOLEAN net_getpnetandstate(NODEINST *ni, PORTPROTO *pp, NETWORK *forcenet,
63
INTBIG index, PNET **netnumber, INTSML *state, PNET **pnetlist,
64
INTBIG nodewidth, INTBIG nindex, INTBIG destsignals);
65
static INTBIG net_mergeseries(PCOMP **pcomp, PNET *pnet, INTBIG *components);
66
static PNET *net_newpnet(NETWORK *net, PNET **pnetlist);
67
static void net_setallexporttopology(void);
68
static void net_setthisexporttopology(PORTPROTO *pp, INTBIG *index);
69
static int net_sortpcompbyhash(const void *e1, const void *e2);
72
* Routine to free all memory associated with this module.
74
void net_freeflatmemory(void)
79
while (net_pcompfree != NOPCOMP)
82
net_pcompfree = net_pcompfree->nextpcomp;
85
while (net_pnetfree != NOPNET)
88
net_pnetfree = net_pnetfree->nextpnet;
91
if (net_comparelistsize > 0) efree((char *)net_comparelist);
94
/*********************** PSEUDO-NETWORK CONSTRUCTION ***********************/
97
* The usage of this module is:
98
* #include "network.h"
101
* INTBIG components, nets, powernets, groundnets;
102
* pcomp = net_makepseudo(facet, &components, &nets, &powernets, &groundnets,
103
* &pnet, hierarchical, mergeparallel, mergeseries, checkfacetoverrides);
105
* do something with the network in "pcomp" and "pnet"
107
* net_freeallpnet(pnet);
108
* net_freeallpcomp(pcomp);
110
* "net_makepseudo" builds a pseudonetwork structure that represents the
111
* network in facet "facet". If it returns NOPCOMP and sets "components" negative,
112
* there is an error (if it returns NOPCOMP with "components" zero, there just are not
113
* any components in the facet).
114
* A linked list of PCOMP objects is returned, one for every component
115
* in the pseudonetwork. A linked list of PNET objects is also returned,
116
* one for every network in the pseudonetwork. Finally, the number of
117
* components, networks, power networks, and ground networks is returned
118
* in the reference parameters "components", "nets", "powernets", and
121
* A number of switches controls the flattening:
122
* If "hierarchical" is true, the network will be fully instantiated.
123
* If "mergeparallel" is true, parallel components are merged into one.
124
* If "mergeseries" is true, series transistors are merged into one.
125
* If "checkfacetoverrides" is true, individual facets may override "mergeparallel".
127
PCOMP *net_makepseudo(NODEPROTO *facet, INTBIG *components, INTBIG *nets, INTBIG *powernets,
128
INTBIG *groundnets, PNET **pnetlist, BOOLEAN hierarchical, BOOLEAN mergeparallel,
129
BOOLEAN mergeseries, BOOLEAN checkfacetoverrides)
132
REGISTER BOOLEAN localmergeparallel, localmergeseries;
133
REGISTER INTBIG i, mergecount;
134
REGISTER NETWORK *net, *subnet;
136
REGISTER VARIABLE *var;
137
REGISTER PORTPROTO *pp, *opp, *npp, **newportlist;
139
/* see if the current facet overrides the options */
140
localmergeparallel = mergeparallel;
141
localmergeseries = mergeseries;
142
if (checkfacetoverrides)
144
var = getvalkey((INTBIG)facet, VNODEPROTO, VINTEGER, net_ncc_optionskey);
145
if (var != NOVARIABLE)
147
if ((var->addr&NCCNOMERGEPARALLELOVER) != 0)
149
if ((var->addr&NCCNOMERGEPARALLEL) == 0) localmergeparallel = TRUE; else
150
localmergeparallel = FALSE;
152
if ((var->addr&NCCMERGESERIESOVER) != 0)
154
if ((var->addr&NCCMERGESERIES) != 0) localmergeseries = TRUE; else
155
localmergeseries = FALSE;
160
/* first create net numbers inside of this facet */
163
for(net = facet->firstnetwork; net != NONETWORK; net = net->nextnetwork)
164
net->temp1 = (INTBIG)NOPNET;
165
for(pp = facet->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
168
if (net->temp1 != (INTBIG)NOPNET) continue;
169
pn = net_newpnet(net, pnetlist);
170
if (pn == NOPNET) { *components = -1; return(NOPCOMP); }
171
if ((pp->userbits&STATEBITS) == PWRPORT) pn->flags |= POWERNET; else
172
if ((pp->userbits&STATEBITS) == GNDPORT) pn->flags |= GROUNDNET;
173
pn->flags |= EXPORTEDNET;
174
net->temp1 = (INTBIG)pn;
175
pn->realportcount = 1;
176
pn->realportlist = pp;
177
for(opp = pp->nextportproto; opp != NOPORTPROTO; opp = opp->nextportproto)
179
if (net != opp->network) continue;
180
newportlist = (PORTPROTO **)emalloc((pn->realportcount+1) *
181
(sizeof (PORTPROTO *)), net_tool->cluster);
182
if (newportlist == 0) { *components = -1; return(NOPCOMP); }
183
for(i=0; i<pn->realportcount; i++)
185
if (pn->realportcount == 1) npp = (PORTPROTO *)pn->realportlist; else
186
npp = ((PORTPROTO **)pn->realportlist)[i];
187
newportlist[i] = npp;
189
newportlist[pn->realportcount] = opp;
190
if (pn->realportcount > 1) efree((char *)pn->realportlist);
191
pn->realportlist = newportlist;
194
if (net->signals > 1)
196
for(i=0; i<net->signals; i++)
198
subnet = net->networklist[i];
199
if (subnet->temp1 != (INTBIG)NOPNET) continue;
200
pn = net_newpnet(subnet, pnetlist);
201
pn->flags |= EXPORTEDNET;
202
subnet->temp1 = (INTBIG)pn;
207
/* establish topology of exports */
208
net_setallexporttopology();
210
/* create a list of pseudocomponents in this facet */
212
begintraversehierarchy();
213
net_toplevelinst = NONODEINST;
214
pcomplist = net_buildpseudo(facet, NOPCOMP, components, pnetlist, hierarchical);
215
if (pcomplist == 0) { *components = -1; return(NOPCOMP); }
216
if (*components == 0)
217
ttyputmsg(_("There are no components in facet %s"), describenodeproto(facet));
219
/* reduce network by merging parallel components */
220
if (localmergeparallel)
222
ttyputmsg(_("--- Merging parallel components in facet %s..."),
223
describenodeproto(facet));
224
mergecount = net_mergeparallel(&pcomplist, *pnetlist, components);
225
if (mergecount < 0) { *components = -1; return(NOPCOMP); }
227
ttyputmsg(_("--- Merged %ld parallel components"), mergecount);
229
if (localmergeseries)
231
mergecount = net_mergeseries(&pcomplist, *pnetlist, components);
233
ttyputmsg(_("--- Merged %ld series transistors in facet %s"),
234
mergecount, describenodeproto(facet));
237
/* report the total number of nets */
238
*nets = net_pseudonode;
240
/* count the power and ground nets */
241
*powernets = *groundnets = 0;
242
for(pn = *pnetlist; pn != NOPNET; pn = pn->nextpnet)
244
if ((pn->flags&POWERNET) != 0) (*powernets)++;
245
if ((pn->flags&GROUNDNET) != 0) (*groundnets)++;
246
if ((pn->flags&(POWERNET|GROUNDNET)) == (POWERNET|GROUNDNET))
247
ttyputmsg(_("WARNING: net %s shorts power and ground"),
248
describenetwork(pn->network));
254
* routine to build a linked list of pseudocomponents in facet "facet". The
255
* list is appended to "initiallist" and returned. The values of "power" and
256
* "ground" are the PNETs of such components. Routine increments the
257
* integer at "components" for every component created. If
258
* "compare_hierarchically" is nonzero, net is flattened. Returns zero on error.
260
PCOMP *net_buildpseudo(NODEPROTO *facet, PCOMP *initiallist, INTBIG *components,
261
PNET **pnetlist, BOOLEAN compare_hierarchically)
263
REGISTER PCOMP *pcomp;
264
REGISTER PORTPROTO *pp, *opp, *realpp, *temprealpp;
265
REGISTER PORTARCINST *pi;
266
REGISTER PORTEXPINST *pe;
267
REGISTER NETWORK *net, *subnet, *foundnet;
268
REGISTER NODEINST *ni;
270
REGISTER INTBIG fun, i, j, k, l, toplevel, flattenit, lambda,
271
nodewidth, nindex, sigcount;
272
BOOLEAN localcompare_hierarchically;
273
INTBIG width, length, pathcount, *indexlist;
274
REGISTER NODEPROTO *realnp, *anp, *cnp;
276
REGISTER VARIABLE *var;
278
if (net_toplevelinst == NONODEINST) toplevel = 1; else
281
/* make simple checks that port characteristics match the name */
282
for(pp = facet->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
284
/* check busses for consistent component characteristics */
285
if (pp->network->signals > 1)
287
for(i=0; i<pp->network->signals; i++)
289
subnet = pp->network->networklist[i];
290
for(opp = facet->firstportproto; opp != NOPORTPROTO; opp = opp->nextportproto)
292
if (opp->network != subnet) continue;
293
if ((opp->userbits&STATEBITS) != (pp->userbits&STATEBITS))
295
ttyputerr(_("Warning: bus export %s is %s but export %s is %s"),
296
pp->protoname, describeportbits(pp), opp->protoname,
297
describeportbits(opp));
305
/* spread power and ground information from appropriate nodes */
306
for(ni = facet->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
308
/* see if power or ground comes from this node */
309
for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
310
if ((pe->exportproto->userbits&STATEBITS) == PWRPORT ||
311
(pe->exportproto->userbits&STATEBITS) == GNDPORT) break;
312
if (pe == NOPORTEXPINST) continue;
314
/* they do: get the network */
316
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
317
if (pi->proto == pp) break;
318
if (pi == NOPORTARCINST) continue;
320
/* propagate power and ground */
321
net = pi->conarcinst->network;
322
if ((pe->exportproto->userbits&STATEBITS) == PWRPORT)
324
pn = (PNET *)net->temp1;
326
pn = net_newpnet(net, pnetlist);
327
pn->flags |= POWERNET;
329
if ((pe->exportproto->userbits&STATEBITS) == GNDPORT)
331
pn = (PNET *)net->temp1;
333
pn = net_newpnet(net, pnetlist);
334
pn->flags |= GROUNDNET;
338
/* generate new pseudo-netnumbers for networks not connected to ports */
339
for(net = facet->firstnetwork; net != NONETWORK; net = net->nextnetwork)
341
if (net->temp1 != (INTBIG)NOPNET) continue;
342
pn = net_newpnet(net, pnetlist);
343
if (pn == NOPNET) return(0);
344
net->temp1 = (INTBIG)pn;
345
if (net->signals > 1)
347
for(i=0; i<net->signals; i++)
349
subnet = net->networklist[i];
350
if (subnet->temp1 != (INTBIG)NOPNET) continue;
351
pn = net_newpnet(subnet, pnetlist);
352
subnet->temp1 = (INTBIG)pn;
357
/* search every component in the facet */
358
for(ni = facet->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
361
if (toplevel != 0) net_toplevelinst = ni;
363
/* ignore recursive references (showing icon in contents) */
364
if (anp->cell == facet->cell) continue;
366
/* if flattening the circuit, explore contents of facet instances */
368
localcompare_hierarchically = compare_hierarchically;
369
var = getvalkey((INTBIG)anp, VNODEPROTO, VINTEGER, net_ncc_optionskey);
370
if (var != NOVARIABLE)
372
if ((var->addr&NCCHIERARCHICALOVER) != 0)
374
if ((var->addr&NCCHIERARCHICAL) != 0) localcompare_hierarchically = TRUE; else
375
localcompare_hierarchically = FALSE;
378
if (anp->primindex == 0 && localcompare_hierarchically) flattenit = 1;
380
/* determine whether the node is arrayed */
381
nodewidth = ni->arraysize;
382
if (nodewidth < 1) nodewidth = 1;
384
/* run through each instantiation of the node */
385
for(nindex = 0; nindex < nodewidth; nindex++)
389
/* if there is an alternate contents facet, use it */
390
realnp = contentsview(anp);
391
if (realnp == NONODEPROTO) realnp = anp;
393
/* put pseudo-netnumbers on the networks of this facet */
394
for(net = realnp->firstnetwork; net != NONETWORK; net = net->nextnetwork)
395
net->temp1 = (INTBIG)NOPNET;
396
for(realpp = realnp->firstportproto; realpp != NOPORTPROTO; realpp = realpp->nextportproto)
398
if (realpp->network->temp1 != (INTBIG)NOPNET) continue;
400
/* if there is an alternate contents facet, compute the port */
401
if (realnp == anp) pp = realpp; else
403
pp = equivalentport(realnp, realpp, anp);
404
if (pp == NOPORTPROTO) pp = anp->firstportproto;
407
/* see if an arc connects to the port */
408
foundnet = NONETWORK;
409
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
411
temprealpp = equivalentport(anp, pi->proto, realnp);
412
if (temprealpp == NOPORTPROTO)
414
if (pi->proto->network == pp->network) break;
417
if (temprealpp->network == realpp->network) break;
420
if (pi != NOPORTARCINST && pi->conarcinst->network != NONETWORK)
422
foundnet = pi->conarcinst->network;
425
/* see if the port is an export */
426
for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
428
temprealpp = equivalentport(anp, pe->proto, realnp);
429
if (temprealpp == NOPORTPROTO)
431
if (pe->proto->network == pp->network) break;
434
if (temprealpp->network == realpp->network) break;
437
if (pe != NOPORTEXPINST) foundnet = pe->exportproto->network; else
439
pn = net_newpnet(realpp->network, pnetlist);
440
if (pn == NOPNET) return(0);
441
if ((realpp->userbits&STATEBITS) == PWRPORT)
443
pn->flags = POWERNET;
444
} else if ((realpp->userbits&STATEBITS) == GNDPORT)
446
pn->flags = GROUNDNET;
448
realpp->network->temp1 = (INTBIG)pn;
451
if (foundnet != NONETWORK)
453
/* propagate export networks to nets inside facet */
454
if (foundnet->signals > 1)
456
sigcount = foundnet->signals;
457
if (nodewidth > 1 && realpp->network->signals * nodewidth == foundnet->signals)
459
/* map wide bus to a particular instantiation of an arrayed node */
460
if (realpp->network->signals == 1)
462
realpp->network->temp1 = foundnet->networklist[nindex]->temp1;
465
for(i=0; i<realpp->network->signals; i++)
466
realpp->network->networklist[i]->temp1 =
467
foundnet->networklist[i + nindex*realpp->network->signals]->temp1;
471
if (realpp->network->signals != foundnet->signals)
473
ttyputerr(_("***ERROR: port %s on node %s in facet %s is %d wide, but is connected/exported with width %d"),
474
realpp->protoname, describenodeinst(ni), describenodeproto(facet),
475
realpp->network->signals, foundnet->signals);
476
sigcount = mini(sigcount, realpp->network->signals);
477
if (sigcount == 1) sigcount = 0;
479
realpp->network->temp1 = (INTBIG)foundnet->temp1;
480
for(i=0; i<sigcount; i++)
481
realpp->network->networklist[i]->temp1 = foundnet->networklist[i]->temp1;
485
realpp->network->temp1 = (INTBIG)foundnet->temp1;
490
/* recurse into the facet */
491
downhierarchy(ni, nindex);
492
initiallist = net_buildpseudo(realnp, initiallist, components, pnetlist,
493
compare_hierarchically);
495
if (initiallist == 0) return(0);
499
/* nonflattenable component: add it to the pseudocomponent list */
500
if (anp->primindex == 0) fun = NPUNKNOWN; else
502
fun = net_getfunction(ni);
503
if (fun == NPCONNECT || fun == NPART || fun == NPUNKNOWN ||
504
fun == NPCONPOWER || fun == NPCONGROUND) continue;
507
/* create a pseudo-component */
508
pcomp = net_allocpcomp();
509
if (pcomp == NOPCOMP) return(0);
510
pcomp->nextpcomp = initiallist;
512
pcomp->function = (INTSML)fun;
513
pcomp->hashreason = 0;
514
gettraversalpath(&nilist, &indexlist, &pathcount);
515
pcomp->hierpathcount = pathcount;
516
if (pcomp->hierpathcount > 0)
518
pcomp->hierpath = (NODEINST **)emalloc(pcomp->hierpathcount *
519
(sizeof (NODEINST *)), net_tool->cluster);
520
if (pcomp->hierpath == 0) return(0);
521
pcomp->hierindex = (INTBIG *)emalloc(pcomp->hierpathcount *
522
SIZEOFINTBIG, net_tool->cluster);
523
if (pcomp->hierindex == 0) return(0);
524
for(i=0; i<pcomp->hierpathcount; i++)
526
pcomp->hierpath[i] = nilist[i];
527
pcomp->hierindex[i] = indexlist[i];
530
pcomp->actuallist = (void *)ni;
531
pcomp->numactual = 1;
532
pcomp->topactual = net_toplevelinst;
535
/* count the number of electrically distinct nets on the component */
536
pcomp->wirecount = 0;
537
cnp = contentsview(anp);
538
for(pp = anp->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
540
/* get real export on contents */
541
if (cnp == NONODEPROTO) realpp = pp; else
543
realpp = equivalentport(anp, pp, cnp);
545
if (realpp == NOPORTPROTO) continue;
549
/* special case for isolated ports */
550
if ((realpp->userbits&PORTISOLATED) != 0)
552
/* add one wire for each arc on the port */
553
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
554
if (pi->proto == pp) pcomp->wirecount++;
558
/* new port, add in the number of signals */
559
if (pp->network->signals <= 1) pcomp->wirecount++; else
560
pcomp->wirecount += pp->network->signals;
563
/* get parameters for the node */
566
case NPTRANMOS: case NPTRA4NMOS:
567
case NPTRADMOS: case NPTRA4DMOS:
568
case NPTRAPMOS: case NPTRA4PMOS:
569
case NPTRANJFET: case NPTRA4NJFET:
570
case NPTRAPJFET: case NPTRA4PJFET:
571
case NPTRADMES: case NPTRA4DMES:
572
case NPTRAEMES: case NPTRA4EMES:
573
/* transistors that have a length and a width */
574
transistorsize(ni, &length, &width);
575
lambda = facet->cell->lib->lambda[facet->tech->techindex];
576
pcomp->length = (float)muldiv(length, WHOLE, lambda);
577
pcomp->width = (float)muldiv(width, WHOLE, lambda);
578
pcomp->flags |= COMPHASWIDLEN;
579
#ifdef IGNOREFOURPORT
580
pcomp->wirecount = 3;
584
case NPTRANPN: case NPTRA4NPN:
585
case NPTRAPNP: case NPTRA4PNP:
586
/* transistors that have an area */
587
transistorsize(ni, &length, &width);
588
lambda = facet->cell->lib->lambda[facet->tech->techindex];
589
if (length < 0) pcomp->length = 0.0; else
590
pcomp->length = (float)muldiv(length, WHOLE, lambda);
592
pcomp->flags |= COMPHASAREA;
596
case NPCAPAC: case NPECAPAC:
597
case NPDIODE: case NPDIODEZ:
599
pcomp->length = net_getpartvalue(ni);
601
pcomp->flags |= COMPHASAREA;
605
/* no further information if there are no wires */
606
if (pcomp->wirecount == 0) continue;
608
/* allocate the port and connection lists */
609
pcomp->portlist = (PORTPROTO **)emalloc(((sizeof (PORTPROTO *)) * pcomp->wirecount),
611
if (pcomp->portlist == 0) return(0);
612
pcomp->state = (INTSML *)emalloc((SIZEOFINTSML * pcomp->wirecount),
614
if (pcomp->state == 0) return(0);
615
pcomp->portindices = (INTSML *)emalloc((SIZEOFINTSML * pcomp->wirecount),
617
if (pcomp->portindices == 0) return(0);
618
pcomp->netnumbers = (PNET **)emalloc(((sizeof (PNET *)) * pcomp->wirecount),
620
if (pcomp->netnumbers == 0) return(0);
621
for(i=0; i<pcomp->wirecount; i++)
624
switch (pcomp->function)
635
/* transistors make the active ports equivalent */
636
pcomp->portlist[0] = anp->firstportproto;
637
pcomp->portlist[1] = pcomp->portlist[0]->nextportproto;
638
pcomp->portlist[2] = pcomp->portlist[1]->nextportproto;
639
if (anp != sch_transistorprim && anp != sch_transistor4prim)
640
pcomp->portlist[2] = pcomp->portlist[2]->nextportproto;
641
for(j=0; j<pcomp->wirecount; j++)
643
pp = pcomp->portlist[j];
644
pcomp->portindices[j] = (INTSML)pp->network->temp2;
645
if (net_getpnetandstate(ni, pp, NONETWORK, -1, &pcomp->netnumbers[j],
646
&pcomp->state[j], pnetlist, nodewidth, nindex, pp->network->signals)) return(0);
659
/* 4-port transistors make the active two equivalent */
660
pcomp->portlist[0] = anp->firstportproto;
661
pcomp->portlist[1] = pcomp->portlist[0]->nextportproto;
662
pcomp->portlist[2] = pcomp->portlist[1]->nextportproto;
663
pcomp->portlist[3] = pcomp->portlist[2]->nextportproto;
664
for(j=0; j<pcomp->wirecount; j++)
666
pp = pcomp->portlist[j];
667
pcomp->portindices[j] = (INTSML)pp->network->temp2;
668
if (net_getpnetandstate(ni, pp, NONETWORK, -1, &pcomp->netnumbers[j],
669
&pcomp->state[j], pnetlist, nodewidth, nindex, pp->network->signals)) return(0);
675
for(pp = anp->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
677
/* get real export on contents */
678
if (cnp == NONODEPROTO) realpp = pp; else
680
realpp = equivalentport(anp, pp, cnp);
682
if (realpp == NOPORTPROTO) continue;
685
sigcount = realpp->network->signals;
687
/* special case for isolated ports */
688
if ((realpp->userbits&PORTISOLATED) != 0)
690
/* add one wire for each arc on the port */
691
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
693
if (pi->proto != pp) continue;
694
pcomp->portlist[j] = pp;
695
pcomp->portindices[j] = (INTSML)pp->network->temp2;
696
if (net_getpnetandstate(ni, pp, pi->conarcinst->network, -1,
697
&pcomp->netnumbers[j], &pcomp->state[j], pnetlist,
698
nodewidth, nindex, sigcount)) return(0);
706
/* single-wire port */
707
pcomp->portlist[j] = pp;
708
pcomp->portindices[j] = (INTSML)realpp->network->temp2;
709
for(l=0; l<j; l++) if (pcomp->portindices[l] == pcomp->portindices[j]) break;
712
if (net_getpnetandstate(ni, pp, NONETWORK, -1, &pcomp->netnumbers[j],
713
&pcomp->state[j], pnetlist, nodewidth, nindex, sigcount)) return(0);
719
for(k=0; k<sigcount; k++)
721
pcomp->portlist[j] = pp;
722
pcomp->portindices[j] = (INTSML)realpp->network->networklist[k]->temp2;
723
for(l=0; l<j; l++) if (pcomp->portindices[l] == pcomp->portindices[j]) break;
726
if (net_getpnetandstate(ni, pp, NONETWORK, k,
727
&pcomp->netnumbers[j], &pcomp->state[j], pnetlist,
728
nodewidth, nindex, sigcount)) return(0);
734
pcomp->wirecount = (INTSML)j;
743
* Routine to examine node "ni", port "pp", and find the PNET that is connected to it.
744
* If "forcenet" is not NONETWORK, use it as the arc site.
745
* If "index" is not negative, look for that entry in a bus.
746
* The PNET and its state are stored in "netnumber" and "state". If nothing is connected,
747
* a new PNET is allocated and saved in the list "pnetlist".
748
* Returns true on error.
750
BOOLEAN net_getpnetandstate(NODEINST *ni, PORTPROTO *pp, NETWORK *forcenet,
751
INTBIG index, PNET **netnumber, INTSML *state, PNET **pnetlist,
752
INTBIG nodewidth, INTBIG nindex, INTBIG destsignals)
754
REGISTER ARCINST *ai;
755
REGISTER INTBIG entry;
756
REGISTER PORTARCINST *pi;
757
REGISTER PORTEXPINST *pe;
758
REGISTER NETWORK *net;
761
/* first look for an arc that connects */
762
for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
764
if (forcenet != NONETWORK)
766
if (forcenet != pi->conarcinst->network) continue;
769
if (pi->proto->network != pp->network) continue;
772
/* pickup the network number of this connection */
777
if (nodewidth > 1 && net->signals == nodewidth)
778
*netnumber = (PNET *)net->networklist[nindex]->temp1; else
779
*netnumber = (PNET *)net->temp1;
783
if (nodewidth > 1 && net->signals == nodewidth * destsignals)
784
entry = index + nindex*destsignals;
785
if (entry < net->signals)
786
*netnumber = (PNET *)net->networklist[entry]->temp1;
788
if ((ai->userbits&ISNEGATED) != 0)
790
if ((ai->end[0].portarcinst == pi && (ai->userbits&REVERSEEND) == 0) ||
791
(ai->end[1].portarcinst == pi && (ai->userbits&REVERSEEND) != 0))
792
*state = NEGATEDPORT;
794
if (*netnumber != NOPNET)
796
if (((*netnumber)->flags&EXPORTEDNET) != 0)
797
*state |= EXPORTEDPORT;
802
for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
804
if (forcenet != NONETWORK)
806
if (forcenet != pe->proto->network) continue;
809
if (pe->proto->network != pp->network) continue;
811
net = pe->exportproto->network;
814
if (nodewidth > 1 && net->signals == nodewidth)
815
*netnumber = (PNET *)net->networklist[nindex]->temp1; else
816
*netnumber = (PNET *)net->temp1;
820
if (nodewidth > 1 && net->signals == nodewidth * destsignals)
821
entry = index + nindex*destsignals;
822
if (entry < net->signals)
823
*netnumber = (PNET *)net->networklist[entry]->temp1;
825
*state |= EXPORTEDPORT;
826
if (*netnumber != NOPNET) return(FALSE);
829
/* not found on arc or export: create a new entry */
830
if (forcenet == NONETWORK)
831
ttyputmsg(_("Warning: facet %s: no connection to node %s, port %s"),
832
describenodeproto(ni->parent), describenodeinst(ni), pp->protoname);
833
pn = net_newpnet(forcenet, pnetlist);
834
if (pn == NOPNET) return(TRUE);
835
pn->network = forcenet;
841
* Routine to fill in the network pointers to components.
843
void net_fillinnetpointers(PCOMP *pcomplist, PNET *pnetlist)
849
for(pn = pnetlist; pn != NOPNET; pn = pn->nextpnet)
851
for(pc = pcomplist; pc != NOPCOMP; pc = pc->nextpcomp)
853
for(i=0; i<pc->wirecount; i++)
855
pn = pc->netnumbers[i];
860
for(pn = pnetlist; pn != NOPNET; pn = pn->nextpnet)
862
if (pn->nodecount <= pn->nodetotal) continue;
863
if (pn->nodetotal > 0)
865
efree((char *)pn->nodelist);
866
efree((char *)pn->nodewire);
869
pn->nodelist = (PCOMP **)emalloc(pn->nodecount * (sizeof (PCOMP *)), net_tool->cluster);
870
if (pn->nodelist == 0) return;
871
pn->nodewire = (INTBIG *)emalloc(pn->nodecount * SIZEOFINTBIG, net_tool->cluster);
872
if (pn->nodelist == 0) return;
873
pn->nodetotal = pn->nodecount;
875
for(pn = pnetlist; pn != NOPNET; pn = pn->nextpnet)
877
for(pc = pcomplist; pc != NOPCOMP; pc = pc->nextpcomp)
879
for(i=0; i<pc->wirecount; i++)
881
pn = pc->netnumbers[i];
882
if (pn->nodelist == 0)
884
pn->nodelist[pn->nodecount] = pc;
885
pn->nodewire[pn->nodecount] = i;
892
* Routine to reduce the network in "pcomp" to merge parallel components.
894
INTBIG net_mergeparallel(PCOMP **pcomp, PNET *pnet, INTBIG *components)
896
REGISTER PCOMP *pc, *opc, *nextpc, *lastpc, **complist;
898
REGISTER INTBIG i, j, k, m, newnum, mergecount, compcount, counter;
899
REGISTER NODEINST *ni, **newlist, *newsingle;
901
net_fillinnetpointers(*pcomp, pnet);
903
/* assign values to each net */
905
for(pn = pnet; pn != NOPNET; pn = pn->nextpnet)
908
pn->timestamp = counter;
911
/* compute hash value for each component */
913
for(pc = *pcomp; pc != NOPCOMP; pc = pc->nextpcomp)
915
pc->flags &= ~COMPDELETED;
916
if (pc->function == NPUNKNOWN) continue;
917
counter = pc->function;
918
for(i=0; i<pc->wirecount; i++)
920
pn = pc->netnumbers[i];
921
counter += pn->timestamp * pc->portindices[i];
924
#if 0 /* allow parallel components to be merged anywhere they are found */
925
/* add in hierarchical path information */
926
for(j=0; j<pc->hierpathcount; j++)
927
counter += ((INTBIG)pc->hierpath[j]) + pc->hierindex[j];
930
pc->timestamp = counter;
934
if (compcount == 0) return(0);
935
complist = (PCOMP **)emalloc(compcount * (sizeof (PCOMP *)), net_tool->cluster);
936
if (complist == 0) return(0);
938
for(pc = *pcomp; pc != NOPCOMP; pc = pc->nextpcomp)
940
if (pc->function == NPUNKNOWN) continue;
941
complist[compcount++] = pc;
943
esort(complist, compcount, sizeof (PCOMP *), net_sortpcompbyhash);
946
for(i=0; i<compcount; i++)
950
if (stopping(STOPREASONNCC)) break;
953
if ((opc->flags & COMPDELETED) != 0) continue;
955
for(m=i+1; m<compcount; m++)
958
if (pc->timestamp != opc->timestamp) break;
959
if ((pc->flags & COMPDELETED) != 0) continue;
961
/* both components must have the same function */
962
if (pc->function != opc->function) continue;
964
#if 0 /* allow parallel components to be merged anywhere they are found */
965
/* both components must be in the same facet */
966
if (pc->hierpathcount != opc->hierpathcount) continue;
967
for(j=0; j<pc->hierpathcount; j++)
968
if (pc->hierpath[j] != opc->hierpath[j] ||
969
pc->hierindex[j] != opc->hierindex[j]) break;
970
if (j < pc->hierpathcount) continue;
973
/* compare the wire lists */
974
if (net_comparewirelist(pc, opc, FALSE)) continue;
976
/* components are equivalent: delete "pc" */
979
/* add "pc"s node pointer to "opc" */
980
newnum = pc->numactual + opc->numactual;
983
newlist = (NODEINST **)emalloc(newnum * (sizeof (NODEINST *)),
985
if (newlist == 0) return(0);
988
for(j=0; j<pc->numactual; j++)
990
if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
991
ni = ((NODEINST **)pc->actuallist)[j];
992
if (newnum == 1) newsingle = ni; else
995
for(j=0; j<opc->numactual; j++)
997
if (opc->numactual == 1) ni = (NODEINST *)opc->actuallist; else
998
ni = ((NODEINST **)opc->actuallist)[j];
999
if (newnum == 1) newsingle = ni; else
1002
if (opc->numactual > 1) efree((char *)opc->actuallist);
1003
if (newnum == 1) opc->actuallist = (void *)newsingle; else
1004
opc->actuallist = (void *)newlist;
1005
opc->numactual = newnum;
1007
/* combine sizes (as specified by Robert Bosnyak) */
1008
if ((pc->flags&(COMPHASWIDLEN|COMPHASAREA)) != 0 &&
1009
(opc->flags&(COMPHASWIDLEN|COMPHASAREA)) != 0)
1011
switch (pc->function)
1013
case NPTRANMOS: case NPTRA4NMOS:
1014
case NPTRADMOS: case NPTRA4DMOS:
1015
case NPTRAPMOS: case NPTRA4PMOS:
1016
/* FET transistors in parallel depend on whether the length is the same */
1017
if (opc->length == pc->length)
1019
/* same-length transistors: sum the width */
1020
opc->width += pc->width;
1023
/* different-length transistors: more complex formula */
1024
if (pc->width + opc->width != 0.0)
1026
opc->length = (pc->width * pc->length + opc->width * opc->length) /
1027
(pc->width + opc->width);
1029
opc->width += pc->width;
1032
case NPTRANPN: case NPTRA4NPN:
1033
case NPTRAPNP: case NPTRA4PNP:
1034
case NPTRANJFET: case NPTRA4NJFET:
1035
case NPTRAPJFET: case NPTRA4PJFET:
1036
case NPTRADMES: case NPTRA4DMES:
1037
case NPTRAEMES: case NPTRA4EMES:
1038
/* nonFET transistors in parallel sum the area */
1039
opc->length += pc->length;
1043
/* resistance and capacitance in parallel take product over sum */
1044
if (pc->length + opc->length != 0.0)
1045
opc->length = (pc->length * opc->length) / (pc->length + opc->length);
1047
case NPCAPAC: case NPECAPAC:
1048
case NPDIODE: case NPDIODEZ:
1049
/* capacitance and diode in parallel sum the farads/area */
1050
opc->length += pc->length;
1055
pc->flags |= COMPDELETED;
1058
efree((char *)complist);
1060
/* remove deleted components */
1062
for(pc = *pcomp; pc != NOPCOMP; pc = nextpc)
1064
nextpc = pc->nextpcomp;
1065
if ((pc->flags&COMPDELETED) != 0)
1067
if (lastpc == NOPCOMP) *pcomp = pc->nextpcomp; else
1068
lastpc->nextpcomp = pc->nextpcomp;
1078
int net_sortpcompbyhash(const void *e1, const void *e2)
1080
REGISTER PCOMP *pc1, *pc2;
1082
pc1 = *((PCOMP **)e1);
1083
pc2 = *((PCOMP **)e2);
1084
return(pc1->timestamp - pc2->timestamp);
1088
* Routine to add PCOMP "pc" to the list of series transistors.
1090
BOOLEAN net_addtoserieslist(PCOMP *pc)
1092
REGISTER INTBIG newtotal, i;
1093
REGISTER PCOMP **newlist;
1095
if (net_serieslistcount >= net_serieslisttotal)
1097
newtotal = net_serieslisttotal * 2;
1098
if (newtotal <= net_serieslistcount)
1099
newtotal = net_serieslistcount+1;
1100
newlist = (PCOMP **)emalloc(newtotal * (sizeof (PCOMP *)), net_tool->cluster);
1101
if (newlist == 0) return(TRUE);
1102
for(i=0; i<net_serieslistcount; i++)
1103
newlist[i] = net_serieslist[i];
1104
if (net_serieslisttotal > 0) efree((char *)net_serieslist);
1105
net_serieslist = newlist;
1106
net_serieslisttotal = newtotal;
1108
net_serieslist[net_serieslistcount] = pc;
1109
net_serieslistcount++;
1114
* Routine to gather a list of series transistors that include "pc". Returns
1115
* the list, and its length in "seriescount". If "seriescount" is less than 2,
1116
* no chain of series transistors has been found.
1118
PCOMP **net_gatherseries(PCOMP *pc, INTBIG *seriescount)
1120
net_serieslistcount = 0;
1121
net_seriescon1 = net_seriescon2 = -1;
1122
(void)net_addtoserieslist(pc);
1123
net_crawlforseries(pc);
1124
*seriescount = net_serieslistcount;
1125
return(net_serieslist);
1129
* Recursive helper routine for "net_gatherseries" to find transistors adjacent
1130
* to "pc" and add them to the series chain if they are series transistors.
1132
void net_crawlforseries(PCOMP *pc)
1134
REGISTER INTBIG i, j, badend;
1135
REGISTER PCOMP *opc;
1138
/* check source and drain connections */
1143
/* connection must be to exactly 1 other component */
1144
pn = pc->netnumbers[i];
1145
if (pn->nodecount != 2) badend = 1; else
1147
opc = pn->nodelist[0];
1148
if (opc == pc) opc = pn->nodelist[1];
1151
/* other component must be the same as this */
1154
if (opc->function != pc->function) badend = 1;
1157
/* both components must be in the same facet */
1160
if (pc->hierpathcount != opc->hierpathcount) continue;
1161
for(j=0; j<pc->hierpathcount; j++)
1162
if (pc->hierpath[j] != opc->hierpath[j] ||
1163
pc->hierindex[j] != opc->hierindex[j]) break;
1164
if (j < pc->hierpathcount) badend = 1;
1167
/* other component must point just to this on its source or drain */
1170
pn = pc->netnumbers[i];
1171
if ((pn->flags&(EXPORTEDNET|POWERNET|GROUNDNET)) != 0) badend = 1;
1174
/* other component must not already be in the list */
1177
for(j=0; j<net_serieslistcount; j++)
1178
if (net_serieslist[j] == opc) break;
1179
if (j < net_serieslistcount) badend = 2;
1184
case 0: /* good end */
1185
/* another series transistor found */
1186
(void)net_addtoserieslist(opc);
1188
/* recursively search for others */
1189
net_crawlforseries(opc);
1191
case 1: /* bad end: end of chain */
1192
/* add to the end list */
1193
if (net_seriescon1 < 0)
1195
net_seriesend1 = pc;
1197
} else if (net_seriescon2 < 0)
1199
net_seriesend2 = pc;
1208
* Routine to reduce the network in "pcomp" to merge series transistors into more complex
1209
* single components.
1211
INTBIG net_mergeseries(PCOMP **pcomp, PNET *pnet, INTBIG *components)
1213
REGISTER PCOMP *pc, *opc, *nextpc, *lastpc, **serieslist, *newpc, *npc;
1214
REGISTER INTBIG i, j, k, t, mergecount;
1216
REGISTER NODEINST *ni;
1218
/* clear flags on every component */
1219
for(pc = *pcomp; pc != NOPCOMP; pc = pc->nextpcomp) pc->timestamp = -1;
1220
net_fillinnetpointers(*pcomp, pnet);
1222
/* scan for series transistors */
1224
for(pc = *pcomp; pc != NOPCOMP; pc = nextpc)
1226
nextpc = pc->nextpcomp;
1227
if (pc->function != NPTRANMOS && pc->function != NPTRADMOS &&
1228
pc->function != NPTRAPMOS) continue;
1230
/* look for adjacent single transistor */
1231
serieslist = net_gatherseries(pc, &seriescount);
1232
if (seriescount <= 1) continue;
1236
/* mark transistors */
1237
for(t=0; t<seriescount; t++) serieslist[t]->timestamp = t;
1239
/* create a new component with all the features of the gates and ends */
1240
newpc = net_allocpcomp();
1241
if (newpc == NOPCOMP) return(0);
1242
newpc->nextpcomp = *pcomp;
1244
newpc->topactual = pc->topactual;
1245
newpc->hierpathcount = pc->hierpathcount;
1246
if (newpc->hierpathcount > 0)
1248
newpc->hierpath = (NODEINST **)emalloc(newpc->hierpathcount *
1249
(sizeof (NODEINST *)), net_tool->cluster);
1250
if (newpc->hierpath == 0) return(0);
1251
newpc->hierindex = (INTBIG *)emalloc(newpc->hierpathcount *
1252
SIZEOFINTBIG, net_tool->cluster);
1253
if (newpc->hierindex == 0) return(0);
1254
for(i=0; i<newpc->hierpathcount; i++)
1256
newpc->hierpath[i] = pc->hierpath[i];
1257
newpc->hierindex[i] = pc->hierindex[i];
1260
newpc->flags = pc->flags;
1261
newpc->function = (INTSML)(pc->function * 1000 + seriescount);
1262
newpc->wirecount = seriescount + 2;
1263
newpc->timestamp = -1;
1264
newpc->hashreason = 0;
1266
/* length is the sum of all lengths, width is the average width */
1267
newpc->length = 0.0;
1269
for(t=0; t<seriescount; t++)
1271
newpc->length += serieslist[t]->length;
1272
newpc->width += serieslist[t]->width;
1274
newpc->width /= seriescount;
1276
/* build "actual" list from all of the individual transistors */
1277
newpc->numactual = 0;
1278
for(t=0; t<seriescount; t++) newpc->numactual += serieslist[t]->numactual;
1279
newpc->actuallist = (NODEINST **)emalloc(newpc->numactual * (sizeof (NODEINST *)),
1281
if (newpc->actuallist == 0) return(0);
1283
for(t=0; t<seriescount; t++)
1285
opc = serieslist[t];
1286
for(k=0; k < opc->numactual; k++)
1288
if (opc->numactual == 1) ni = (NODEINST *)opc->actuallist; else
1289
ni = ((NODEINST **)opc->actuallist)[k];
1290
((NODEINST **)newpc->actuallist)[j++] = ni;
1294
/* allocate the pointer arrays */
1295
newpc->portlist = (PORTPROTO **)emalloc(((sizeof (PORTPROTO *)) * newpc->wirecount),
1297
if (newpc->portlist == 0) return(0);
1298
newpc->state = (INTSML *)emalloc((SIZEOFINTSML * newpc->wirecount),
1300
if (newpc->state == 0) return(0);
1301
newpc->portindices = (INTSML *)emalloc((SIZEOFINTSML * newpc->wirecount),
1303
if (newpc->portindices == 0) return(0);
1304
newpc->netnumbers = (PNET **)emalloc(((sizeof (PNET *)) * newpc->wirecount),
1306
if (newpc->netnumbers == 0) return(0);
1308
/* pick up gates from all series transistors */
1309
for(t=0; t<seriescount; t++)
1311
newpc->portindices[t] = (INTSML)getprime(0);
1312
newpc->portlist[t] = serieslist[t]->portlist[0];
1313
newpc->netnumbers[t] = serieslist[t]->netnumbers[0];
1314
newpc->state[t] = serieslist[t]->state[0];
1317
/* add in new source and drain */
1318
newpc->portindices[t] = (INTSML)getprime(1);
1319
newpc->portlist[t] = net_seriesend1->portlist[net_seriescon1];
1320
newpc->netnumbers[t] = net_seriesend1->netnumbers[net_seriescon1];
1321
newpc->state[t] = net_seriesend1->state[net_seriescon1];
1323
newpc->portindices[t] = (INTSML)getprime(1);
1324
newpc->portlist[t] = net_seriesend2->portlist[net_seriescon2];
1325
newpc->netnumbers[t] = net_seriesend2->netnumbers[net_seriescon2];
1326
newpc->state[t] = net_seriesend2->state[net_seriescon2];
1329
/* fix pointer to the next transistor */
1330
while (nextpc != NOPCOMP && nextpc->timestamp != -1)
1331
nextpc = nextpc->nextpcomp;
1333
/* remove the series transistors */
1335
for(opc = *pcomp; opc != NOPCOMP; opc = npc)
1337
npc = opc->nextpcomp;
1338
if (opc->timestamp != -1)
1341
if (lastpc == NOPCOMP) *pcomp = npc; else
1342
lastpc->nextpcomp = npc;
1354
* routine to compare pseudocomponent "p1" and "p2", returning true if they
1357
BOOLEAN net_comparewirelist(PCOMP *p1, PCOMP *p2, BOOLEAN useportnames)
1359
REGISTER INTBIG i, j;
1361
/* simple test: number of wire lists must be equal */
1362
if (p1->wirecount != p2->wirecount) return(TRUE);
1364
/* if ports must match in sequence, check is simpler */
1365
if (p1->function == NPTRANPN || p1->function == NPTRAPNP ||
1366
p1->function == NPDIODE || p1->function == NPDIODEZ ||
1367
p1->function == NPBUFFER || p1->function == NPFLIPFLOP ||
1368
p1->function == NPUNKNOWN)
1370
for(i=0; i<p1->wirecount; i++)
1372
if (p1->netnumbers[i] != p2->netnumbers[i]) return(TRUE);
1377
/* make sure there is memory for flags corresponding to component 2 */
1378
if (p2->wirecount > net_comparelistsize)
1380
if (net_comparelistsize != 0) efree((char *)net_comparelist);
1381
net_comparelist = (BOOLEAN *)emalloc(((sizeof (BOOLEAN)) * p2->wirecount),
1383
net_comparelistsize = p2->wirecount;
1386
/* reset flags in list for component 2 */
1387
for(j=0; j<p2->wirecount; j++) net_comparelist[j] = FALSE;
1389
for(i=0; i<p1->wirecount; i++)
1391
if (p1->netnumbers[i]->nodecount == 0) return(TRUE);
1392
for(j=0; j<p2->wirecount; j++)
1394
if (net_comparelist[j]) continue;
1395
if (p1->portindices[i] != p2->portindices[j]) continue;
1396
if (p1->netnumbers[i] != p2->netnumbers[j]) continue;
1397
net_comparelist[j] = TRUE;
1400
if (j >= p2->wirecount) return(TRUE);
1405
float net_getpartvalue(NODEINST *ni)
1407
REGISTER NODEPROTO *np;
1408
REGISTER VARIABLE *var;
1414
if (np->primindex == 0) return(0.0);
1416
/* diodes have area on them */
1417
if (np == sch_diodeprim)
1419
var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_diodekey);
1420
pt = describesimplevariable(var);
1421
return((float)atof(pt));
1424
/* capacitors have Farads on them */
1425
if (np == sch_capacitorprim)
1427
var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_capacitancekey);
1428
pt = describesimplevariable(var);
1429
value = (float)atof(pt);
1433
if (tolower(pt[i-1]) == 'f')
1435
value = value / 1000000000000.0f;
1436
} else if (tolower(pt[i-1]) == 'p')
1438
value = value / 1000000000.0f;
1439
} else if (tolower(pt[i-1]) == 'u')
1441
value = value / 1000000.0f;
1442
} else if (tolower(pt[i-1]) == 'm')
1444
value = value / 1000.0f;
1450
/* resistors have Ohms on them */
1451
if (np == sch_resistorprim)
1453
var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_resistancekey);
1454
pt = describesimplevariable(var);
1455
value = (float)atof(pt);
1459
if (tolower(pt[i-1]) == 'g')
1461
value = value * 1000000000.0f;
1462
} else if (i > 2 && namesame(&pt[i-3], "meg") == 0)
1464
value = value * 1000000.0f;
1465
} else if (tolower(pt[i-1]) == 'k')
1467
value = value * 1000.0f;
1473
/* inductors have Henrys on them */
1474
if (np == sch_inductorprim)
1476
var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_inductancekey);
1477
pt = describesimplevariable(var);
1478
value = (float)atof(pt);
1482
if (tolower(pt[i-1]) == 'u')
1484
value = value / 1000000.0f;
1485
} else if (tolower(pt[i-1]) == 'm')
1487
value = value / 1000.0f;
1495
/*********************** ALLOCATION ***********************/
1498
* routine to create a new PNET module for network "net" (if this is a global net,
1499
* merge it with others of the same name). Increases the net number count in the
1500
* global "net_pseudonode" and adds the module to the list in "pnetlist".
1501
* Return the module (NOPNET on error).
1503
PNET *net_newpnet(NETWORK *net, PNET **pnetlist)
1506
REGISTER NETWORK *onet;
1507
REGISTER char *globalname;
1508
REGISTER INTBIG characteristics;
1510
/* if the net is global, look for an equivalent */
1511
if (net != NONETWORK && net->globalnet >= 0 &&
1512
net->globalnet < net->parent->globalnetcount)
1514
globalname = net->parent->globalnetnames[net->globalnet];
1515
for(pn = *pnetlist; pn != NOPNET; pn = pn->nextpnet)
1517
if ((pn->flags&GLOBALNET) == 0) continue;
1519
if (onet == NONETWORK) continue;
1520
if (onet->globalnet < 0) continue;
1521
if (onet->globalnet >= onet->parent->globalnetcount) continue;
1522
if (namesame(onet->parent->globalnetnames[onet->globalnet], globalname) == 0)
1527
/* global net not found */
1528
pn = net_allocpnet();
1529
if (pn == 0) return(NOPNET);
1531
pn->nextpnet = *pnetlist;
1534
if (net != NONETWORK && net->globalnet >= 0 &&
1535
net->globalnet < net->parent->globalnetcount)
1537
pn->flags |= GLOBALNET;
1538
characteristics = net->parent->globalnetchar[net->globalnet];
1539
if (characteristics == PWRPORT) pn->flags |= POWERNET; else
1540
if (characteristics == GNDPORT) pn->flags |= GROUNDNET;
1546
* routine to allocate a new pcomp module from the pool (if any) or memory
1548
PCOMP *net_allocpcomp(void)
1552
if (net_pcompfree == NOPCOMP)
1554
pc = (PCOMP *)emalloc(sizeof (PCOMP), net_tool->cluster);
1555
if (pc == 0) return(NOPCOMP);
1559
net_pcompfree = (PCOMP *)pc->nextpcomp;
1566
* routine to return pcomp module "pc" to the pool of free modules
1568
void net_freepcomp(PCOMP *pc)
1570
if (pc->wirecount != 0)
1572
efree((char *)pc->portlist);
1573
efree((char *)pc->state);
1574
efree((char *)pc->netnumbers);
1575
efree((char *)pc->portindices);
1577
if (pc->numactual > 1) efree((char *)pc->actuallist);
1578
if (pc->hashreason != 0) efree((char *)pc->hashreason);
1579
if (pc->hierpathcount != 0)
1581
efree((char *)pc->hierpath);
1582
efree((char *)pc->hierindex);
1585
pc->nextpcomp = net_pcompfree;
1590
* routine to allocate a new pnet module from the pool (if any) or memory
1592
PNET *net_allocpnet(void)
1596
if (net_pnetfree == NOPNET)
1598
pn = (PNET *)emalloc(sizeof (PNET), net_tool->cluster);
1599
if (pn == 0) return(NOPNET);
1603
net_pnetfree = (PNET *)pn->nextpnet;
1609
pn->realportcount = 0;
1614
* routine to return pnet module "pn" to the pool of free modules
1616
void net_freepnet(PNET *pn)
1618
if (pn->nodetotal > 0)
1620
efree((char *)pn->nodelist);
1621
efree((char *)pn->nodewire);
1623
if (pn->realportcount > 1)
1624
efree((char *)pn->realportlist);
1626
pn->nextpnet = net_pnetfree;
1631
* routine to free all allocated structures in the list of pseudonets
1632
* headed by "pnlist"
1634
void net_freeallpnet(PNET *pnlist)
1636
REGISTER PNET *pn, *nextpn;
1638
for(pn = pnlist; pn != NOPNET; pn = nextpn)
1640
nextpn = pn->nextpnet;
1646
* routine to free all allocated structures in the list of pseudocomponents
1647
* headed by "pclist"
1649
void net_freeallpcomp(PCOMP *pclist)
1651
REGISTER PCOMP *pc, *nextpc;
1653
for(pc = pclist; pc != NOPCOMP; pc = nextpc)
1655
nextpc = pc->nextpcomp;
1660
/*********************** COMPONENT FUNCTION ***********************/
1662
#define NOTRANMODEL ((TRANMODEL *)-1)
1664
typedef struct Itranmodel
1668
struct Itranmodel *nexttranmodel;
1671
static TRANMODEL *net_firsttranmodel = NOTRANMODEL;
1673
/* must be larger than largest node function entry in "efunction.h" */
1674
static INTBIG net_tranmodelindex = 100;
1677
* routine to return the function of node "ni"
1679
INTBIG net_getfunction(NODEINST *ni)
1681
REGISTER INTBIG fun;
1682
REGISTER TRANMODEL *tm;
1684
fun = nodefunction(ni);
1692
#ifdef IGNOREFOURPORT
1699
#ifdef IGNOREFOURPORT
1700
case NPTRA4NMOS: fun = NPTRANMOS; break;
1701
case NPTRA4DMOS: fun = NPTRADMOS; break;
1702
case NPTRA4PMOS: fun = NPTRAPMOS; break;
1703
case NPTRA4NJFET: fun = NPTRANJFET; break;
1704
case NPTRA4PJFET: fun = NPTRAPJFET; break;
1705
case NPTRA4DMES: fun = NPTRADMES; break;
1706
case NPTRA4EMES: fun = NPTRAEMES; break;
1707
case NPTRA4NPN: fun = NPTRANPN; break;
1708
case NPTRA4PNP: fun = NPTRAPNP; break;
1712
/* self-referential transistor: lookup the string in the table */
1713
for(tm = net_firsttranmodel; tm != NOTRANMODEL; tm = tm->nexttranmodel)
1714
if (namesame(tm->modelname, ni->proto->primname) == 0) break;
1715
if (tm == NOTRANMODEL)
1717
/* new table entry */
1718
tm = (TRANMODEL *)emalloc(sizeof (TRANMODEL), net_tool->cluster);
1720
(void)allocstring(&tm->modelname, ni->proto->primname, net_tool->cluster);
1721
tm->tmindex = net_tranmodelindex++;
1722
tm->nexttranmodel = net_firsttranmodel;
1723
net_firsttranmodel = tm;
1739
void net_setallexporttopology(void)
1741
REGISTER LIBRARY *lib;
1742
REGISTER NODEPROTO *np;
1743
REGISTER INTBIG i, j, len;
1744
REGISTER char *pt, *name, *oname, **strings;
1747
REGISTER VARIABLE *var, *ovar;
1748
REGISTER PORTPROTO *pp;
1750
REGISTER TECHNOLOGY *tech;
1751
REGISTER NETWORK *net, *onet;
1753
/* clear prime number indices in the cells */
1754
for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1755
for(c = lib->firstcell; c != NOCELL; c = c->nextcell)
1758
/* clear network topology information */
1759
for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1761
for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1763
for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1768
/* assign network topology information from previous NCC runs */
1769
for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1771
/* assign topology information uniformly in each cell */
1772
for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1774
for(i=0; i<np->numvar; i++)
1776
var = &np->firstvar[i];
1777
pt = makename(var->key);
1778
if (namesamen(pt, "NET_ncc_last_result", 19) != 0) continue;
1779
net_parsenccresult(np, var, &onp, &matchdate);
1780
if (onp == NONODEPROTO) continue;
1781
if (np->revisiondate > matchdate) continue;
1783
/* valid NCC match from this facet to "onp", see if it is reciprocated */
1784
ovar = net_nccfindmatch(onp, np, &matchdate);
1785
if (ovar == NOVARIABLE) continue;
1786
if (onp->revisiondate > matchdate) continue;
1788
/* found match: assign network pointers */
1789
len = getlength(var);
1790
strings = (char **)var->addr;
1791
for(j=0; j<len; j++)
1794
if (namesamen(pt, "EXPORT ", 7) != 0) continue;
1797
while (*pt != 0 && *pt != ':') pt++;
1798
if (*pt == 0) continue;
1802
/* found the names: make the assignment */
1803
net = getnetwork(name, np);
1804
onet = getnetwork(oname, onp);
1805
if (net != NONETWORK && onet != NONETWORK)
1807
if (net->temp2 == 0 && onet->temp2 == 0)
1809
net->temp2 = onet->temp2 = getprime(np->cell->temp2++);
1818
/* assign remaining network topology based on export names */
1819
for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1821
/* assign topology information uniformly in each cell */
1822
for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1824
/* first pass: ignore icon and skeleton views */
1825
if (np->cellview == el_iconview || np->cellview == el_skeletonview) continue;
1826
for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1828
if (pp->network->temp2 != 0) continue;
1829
net_setthisexporttopology(pp, &np->cell->temp2);
1831
for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1833
if (net->temp2 == 0) net->temp2 = getprime(np->cell->temp2++);
1836
for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1838
/* second pass: do icon and skeleton views */
1839
if (np->cellview != el_iconview && np->cellview != el_skeletonview) continue;
1840
for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1842
if (pp->network->temp2 != 0) continue;
1843
net_setthisexporttopology(pp, &np->cell->temp2);
1845
for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1847
if (net->temp2 == 0) net->temp2 = getprime(np->cell->temp2++);
1851
for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
1853
for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1855
switch ((np->userbits&NFUNCTION) >> NFUNCTIONSH)
1857
case NPTRANMOS: case NPTRADMOS: case NPTRAPMOS:
1858
case NPTRANJFET: case NPTRAPJFET:
1859
case NPTRADMES: case NPTRAEMES:
1860
pp = np->firstportproto; pp->network->temp2 = getprime(0); /* poly */
1861
pp = pp->nextportproto; pp->network->temp2 = getprime(1); /* active */
1862
pp = pp->nextportproto; pp->network->temp2 = getprime(0); /* poly */
1863
pp = pp->nextportproto; pp->network->temp2 = getprime(1); /* active */
1866
pp = np->firstportproto; pp->network->temp2 = getprime(0); /* poly */
1867
pp = pp->nextportproto; pp->network->temp2 = getprime(1); /* active */
1868
pp = pp->nextportproto; pp->network->temp2 = getprime(1); /* active */
1871
pp = np->firstportproto; pp->network->temp2 = getprime(0); /* poly */
1872
pp = pp->nextportproto; pp->network->temp2 = getprime(1); /* active */
1873
pp = pp->nextportproto; pp->network->temp2 = getprime(1); /* active */
1874
pp = pp->nextportproto; pp->network->temp2 = getprime(2); /* bias */
1876
case NPTRANPN: case NPTRAPNP:
1877
pp = np->firstportproto; pp->network->temp2 = getprime(0); /* collector */
1878
pp = pp->nextportproto; pp->network->temp2 = getprime(1); /* emitter */
1879
pp = pp->nextportproto; pp->network->temp2 = getprime(2); /* base */
1883
for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1885
pp->network->temp2 = getprime(i);
1894
void net_setthisexporttopology(PORTPROTO *pp, INTBIG *index)
1896
REGISTER NETWORK *net, *subnet;
1898
REGISTER char *name;
1900
/* assign the unique prime numbers to the export's network */
1902
if (net->temp2 == 0)
1904
net->temp2 = net_findotherexporttopology(pp->parent, pp->protoname);
1905
if (net->temp2 == 0) net->temp2 = getprime((*index)++);
1907
if (net->signals > 1)
1909
for(i=0; i<net->signals; i++)
1911
subnet = net->networklist[i];
1912
if (subnet->temp2 == 0)
1914
if (subnet->namecount > 0) name = subnet->netname; else
1915
name = pp->protoname;
1916
subnet->temp2 = net_findotherexporttopology(pp->parent, name);
1917
if (subnet->temp2 == 0) subnet->temp2 = getprime((*index)++);
1923
INTBIG net_findotherexporttopology(NODEPROTO *parent, char *exportname)
1925
REGISTER NODEPROTO *np;
1926
REGISTER PORTPROTO *opp;
1927
REGISTER NETWORK *net;
1929
/* first look for an equivalent export in another facet */
1930
for(np = parent->cell->lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1932
if (np == parent) continue;
1933
if (np->cell != parent->cell) continue;
1935
/* facet from the same cell: look for an equivalent port */
1936
for(opp = np->firstportproto; opp != NOPORTPROTO; opp = opp->nextportproto)
1938
if (namesame(exportname, opp->protoname) != 0) continue;
1939
if (opp->network->temp2 != 0) return(opp->network->temp2);
1943
/* next look for an equivalent network name in another facet */
1944
for(np = parent->cell->lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1946
if (np == parent) continue;
1947
if (np->cell != parent->cell) continue;
1949
/* facet from the same cell: look for an equivalent network name */
1950
net = getnetwork(exportname, np);
1951
if (net == NONETWORK) continue;
1952
if (net->temp2 != 0) return(net->temp2);