~ubuntu-branches/ubuntu/intrepid/electric/intrepid

« back to all changes in this revision

Viewing changes to src/net/netflat.c

  • Committer: Bazaar Package Importer
  • Author(s): Onkar Shinde
  • Date: 2008-07-23 02:09:53 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080723020953-1gmnv7q2wpsdbnop
Tags: 8.07-0ubuntu1
* New Upstream version. Please check changelog for details. (LP: #242720)
* debian/control
  - Add build dependencies *-jdk, cdbs and bsh.
  - Remove build dependency dpatch. We will be using CDBS simple patchsys.
  - Refreshed runtime dependencies to default-jre | java2-runtime and bsh.
  - Added home page field.
  - Standard version 3.8.0.
  - Modify Maintainer value to match the DebianMaintainerField
    specification.
  - Changed email address for original maintainer to indicate who has
    refreshed the packaging.
* debian/rules
  - Revamped to use cdbs.
  - Added get-orig-source target.
* debian/patches
  - 00list, 02_sensible-browser.dpatch, 01_errors-numbers.dpatch,
    03_manpage.dpatch - Deleted, not relevant anymore.
  - 01_fix_build_xml.patch - Patch to fix the build.xml.
* debian/ant.properties
  - File to set various compilation properties.
* debian/electric.1
  - Remove the entry that causes lintian warning.
* debian/electric.desktop
  - Change as suggested by desktop-file-validate.
* debian/electric.docs
  - Updated as per changes in file names.
* debian/electric.svg
  - Name changed from electric_icon.svg.
* debian/install
  - Added appropriate locations for jar file, desktop file and wrapper shell
    script.
* debian/README.source
  - Added to comply with standards version 3.8.0.
* debian/TODO.Debian
  - Name changed form TODO.
* debain/wrapper/electric
  - Wrapper shell script to launch the application.
* debian/manpages
  - Added for installation of manpage.
* debian/watch
  - Updated to match jar files instead of older tar.gz files.
* debian/dirs
  - Removed, not needed anymore.
* debian/{electric.doc-base, electric.examples, substvars}
  - Removed, not relevant anymore.
* debian/*.debhelper
  - Removed auto generated files. Not relevant anymore.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Electric(tm) VLSI Design System
3
 
 *
4
 
 * File: netflat.c
5
 
 * Network tool: module for fully instantiating a hierarchical network
6
 
 * Written by: Steven M. Rubin, Static Free Software
7
 
 *
8
 
 * Copyright (c) 2000 Static Free Software.
9
 
 *
10
 
 * Electric(tm) is free software; you can redistribute it and/or modify
11
 
 * it under the terms of the GNU General Public License as published by
12
 
 * the Free Software Foundation; either version 2 of the License, or
13
 
 * (at your option) any later version.
14
 
 *
15
 
 * Electric(tm) is distributed in the hope that it will be useful,
16
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 
 * GNU General Public License for more details.
19
 
 *
20
 
 * You should have received a copy of the GNU General Public License
21
 
 * along with Electric(tm); see the file COPYING.  If not, write to
22
 
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23
 
 * Boston, Mass 02111-1307, USA.
24
 
 *
25
 
 * Static Free Software
26
 
 * 4119 Alpine Road
27
 
 * Portola Valley, California 94028
28
 
 * info@staticfreesoft.com
29
 
 */
30
 
 
31
 
#include "global.h"
32
 
#include "network.h"
33
 
#include "efunction.h"
34
 
#include "tecschem.h"
35
 
 
36
 
#define IGNOREFOURPORT 1                                /* comment out to handle 4-port transistors properly */
37
 
 
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 */
42
 
 
43
 
/* working memory for "net_comparewirelist()" */
44
 
static INTBIG     net_comparelistsize = 0;
45
 
static BOOLEAN   *net_comparelist;
46
 
 
47
 
/* working memory for "net_mergeseries()" */
48
 
static PCOMP    **net_serieslist;
49
 
static INTBIG     net_serieslistcount;
50
 
static INTBIG     net_serieslisttotal = 0;
51
 
 
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);
70
 
 
71
 
/*
72
 
 * Routine to free all memory associated with this module.
73
 
 */
74
 
void net_freeflatmemory(void)
75
 
{
76
 
        REGISTER PCOMP *p;
77
 
        REGISTER PNET *pn;
78
 
 
79
 
        while (net_pcompfree != NOPCOMP)
80
 
        {
81
 
                p = net_pcompfree;
82
 
                net_pcompfree = net_pcompfree->nextpcomp;
83
 
                efree((char *)p);
84
 
        }
85
 
        while (net_pnetfree != NOPNET)
86
 
        {
87
 
                pn = net_pnetfree;
88
 
                net_pnetfree = net_pnetfree->nextpnet;
89
 
                efree((char *)pn);
90
 
        }
91
 
        if (net_comparelistsize > 0) efree((char *)net_comparelist);
92
 
}
93
 
 
94
 
/*********************** PSEUDO-NETWORK CONSTRUCTION ***********************/
95
 
 
96
 
/*
97
 
 * The usage of this module is:
98
 
 *   #include "network.h"
99
 
 *   PCOMP *pcomp;
100
 
 *   PNET *pnet;
101
 
 *   INTBIG components, nets, powernets, groundnets;
102
 
 *   pcomp = net_makepseudo(facet, &components, &nets, &powernets, &groundnets,
103
 
 *          &pnet, hierarchical, mergeparallel, mergeseries, checkfacetoverrides);
104
 
 *   .....
105
 
 *        do something with the network in "pcomp" and "pnet"
106
 
 *   .....
107
 
 *   net_freeallpnet(pnet);
108
 
 *   net_freeallpcomp(pcomp);
109
 
 *
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
119
 
 * "groundnets".
120
 
 *
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".
126
 
 */
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)
130
 
{
131
 
        PCOMP *pcomplist;
132
 
        REGISTER BOOLEAN localmergeparallel, localmergeseries;
133
 
        REGISTER INTBIG i, mergecount;
134
 
        REGISTER NETWORK *net, *subnet;
135
 
        REGISTER PNET *pn;
136
 
        REGISTER VARIABLE *var;
137
 
        REGISTER PORTPROTO *pp, *opp, *npp, **newportlist;
138
 
 
139
 
        /* see if the current facet overrides the options */
140
 
        localmergeparallel = mergeparallel;
141
 
        localmergeseries = mergeseries;
142
 
        if (checkfacetoverrides)
143
 
        {
144
 
                var = getvalkey((INTBIG)facet, VNODEPROTO, VINTEGER, net_ncc_optionskey);
145
 
                if (var != NOVARIABLE)
146
 
                {
147
 
                        if ((var->addr&NCCNOMERGEPARALLELOVER) != 0)
148
 
                        {
149
 
                                if ((var->addr&NCCNOMERGEPARALLEL) == 0) localmergeparallel = TRUE; else
150
 
                                        localmergeparallel = FALSE;
151
 
                        }
152
 
                        if ((var->addr&NCCMERGESERIESOVER) != 0)
153
 
                        {
154
 
                                if ((var->addr&NCCMERGESERIES) != 0) localmergeseries = TRUE; else
155
 
                                        localmergeseries = FALSE;
156
 
                        }
157
 
                }
158
 
        }
159
 
 
160
 
        /* first create net numbers inside of this facet */
161
 
        net_pseudonode = 0;
162
 
        *pnetlist = NOPNET;
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)
166
 
        {
167
 
                net = pp->network;
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)
178
 
                {
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++)
184
 
                        {
185
 
                                if (pn->realportcount == 1) npp = (PORTPROTO *)pn->realportlist; else
186
 
                                        npp = ((PORTPROTO **)pn->realportlist)[i];
187
 
                                newportlist[i] = npp;
188
 
                        }
189
 
                        newportlist[pn->realportcount] = opp;
190
 
                        if (pn->realportcount > 1) efree((char *)pn->realportlist);
191
 
                        pn->realportlist = newportlist;
192
 
                        pn->realportcount++;
193
 
                }
194
 
                if (net->signals > 1)
195
 
                {
196
 
                        for(i=0; i<net->signals; i++)
197
 
                        {
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;
203
 
                        }
204
 
                }
205
 
        }
206
 
 
207
 
        /* establish topology of exports */
208
 
        net_setallexporttopology();
209
 
 
210
 
        /* create a list of pseudocomponents in this facet */
211
 
        *components = 0;
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));
218
 
 
219
 
        /* reduce network by merging parallel components */
220
 
        if (localmergeparallel)
221
 
        {
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); }
226
 
                if (mergecount != 0)
227
 
                        ttyputmsg(_("--- Merged %ld parallel components"), mergecount);
228
 
        }
229
 
        if (localmergeseries)
230
 
        {
231
 
                mergecount = net_mergeseries(&pcomplist, *pnetlist, components);
232
 
                if (mergecount != 0)
233
 
                        ttyputmsg(_("--- Merged %ld series transistors in facet %s"),
234
 
                                mergecount, describenodeproto(facet));
235
 
        }
236
 
 
237
 
        /* report the total number of nets */
238
 
        *nets = net_pseudonode;
239
 
 
240
 
        /* count the power and ground nets */
241
 
        *powernets = *groundnets = 0;
242
 
        for(pn = *pnetlist; pn != NOPNET; pn = pn->nextpnet)
243
 
        {
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));
249
 
        }
250
 
        return(pcomplist);
251
 
}
252
 
 
253
 
/*
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.
259
 
 */
260
 
PCOMP *net_buildpseudo(NODEPROTO *facet, PCOMP *initiallist, INTBIG *components,
261
 
        PNET **pnetlist, BOOLEAN compare_hierarchically)
262
 
{
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;
269
 
        NODEINST **nilist;
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;
275
 
        REGISTER PNET *pn;
276
 
        REGISTER VARIABLE *var;
277
 
 
278
 
        if (net_toplevelinst == NONODEINST) toplevel = 1; else
279
 
                toplevel = 0;
280
 
 
281
 
        /* make simple checks that port characteristics match the name */
282
 
        for(pp = facet->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
283
 
        {
284
 
                /* check busses for consistent component characteristics */
285
 
                if (pp->network->signals > 1)
286
 
                {
287
 
                        for(i=0; i<pp->network->signals; i++)
288
 
                        {
289
 
                                subnet = pp->network->networklist[i];
290
 
                                for(opp = facet->firstportproto; opp != NOPORTPROTO; opp = opp->nextportproto)
291
 
                                {
292
 
                                        if (opp->network != subnet) continue;
293
 
                                        if ((opp->userbits&STATEBITS) != (pp->userbits&STATEBITS))
294
 
                                        {
295
 
                                                ttyputerr(_("Warning: bus export %s is %s but export %s is %s"),
296
 
                                                        pp->protoname, describeportbits(pp), opp->protoname,
297
 
                                                                describeportbits(opp));
298
 
                                        }
299
 
                                        break;
300
 
                                }
301
 
                        }
302
 
                }
303
 
        }
304
 
 
305
 
        /* spread power and ground information from appropriate nodes */
306
 
        for(ni = facet->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
307
 
        {
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;
313
 
 
314
 
                /* they do: get the network */
315
 
                pp = pe->proto;
316
 
                for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
317
 
                        if (pi->proto == pp) break;
318
 
                if (pi == NOPORTARCINST) continue;
319
 
 
320
 
                /* propagate power and ground */
321
 
                net = pi->conarcinst->network;
322
 
                if ((pe->exportproto->userbits&STATEBITS) == PWRPORT)
323
 
                {
324
 
                        pn = (PNET *)net->temp1;
325
 
                        if (pn == NOPNET)
326
 
                                pn = net_newpnet(net, pnetlist);
327
 
                        pn->flags |= POWERNET;
328
 
                }
329
 
                if ((pe->exportproto->userbits&STATEBITS) == GNDPORT)
330
 
                {
331
 
                        pn = (PNET *)net->temp1;
332
 
                        if (pn == NOPNET)
333
 
                                pn = net_newpnet(net, pnetlist);
334
 
                        pn->flags |= GROUNDNET;
335
 
                }
336
 
        }
337
 
 
338
 
        /* generate new pseudo-netnumbers for networks not connected to ports */
339
 
        for(net = facet->firstnetwork; net != NONETWORK; net = net->nextnetwork)
340
 
        {
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)
346
 
                {
347
 
                        for(i=0; i<net->signals; i++)
348
 
                        {
349
 
                                subnet = net->networklist[i];
350
 
                                if (subnet->temp1 != (INTBIG)NOPNET) continue;
351
 
                                pn = net_newpnet(subnet, pnetlist);
352
 
                                subnet->temp1 = (INTBIG)pn;
353
 
                        }
354
 
                }
355
 
        }
356
 
 
357
 
        /* search every component in the facet */
358
 
        for(ni = facet->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
359
 
        {
360
 
                anp = ni->proto;
361
 
                if (toplevel != 0) net_toplevelinst = ni;
362
 
 
363
 
                /* ignore recursive references (showing icon in contents) */
364
 
                if (anp->cell == facet->cell) continue;
365
 
 
366
 
                /* if flattening the circuit, explore contents of facet instances */
367
 
                flattenit = 0;
368
 
                localcompare_hierarchically = compare_hierarchically;
369
 
                var = getvalkey((INTBIG)anp, VNODEPROTO, VINTEGER, net_ncc_optionskey);
370
 
                if (var != NOVARIABLE)
371
 
                {
372
 
                        if ((var->addr&NCCHIERARCHICALOVER) != 0)
373
 
                        {
374
 
                                if ((var->addr&NCCHIERARCHICAL) != 0) localcompare_hierarchically = TRUE; else
375
 
                                        localcompare_hierarchically = FALSE;
376
 
                        }
377
 
                }
378
 
                if (anp->primindex == 0 && localcompare_hierarchically) flattenit = 1;
379
 
 
380
 
                /* determine whether the node is arrayed */
381
 
                nodewidth = ni->arraysize;
382
 
                if (nodewidth < 1) nodewidth = 1;
383
 
 
384
 
                /* run through each instantiation of the node */
385
 
                for(nindex = 0; nindex < nodewidth; nindex++)
386
 
                {
387
 
                        if (flattenit != 0)             
388
 
                        {
389
 
                                /* if there is an alternate contents facet, use it */
390
 
                                realnp = contentsview(anp);
391
 
                                if (realnp == NONODEPROTO) realnp = anp;
392
 
 
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)
397
 
                                {
398
 
                                        if (realpp->network->temp1 != (INTBIG)NOPNET) continue;
399
 
 
400
 
                                        /* if there is an alternate contents facet, compute the port */
401
 
                                        if (realnp == anp) pp = realpp; else
402
 
                                        {
403
 
                                                pp = equivalentport(realnp, realpp, anp);
404
 
                                                if (pp == NOPORTPROTO) pp = anp->firstportproto;
405
 
                                        }
406
 
 
407
 
                                        /* see if an arc connects to the port */
408
 
                                        foundnet = NONETWORK;
409
 
                                        for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
410
 
                                        {
411
 
                                                temprealpp = equivalentport(anp, pi->proto, realnp);
412
 
                                                if (temprealpp == NOPORTPROTO)
413
 
                                                {
414
 
                                                        if (pi->proto->network == pp->network) break;
415
 
                                                } else
416
 
                                                {
417
 
                                                        if (temprealpp->network == realpp->network) break;
418
 
                                                }
419
 
                                        }
420
 
                                        if (pi != NOPORTARCINST && pi->conarcinst->network != NONETWORK)
421
 
                                        {
422
 
                                                foundnet = pi->conarcinst->network;
423
 
                                        } else
424
 
                                        {
425
 
                                                /* see if the port is an export */
426
 
                                                for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
427
 
                                                {
428
 
                                                        temprealpp = equivalentport(anp, pe->proto, realnp);
429
 
                                                        if (temprealpp == NOPORTPROTO)
430
 
                                                        {
431
 
                                                                if (pe->proto->network == pp->network) break;
432
 
                                                        } else
433
 
                                                        {
434
 
                                                                if (temprealpp->network == realpp->network) break;
435
 
                                                        }
436
 
                                                }
437
 
                                                if (pe != NOPORTEXPINST) foundnet = pe->exportproto->network; else
438
 
                                                {
439
 
                                                        pn = net_newpnet(realpp->network, pnetlist);
440
 
                                                        if (pn == NOPNET) return(0);
441
 
                                                        if ((realpp->userbits&STATEBITS) == PWRPORT)
442
 
                                                        {
443
 
                                                                pn->flags = POWERNET;
444
 
                                                        } else if ((realpp->userbits&STATEBITS) == GNDPORT)
445
 
                                                        {
446
 
                                                                pn->flags = GROUNDNET;
447
 
                                                        }
448
 
                                                        realpp->network->temp1 = (INTBIG)pn;
449
 
                                                }
450
 
                                        }
451
 
                                        if (foundnet != NONETWORK)
452
 
                                        {
453
 
                                                /* propagate export networks to nets inside facet */
454
 
                                                if (foundnet->signals > 1)
455
 
                                                {
456
 
                                                        sigcount = foundnet->signals;
457
 
                                                        if (nodewidth > 1 && realpp->network->signals * nodewidth == foundnet->signals)
458
 
                                                        {
459
 
                                                                /* map wide bus to a particular instantiation of an arrayed node */
460
 
                                                                if (realpp->network->signals == 1)
461
 
                                                                {
462
 
                                                                        realpp->network->temp1 = foundnet->networklist[nindex]->temp1;
463
 
                                                                } else
464
 
                                                                {
465
 
                                                                        for(i=0; i<realpp->network->signals; i++)
466
 
                                                                                realpp->network->networklist[i]->temp1 =
467
 
                                                                                        foundnet->networklist[i + nindex*realpp->network->signals]->temp1;
468
 
                                                                }
469
 
                                                        } else
470
 
                                                        {
471
 
                                                                if (realpp->network->signals != foundnet->signals)
472
 
                                                                {
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;
478
 
                                                                }
479
 
                                                                realpp->network->temp1 = (INTBIG)foundnet->temp1;
480
 
                                                                for(i=0; i<sigcount; i++)
481
 
                                                                        realpp->network->networklist[i]->temp1 = foundnet->networklist[i]->temp1;
482
 
                                                        }
483
 
                                                } else
484
 
                                                {
485
 
                                                        realpp->network->temp1 = (INTBIG)foundnet->temp1;
486
 
                                                }
487
 
                                        }
488
 
                                }
489
 
 
490
 
                                /* recurse into the facet */
491
 
                                downhierarchy(ni, nindex);
492
 
                                initiallist = net_buildpseudo(realnp, initiallist, components, pnetlist,
493
 
                                        compare_hierarchically);
494
 
                                uphierarchy();
495
 
                                if (initiallist == 0) return(0);
496
 
                                continue;
497
 
                        }
498
 
 
499
 
                        /* nonflattenable component: add it to the pseudocomponent list */
500
 
                        if (anp->primindex == 0) fun = NPUNKNOWN; else
501
 
                        {
502
 
                                fun = net_getfunction(ni);
503
 
                                if (fun == NPCONNECT || fun == NPART || fun == NPUNKNOWN ||
504
 
                                        fun == NPCONPOWER || fun == NPCONGROUND) continue;
505
 
                        }
506
 
 
507
 
                        /* create a pseudo-component */
508
 
                        pcomp = net_allocpcomp();
509
 
                        if (pcomp == NOPCOMP) return(0);
510
 
                        pcomp->nextpcomp = initiallist;
511
 
                        initiallist = pcomp;
512
 
                        pcomp->function = (INTSML)fun;
513
 
                        pcomp->hashreason = 0;
514
 
                        gettraversalpath(&nilist, &indexlist, &pathcount);
515
 
                        pcomp->hierpathcount = pathcount;
516
 
                        if (pcomp->hierpathcount > 0)
517
 
                        {
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++)
525
 
                                {
526
 
                                        pcomp->hierpath[i] = nilist[i];
527
 
                                        pcomp->hierindex[i] = indexlist[i];
528
 
                                }
529
 
                        }
530
 
                        pcomp->actuallist = (void *)ni;
531
 
                        pcomp->numactual = 1;
532
 
                        pcomp->topactual = net_toplevelinst;
533
 
                        (*components)++;
534
 
 
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)
539
 
                        {
540
 
                                /* get real export on contents */
541
 
                                if (cnp == NONODEPROTO) realpp = pp; else
542
 
                                {
543
 
                                        realpp = equivalentport(anp, pp, cnp);
544
 
#if 1
545
 
                                        if (realpp == NOPORTPROTO) continue;
546
 
#endif
547
 
                                }
548
 
 
549
 
                                /* special case for isolated ports */
550
 
                                if ((realpp->userbits&PORTISOLATED) != 0)
551
 
                                {
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++;
555
 
                                        continue;
556
 
                                }
557
 
 
558
 
                                /* new port, add in the number of signals */
559
 
                                if (pp->network->signals <= 1) pcomp->wirecount++; else
560
 
                                        pcomp->wirecount += pp->network->signals;
561
 
                        }
562
 
 
563
 
                        /* get parameters for the node */
564
 
                        switch (fun)
565
 
                        {
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;
581
 
#endif
582
 
                                        break;
583
 
 
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);
591
 
                                        pcomp->width = 0.0;
592
 
                                        pcomp->flags |= COMPHASAREA;
593
 
                                        break;
594
 
 
595
 
                                case NPRESIST:
596
 
                                case NPCAPAC:   case NPECAPAC:
597
 
                                case NPDIODE:   case NPDIODEZ:
598
 
                                case NPINDUCT:
599
 
                                        pcomp->length = net_getpartvalue(ni);
600
 
                                        pcomp->width = 0.0;
601
 
                                        pcomp->flags |= COMPHASAREA;
602
 
                                        break;
603
 
                        }
604
 
 
605
 
                        /* no further information if there are no wires */
606
 
                        if (pcomp->wirecount == 0) continue;
607
 
 
608
 
                        /* allocate the port and connection lists */
609
 
                        pcomp->portlist = (PORTPROTO **)emalloc(((sizeof (PORTPROTO *)) * pcomp->wirecount),
610
 
                                net_tool->cluster);
611
 
                        if (pcomp->portlist == 0) return(0);
612
 
                        pcomp->state = (INTSML *)emalloc((SIZEOFINTSML * pcomp->wirecount),
613
 
                                net_tool->cluster);
614
 
                        if (pcomp->state == 0) return(0);
615
 
                        pcomp->portindices = (INTSML *)emalloc((SIZEOFINTSML * pcomp->wirecount),
616
 
                                net_tool->cluster);
617
 
                        if (pcomp->portindices == 0) return(0);
618
 
                        pcomp->netnumbers = (PNET **)emalloc(((sizeof (PNET *)) * pcomp->wirecount),
619
 
                                net_tool->cluster);
620
 
                        if (pcomp->netnumbers == 0) return(0);
621
 
                        for(i=0; i<pcomp->wirecount; i++)
622
 
                                pcomp->state[i] = 0;
623
 
 
624
 
                        switch (pcomp->function)
625
 
                        {
626
 
                                case NPTRANMOS:
627
 
                                case NPTRADMOS:
628
 
                                case NPTRAPMOS:
629
 
                                case NPTRADMES:
630
 
                                case NPTRAEMES:
631
 
                                case NPTRANPN:
632
 
                                case NPTRAPNP:
633
 
                                case NPTRANJFET:
634
 
                                case NPTRAPJFET:
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++)
642
 
                                        {
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);
647
 
                                        }
648
 
                                        break;
649
 
 
650
 
                                case NPTRA4NMOS:
651
 
                                case NPTRA4DMOS:
652
 
                                case NPTRA4PMOS:
653
 
                                case NPTRA4DMES:
654
 
                                case NPTRA4EMES:
655
 
                                case NPTRA4NPN:
656
 
                                case NPTRA4PNP:
657
 
                                case NPTRA4NJFET:
658
 
                                case NPTRA4PJFET:
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++)
665
 
                                        {
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);
670
 
                                        }
671
 
                                        break;
672
 
 
673
 
                                default:
674
 
                                        j = 0;
675
 
                                        for(pp = anp->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
676
 
                                        {
677
 
                                                /* get real export on contents */
678
 
                                                if (cnp == NONODEPROTO) realpp = pp; else
679
 
                                                {
680
 
                                                        realpp = equivalentport(anp, pp, cnp);
681
 
#if 1
682
 
                                                        if (realpp == NOPORTPROTO) continue;
683
 
#endif
684
 
                                                }
685
 
                                                sigcount = realpp->network->signals;
686
 
 
687
 
                                                /* special case for isolated ports */
688
 
                                                if ((realpp->userbits&PORTISOLATED) != 0)
689
 
                                                {
690
 
                                                        /* add one wire for each arc on the port */
691
 
                                                        for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
692
 
                                                        {
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);
699
 
                                                                j++;
700
 
                                                        }
701
 
                                                        continue;
702
 
                                                }
703
 
 
704
 
                                                if (sigcount <= 1)
705
 
                                                {
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;
710
 
                                                        if (l >= j)
711
 
                                                        {
712
 
                                                                if (net_getpnetandstate(ni, pp, NONETWORK, -1, &pcomp->netnumbers[j],
713
 
                                                                        &pcomp->state[j], pnetlist, nodewidth, nindex, sigcount)) return(0);
714
 
                                                                j++;
715
 
                                                        }
716
 
                                                } else
717
 
                                                {
718
 
                                                        /* bus port */
719
 
                                                        for(k=0; k<sigcount; k++)
720
 
                                                        {
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;
724
 
                                                                if (l >= j)
725
 
                                                                {
726
 
                                                                        if (net_getpnetandstate(ni, pp, NONETWORK, k,
727
 
                                                                                &pcomp->netnumbers[j], &pcomp->state[j], pnetlist,
728
 
                                                                                        nodewidth, nindex, sigcount)) return(0);
729
 
                                                                        j++;
730
 
                                                                }
731
 
                                                        }
732
 
                                                }
733
 
                                        }
734
 
                                        pcomp->wirecount = (INTSML)j;
735
 
                                        break;
736
 
                        }
737
 
                }
738
 
        }
739
 
        return(initiallist);
740
 
}
741
 
 
742
 
/*
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.
749
 
 */
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)
753
 
{
754
 
        REGISTER ARCINST *ai;
755
 
        REGISTER INTBIG entry;
756
 
        REGISTER PORTARCINST *pi;
757
 
        REGISTER PORTEXPINST *pe;
758
 
        REGISTER NETWORK *net;
759
 
        REGISTER PNET *pn;
760
 
 
761
 
        /* first look for an arc that connects */
762
 
        for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
763
 
        {
764
 
                if (forcenet != NONETWORK)
765
 
                {
766
 
                        if (forcenet != pi->conarcinst->network) continue;
767
 
                } else
768
 
                {
769
 
                        if (pi->proto->network != pp->network) continue;
770
 
                }
771
 
 
772
 
                /* pickup the network number of this connection */
773
 
                ai = pi->conarcinst;
774
 
                net = ai->network;
775
 
                if (index < 0)
776
 
                {
777
 
                        if (nodewidth > 1 && net->signals == nodewidth)
778
 
                                *netnumber = (PNET *)net->networklist[nindex]->temp1; else
779
 
                                        *netnumber = (PNET *)net->temp1;
780
 
                } else
781
 
                {
782
 
                        entry = index;
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;
787
 
                }
788
 
                if ((ai->userbits&ISNEGATED) != 0)
789
 
                {
790
 
                        if ((ai->end[0].portarcinst == pi && (ai->userbits&REVERSEEND) == 0) ||
791
 
                                (ai->end[1].portarcinst == pi && (ai->userbits&REVERSEEND) != 0))
792
 
                                        *state = NEGATEDPORT;
793
 
                }
794
 
                if (*netnumber != NOPNET)
795
 
                {
796
 
                        if (((*netnumber)->flags&EXPORTEDNET) != 0)
797
 
                                *state |= EXPORTEDPORT;
798
 
                        return(FALSE);
799
 
                }
800
 
        }
801
 
 
802
 
        for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
803
 
        {
804
 
                if (forcenet != NONETWORK)
805
 
                {
806
 
                        if (forcenet != pe->proto->network) continue;
807
 
                } else
808
 
                {
809
 
                        if (pe->proto->network != pp->network) continue;
810
 
                }
811
 
                net = pe->exportproto->network;
812
 
                if (index < 0)
813
 
                {
814
 
                        if (nodewidth > 1 && net->signals == nodewidth)
815
 
                                *netnumber = (PNET *)net->networklist[nindex]->temp1; else
816
 
                                        *netnumber = (PNET *)net->temp1;
817
 
                } else
818
 
                {
819
 
                        entry = index;
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;
824
 
                }
825
 
                *state |= EXPORTEDPORT;
826
 
                if (*netnumber != NOPNET) return(FALSE);
827
 
        }
828
 
 
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;
836
 
        *netnumber = pn;
837
 
        return(FALSE);
838
 
}
839
 
 
840
 
/*
841
 
 * Routine to fill in the network pointers to components.
842
 
 */
843
 
void net_fillinnetpointers(PCOMP *pcomplist, PNET *pnetlist)
844
 
{
845
 
        REGISTER PCOMP *pc;
846
 
        REGISTER PNET *pn;
847
 
        REGISTER INTBIG i;
848
 
 
849
 
        for(pn = pnetlist; pn != NOPNET; pn = pn->nextpnet)
850
 
                pn->nodecount = 0;
851
 
        for(pc = pcomplist; pc != NOPCOMP; pc = pc->nextpcomp)
852
 
        {
853
 
                for(i=0; i<pc->wirecount; i++)
854
 
                {
855
 
                        pn = pc->netnumbers[i];
856
 
                        pn->nodecount++;
857
 
                }
858
 
        }
859
 
 
860
 
        for(pn = pnetlist; pn != NOPNET; pn = pn->nextpnet)
861
 
        {
862
 
                if (pn->nodecount <= pn->nodetotal) continue;
863
 
                if (pn->nodetotal > 0)
864
 
                {
865
 
                        efree((char *)pn->nodelist);
866
 
                        efree((char *)pn->nodewire);
867
 
                        pn->nodetotal = 0;
868
 
                }
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;
874
 
        }
875
 
        for(pn = pnetlist; pn != NOPNET; pn = pn->nextpnet)
876
 
                pn->nodecount = 0;
877
 
        for(pc = pcomplist; pc != NOPCOMP; pc = pc->nextpcomp)
878
 
        {
879
 
                for(i=0; i<pc->wirecount; i++)
880
 
                {
881
 
                        pn = pc->netnumbers[i];
882
 
                        if (pn->nodelist == 0)
883
 
                                continue;
884
 
                        pn->nodelist[pn->nodecount] = pc;
885
 
                        pn->nodewire[pn->nodecount] = i;
886
 
                        pn->nodecount++;
887
 
                }
888
 
        }
889
 
}       
890
 
 
891
 
/*
892
 
 * Routine to reduce the network in "pcomp" to merge parallel components.
893
 
 */
894
 
INTBIG net_mergeparallel(PCOMP **pcomp, PNET *pnet, INTBIG *components)
895
 
{
896
 
        REGISTER PCOMP *pc, *opc, *nextpc, *lastpc, **complist;
897
 
        REGISTER PNET *pn;
898
 
        REGISTER INTBIG i, j, k, m, newnum, mergecount, compcount, counter;
899
 
        REGISTER NODEINST *ni, **newlist, *newsingle;
900
 
 
901
 
        net_fillinnetpointers(*pcomp, pnet);
902
 
 
903
 
        /* assign values to each net */
904
 
        counter = 0;
905
 
        for(pn = pnet; pn != NOPNET; pn = pn->nextpnet)
906
 
        {
907
 
                counter += 6;
908
 
                pn->timestamp = counter;
909
 
        }
910
 
 
911
 
        /* compute hash value for each component */
912
 
        compcount = 0;
913
 
        for(pc = *pcomp; pc != NOPCOMP; pc = pc->nextpcomp)
914
 
        {
915
 
                pc->flags &= ~COMPDELETED;
916
 
                if (pc->function == NPUNKNOWN) continue;
917
 
                counter = pc->function;
918
 
                for(i=0; i<pc->wirecount; i++)
919
 
                {
920
 
                        pn = pc->netnumbers[i];
921
 
                        counter += pn->timestamp * pc->portindices[i];
922
 
                }
923
 
 
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];
928
 
#endif
929
 
 
930
 
                pc->timestamp = counter;
931
 
                compcount++;
932
 
        }
933
 
 
934
 
        if (compcount == 0) return(0);
935
 
        complist = (PCOMP **)emalloc(compcount * (sizeof (PCOMP *)), net_tool->cluster);
936
 
        if (complist == 0) return(0);
937
 
        compcount = 0;
938
 
        for(pc = *pcomp; pc != NOPCOMP; pc = pc->nextpcomp)
939
 
        {
940
 
                if (pc->function == NPUNKNOWN) continue;
941
 
                complist[compcount++] = pc;
942
 
        }
943
 
        esort(complist, compcount, sizeof (PCOMP *), net_sortpcompbyhash);
944
 
 
945
 
        mergecount = 0;
946
 
        for(i=0; i<compcount; i++)
947
 
        {
948
 
                if ((i%5) == 0)
949
 
                {
950
 
                        if (stopping(STOPREASONNCC)) break;
951
 
                }
952
 
                opc = complist[i];
953
 
                if ((opc->flags & COMPDELETED) != 0) continue;
954
 
 
955
 
                for(m=i+1; m<compcount; m++)
956
 
                {
957
 
                        pc = complist[m];
958
 
                        if (pc->timestamp != opc->timestamp) break;
959
 
                        if ((pc->flags & COMPDELETED) != 0) continue;
960
 
 
961
 
                        /* both components must have the same function */
962
 
                        if (pc->function != opc->function) continue;
963
 
 
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;
971
 
#endif
972
 
 
973
 
                        /* compare the wire lists */
974
 
                        if (net_comparewirelist(pc, opc, FALSE)) continue;
975
 
 
976
 
                        /* components are equivalent: delete "pc" */
977
 
                        mergecount++;
978
 
 
979
 
                        /* add "pc"s node pointer to "opc" */
980
 
                        newnum = pc->numactual + opc->numactual;
981
 
                        if (newnum > 1)
982
 
                        {
983
 
                                newlist = (NODEINST **)emalloc(newnum * (sizeof (NODEINST *)),
984
 
                                        net_tool->cluster);
985
 
                                if (newlist == 0) return(0);
986
 
                        }
987
 
                        k = 0;
988
 
                        for(j=0; j<pc->numactual; j++)
989
 
                        {
990
 
                                if (pc->numactual == 1) ni = (NODEINST *)pc->actuallist; else
991
 
                                        ni = ((NODEINST **)pc->actuallist)[j];
992
 
                                if (newnum == 1) newsingle = ni; else
993
 
                                        newlist[k++] = ni;
994
 
                        }
995
 
                        for(j=0; j<opc->numactual; j++)
996
 
                        {
997
 
                                if (opc->numactual == 1) ni = (NODEINST *)opc->actuallist; else
998
 
                                        ni = ((NODEINST **)opc->actuallist)[j];
999
 
                                if (newnum == 1) newsingle = ni; else
1000
 
                                        newlist[k++] = ni;
1001
 
                        }
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;
1006
 
 
1007
 
                        /* combine sizes (as specified by Robert Bosnyak) */
1008
 
                        if ((pc->flags&(COMPHASWIDLEN|COMPHASAREA)) != 0 &&
1009
 
                                (opc->flags&(COMPHASWIDLEN|COMPHASAREA)) != 0)
1010
 
                        {
1011
 
                                switch (pc->function)
1012
 
                                {
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)
1018
 
                                                {
1019
 
                                                        /* same-length transistors: sum the width */
1020
 
                                                        opc->width += pc->width;
1021
 
                                                } else
1022
 
                                                {
1023
 
                                                        /* different-length transistors: more complex formula */
1024
 
                                                        if (pc->width + opc->width != 0.0)
1025
 
                                                        {
1026
 
                                                                opc->length = (pc->width * pc->length + opc->width * opc->length) /
1027
 
                                                                        (pc->width + opc->width);
1028
 
                                                        }
1029
 
                                                        opc->width += pc->width;
1030
 
                                                }
1031
 
                                                break;
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;
1040
 
                                                break;
1041
 
                                        case NPRESIST:
1042
 
                                        case NPINDUCT:
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);
1046
 
                                                break;
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;
1051
 
                                                break;
1052
 
                                }
1053
 
                        }
1054
 
 
1055
 
                        pc->flags |= COMPDELETED;
1056
 
                }
1057
 
        }
1058
 
        efree((char *)complist);
1059
 
 
1060
 
        /* remove deleted components */
1061
 
        lastpc = NOPCOMP;
1062
 
        for(pc = *pcomp; pc != NOPCOMP; pc = nextpc)
1063
 
        {
1064
 
                nextpc = pc->nextpcomp;
1065
 
                if ((pc->flags&COMPDELETED) != 0)
1066
 
                {
1067
 
                        if (lastpc == NOPCOMP) *pcomp = pc->nextpcomp; else
1068
 
                                lastpc->nextpcomp = pc->nextpcomp;
1069
 
                        net_freepcomp(pc);
1070
 
                        (*components)--;
1071
 
                        continue;
1072
 
                }
1073
 
                lastpc = pc;
1074
 
        }
1075
 
        return(mergecount);
1076
 
}
1077
 
 
1078
 
int net_sortpcompbyhash(const void *e1, const void *e2)
1079
 
{
1080
 
        REGISTER PCOMP *pc1, *pc2;
1081
 
 
1082
 
        pc1 = *((PCOMP **)e1);
1083
 
        pc2 = *((PCOMP **)e2);
1084
 
        return(pc1->timestamp - pc2->timestamp);
1085
 
}
1086
 
 
1087
 
/*
1088
 
 * Routine to add PCOMP "pc" to the list of series transistors.
1089
 
 */
1090
 
BOOLEAN net_addtoserieslist(PCOMP *pc)
1091
 
{
1092
 
        REGISTER INTBIG newtotal, i;
1093
 
        REGISTER PCOMP **newlist;
1094
 
 
1095
 
        if (net_serieslistcount >= net_serieslisttotal)
1096
 
        {
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;
1107
 
        }
1108
 
        net_serieslist[net_serieslistcount] = pc;
1109
 
        net_serieslistcount++;
1110
 
        return(FALSE);
1111
 
}
1112
 
 
1113
 
/*
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.
1117
 
 */
1118
 
PCOMP **net_gatherseries(PCOMP *pc, INTBIG *seriescount)
1119
 
{
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);
1126
 
}
1127
 
 
1128
 
/*
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.
1131
 
 */
1132
 
void net_crawlforseries(PCOMP *pc)
1133
 
{
1134
 
        REGISTER INTBIG i, j, badend;
1135
 
        REGISTER PCOMP *opc;
1136
 
        REGISTER PNET *pn;
1137
 
 
1138
 
        /* check source and drain connections */
1139
 
        for(i=1; i<3; i++)
1140
 
        {
1141
 
                badend = 0;
1142
 
 
1143
 
                /* connection must be to exactly 1 other component */
1144
 
                pn = pc->netnumbers[i];
1145
 
                if (pn->nodecount != 2) badend = 1; else
1146
 
                {
1147
 
                        opc = pn->nodelist[0];
1148
 
                        if (opc == pc) opc = pn->nodelist[1];
1149
 
                }
1150
 
 
1151
 
                /* other component must be the same as this */
1152
 
                if (badend == 0)
1153
 
                {
1154
 
                        if (opc->function != pc->function) badend = 1;
1155
 
                }
1156
 
 
1157
 
                /* both components must be in the same facet */
1158
 
                if (badend == 0)
1159
 
                {
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;
1165
 
                }
1166
 
 
1167
 
                /* other component must point just to this on its source or drain */
1168
 
                if (badend == 0)
1169
 
                {
1170
 
                        pn = pc->netnumbers[i];
1171
 
                        if ((pn->flags&(EXPORTEDNET|POWERNET|GROUNDNET)) != 0) badend = 1;
1172
 
                }
1173
 
 
1174
 
                /* other component must not already be in the list */
1175
 
                if (badend == 0)
1176
 
                {
1177
 
                        for(j=0; j<net_serieslistcount; j++)
1178
 
                                if (net_serieslist[j] == opc) break;
1179
 
                        if (j < net_serieslistcount) badend = 2;
1180
 
                }
1181
 
 
1182
 
                switch (badend)
1183
 
                {
1184
 
                        case 0:         /* good end */
1185
 
                                /* another series transistor found */
1186
 
                                (void)net_addtoserieslist(opc);
1187
 
 
1188
 
                                /* recursively search for others */
1189
 
                                net_crawlforseries(opc);
1190
 
                                break;
1191
 
                        case 1:         /* bad end: end of chain */
1192
 
                                /* add to the end list */
1193
 
                                if (net_seriescon1 < 0)
1194
 
                                {
1195
 
                                        net_seriesend1 = pc;
1196
 
                                        net_seriescon1 = i;
1197
 
                                } else if (net_seriescon2 < 0)
1198
 
                                {
1199
 
                                        net_seriesend2 = pc;
1200
 
                                        net_seriescon2 = i;
1201
 
                                }
1202
 
                                break;
1203
 
                }
1204
 
        }
1205
 
}
1206
 
 
1207
 
/*
1208
 
 * Routine to reduce the network in "pcomp" to merge series transistors into more complex
1209
 
 * single components.
1210
 
 */
1211
 
INTBIG net_mergeseries(PCOMP **pcomp, PNET *pnet, INTBIG *components)
1212
 
{
1213
 
        REGISTER PCOMP *pc, *opc, *nextpc, *lastpc, **serieslist, *newpc, *npc;
1214
 
        REGISTER INTBIG i, j, k, t, mergecount;
1215
 
        INTBIG seriescount;
1216
 
        REGISTER NODEINST *ni;
1217
 
 
1218
 
        /* clear flags on every component */
1219
 
        for(pc = *pcomp; pc != NOPCOMP; pc = pc->nextpcomp) pc->timestamp = -1;
1220
 
        net_fillinnetpointers(*pcomp, pnet);
1221
 
 
1222
 
        /* scan for series transistors */
1223
 
        mergecount = 0;
1224
 
        for(pc = *pcomp; pc != NOPCOMP; pc = nextpc)
1225
 
        {
1226
 
                nextpc = pc->nextpcomp;
1227
 
                if (pc->function != NPTRANMOS && pc->function != NPTRADMOS &&
1228
 
                        pc->function != NPTRAPMOS) continue;
1229
 
 
1230
 
                /* look for adjacent single transistor */
1231
 
                serieslist = net_gatherseries(pc, &seriescount);
1232
 
                if (seriescount <= 1) continue;
1233
 
 
1234
 
                mergecount++;
1235
 
 
1236
 
                /* mark transistors */
1237
 
                for(t=0; t<seriescount; t++) serieslist[t]->timestamp = t;
1238
 
 
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;
1243
 
                *pcomp = newpc;
1244
 
                newpc->topactual = pc->topactual;
1245
 
                newpc->hierpathcount = pc->hierpathcount;
1246
 
                if (newpc->hierpathcount > 0)
1247
 
                {
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++)
1255
 
                        {
1256
 
                                newpc->hierpath[i] = pc->hierpath[i];
1257
 
                                newpc->hierindex[i] = pc->hierindex[i];
1258
 
                        }
1259
 
                }
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;
1265
 
 
1266
 
                /* length is the sum of all lengths, width is the average width */
1267
 
                newpc->length = 0.0;
1268
 
                newpc->width = 0.0;
1269
 
                for(t=0; t<seriescount; t++)
1270
 
                {
1271
 
                        newpc->length += serieslist[t]->length;
1272
 
                        newpc->width += serieslist[t]->width;
1273
 
                }
1274
 
                newpc->width /= seriescount;
1275
 
 
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 *)),
1280
 
                        net_tool->cluster);
1281
 
                if (newpc->actuallist == 0) return(0);
1282
 
                j = 0;
1283
 
                for(t=0; t<seriescount; t++)
1284
 
                {
1285
 
                        opc = serieslist[t];
1286
 
                        for(k=0; k < opc->numactual; k++)
1287
 
                        {
1288
 
                                if (opc->numactual == 1) ni = (NODEINST *)opc->actuallist; else
1289
 
                                        ni = ((NODEINST **)opc->actuallist)[k];
1290
 
                                ((NODEINST **)newpc->actuallist)[j++] = ni;
1291
 
                        }
1292
 
                }
1293
 
 
1294
 
                /* allocate the pointer arrays */
1295
 
                newpc->portlist = (PORTPROTO **)emalloc(((sizeof (PORTPROTO *)) * newpc->wirecount),
1296
 
                        net_tool->cluster);
1297
 
                if (newpc->portlist == 0) return(0);
1298
 
                newpc->state = (INTSML *)emalloc((SIZEOFINTSML * newpc->wirecount),
1299
 
                        net_tool->cluster);
1300
 
                if (newpc->state == 0) return(0);
1301
 
                newpc->portindices = (INTSML *)emalloc((SIZEOFINTSML * newpc->wirecount),
1302
 
                        net_tool->cluster);
1303
 
                if (newpc->portindices == 0) return(0);
1304
 
                newpc->netnumbers = (PNET **)emalloc(((sizeof (PNET *)) * newpc->wirecount),
1305
 
                        net_tool->cluster);
1306
 
                if (newpc->netnumbers == 0) return(0);
1307
 
 
1308
 
                /* pick up gates from all series transistors */
1309
 
                for(t=0; t<seriescount; t++)
1310
 
                {
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];
1315
 
                }
1316
 
 
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];
1322
 
                t++;
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];
1327
 
                (*components)++;
1328
 
 
1329
 
                /* fix pointer to the next transistor */
1330
 
                while (nextpc != NOPCOMP && nextpc->timestamp != -1)
1331
 
                        nextpc = nextpc->nextpcomp;
1332
 
 
1333
 
                /* remove the series transistors */
1334
 
                lastpc = NOPCOMP;
1335
 
                for(opc = *pcomp; opc != NOPCOMP; opc = npc)
1336
 
                {
1337
 
                        npc = opc->nextpcomp;
1338
 
                        if (opc->timestamp != -1)
1339
 
                        {
1340
 
                                /* remove this */
1341
 
                                if (lastpc == NOPCOMP) *pcomp = npc; else
1342
 
                                        lastpc->nextpcomp = npc;
1343
 
                                net_freepcomp(opc);
1344
 
                                (*components)--;
1345
 
                                continue;
1346
 
                        }
1347
 
                        lastpc = opc;
1348
 
                }
1349
 
        }
1350
 
        return(mergecount);
1351
 
}
1352
 
 
1353
 
/*
1354
 
 * routine to compare pseudocomponent "p1" and "p2", returning true if they
1355
 
 * are different.
1356
 
 */
1357
 
BOOLEAN net_comparewirelist(PCOMP *p1, PCOMP *p2, BOOLEAN useportnames)
1358
 
{
1359
 
        REGISTER INTBIG i, j;
1360
 
 
1361
 
        /* simple test: number of wire lists must be equal */
1362
 
        if (p1->wirecount != p2->wirecount) return(TRUE);
1363
 
 
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)
1369
 
        {
1370
 
                for(i=0; i<p1->wirecount; i++)
1371
 
                {
1372
 
                        if (p1->netnumbers[i] != p2->netnumbers[i]) return(TRUE);
1373
 
                }
1374
 
                return(FALSE);
1375
 
        }
1376
 
 
1377
 
        /* make sure there is memory for flags corresponding to component 2 */
1378
 
        if (p2->wirecount > net_comparelistsize)
1379
 
        {
1380
 
                if (net_comparelistsize != 0) efree((char *)net_comparelist);
1381
 
                net_comparelist = (BOOLEAN *)emalloc(((sizeof (BOOLEAN)) * p2->wirecount),
1382
 
                        net_tool->cluster);
1383
 
                net_comparelistsize = p2->wirecount;
1384
 
        }
1385
 
 
1386
 
        /* reset flags in list for component 2 */
1387
 
        for(j=0; j<p2->wirecount; j++) net_comparelist[j] = FALSE;
1388
 
 
1389
 
        for(i=0; i<p1->wirecount; i++)
1390
 
        {
1391
 
                if (p1->netnumbers[i]->nodecount == 0) return(TRUE);
1392
 
                for(j=0; j<p2->wirecount; j++)
1393
 
                {
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;
1398
 
                        break;
1399
 
                }
1400
 
                if (j >= p2->wirecount) return(TRUE);
1401
 
        }
1402
 
        return(FALSE);
1403
 
}
1404
 
 
1405
 
float net_getpartvalue(NODEINST *ni)
1406
 
{
1407
 
        REGISTER NODEPROTO *np;
1408
 
        REGISTER VARIABLE *var;
1409
 
        REGISTER INTBIG i;
1410
 
        float value;
1411
 
        REGISTER char *pt;
1412
 
 
1413
 
        np = ni->proto;
1414
 
        if (np->primindex == 0) return(0.0);
1415
 
 
1416
 
        /* diodes have area on them */
1417
 
        if (np == sch_diodeprim)
1418
 
        {
1419
 
                var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_diodekey);
1420
 
                pt = describesimplevariable(var);
1421
 
                return((float)atof(pt));
1422
 
        }
1423
 
 
1424
 
        /* capacitors have Farads on them */
1425
 
        if (np == sch_capacitorprim)
1426
 
        {
1427
 
                var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_capacitancekey);
1428
 
                pt = describesimplevariable(var);
1429
 
                value = (float)atof(pt);
1430
 
                i = strlen(pt);
1431
 
                if (i > 0)
1432
 
                {
1433
 
                        if (tolower(pt[i-1]) == 'f')
1434
 
                        {
1435
 
                                value = value / 1000000000000.0f;
1436
 
                        } else if (tolower(pt[i-1]) == 'p')
1437
 
                        {
1438
 
                                value = value / 1000000000.0f;
1439
 
                        } else if (tolower(pt[i-1]) == 'u')
1440
 
                        {
1441
 
                                value = value / 1000000.0f;
1442
 
                        } else if (tolower(pt[i-1]) == 'm')
1443
 
                        {
1444
 
                                value = value / 1000.0f;
1445
 
                        }
1446
 
                }
1447
 
                return(value);
1448
 
        }
1449
 
 
1450
 
        /* resistors have Ohms on them */
1451
 
        if (np == sch_resistorprim)
1452
 
        {
1453
 
                var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_resistancekey);
1454
 
                pt = describesimplevariable(var);
1455
 
                value = (float)atof(pt);
1456
 
                i = strlen(pt);
1457
 
                if (i > 0)
1458
 
                {
1459
 
                        if (tolower(pt[i-1]) == 'g')
1460
 
                        {
1461
 
                                value = value * 1000000000.0f;
1462
 
                        } else if (i > 2 && namesame(&pt[i-3], "meg") == 0)
1463
 
                        {
1464
 
                                value = value * 1000000.0f;
1465
 
                        } else if (tolower(pt[i-1]) == 'k')
1466
 
                        {
1467
 
                                value = value * 1000.0f;
1468
 
                        }
1469
 
                }
1470
 
                return(value);
1471
 
        }
1472
 
 
1473
 
        /* inductors have Henrys on them */
1474
 
        if (np == sch_inductorprim)
1475
 
        {
1476
 
                var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_inductancekey);
1477
 
                pt = describesimplevariable(var);
1478
 
                value = (float)atof(pt);
1479
 
                i = strlen(pt);
1480
 
                if (i > 0)
1481
 
                {
1482
 
                        if (tolower(pt[i-1]) == 'u')
1483
 
                        {
1484
 
                                value = value / 1000000.0f;
1485
 
                        } else if (tolower(pt[i-1]) == 'm')
1486
 
                        {
1487
 
                                value = value / 1000.0f;
1488
 
                        }
1489
 
                }
1490
 
                return(value);
1491
 
        }
1492
 
        return(0.0);
1493
 
}
1494
 
 
1495
 
/*********************** ALLOCATION ***********************/
1496
 
 
1497
 
/*
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).
1502
 
 */
1503
 
PNET *net_newpnet(NETWORK *net, PNET **pnetlist)
1504
 
{
1505
 
        REGISTER PNET *pn;
1506
 
        REGISTER NETWORK *onet;
1507
 
        REGISTER char *globalname;
1508
 
        REGISTER INTBIG characteristics;
1509
 
 
1510
 
        /* if the net is global, look for an equivalent */
1511
 
        if (net != NONETWORK && net->globalnet >= 0 &&
1512
 
                net->globalnet < net->parent->globalnetcount)
1513
 
        {
1514
 
                globalname = net->parent->globalnetnames[net->globalnet];
1515
 
                for(pn = *pnetlist; pn != NOPNET; pn = pn->nextpnet)
1516
 
                {
1517
 
                        if ((pn->flags&GLOBALNET) == 0) continue;
1518
 
                        onet = pn->network;
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)
1523
 
                                return(pn);
1524
 
                }
1525
 
        }
1526
 
 
1527
 
        /* global net not found */
1528
 
        pn = net_allocpnet();
1529
 
        if (pn == 0) return(NOPNET);
1530
 
        net_pseudonode++;
1531
 
        pn->nextpnet = *pnetlist;
1532
 
        *pnetlist = pn;
1533
 
        pn->network = net;
1534
 
        if (net != NONETWORK && net->globalnet >= 0 &&
1535
 
                net->globalnet < net->parent->globalnetcount)
1536
 
        {
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;
1541
 
        }
1542
 
        return(pn);
1543
 
}
1544
 
 
1545
 
/*
1546
 
 * routine to allocate a new pcomp module from the pool (if any) or memory
1547
 
 */
1548
 
PCOMP *net_allocpcomp(void)
1549
 
{
1550
 
        REGISTER PCOMP *pc;
1551
 
 
1552
 
        if (net_pcompfree == NOPCOMP)
1553
 
        {
1554
 
                pc = (PCOMP *)emalloc(sizeof (PCOMP), net_tool->cluster);
1555
 
                if (pc == 0) return(NOPCOMP);
1556
 
        } else
1557
 
        {
1558
 
                pc = net_pcompfree;
1559
 
                net_pcompfree = (PCOMP *)pc->nextpcomp;
1560
 
        }
1561
 
        pc->flags = 0;
1562
 
        return(pc);
1563
 
}
1564
 
 
1565
 
/*
1566
 
 * routine to return pcomp module "pc" to the pool of free modules
1567
 
 */
1568
 
void net_freepcomp(PCOMP *pc)
1569
 
{
1570
 
        if (pc->wirecount != 0)
1571
 
        {
1572
 
                efree((char *)pc->portlist);
1573
 
                efree((char *)pc->state);
1574
 
                efree((char *)pc->netnumbers);
1575
 
                efree((char *)pc->portindices);
1576
 
        }
1577
 
        if (pc->numactual > 1) efree((char *)pc->actuallist);
1578
 
        if (pc->hashreason != 0) efree((char *)pc->hashreason);
1579
 
        if (pc->hierpathcount != 0)
1580
 
        {
1581
 
                efree((char *)pc->hierpath);
1582
 
                efree((char *)pc->hierindex);
1583
 
        }
1584
 
 
1585
 
        pc->nextpcomp = net_pcompfree;
1586
 
        net_pcompfree = pc;
1587
 
}
1588
 
 
1589
 
/*
1590
 
 * routine to allocate a new pnet module from the pool (if any) or memory
1591
 
 */
1592
 
PNET *net_allocpnet(void)
1593
 
{
1594
 
        REGISTER PNET *pn;
1595
 
 
1596
 
        if (net_pnetfree == NOPNET)
1597
 
        {
1598
 
                pn = (PNET *)emalloc(sizeof (PNET), net_tool->cluster);
1599
 
                if (pn == 0) return(NOPNET);
1600
 
        } else
1601
 
        {
1602
 
                pn = net_pnetfree;
1603
 
                net_pnetfree = (PNET *)pn->nextpnet;
1604
 
        }
1605
 
 
1606
 
        pn->flags = 0;
1607
 
        pn->nodetotal = 0;
1608
 
        pn->nodecount = 0;
1609
 
        pn->realportcount = 0;
1610
 
        return(pn);
1611
 
}
1612
 
 
1613
 
/*
1614
 
 * routine to return pnet module "pn" to the pool of free modules
1615
 
 */
1616
 
void net_freepnet(PNET *pn)
1617
 
{
1618
 
        if (pn->nodetotal > 0)
1619
 
        {
1620
 
                efree((char *)pn->nodelist);
1621
 
                efree((char *)pn->nodewire);
1622
 
        }
1623
 
        if (pn->realportcount > 1)
1624
 
                efree((char *)pn->realportlist);
1625
 
 
1626
 
        pn->nextpnet = net_pnetfree;
1627
 
        net_pnetfree = pn;
1628
 
}
1629
 
 
1630
 
/*
1631
 
 * routine to free all allocated structures in the list of pseudonets
1632
 
 * headed by "pnlist"
1633
 
 */
1634
 
void net_freeallpnet(PNET *pnlist)
1635
 
{
1636
 
        REGISTER PNET *pn, *nextpn;
1637
 
 
1638
 
        for(pn = pnlist; pn != NOPNET; pn = nextpn)
1639
 
        {
1640
 
                nextpn = pn->nextpnet;
1641
 
                net_freepnet(pn);
1642
 
        }
1643
 
}
1644
 
 
1645
 
/*
1646
 
 * routine to free all allocated structures in the list of pseudocomponents
1647
 
 * headed by "pclist"
1648
 
 */
1649
 
void net_freeallpcomp(PCOMP *pclist)
1650
 
{
1651
 
        REGISTER PCOMP *pc, *nextpc;
1652
 
 
1653
 
        for(pc = pclist; pc != NOPCOMP; pc = nextpc)
1654
 
        {
1655
 
                nextpc = pc->nextpcomp;
1656
 
                net_freepcomp(pc);
1657
 
        }
1658
 
}
1659
 
 
1660
 
/*********************** COMPONENT FUNCTION ***********************/
1661
 
 
1662
 
#define NOTRANMODEL ((TRANMODEL *)-1)
1663
 
 
1664
 
typedef struct Itranmodel
1665
 
{
1666
 
        char *modelname;
1667
 
        INTBIG tmindex;
1668
 
        struct Itranmodel *nexttranmodel;
1669
 
} TRANMODEL;
1670
 
 
1671
 
static TRANMODEL *net_firsttranmodel = NOTRANMODEL;
1672
 
 
1673
 
/* must be larger than largest node function entry in "efunction.h" */
1674
 
static INTBIG net_tranmodelindex = 100;
1675
 
 
1676
 
/*
1677
 
 * routine to return the function of node "ni"
1678
 
 */
1679
 
INTBIG net_getfunction(NODEINST *ni)
1680
 
{
1681
 
        REGISTER INTBIG fun;
1682
 
        REGISTER TRANMODEL *tm;
1683
 
 
1684
 
        fun = nodefunction(ni);
1685
 
        switch (fun)
1686
 
        {
1687
 
                case NPTRANS:
1688
 
                        fun = NPTRANMOS;
1689
 
                        break;
1690
 
 
1691
 
                case NPTRANS4:
1692
 
#ifdef IGNOREFOURPORT
1693
 
                        fun = NPTRANMOS;
1694
 
#else
1695
 
                        fun = NPTRA4NMOS;
1696
 
#endif
1697
 
                        break;
1698
 
 
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;
1709
 
#endif
1710
 
 
1711
 
                case NPTRANSREF:
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)
1716
 
                        {
1717
 
                                /* new table entry */
1718
 
                                tm = (TRANMODEL *)emalloc(sizeof (TRANMODEL), net_tool->cluster);
1719
 
                                if (tm == 0) break;
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;
1724
 
                        }
1725
 
                        fun = tm->tmindex;
1726
 
                        break;
1727
 
 
1728
 
                case NPPIN:
1729
 
                case NPNODE:
1730
 
                case NPCONTACT:
1731
 
                case NPWELL:
1732
 
                case NPSUBSTRATE:
1733
 
                        fun = NPCONNECT;
1734
 
                        break;
1735
 
        }
1736
 
        return(fun);
1737
 
}
1738
 
 
1739
 
void net_setallexporttopology(void)
1740
 
{
1741
 
        REGISTER LIBRARY *lib;
1742
 
        REGISTER NODEPROTO *np;
1743
 
        REGISTER INTBIG i, j, len;
1744
 
        REGISTER char *pt, *name, *oname, **strings;
1745
 
        UINTBIG matchdate;
1746
 
        NODEPROTO *onp;
1747
 
        REGISTER VARIABLE *var, *ovar;
1748
 
        REGISTER PORTPROTO *pp;
1749
 
        REGISTER CELL *c;
1750
 
        REGISTER TECHNOLOGY *tech;
1751
 
        REGISTER NETWORK *net, *onet;
1752
 
 
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)
1756
 
                        c->temp2 = 0;
1757
 
 
1758
 
        /* clear network topology information */
1759
 
        for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1760
 
        {
1761
 
                for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1762
 
                {
1763
 
                        for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1764
 
                                net->temp2 = 0;
1765
 
                }
1766
 
        }
1767
 
 
1768
 
        /* assign network topology information from previous NCC runs */
1769
 
        for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1770
 
        {
1771
 
                /* assign topology information uniformly in each cell */
1772
 
                for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1773
 
                {
1774
 
                        for(i=0; i<np->numvar; i++)
1775
 
                        {
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;
1782
 
 
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;
1787
 
 
1788
 
                                /* found match: assign network pointers */
1789
 
                                len = getlength(var);
1790
 
                                strings = (char **)var->addr;
1791
 
                                for(j=0; j<len; j++)
1792
 
                                {
1793
 
                                        pt = strings[j];
1794
 
                                        if (namesamen(pt, "EXPORT ", 7) != 0) continue;
1795
 
                                        pt += 7;
1796
 
                                        name = pt;
1797
 
                                        while (*pt != 0 && *pt != ':') pt++;
1798
 
                                        if (*pt == 0) continue;
1799
 
                                        *pt = 0;
1800
 
                                        oname = pt+1;
1801
 
 
1802
 
                                        /* found the names: make the assignment */
1803
 
                                        net = getnetwork(name, np);
1804
 
                                        onet = getnetwork(oname, onp);
1805
 
                                        if (net != NONETWORK && onet != NONETWORK)
1806
 
                                        {
1807
 
                                                if (net->temp2 == 0 && onet->temp2 == 0)
1808
 
                                                {
1809
 
                                                        net->temp2 = onet->temp2 = getprime(np->cell->temp2++);
1810
 
                                                }
1811
 
                                        }
1812
 
                                        *pt = ':';
1813
 
                                }
1814
 
                        }
1815
 
                }
1816
 
        }
1817
 
 
1818
 
        /* assign remaining network topology based on export names */
1819
 
        for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1820
 
        {
1821
 
                /* assign topology information uniformly in each cell */
1822
 
                for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1823
 
                {
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)
1827
 
                        {
1828
 
                                if (pp->network->temp2 != 0) continue;
1829
 
                                net_setthisexporttopology(pp, &np->cell->temp2);
1830
 
                        }
1831
 
                        for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1832
 
                        {
1833
 
                                if (net->temp2 == 0) net->temp2 = getprime(np->cell->temp2++);
1834
 
                        }
1835
 
                }
1836
 
                for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1837
 
                {
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)
1841
 
                        {
1842
 
                                if (pp->network->temp2 != 0) continue;
1843
 
                                net_setthisexporttopology(pp, &np->cell->temp2);
1844
 
                        }
1845
 
                        for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1846
 
                        {
1847
 
                                if (net->temp2 == 0) net->temp2 = getprime(np->cell->temp2++);
1848
 
                        }
1849
 
                }
1850
 
        }
1851
 
        for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
1852
 
        {
1853
 
                for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1854
 
                {
1855
 
                        switch ((np->userbits&NFUNCTION) >> NFUNCTIONSH)
1856
 
                        {
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 */
1864
 
                                        break;
1865
 
                                case NPTRANS:
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 */
1869
 
                                        break;
1870
 
                                case NPTRANS4:
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 */
1875
 
                                        break;
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 */
1880
 
                                        break;
1881
 
                                default:
1882
 
                                        i = 0;
1883
 
                                        for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1884
 
                                        {
1885
 
                                                pp->network->temp2 = getprime(i);
1886
 
                                                i++;
1887
 
                                        }
1888
 
                                        break;
1889
 
                        }
1890
 
                }
1891
 
        }
1892
 
}
1893
 
 
1894
 
void net_setthisexporttopology(PORTPROTO *pp, INTBIG *index)
1895
 
{
1896
 
        REGISTER NETWORK *net, *subnet;
1897
 
        REGISTER INTBIG i;
1898
 
        REGISTER char *name;
1899
 
 
1900
 
        /* assign the unique prime numbers to the export's network */
1901
 
        net = pp->network;
1902
 
        if (net->temp2 == 0)
1903
 
        {
1904
 
                net->temp2 = net_findotherexporttopology(pp->parent, pp->protoname);
1905
 
                if (net->temp2 == 0) net->temp2 = getprime((*index)++);
1906
 
        }
1907
 
        if (net->signals > 1)
1908
 
        {
1909
 
                for(i=0; i<net->signals; i++)
1910
 
                {
1911
 
                        subnet = net->networklist[i];
1912
 
                        if (subnet->temp2 == 0)
1913
 
                        {
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)++);
1918
 
                        }
1919
 
                }
1920
 
        }
1921
 
}
1922
 
 
1923
 
INTBIG net_findotherexporttopology(NODEPROTO *parent, char *exportname)
1924
 
{
1925
 
        REGISTER NODEPROTO *np;
1926
 
        REGISTER PORTPROTO *opp;
1927
 
        REGISTER NETWORK *net;
1928
 
 
1929
 
        /* first look for an equivalent export in another facet */
1930
 
        for(np = parent->cell->lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1931
 
        {
1932
 
                if (np == parent) continue;
1933
 
                if (np->cell != parent->cell) continue;
1934
 
 
1935
 
                /* facet from the same cell: look for an equivalent port */
1936
 
                for(opp = np->firstportproto; opp != NOPORTPROTO; opp = opp->nextportproto)
1937
 
                {
1938
 
                        if (namesame(exportname, opp->protoname) != 0) continue;
1939
 
                        if (opp->network->temp2 != 0) return(opp->network->temp2);
1940
 
                }
1941
 
        }
1942
 
 
1943
 
        /* next look for an equivalent network name in another facet */
1944
 
        for(np = parent->cell->lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1945
 
        {
1946
 
                if (np == parent) continue;
1947
 
                if (np->cell != parent->cell) continue;
1948
 
 
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);
1953
 
        }
1954
 
        return(0);
1955
 
}