~ubuntu-branches/ubuntu/jaunty/electric/jaunty

« back to all changes in this revision

Viewing changes to src/db/dbtech.c

  • Committer: Bazaar Package Importer
  • Author(s): Onkar Shinde
  • Date: 2009-01-08 02:05:08 UTC
  • mfrom: (1.3.1 upstream) (3.1.3 sid)
  • mto: (3.1.4 sid)
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: james.westby@ubuntu.com-20090108020508-3e7e6241i7bkit2l
New upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Electric(tm) VLSI Design System
3
 
 *
4
 
 * File: dbtech.c
5
 
 * Database technology helper routines
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 "database.h"
33
 
#include "egraphics.h"
34
 
#include "tech.h"
35
 
#include "tecgen.h"
36
 
#include "tecart.h"
37
 
#include "tecschem.h"
38
 
#include "drc.h"
39
 
#include "efunction.h"
40
 
#include <math.h>
41
 
 
42
 
       INTBIG      tech_realpolys;                                      /* polygon count without displayable variables */
43
 
       WINDOWPART *tech_curwindowpart;                          /* window used in getting polygons from node/arc */
44
 
static BOOLEAN    *tech_equivtable = 0;
45
 
static TECHNOLOGY *db_convertpseudotech = NOTECHNOLOGY;
46
 
static INTBIG     *db_convertpseudoarray = 0;
47
 
 
48
 
/* keys to variables */
49
 
static INTBIG      tech_techlayer3dheightkey;           /* key for "TECH_layer_3dheight" */
50
 
static INTBIG      tech_techlayer3dthicknesskey;        /* key for "TECH_layer_3dthickness" */
51
 
       INTBIG      db_tech_node_width_offset_key;       /* variable "TECH_node_width_offset" */
52
 
       INTBIG      db_tech_layer_function_key;          /* variable "TECH_layer_function" */
53
 
       INTBIG      db_tech_layer_names_key;                     /* variable "TECH_layer_names" */
54
 
       INTBIG      db_tech_arc_width_offset_key;        /* variable "TECH_arc_width_offset" */
55
 
 
56
 
/* cached variables */
57
 
static INTBIG    **tech_node_widoff = 0;                        /* cache for "nodesizeoffset" */
58
 
static INTBIG    **tech_layer_function = 0;                     /* cache for "layerfunction" */
59
 
static char     ***tech_layer_names = 0;                        /* cache for "layername" */
60
 
static INTBIG    **tech_arc_widoff = 0;                         /* cache for "arcwidthoffset" */
61
 
static INTBIG    **tech_drcmaxdistances = 0;            /* cache for "maxdrcsurround" */
62
 
static INTBIG     *tech_drcwidelimit = 0;                       /* cache for "drcmindistance" */
63
 
static INTBIG    **tech_drcminwidth = 0;                        /* cache for "drcminwidth" */
64
 
static INTBIG    **tech_drcminnodesize = 0;                     /* cache for "drcminnodesize" */
65
 
static char     ***tech_drcminwidthrule = 0;            /* cache for "drcminwidth" */
66
 
static char     ***tech_drcminnodesizerule = 0;         /* cache for "drcminnodesize" */
67
 
static INTBIG    **tech_drcconndistance = 0;            /* cache for "drcmindistance" */
68
 
static INTBIG    **tech_drcuncondistance = 0;           /* cache for "drcmindistance" */
69
 
static INTBIG    **tech_drcconndistancew = 0;           /* cache for "drcmindistance" */
70
 
static INTBIG    **tech_drcuncondistancew = 0;          /* cache for "drcmindistance" */
71
 
static INTBIG    **tech_drcconndistancem = 0;           /* cache for "drcmindistance" */
72
 
static INTBIG    **tech_drcuncondistancem = 0;          /* cache for "drcmindistance" */
73
 
static INTBIG    **tech_drcedgedistance = 0;            /* cache for "drcmindistance" */
74
 
static char     ***tech_drccondistancerule = 0;         /* cache for "drcmindistance" */
75
 
static char     ***tech_drcuncondistancerule = 0;       /* cache for "drcmindistance" */
76
 
static char     ***tech_drccondistancewrule = 0;        /* cache for "drcmindistance" */
77
 
static char     ***tech_drcuncondistancewrule = 0;      /* cache for "drcmindistance" */
78
 
static char     ***tech_drccondistancemrule = 0;        /* cache for "drcmindistance" */
79
 
static char     ***tech_drcuncondistancemrule = 0;      /* cache for "drcmindistance" */
80
 
static char     ***tech_drcedgedistancerule = 0;        /* cache for "drcmindistance" */
81
 
static TECHNOLOGY *tech_3dcurtech = NOTECHNOLOGY;
82
 
static INTBIG     *tech_3dcurthicknessarray;
83
 
static INTBIG     *tech_3dcurheightarray;
84
 
 
85
 
 
86
 
#define NOROUTINELIST ((ROUTINELIST *)-1)
87
 
 
88
 
typedef struct Iroutinelist
89
 
{
90
 
        void               (*routine)(void);
91
 
        INTBIG               count;
92
 
        INTBIG              *variablekeys;
93
 
        struct Iroutinelist *nextroutinelist;
94
 
} ROUTINELIST;
95
 
static ROUTINELIST *tech_firstcache = NOROUTINELIST;
96
 
 
97
 
/* shared prototypes */
98
 
void   tech_initmaxdrcsurround(void);
99
 
 
100
 
/* prototypes for local routines */
101
 
static INTBIG tech_getdrcmindistance(TECHNOLOGY*, INTBIG, INTBIG, BOOLEAN, INTBIG, BOOLEAN, INTBIG*, char **);
102
 
static void   tech_3ddefaultlayerheight(TECHNOLOGY *tech);
103
 
static void   tech_nodeprotosizeoffset(NODEPROTO *np, INTBIG *lx, INTBIG *ly, INTBIG *hx, INTBIG *hy,
104
 
                                INTBIG lambda);
105
 
static INTBIG tech_arcprotowidthoffset(ARCPROTO *ap, INTBIG lambda);
106
 
static void   tech_initnodesizeoffset(void);
107
 
static void   tech_initlayerfunction(void);
108
 
static void   tech_initlayername(void);
109
 
static void   tech_initarcwidthoffset(void);
110
 
 
111
 
/*
112
 
 * Routine to free all memory associated with this module.
113
 
 */
114
 
void db_freetechnologymemory(void)
115
 
{
116
 
        REGISTER ROUTINELIST *rl;
117
 
 
118
 
        while (tech_firstcache != NOROUTINELIST)
119
 
        {
120
 
                rl = tech_firstcache;
121
 
                if (rl->count > 0) efree((char *)rl->variablekeys);
122
 
                tech_firstcache = tech_firstcache->nextroutinelist;
123
 
                efree((char *)rl);
124
 
        }
125
 
        if (tech_equivtable != 0) efree((char *)tech_equivtable);
126
 
        if (db_convertpseudoarray != 0) efree((char *)db_convertpseudoarray);
127
 
 
128
 
        if (tech_node_widoff != 0) efree((char *)tech_node_widoff);
129
 
        if (tech_layer_function != 0) efree((char *)tech_layer_function);
130
 
        if (tech_layer_names != 0) efree((char *)tech_layer_names);
131
 
        if (tech_arc_widoff != 0) efree((char *)tech_arc_widoff);
132
 
        if (tech_drcmaxdistances != 0) efree((char *)tech_drcmaxdistances);
133
 
        if (tech_drcwidelimit != 0) efree((char *)tech_drcwidelimit);
134
 
        if (tech_drcminwidth != 0) efree((char *)tech_drcminwidth);
135
 
        if (tech_drcminnodesize != 0) efree((char *)tech_drcminnodesize);
136
 
        if (tech_drcminwidthrule != 0) efree((char *)tech_drcminwidthrule);
137
 
        if (tech_drcminnodesizerule != 0) efree((char *)tech_drcminnodesizerule);
138
 
        if (tech_drcconndistance != 0) efree((char *)tech_drcconndistance);
139
 
        if (tech_drcuncondistance != 0) efree((char *)tech_drcuncondistance);
140
 
        if (tech_drcconndistancew != 0) efree((char *)tech_drcconndistancew);
141
 
        if (tech_drcuncondistancew != 0) efree((char *)tech_drcuncondistancew);
142
 
        if (tech_drcconndistancem != 0) efree((char *)tech_drcconndistancem);
143
 
        if (tech_drcuncondistancem != 0) efree((char *)tech_drcuncondistancem);
144
 
        if (tech_drcedgedistance != 0) efree((char *)tech_drcedgedistance);
145
 
        if (tech_drccondistancerule != 0) efree((char *)tech_drccondistancerule);
146
 
        if (tech_drcuncondistancerule != 0) efree((char *)tech_drcuncondistancerule);
147
 
        if (tech_drccondistancewrule != 0) efree((char *)tech_drccondistancewrule);
148
 
        if (tech_drcuncondistancewrule != 0) efree((char *)tech_drcuncondistancewrule);
149
 
        if (tech_drccondistancemrule != 0) efree((char *)tech_drccondistancemrule);
150
 
        if (tech_drcuncondistancemrule != 0) efree((char *)tech_drcuncondistancemrule);
151
 
        if (tech_drcedgedistancerule != 0) efree((char *)tech_drcedgedistancerule);
152
 
}
153
 
 
154
 
/******************** TECHNOLOGY ALLOCATION ********************/
155
 
 
156
 
/*
157
 
 * routine to allocate a technology from memory cluster "cluster" and return its
158
 
 * address.  The routine returns NOTECHNOLOGY if allocation fails.
159
 
 */
160
 
TECHNOLOGY *alloctechnology(CLUSTER *cluster)
161
 
{
162
 
        REGISTER TECHNOLOGY *tech;
163
 
 
164
 
        tech = (TECHNOLOGY *)emalloc((sizeof (TECHNOLOGY)), cluster);
165
 
        if (tech == 0) return((TECHNOLOGY *)db_error(DBNOMEM|DBALLOCTECHNOLOGY));
166
 
        tech->techname = NOSTRING;
167
 
        tech->techindex = 0;
168
 
        tech->deflambda = 2000;
169
 
        tech->firstnodeproto = NONODEPROTO;
170
 
        tech->firstarcproto = NOARCPROTO;
171
 
        tech->firstvar = NOVARIABLE;
172
 
        tech->numvar = 0;
173
 
        tech->parse = NOCOMCOMP;
174
 
        tech->cluster = cluster;
175
 
        tech->techdescript = NOSTRING;
176
 
        tech->init = 0;
177
 
        tech->term = 0;
178
 
        tech->setmode = 0;
179
 
        tech->request = 0;
180
 
        tech->nodepolys = 0;
181
 
        tech->nodeEpolys = 0;
182
 
        tech->shapenodepoly = 0;
183
 
        tech->shapeEnodepoly = 0;
184
 
        tech->nodesizeoffset = 0;
185
 
        tech->shapeportpoly = 0;
186
 
        tech->arcpolys = 0;
187
 
        tech->shapearcpoly = 0;
188
 
        tech->arcwidthoffset = 0;
189
 
        tech->nexttechnology = NOTECHNOLOGY;
190
 
        tech->userbits = tech->temp1 = tech->temp2 = 0;
191
 
        tech->variables = (TECH_VARIABLES *)-1;
192
 
        tech->layercount = 0;
193
 
        tech->layers = NULL;
194
 
        tech->arcprotocount = 0;
195
 
        tech->arcprotos = NULL;
196
 
        tech->nodeprotocount = 0;
197
 
        tech->nodeprotos = NULL;
198
 
        return(tech);
199
 
}
200
 
 
201
 
/*
202
 
 * routine to return technology "tech" to the pool of free technologies
203
 
 */
204
 
void freetechnology(TECHNOLOGY *tech)
205
 
{
206
 
        REGISTER CLUSTER *clus;
207
 
        REGISTER INTBIG i, j;
208
 
        REGISTER NODEPROTO *np, *nextnp;
209
 
        REGISTER PORTPROTO *pp, *nextpp;
210
 
        REGISTER ARCPROTO *ap, *nextap;
211
 
        REGISTER TECH_NODES *tn;
212
 
 
213
 
        if (tech == NOTECHNOLOGY) return;
214
 
        for(np = tech->firstnodeproto; np != NONODEPROTO; np = nextnp)
215
 
        {
216
 
                nextnp = np->nextnodeproto;
217
 
                for(pp = np->firstportproto; pp != NOPORTPROTO; pp = nextpp)
218
 
                {
219
 
                        nextpp = pp->nextportproto;
220
 
                        efree((char *)pp->protoname);
221
 
                        freeportproto(pp);
222
 
                }
223
 
                efree((char *)np->primname);
224
 
                freenodeproto(np);
225
 
        }
226
 
        for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = nextap)
227
 
        {
228
 
                nextap = ap->nextarcproto;
229
 
                efree((char *)ap->protoname);
230
 
                db_freearcproto(ap);
231
 
        }
232
 
        if (tech->numvar != 0) db_freevars(&tech->firstvar, &tech->numvar);
233
 
        efree((char *)tech->techname);
234
 
        efree((char *)tech->techdescript);
235
 
        if ((tech->userbits&STATICTECHNOLOGY) == 0)
236
 
        {
237
 
                for(i=0; i<tech->layercount; i++)
238
 
                        efree((char *)tech->layers[i]);
239
 
                efree((char *)tech->layers);
240
 
                for(i=0; i<tech->arcprotocount; i++)
241
 
                {
242
 
                        efree((char *)tech->arcprotos[i]->arcname);
243
 
                        efree((char *)tech->arcprotos[i]->list);
244
 
                        efree((char *)tech->arcprotos[i]);
245
 
                }
246
 
                efree((char *)tech->arcprotos);
247
 
                for(i=0; i<tech->nodeprotocount; i++)
248
 
                {
249
 
                        tn = tech->nodeprotos[i];
250
 
                        efree((char *)tn->nodename);
251
 
                        for(j=0; j<tn->portcount; j++)
252
 
                                efree((char *)tn->portlist[j].protoname);
253
 
                        efree((char *)tn->portlist);
254
 
                        if (tn->special != SERPTRANS)
255
 
                                efree((char *)tn->layerlist); else
256
 
                        {
257
 
                                efree((char *)tn->gra);
258
 
                                efree((char *)tn->ele);
259
 
                        }
260
 
                        efree((char *)tn);
261
 
                }
262
 
                efree((char *)tech->nodeprotos);
263
 
        }
264
 
        clus = tech->cluster;
265
 
        efree((char *)tech);
266
 
        freecluster(clus);
267
 
}
268
 
 
269
 
/*
270
 
 * routine to insert technology "tech" into the global linked list and to
271
 
 * announce this change to all cached routines.
272
 
 */
273
 
void addtechnology(TECHNOLOGY *tech)
274
 
{
275
 
        REGISTER TECHNOLOGY *t, *lastt;
276
 
        REGISTER ROUTINELIST *rl;
277
 
        REGISTER INTBIG *newlam;
278
 
        REGISTER INTBIG i;
279
 
        REGISTER LIBRARY *lib;
280
 
 
281
 
        /* link it at the end of the list */
282
 
        for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology) lastt = t;
283
 
        lastt->nexttechnology = tech;
284
 
        tech->nexttechnology = NOTECHNOLOGY;
285
 
 
286
 
        /* recount the number of technologies and renumber them */
287
 
        el_maxtech = 0;
288
 
        for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
289
 
                t->techindex = el_maxtech++;
290
 
 
291
 
        /* adjust the "lambda" array in all libraries */
292
 
        for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
293
 
        {
294
 
                newlam = emalloc(((el_maxtech+1) * SIZEOFINTBIG), db_cluster);
295
 
                if (newlam == 0)
296
 
                {
297
 
                        (void)db_error(DBNOMEM|DBADDTECHNOLOGY);
298
 
                        return;
299
 
                }
300
 
                for(i=0; i<el_maxtech-1; i++) newlam[i] = lib->lambda[i];
301
 
                newlam[el_maxtech-1] = tech->deflambda;
302
 
                newlam[el_maxtech] = -1;
303
 
                efree((char *)lib->lambda);
304
 
                lib->lambda = newlam;
305
 
        }
306
 
 
307
 
        /* announce the change to the number of technologies */
308
 
        for(rl = tech_firstcache; rl != NOROUTINELIST; rl = rl->nextroutinelist)
309
 
                (*rl->routine)();
310
 
}
311
 
 
312
 
/*
313
 
 * routine to delete technology "tech" from the global list.  Returns
314
 
 * true on error.
315
 
 */
316
 
BOOLEAN killtechnology(TECHNOLOGY *tech)
317
 
{
318
 
        REGISTER TECHNOLOGY *t, *lastt;
319
 
        REGISTER ROUTINELIST *rl;
320
 
        REGISTER LIBRARY *lib;
321
 
        REGISTER INTBIG *newlam;
322
 
        REGISTER INTBIG i, j;
323
 
        REGISTER NODEPROTO *np;
324
 
        REGISTER NODEINST *ni;
325
 
        REGISTER ARCINST *ai;
326
 
 
327
 
        /* cannot kill the generic technology */
328
 
        if (tech == gen_tech)
329
 
        {
330
 
                (void)db_error(DBLASTECH|DBKILLTECHNOLOGY);
331
 
                return(TRUE);
332
 
        }
333
 
 
334
 
        /* make sure there are no objects from this technology */
335
 
        for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
336
 
        {
337
 
                for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
338
 
                {
339
 
                        for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
340
 
                                if (ni->proto->primindex != 0 && ni->proto->tech == tech) break;
341
 
                        if (ni != NONODEINST) break;
342
 
                        for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
343
 
                                if (ai->proto->tech == tech) break;
344
 
                        if (ai != NOARCINST) break;
345
 
                }
346
 
                if (np != NONODEPROTO)
347
 
                {
348
 
                        (void)db_error(DBTECINUSE|DBKILLTECHNOLOGY);
349
 
                        return(TRUE);
350
 
                }
351
 
        }
352
 
 
353
 
        /* adjust the "lambda" array in all libraries */
354
 
        for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
355
 
        {
356
 
                newlam = emalloc((el_maxtech * SIZEOFINTBIG), db_cluster);
357
 
                if (newlam == 0)
358
 
                {
359
 
                        (void)db_error(DBNOMEM|DBKILLTECHNOLOGY);
360
 
                        return(TRUE);
361
 
                }
362
 
                for(i = j = 0, t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology, j++)
363
 
                {
364
 
                        if (t == tech) continue;
365
 
                        newlam[i++] = lib->lambda[j];
366
 
                }
367
 
                newlam[i] = -1;
368
 
                efree((char *)lib->lambda);
369
 
                lib->lambda = newlam;
370
 
        }
371
 
 
372
 
        /* remove "tech" from linked list */
373
 
        lastt = NOTECHNOLOGY;
374
 
        for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
375
 
        {
376
 
                if (t == tech) break;
377
 
                lastt = t;
378
 
        }
379
 
        if (lastt == NOTECHNOLOGY) el_technologies = tech->nexttechnology; else
380
 
                lastt->nexttechnology = tech->nexttechnology;
381
 
 
382
 
        /* deallocate the technology */
383
 
        if (tech->numvar != 0) db_freevars(&tech->firstvar, &tech->numvar);
384
 
        freetechnology(tech);
385
 
 
386
 
        /* recount the number of technologies and renumber them */
387
 
        el_maxtech = 0;
388
 
        for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
389
 
                t->techindex = el_maxtech++;
390
 
 
391
 
        /* announce the change to the number of technologies */
392
 
        for(rl = tech_firstcache; rl != NOROUTINELIST; rl = rl->nextroutinelist)
393
 
                (*rl->routine)();
394
 
        return(0);
395
 
}
396
 
 
397
 
void telltech(TECHNOLOGY *tech, INTBIG count, char *par[])
398
 
{
399
 
        if (tech->setmode == 0) return;
400
 
        (*tech->setmode)(count, par);
401
 
}
402
 
 
403
 
INTBIG asktech(TECHNOLOGY *tech, char *command, ...)
404
 
{
405
 
        va_list ap;
406
 
        INTBIG result;
407
 
 
408
 
        if (tech->request == 0) return(0);
409
 
        var_start(ap, command);
410
 
        result = (*tech->request)(command, ap);
411
 
        va_end(ap);
412
 
        return(result);
413
 
}
414
 
 
415
 
/******************** VARIABLE CACHING ********************/
416
 
 
417
 
/* this should be called whenever "DRC_min_unconnected_distances" changes!!! */
418
 
 
419
 
/*
420
 
 * routine to initialize the database variables "DRC_max_distances",
421
 
 * "DRC_min_unconnected_distances", "DRC_min_connected_distances", and "DRC_min_width".
422
 
 * This is called once at initialization and again whenever the arrays are changed.
423
 
 */
424
 
void tech_initmaxdrcsurround(void)
425
 
{
426
 
        REGISTER VARIABLE *var;
427
 
        REGISTER TECHNOLOGY *t;
428
 
        REGISTER INTBIG j, total, l, *dist, m;
429
 
        INTBIG edge;
430
 
 
431
 
        if (tech_drcmaxdistances != 0) efree((char *)tech_drcmaxdistances);
432
 
        if (tech_drcwidelimit != 0) efree((char *)tech_drcwidelimit);
433
 
        if (tech_drcminwidth != 0) efree((char *)tech_drcminwidth);
434
 
        if (tech_drcminnodesize != 0) efree((char *)tech_drcminnodesize);
435
 
        if (tech_drcminwidthrule != 0) efree((char *)tech_drcminwidthrule);
436
 
        if (tech_drcminnodesizerule != 0) efree((char *)tech_drcminnodesizerule);
437
 
        if (tech_drcconndistance != 0) efree((char *)tech_drcconndistance);
438
 
        if (tech_drcuncondistance != 0) efree((char *)tech_drcuncondistance);
439
 
        if (tech_drcconndistancew != 0) efree((char *)tech_drcconndistancew);
440
 
        if (tech_drcuncondistancew != 0) efree((char *)tech_drcuncondistancew);
441
 
        if (tech_drcconndistancem != 0) efree((char *)tech_drcconndistancem);
442
 
        if (tech_drcuncondistancem != 0) efree((char *)tech_drcuncondistancem);
443
 
        if (tech_drcedgedistance != 0) efree((char *)tech_drcedgedistance);
444
 
        if (tech_drccondistancerule != 0) efree((char *)tech_drccondistancerule);
445
 
        if (tech_drcuncondistancerule != 0) efree((char *)tech_drcuncondistancerule);
446
 
        if (tech_drccondistancewrule != 0) efree((char *)tech_drccondistancewrule);
447
 
        if (tech_drcuncondistancewrule != 0) efree((char *)tech_drcuncondistancewrule);
448
 
        if (tech_drccondistancemrule != 0) efree((char *)tech_drccondistancemrule);
449
 
        if (tech_drcuncondistancemrule != 0) efree((char *)tech_drcuncondistancemrule);
450
 
        if (tech_drcedgedistancerule != 0) efree((char *)tech_drcedgedistancerule);
451
 
 
452
 
        tech_drcmaxdistances = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
453
 
        if (tech_drcmaxdistances == 0) return;
454
 
        tech_drcwidelimit = (INTBIG *)emalloc((el_maxtech * SIZEOFINTBIG), db_cluster);
455
 
        if (tech_drcwidelimit == 0) return;
456
 
        tech_drcminwidth = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
457
 
        if (tech_drcminwidth == 0) return;
458
 
        tech_drcminnodesize = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
459
 
        if (tech_drcminnodesize == 0) return;
460
 
        tech_drcminwidthrule = (char ***)emalloc((el_maxtech * (sizeof (char **))), db_cluster);
461
 
        if (tech_drcminwidthrule == 0) return;
462
 
        tech_drcminnodesizerule = (char ***)emalloc((el_maxtech * (sizeof (char **))), db_cluster);
463
 
        if (tech_drcminnodesizerule == 0) return;
464
 
        tech_drcconndistance = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
465
 
        if (tech_drcconndistance == 0) return;
466
 
        tech_drcuncondistance = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
467
 
        if (tech_drcuncondistance == 0) return;
468
 
        tech_drcconndistancew = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
469
 
        if (tech_drcconndistancew == 0) return;
470
 
        tech_drcuncondistancew = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
471
 
        if (tech_drcuncondistancew == 0) return;
472
 
        tech_drcconndistancem = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
473
 
        if (tech_drcconndistancem == 0) return;
474
 
        tech_drcuncondistancem = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
475
 
        if (tech_drcuncondistancem == 0) return;
476
 
        tech_drcedgedistance = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
477
 
        if (tech_drcedgedistance == 0) return;
478
 
        tech_drccondistancerule = (char ***)emalloc((el_maxtech * (sizeof (char **))), db_cluster);
479
 
        if (tech_drccondistancerule == 0) return;
480
 
        tech_drcuncondistancerule = (char ***)emalloc((el_maxtech * (sizeof (char **))), db_cluster);
481
 
        if (tech_drcuncondistancerule == 0) return;
482
 
        tech_drccondistancewrule = (char ***)emalloc((el_maxtech * (sizeof (char **))), db_cluster);
483
 
        if (tech_drccondistancewrule == 0) return;
484
 
        tech_drcuncondistancewrule = (char ***)emalloc((el_maxtech * (sizeof (char **))), db_cluster);
485
 
        if (tech_drcuncondistancewrule == 0) return;
486
 
        tech_drccondistancemrule = (char ***)emalloc((el_maxtech * (sizeof (char **))), db_cluster);
487
 
        if (tech_drccondistancemrule == 0) return;
488
 
        tech_drcuncondistancemrule = (char ***)emalloc((el_maxtech * (sizeof (char **))), db_cluster);
489
 
        if (tech_drcuncondistancemrule == 0) return;
490
 
        tech_drcedgedistancerule = (char ***)emalloc((el_maxtech * (sizeof (char **))), db_cluster);
491
 
        if (tech_drcedgedistancerule == 0) return;
492
 
 
493
 
        for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
494
 
        {
495
 
                tech_drcmaxdistances[t->techindex] = 0;
496
 
                tech_drcwidelimit[t->techindex] = -1;
497
 
                tech_drcminwidth[t->techindex] = 0;
498
 
                tech_drcminnodesize[t->techindex] = 0;
499
 
                tech_drcminwidthrule[t->techindex] = 0;
500
 
                tech_drcminnodesizerule[t->techindex] = 0;
501
 
                tech_drcconndistance[t->techindex] = 0;
502
 
                tech_drcuncondistance[t->techindex] = 0;
503
 
                tech_drcconndistancew[t->techindex] = 0;
504
 
                tech_drcuncondistancew[t->techindex] = 0;
505
 
                tech_drcconndistancem[t->techindex] = 0;
506
 
                tech_drcuncondistancem[t->techindex] = 0;
507
 
                tech_drcedgedistance[t->techindex] = 0;
508
 
                tech_drccondistancerule[t->techindex] = 0;
509
 
                tech_drcuncondistancerule[t->techindex] = 0;
510
 
                tech_drccondistancewrule[t->techindex] = 0;
511
 
                tech_drcuncondistancewrule[t->techindex] = 0;
512
 
                tech_drccondistancemrule[t->techindex] = 0;
513
 
                tech_drcuncondistancemrule[t->techindex] = 0;
514
 
                tech_drcedgedistancerule[t->techindex] = 0;
515
 
 
516
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT, dr_wide_limitkey);
517
 
                if (var != NOVARIABLE) tech_drcwidelimit[t->techindex] = var->addr;
518
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT|VISARRAY, dr_min_widthkey);
519
 
                if (var != NOVARIABLE) tech_drcminwidth[t->techindex] = (INTBIG *)var->addr;
520
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT|VISARRAY, dr_min_node_sizekey);
521
 
                if (var != NOVARIABLE) tech_drcminnodesize[t->techindex] = (INTBIG *)var->addr;
522
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VSTRING|VISARRAY, dr_min_width_rulekey);
523
 
                if (var != NOVARIABLE) tech_drcminwidthrule[t->techindex] = (char **)var->addr;
524
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VSTRING|VISARRAY, dr_min_node_size_rulekey);
525
 
                if (var != NOVARIABLE) tech_drcminnodesizerule[t->techindex] = (char **)var->addr;
526
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT|VISARRAY, dr_connected_distanceskey);
527
 
                if (var != NOVARIABLE) tech_drcconndistance[t->techindex] = (INTBIG *)var->addr;
528
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT|VISARRAY, dr_unconnected_distanceskey);
529
 
                if (var != NOVARIABLE) tech_drcuncondistance[t->techindex] = (INTBIG *)var->addr;
530
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT|VISARRAY, dr_connected_distancesWkey);
531
 
                if (var != NOVARIABLE) tech_drcconndistancew[t->techindex] = (INTBIG *)var->addr;
532
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT|VISARRAY, dr_unconnected_distancesWkey);
533
 
                if (var != NOVARIABLE) tech_drcuncondistancew[t->techindex] = (INTBIG *)var->addr;
534
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT|VISARRAY, dr_connected_distancesMkey);
535
 
                if (var != NOVARIABLE) tech_drcconndistancem[t->techindex] = (INTBIG *)var->addr;
536
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT|VISARRAY, dr_unconnected_distancesMkey);
537
 
                if (var != NOVARIABLE) tech_drcuncondistancem[t->techindex] = (INTBIG *)var->addr;
538
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT|VISARRAY, dr_edge_distanceskey);
539
 
                if (var != NOVARIABLE) tech_drcedgedistance[t->techindex] = (INTBIG *)var->addr;
540
 
 
541
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VSTRING|VISARRAY, dr_connected_distances_rulekey);
542
 
                if (var != NOVARIABLE) tech_drccondistancerule[t->techindex] = (char **)var->addr;
543
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VSTRING|VISARRAY, dr_unconnected_distances_rulekey);
544
 
                if (var != NOVARIABLE) tech_drcuncondistancerule[t->techindex] = (char **)var->addr;
545
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VSTRING|VISARRAY, dr_connected_distancesW_rulekey);
546
 
                if (var != NOVARIABLE) tech_drccondistancewrule[t->techindex] = (char **)var->addr;
547
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VSTRING|VISARRAY, dr_unconnected_distancesW_rulekey);
548
 
                if (var != NOVARIABLE) tech_drcuncondistancewrule[t->techindex] = (char **)var->addr;
549
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VSTRING|VISARRAY, dr_connected_distancesM_rulekey);
550
 
                if (var != NOVARIABLE) tech_drccondistancemrule[t->techindex] = (char **)var->addr;
551
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VSTRING|VISARRAY, dr_unconnected_distancesM_rulekey);
552
 
                if (var != NOVARIABLE) tech_drcuncondistancemrule[t->techindex] = (char **)var->addr;
553
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VSTRING|VISARRAY, dr_edge_distances_rulekey);
554
 
                if (var != NOVARIABLE) tech_drcedgedistancerule[t->techindex] = (char **)var->addr;
555
 
 
556
 
                /* compute max distances if there are any there */
557
 
                if (tech_drcuncondistance[t->techindex] == 0) continue;
558
 
                total = t->layercount;
559
 
                dist = emalloc((total * SIZEOFINTBIG), el_tempcluster);
560
 
                if (dist == 0) continue;
561
 
                for(l=0; l<total; l++)
562
 
                {
563
 
                        m = XX;
564
 
                        for(j=0; j<total; j++)
565
 
                                m = maxi(m, tech_getdrcmindistance(t, l, j, FALSE, 1, FALSE, &edge, 0));
566
 
                        dist[l] = m;
567
 
                }
568
 
                nextchangequiet();
569
 
                if (setvalkey((INTBIG)t, VTECHNOLOGY, dr_max_distanceskey, (INTBIG)dist,
570
 
                        VFRACT|VDONTSAVE|VISARRAY|(total<<VLENGTHSH)) != NOVARIABLE)
571
 
                {
572
 
                        var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT|VISARRAY, dr_max_distanceskey);
573
 
                        if (var != NOVARIABLE) tech_drcmaxdistances[t->techindex] = (INTBIG *)var->addr;
574
 
                }
575
 
                efree((char *)dist);
576
 
        }
577
 
}
578
 
 
579
 
/*
580
 
 * routine to initialize the database variable "TECH_node_width_offset".  This
581
 
 * is called once at initialization and again whenever the array is changed.
582
 
 */
583
 
void tech_initnodesizeoffset(void)
584
 
{
585
 
        REGISTER VARIABLE *var;
586
 
        REGISTER TECHNOLOGY *tech;
587
 
 
588
 
        /* free the old cache list if it exists */
589
 
        if (tech_node_widoff != 0) efree((char *)tech_node_widoff);
590
 
 
591
 
        /* allocate a new cache list */
592
 
        tech_node_widoff = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
593
 
        if (tech_node_widoff == 0) return;
594
 
 
595
 
        /* load the cache list */
596
 
        for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
597
 
        {
598
 
                var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT|VISARRAY, db_tech_node_width_offset_key);
599
 
                tech_node_widoff[tech->techindex] = (var == NOVARIABLE ? 0 : (INTBIG *)var->addr);
600
 
        }
601
 
}
602
 
 
603
 
/*
604
 
 * routine to initialize the database variable "TECH_layer_function".  This
605
 
 * is called once at initialization and again whenever the array is changed.
606
 
 */
607
 
void tech_initlayerfunction(void)
608
 
{
609
 
        REGISTER VARIABLE *var;
610
 
        REGISTER TECHNOLOGY *t;
611
 
 
612
 
        if (tech_layer_function != 0) efree((char *)tech_layer_function);
613
 
 
614
 
        tech_layer_function = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
615
 
        if (tech_layer_function == 0) return;
616
 
 
617
 
        for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
618
 
        {
619
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VINTEGER|VISARRAY, db_tech_layer_function_key);
620
 
                tech_layer_function[t->techindex] = (var == NOVARIABLE ? 0 : (INTBIG *)var->addr);
621
 
        }
622
 
}
623
 
 
624
 
/*
625
 
 * routine to initialize the database variable "TECH_layer_names".  This
626
 
 * is called once at initialization and again whenever the array is changed.
627
 
 */
628
 
void tech_initlayername(void)
629
 
{
630
 
        REGISTER VARIABLE *var;
631
 
        REGISTER TECHNOLOGY *t;
632
 
 
633
 
        if (tech_layer_names != 0) efree((char *)tech_layer_names);
634
 
 
635
 
        tech_layer_names = (char ***)emalloc((el_maxtech * (sizeof (char **))), db_cluster);
636
 
        if (tech_layer_names == 0) return;
637
 
 
638
 
        for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
639
 
        {
640
 
                var = getvalkey((INTBIG)t, VTECHNOLOGY, VSTRING|VISARRAY, db_tech_layer_names_key);
641
 
                tech_layer_names[t->techindex] = (var == NOVARIABLE ? 0 : (char **)var->addr);
642
 
        }
643
 
}
644
 
 
645
 
/*
646
 
 * routine to initialize the database variable "TECH_arc_width_offset".  This
647
 
 * is called once at initialization and again whenever the array is changed.
648
 
 */
649
 
void tech_initarcwidthoffset(void)
650
 
{
651
 
        REGISTER VARIABLE *var;
652
 
        REGISTER TECHNOLOGY *tech;
653
 
 
654
 
        if (tech_arc_widoff != 0) efree((char *)tech_arc_widoff);
655
 
 
656
 
        tech_arc_widoff = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
657
 
        if (tech_arc_widoff == 0) return;
658
 
 
659
 
        for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
660
 
        {
661
 
                var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT|VISARRAY, db_tech_arc_width_offset_key);
662
 
                tech_arc_widoff[tech->techindex] = (var == NOVARIABLE ? 0 : (INTBIG *)var->addr);
663
 
        }
664
 
}
665
 
 
666
 
/*
667
 
 * routine to register function "proc" in a list that will be invoked
668
 
 * whenever the number of technologies changes.  Also the "count"
669
 
 * variable keys in "variablekeys" will be checked for updates, such that
670
 
 * whenever those keys are changed on any technology, the routine will
671
 
 * be invoked.
672
 
 */
673
 
void registertechnologycache(void (*proc)(void), INTBIG count, INTBIG *variablekeys)
674
 
{
675
 
        REGISTER ROUTINELIST *rl;
676
 
        REGISTER INTBIG i;
677
 
 
678
 
        /* allocate a ROUTINELIST object */
679
 
        rl = (ROUTINELIST *)emalloc(sizeof (ROUTINELIST), db_cluster);
680
 
        if (rl == 0) return;
681
 
 
682
 
        /* put this object at the start */
683
 
        rl->nextroutinelist = tech_firstcache;
684
 
        tech_firstcache = rl;
685
 
 
686
 
        /* insert the data and run the routine */
687
 
        rl->routine = proc;
688
 
        rl->count = count;
689
 
        if (count > 0)
690
 
        {
691
 
                rl->variablekeys = (INTBIG *)emalloc(count * SIZEOFINTBIG, db_cluster);
692
 
                for(i=0; i<count; i++) rl->variablekeys[i] = variablekeys[i];
693
 
        }
694
 
        (*proc)();
695
 
}
696
 
 
697
 
/*
698
 
 * routine called once at initialization to register the database
699
 
 * functions that cache technology-related variables
700
 
 */
701
 
void db_inittechcache(void)
702
 
{
703
 
        INTBIG keys[20];
704
 
 
705
 
        keys[0] = dr_wide_limitkey;
706
 
        keys[1] = dr_min_widthkey;
707
 
        keys[2] = dr_min_width_rulekey;
708
 
        keys[3] = dr_min_node_sizekey;
709
 
        keys[4] = dr_min_node_size_rulekey;
710
 
        keys[5] = dr_connected_distanceskey;
711
 
        keys[6] = dr_connected_distances_rulekey;
712
 
        keys[7] = dr_unconnected_distanceskey;
713
 
        keys[8] = dr_unconnected_distances_rulekey;
714
 
        keys[9] = dr_connected_distancesWkey;
715
 
        keys[10] = dr_connected_distancesW_rulekey;
716
 
        keys[11] = dr_unconnected_distancesWkey;
717
 
        keys[12] = dr_unconnected_distancesW_rulekey;
718
 
        keys[13] = dr_connected_distancesMkey;
719
 
        keys[14] = dr_connected_distancesM_rulekey;
720
 
        keys[15] = dr_unconnected_distancesMkey;
721
 
        keys[16] = dr_unconnected_distancesM_rulekey;
722
 
        keys[17] = dr_edge_distanceskey;
723
 
        keys[18] = dr_edge_distances_rulekey;
724
 
        keys[19] = dr_max_distanceskey;
725
 
 
726
 
        registertechnologycache(tech_initmaxdrcsurround, 20, keys);
727
 
 
728
 
        keys[0] = db_tech_node_width_offset_key;
729
 
        registertechnologycache(tech_initnodesizeoffset, 1, keys);
730
 
 
731
 
        keys[0] = db_tech_layer_function_key;
732
 
        registertechnologycache(tech_initlayerfunction, 1, keys);
733
 
 
734
 
        keys[0] = db_tech_layer_names_key;
735
 
        registertechnologycache(tech_initlayername, 1, keys);
736
 
 
737
 
        keys[0] = db_tech_arc_width_offset_key;
738
 
        registertechnologycache(tech_initarcwidthoffset, 1, keys);
739
 
}
740
 
 
741
 
/*
742
 
 * Routine called when key "keyval" on a technology changes.
743
 
 */
744
 
void changedtechnologyvariable(INTBIG keyval)
745
 
{
746
 
        REGISTER ROUTINELIST *rl;
747
 
        REGISTER INTBIG i;
748
 
 
749
 
        for(rl = tech_firstcache; rl != NOROUTINELIST; rl = rl->nextroutinelist)
750
 
        {
751
 
                for(i=0; i<rl->count; i++)
752
 
                {
753
 
                        if (rl->variablekeys[i] == keyval)
754
 
                        {
755
 
                                (*rl->routine)();
756
 
                                return;
757
 
                        }
758
 
                }
759
 
        }
760
 
}
761
 
 
762
 
/******************** NODEINST DESCRIPTION ********************/
763
 
 
764
 
/*
765
 
 * routine to report the number of distinct graphical polygons used to compose
766
 
 * primitive nodeinst "ni".  If "reasonable" is nonzero, it is loaded with
767
 
 * a smaller number of polygons (when multicut contacts grow too large, then
768
 
 * a reasonable number of polygons is returned instead of the true number).
769
 
 */
770
 
INTBIG nodepolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win)
771
 
{
772
 
        REGISTER INTBIG pindex, count, reasonablecount, cutcount, displayablepolys;
773
 
        INTBIG fewer;
774
 
        TECH_NODES *thistn;
775
 
        REGISTER NODEPROTO *np;
776
 
 
777
 
        np = ni->proto;
778
 
        tech_curwindowpart = win;
779
 
        pindex = np->primindex;
780
 
        if (pindex == 0)
781
 
        {
782
 
                if (reasonable != 0) *reasonable = 0;
783
 
                return(0);
784
 
        }
785
 
 
786
 
        /* if the technology has its own routine, use it */
787
 
        if (np->tech->nodepolys != 0)
788
 
        {
789
 
                count = (*(np->tech->nodepolys))(ni, reasonable, win);
790
 
                return(count);
791
 
        }
792
 
 
793
 
        thistn = np->tech->nodeprotos[pindex-1];
794
 
        reasonablecount = count = thistn->layercount;
795
 
        switch (thistn->special)
796
 
        {
797
 
                case MULTICUT:
798
 
                        cutcount = tech_moscutcount(ni, thistn->f1, thistn->f2, thistn->f3, thistn->f4, &fewer);
799
 
                        count += cutcount - 1;
800
 
                        reasonablecount += fewer - 1;
801
 
                        break;
802
 
                case SERPTRANS:
803
 
                        reasonablecount = count = tech_inittrans(count, ni);
804
 
                        break;
805
 
        }
806
 
 
807
 
        /* zero the count if this node is not to be displayed */
808
 
        if ((ni->userbits&WIPED) != 0) reasonablecount = count = 0; else
809
 
        {
810
 
                /* zero the count if this node erases when connected to 1 or 2 arcs */
811
 
                if ((np->userbits&WIPEON1OR2) != 0)
812
 
                {
813
 
                        if (tech_pinusecount(ni, win)) reasonablecount = count = 0;
814
 
                }
815
 
        }
816
 
 
817
 
        /* add in displayable variables */
818
 
        tech_realpolys = count;
819
 
        displayablepolys = tech_displayablenvars(ni, win);
820
 
        count += displayablepolys;
821
 
        reasonablecount += displayablepolys;
822
 
        if (reasonable != 0) *reasonable = reasonablecount;
823
 
        return(count);
824
 
}
825
 
 
826
 
/*
827
 
 * routine to report the number of distinct electrical polygons used to
828
 
 * compose primitive nodeinst "ni".  If "reasonable" is nonzero, it is loaded with
829
 
 * a smaller number of polygons (when multicut contacts grow too large, then
830
 
 * a reasonable number of polygons is returned instead of the true number).
831
 
 */
832
 
INTBIG nodeEpolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win)
833
 
{
834
 
        REGISTER INTBIG pindex, count, reasonablecount, cutcount;
835
 
        INTBIG fewer;
836
 
        REGISTER TECH_NODES *thistn;
837
 
 
838
 
        pindex = ni->proto->primindex;
839
 
        tech_curwindowpart = win;
840
 
        if (pindex == 0)
841
 
        {
842
 
                if (reasonable != 0) *reasonable = 0;
843
 
                return(0);
844
 
        }
845
 
 
846
 
        /* if the technology has its own routine, use it */
847
 
        if (ni->proto->tech->nodeEpolys != 0)
848
 
        {
849
 
                count = (*(ni->proto->tech->nodeEpolys))(ni, reasonable, win);
850
 
                return(count);
851
 
        }
852
 
 
853
 
        thistn = ni->proto->tech->nodeprotos[pindex-1];
854
 
        reasonablecount = count = thistn->layercount;
855
 
        switch (thistn->special)
856
 
        {
857
 
                case MULTICUT:
858
 
                        cutcount = tech_moscutcount(ni, thistn->f1, thistn->f2, thistn->f3, thistn->f4, &fewer);
859
 
                        count += cutcount - 1;
860
 
                        reasonablecount += fewer - 1;
861
 
                        break;
862
 
                case SERPTRANS:
863
 
                        reasonablecount = count = tech_inittrans(thistn->f1, ni);
864
 
                        break;
865
 
        }
866
 
        if (reasonable != 0) *reasonable = reasonablecount;
867
 
        return(count);
868
 
}
869
 
 
870
 
/*
871
 
 * routine to report the shape of graphical polygon "box" of primitive
872
 
 * nodeinst "ni".  The polygon is returned in "poly".
873
 
 */
874
 
void shapenodepoly(NODEINST *ni, INTBIG box, POLYGON *poly)
875
 
{
876
 
        TECH_POLYGON *lay;
877
 
        REGISTER TECH_PORTS *p;
878
 
        REGISTER INTBIG pindex, count;
879
 
        REGISTER NODEPROTO *np;
880
 
        REGISTER INTBIG lambda;
881
 
        REGISTER TECH_NODES *thistn;
882
 
 
883
 
        np = ni->proto;
884
 
        pindex = np->primindex;
885
 
        if (pindex == 0) return;
886
 
        poly->tech = np->tech;
887
 
 
888
 
        /* if the technology has its own routine, use it */
889
 
        if (np->tech->shapenodepoly != 0)
890
 
        {
891
 
                (*(np->tech->shapenodepoly))(ni, box, poly);
892
 
                return;
893
 
        }
894
 
 
895
 
        /* handle displayable variables */
896
 
        if (box >= tech_realpolys)
897
 
        {
898
 
                (void)tech_filldisplayablenvar(ni, poly, tech_curwindowpart, 0);
899
 
                return;
900
 
        }
901
 
 
902
 
        thistn = np->tech->nodeprotos[pindex-1];
903
 
        lambda = lambdaofnode(ni);
904
 
        switch (thistn->special)
905
 
        {
906
 
                case SERPTRANS:
907
 
                        if (box > 1 || (ni->userbits&NSHORT) == 0) p = (TECH_PORTS *)0; else
908
 
                                p = thistn->portlist;
909
 
                        tech_filltrans(poly, &lay, thistn->gra, ni, lambda, box, p);
910
 
                        break;
911
 
 
912
 
                case MULTICUT:
913
 
                        count = thistn->layercount - 1;
914
 
                        if (box >= count)
915
 
                        {
916
 
                                lay = &thistn->layerlist[count];
917
 
                                tech_moscutpoly(ni, box-count, lay->points);
918
 
                                tech_fillpoly(poly, lay, ni, lambda, FILLED);
919
 
                                break;
920
 
                        }
921
 
 
922
 
                default:
923
 
                        lay = &thistn->layerlist[box];
924
 
                        tech_fillpoly(poly, lay, ni, lambda, FILLED);
925
 
                        break;
926
 
        }
927
 
 
928
 
        poly->desc = np->tech->layers[poly->layer];
929
 
}
930
 
 
931
 
/*
932
 
 * routine to report the shape of electrical polygon "box" of primitive
933
 
 * nodeinst "ni".  The polygon is returned in "poly".
934
 
 */
935
 
void shapeEnodepoly(NODEINST *ni, INTBIG box, POLYGON *poly)
936
 
{
937
 
        TECH_POLYGON *lay;
938
 
        REGISTER INTBIG pindex, count;
939
 
        REGISTER NODEPROTO *np;
940
 
        REGISTER INTBIG lambda;
941
 
        REGISTER TECH_NODES *thistn;
942
 
 
943
 
        np = ni->proto;
944
 
        pindex = np->primindex;
945
 
        if (pindex == 0) return;
946
 
        poly->tech = np->tech;
947
 
 
948
 
        /* if the technology has its own routine, use it */
949
 
        if (np->tech->shapeEnodepoly != 0)
950
 
        {
951
 
                (*(np->tech->shapeEnodepoly))(ni, box, poly);
952
 
                return;
953
 
        }
954
 
 
955
 
        thistn = np->tech->nodeprotos[pindex-1];
956
 
        lambda = lambdaofnode(ni);
957
 
        switch (thistn->special)
958
 
        {
959
 
                case MOSTRANS:
960
 
                        lay = &((TECH_POLYGON *)thistn->ele)[box];
961
 
                        tech_fillpoly(poly, lay, ni, lambda, FILLED);
962
 
                        break;
963
 
 
964
 
                case SERPTRANS:
965
 
                        tech_filltrans(poly, &lay, thistn->ele, ni, lambda, box, (TECH_PORTS *)0);
966
 
                        break;
967
 
 
968
 
                case MULTICUT:
969
 
                        count = thistn->layercount - 1;
970
 
                        if (box >= count)
971
 
                        {
972
 
                                lay = &thistn->layerlist[count];
973
 
                                tech_moscutpoly(ni, box-count, lay->points);
974
 
                                tech_fillpoly(poly, lay, ni, lambda, FILLED);
975
 
                                break;
976
 
                        }
977
 
 
978
 
                default:
979
 
                        lay = &thistn->layerlist[box];
980
 
                        tech_fillpoly(poly, lay, ni, lambda, FILLED);
981
 
                        break;
982
 
        }
983
 
 
984
 
        /* handle port prototype association */
985
 
        if (lay->portnum < 0) poly->portproto = NOPORTPROTO; else
986
 
                poly->portproto = thistn->portlist[lay->portnum].addr;
987
 
 
988
 
        poly->desc = np->tech->layers[poly->layer];
989
 
}
990
 
 
991
 
/*
992
 
 * routine to report the acutal size offsets of nodeinst "ni".
993
 
 * This is not always obvious since the extent of a nodeinst is not
994
 
 * necessarily its size.  This routine accesses the "node_width_offset"
995
 
 * variable on the technology objects.
996
 
 */
997
 
void nodesizeoffset(NODEINST *ni, INTBIG *lx, INTBIG *ly, INTBIG *hx, INTBIG *hy)
998
 
{
999
 
        REGISTER NODEPROTO *np;
1000
 
 
1001
 
        np = ni->proto;
1002
 
        if (np->primindex == 0) { *lx = *ly = *hx = *hy = 0;   return; }
1003
 
 
1004
 
        /* if the technology has its own routine, use it */
1005
 
        if (np->tech->nodesizeoffset != 0)
1006
 
        {
1007
 
                (*(np->tech->nodesizeoffset))(ni, lx, ly, hx, hy);
1008
 
                return;
1009
 
        }
1010
 
 
1011
 
        /* use value from prototype */
1012
 
        tech_nodeprotosizeoffset(ni->proto, lx, ly, hx, hy, lambdaofnode(ni));
1013
 
}
1014
 
 
1015
 
/*
1016
 
 * routine to report the acutal size offsets of node prototype "np".
1017
 
 * This is not always obvious since the extent of a nodeinst is not
1018
 
 * necessarily its size.  This routine accesses the "node_width_offset"
1019
 
 * variable on the technology objects.
1020
 
 */
1021
 
void nodeprotosizeoffset(NODEPROTO *np, INTBIG *lx, INTBIG *ly, INTBIG *hx, INTBIG *hy)
1022
 
{
1023
 
        tech_nodeprotosizeoffset(np, lx, ly, hx, hy, el_curlib->lambda[np->tech->techindex]);
1024
 
}
1025
 
 
1026
 
/*
1027
 
 * support routine for "nodesizeoffset" and "nodeprotosizeoffset" to report
1028
 
 * the acutal size offsets of a node prototype.
1029
 
 */
1030
 
void tech_nodeprotosizeoffset(NODEPROTO *np, INTBIG *lx, INTBIG *ly, INTBIG *hx, INTBIG *hy,
1031
 
        INTBIG lambda)
1032
 
{
1033
 
        REGISTER INTBIG *base, *addr;
1034
 
 
1035
 
        *lx = *ly = *hx = *hy = 0;
1036
 
        if (np->primindex == 0) return;
1037
 
 
1038
 
        /* make sure cache of information is valid */
1039
 
        if (tech_node_widoff == 0)
1040
 
        {
1041
 
                tech_initnodesizeoffset();
1042
 
                if (tech_node_widoff == 0) return;
1043
 
        }
1044
 
 
1045
 
        addr = tech_node_widoff[np->tech->techindex];
1046
 
        if (addr == 0) return;
1047
 
 
1048
 
        base = &addr[(np->primindex-1)*4];
1049
 
        *lx = *base++ * lambda/WHOLE;
1050
 
        *hx = *base++ * lambda/WHOLE;
1051
 
        *ly = *base++ * lambda/WHOLE;
1052
 
        *hy = *base * lambda/WHOLE;
1053
 
}
1054
 
 
1055
 
/*
1056
 
 * routine to return the function code for nodeinst "ni" (see "efunction.h").
1057
 
 */
1058
 
INTBIG nodefunction(NODEINST *ni)
1059
 
{
1060
 
        REGISTER INTBIG type;
1061
 
 
1062
 
        if (ni->proto->primindex == 0) return(NPUNKNOWN);
1063
 
        type = (ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH;
1064
 
        switch (type)
1065
 
        {
1066
 
                case NPCAPAC:           /* capacitor */
1067
 
                        switch (ni->userbits&NTECHBITS)
1068
 
                        {
1069
 
                                case CAPACNORM: type = NPCAPAC;    break;       /* Capacitor is normal */
1070
 
                                case CAPACELEC: type = NPECAPAC;   break;       /* Capacitor is Electrolytic */
1071
 
                        }
1072
 
                        break;
1073
 
 
1074
 
                case NPDIODE:           /* diode */
1075
 
                        switch (ni->userbits&NTECHBITS)
1076
 
                        {
1077
 
                                case DIODENORM:  type = NPDIODE;    break;      /* Diode is normal */
1078
 
                                case DIODEZENER: type = NPDIODEZ;   break;      /* Diode is Zener */
1079
 
                        }
1080
 
                        break;
1081
 
 
1082
 
                case NPTRANS:           /* undefined transistor: look at its transistor type */
1083
 
                        switch (ni->userbits&NTECHBITS)
1084
 
                        {
1085
 
                                case TRANNMOS:  type = NPTRANMOS;    break;     /* Transistor is N channel MOS */
1086
 
                                case TRANDMOS:  type = NPTRADMOS;    break;     /* Transistor is Depletion MOS */
1087
 
                                case TRANPMOS:  type = NPTRAPMOS;    break;     /* Transistor is P channel MOS */
1088
 
                                case TRANNPN:   type = NPTRANPN;     break;     /* Transistor is NPN Junction */
1089
 
                                case TRANPNP:   type = NPTRAPNP;     break;     /* Transistor is PNP Junction */
1090
 
                                case TRANNJFET: type = NPTRANJFET;   break;     /* Transistor is N Channel Junction FET */
1091
 
                                case TRANPJFET: type = NPTRAPJFET;   break;     /* Transistor is P Channel Junction FET */
1092
 
                                case TRANDMES:  type = NPTRADMES;    break;     /* Transistor is Depletion MESFET */
1093
 
                                case TRANEMES:  type = NPTRAEMES;    break;     /* Transistor is Enhancement MESFET */
1094
 
                        }
1095
 
                        break;
1096
 
 
1097
 
                case NPTRANS4:          /* undefined 4-port-transistor: look at its transistor type */
1098
 
                        switch (ni->userbits&NTECHBITS)
1099
 
                        {
1100
 
                                case TRANNMOS:  type = NPTRA4NMOS;   break;     /* Transistor is N channel MOS */
1101
 
                                case TRANDMOS:  type = NPTRA4DMOS;   break;     /* Transistor is Depletion MOS */
1102
 
                                case TRANPMOS:  type = NPTRA4PMOS;   break;     /* Transistor is P channel MOS */
1103
 
                                case TRANNPN:   type = NPTRA4NPN;    break;     /* Transistor is NPN Junction */
1104
 
                                case TRANPNP:   type = NPTRA4PNP;    break;     /* Transistor is PNP Junction */
1105
 
                                case TRANNJFET: type = NPTRA4NJFET;  break;     /* Transistor is N Channel Junction FET */
1106
 
                                case TRANPJFET: type = NPTRA4PJFET;  break;     /* Transistor is P Channel Junction FET */
1107
 
                                case TRANDMES:  type = NPTRA4DMES;   break;     /* Transistor is Depletion MESFET */
1108
 
                                case TRANEMES:  type = NPTRA4EMES;   break;     /* Transistor is Enhancement MESFET */
1109
 
                        }
1110
 
                        break;
1111
 
 
1112
 
                case NPTLINE:           /* two-port device: look for more information */
1113
 
                        switch (ni->userbits&NTECHBITS)
1114
 
                        {
1115
 
                                case TWOPVCCS:  type = NPVCCS;     break;       /* Two-port is Transconductance (VCCS) */
1116
 
                                case TWOPCCVS:  type = NPCCVS;     break;       /* Two-port is Transresistance (CCVS) */
1117
 
                                case TWOPVCVS:  type = NPVCVS;     break;       /* Two-port is Voltage gain (VCVS) */
1118
 
                                case TWOPCCCS:  type = NPCCCS;     break;       /* Two-port is Current gain (CCCS) */
1119
 
                                case TWOPTLINE: type = NPTLINE;    break;       /* Two-port is Transmission Line */
1120
 
                        }
1121
 
                        break;
1122
 
        }
1123
 
        return(type);
1124
 
}
1125
 
 
1126
 
/* these must match the "define"s in "efunction.h" */
1127
 
typedef struct
1128
 
{
1129
 
        char *nodefunname;              /* node function name */
1130
 
        char *shortfunname;             /* short node function name */
1131
 
        char *constantfunname;  /* actual code name */
1132
 
} NODEFUNCTION;
1133
 
 
1134
 
static NODEFUNCTION db_nodefunname[] =
1135
 
{
1136
 
        {N_("unknown"),                                         N_("node"),     "NPUNKNOWN"},   /* NPUNKNOWN */
1137
 
        {N_("pin"),                                                     N_("pin"),      "NPPIN"},               /* NPPIN */
1138
 
        {N_("contact"),                                         N_("contact"),  "NPCONTACT"},   /* NPCONTACT */
1139
 
        {N_("pure-layer-node"),                         N_("plnode"),   "NPNODE"},              /* NPNODE */
1140
 
        {N_("connection"),                                      N_("conn"),     "NPCONNECT"},   /* NPCONNECT */
1141
 
        {N_("nMOS-transistor"),                         N_("nmos"),     "NPCONNECT"},   /* NPCONNECT */
1142
 
        {N_("DMOS-transistor"),                         N_("dmos"),     "NPTRADMOS"},   /* NPTRADMOS */
1143
 
        {N_("pMOS-transistor"),                         N_("pmos"),     "NPTRAPMOS"},   /* NPTRAPMOS */
1144
 
        {N_("NPN-transistor"),                          N_("npn"),      "NPTRANPN"},    /* NPTRANPN */
1145
 
        {N_("PNP-transistor"),                          N_("pnp"),      "NPTRAPNP"},    /* NPTRAPNP */
1146
 
        {N_("n-type-JFET-transistor"),          N_("njfet"),    "NPTRANJFET"},  /* NPTRANJFET */
1147
 
        {N_("p-type-JFET-transistor"),          N_("pjfet"),    "NPTRAPJFET"},  /* NPTRAPJFET */
1148
 
        {N_("depletion-mesfet"),                        N_("dmes"),     "NPTRADMES"},   /* NPTRADMES */
1149
 
        {N_("enhancement-mesfet"),                      N_("emes"),     "NPTRAEMES"},   /* NPTRAEMES */
1150
 
        {N_("prototype-defined-transistor"),N_("tref"),     "NPTRANSREF"},      /* NPTRANSREF */
1151
 
        {N_("transistor"),                                      N_("trans"),    "NPTRANS"},             /* NPTRANS */
1152
 
        {N_("4-port-nMOS-transistor"),          N_("nmos4p"),   "NPTRA4NMOS"},  /* NPTRA4NMOS */
1153
 
        {N_("4-port-DMOS-transistor"),          N_("dmos4p"),   "NPTRA4DMOS"},  /* NPTRA4DMOS */
1154
 
        {N_("4-port-pMOS-transistor"),          N_("pmos4p"),   "NPTRA4PMOS"},  /* NPTRA4PMOS */
1155
 
        {N_("4-port-NPN-transistor"),           N_("npn4p"),    "NPTRA4NPN"},   /* NPTRA4NPN */
1156
 
        {N_("4-port-PNP-transistor"),           N_("pnp4p"),    "NPTRA4PNP"},   /* NPTRA4PNP */
1157
 
        {N_("4-port-n-type-JFET-transistor"),N_("njfet4p"), "NPTRA4NJFET"},     /* NPTRA4NJFET */
1158
 
        {N_("4-port-p-type-JFET-transistor"),N_("pjfet4p"), "NPTRA4PJFET"},     /* NPTRA4PJFET */
1159
 
        {N_("4-port-depletion-mesfet"),         N_("dmes4p"),   "NPTRA4DMES"},  /* NPTRA4DMES */
1160
 
        {N_("4-port-enhancement-mesfet"),       N_("emes4p"),   "NPTRA4EMES"},  /* NPTRA4EMES */
1161
 
        {N_("4-port-transistor"),                       N_("trans4p"),  "NPTRANS4"},    /* NPTRANS4 */
1162
 
        {N_("resistor"),                                        N_("res"),      "NPRESIST"},    /* NPRESIST */
1163
 
        {N_("capacitor"),                                       N_("cap"),      "NPCAPAC"},             /* NPCAPAC */
1164
 
        {N_("electrolytic-capacitor"),          N_("ecap"),     "NPECAPAC"},    /* NPECAPAC */
1165
 
        {N_("diode"),                                           N_("diode"),    "NPDIODE"},             /* NPDIODE */
1166
 
        {N_("zener-diode"),                                     N_("zdiode"),   "NPDIODEZ"},    /* NPDIODEZ */
1167
 
        {N_("inductor"),                                        N_("ind"),      "NPINDUCT"},    /* NPINDUCT */
1168
 
        {N_("meter"),                                           N_("meter"),    "NPMETER"},             /* NPMETER */
1169
 
        {N_("base"),                                            N_("base"),     "NPBASE"},              /* NPBASE */
1170
 
        {N_("emitter"),                                         N_("emit"),     "NPEMIT"},              /* NPEMIT */
1171
 
        {N_("collector"),                                       N_("coll"),     "NPCOLLECT"},   /* NPCOLLECT */
1172
 
        {N_("buffer"),                                          N_("buf"),      "NPBUFFER"},    /* NPBUFFER */
1173
 
        {N_("AND-gate"),                                        N_("and"),      "NPGATEAND"},   /* NPGATEAND */
1174
 
        {N_("OR-gate"),                                         N_("or"),       "NPGATEOR"},    /* NPGATEOR */
1175
 
        {N_("XOR-gate"),                                        N_("xor"),      "NPGATEXOR"},   /* NPGATEXOR */
1176
 
        {N_("flip-flop"),                                       N_("ff"),       "NPFLIPFLOP"},  /* NPFLIPFLOP */
1177
 
        {N_("multiplexor"),                                     N_("mux"),      "NPMUX"},               /* NPMUX */
1178
 
        {N_("power"),                                           N_("pwr"),      "NPCONPOWER"},  /* NPCONPOWER */
1179
 
        {N_("ground"),                                          N_("gnd"),      "NPCONGROUND"}, /* NPCONGROUND */
1180
 
        {N_("source"),                                          N_("source"),   "NPSOURCE"},    /* NPSOURCE */
1181
 
        {N_("substrate"),                                       N_("substr"),   "NPSUBSTRATE"}, /* NPSUBSTRATE */
1182
 
        {N_("well"),                                            N_("well"),     "NPWELL"},              /* NPWELL */
1183
 
        {N_("artwork"),                                         N_("art"),      "NPART"},               /* NPART */
1184
 
        {N_("array"),                                           N_("array"),    "NPARRAY"},             /* NPARRAY */
1185
 
        {N_("align"),                                           N_("align"),    "NPALIGN"},             /* NPALIGN */
1186
 
        {N_("ccvs"),                                            N_("ccvs"),     "NPCCVS"},              /* NPCCVS */
1187
 
        {N_("cccs"),                                            N_("cccs"),     "NPCCCS"},              /* NPCCCS */
1188
 
        {N_("vcvs"),                                            N_("vcvs"),     "NPVCVS"},              /* NPVCVS */
1189
 
        {N_("vccs"),                                            N_("vccs"),     "NPVCCS"},              /* NPVCCS */
1190
 
        {N_("transmission-line"),                       N_("transm"),   "NPTLINE"}              /* NPTLINE */
1191
 
};
1192
 
 
1193
 
/*
1194
 
 * routine to return the name of node "ni" with function "fun"
1195
 
 */
1196
 
char *nodefunctionname(INTBIG fun, NODEINST *ni)
1197
 
{
1198
 
        if (fun == NPTRANSREF && ni != NONODEINST)
1199
 
        {
1200
 
                (void)initinfstr();
1201
 
                (void)formatinfstr(_("Transistor-%s"), ni->proto->primname);
1202
 
                return(returninfstr());
1203
 
        }
1204
 
        if (fun < 0 || fun >= MAXNODEFUNCTION) return("");
1205
 
        return(_(db_nodefunname[fun].nodefunname));
1206
 
}
1207
 
 
1208
 
/*
1209
 
 * routine to return the short name of node function "fun"
1210
 
 */
1211
 
char *nodefunctionshortname(INTBIG fun)
1212
 
{
1213
 
        if (fun < 0 || fun >= MAXNODEFUNCTION) return("");
1214
 
        return(_(db_nodefunname[fun].shortfunname));
1215
 
}
1216
 
 
1217
 
/*
1218
 
 * routine to return the constant name of node function "fun"
1219
 
 */
1220
 
char *nodefunctionconstantname(INTBIG fun)
1221
 
{
1222
 
        if (fun < 0 || fun >= MAXNODEFUNCTION) return("");
1223
 
        return(db_nodefunname[fun].constantfunname);
1224
 
}
1225
 
 
1226
 
/*
1227
 
 * routine to tell whether geometry module "pos" points to a field-effect
1228
 
 * transtor.  Returns true if so.
1229
 
 */
1230
 
BOOLEAN isfet(GEOM *pos)
1231
 
{
1232
 
        REGISTER INTBIG fun;
1233
 
 
1234
 
        if (!pos->entryisnode) return(FALSE);
1235
 
        fun = nodefunction(pos->entryaddr.ni);
1236
 
        switch (fun)
1237
 
        {
1238
 
                case NPTRANMOS:   case NPTRA4NMOS:
1239
 
                case NPTRADMOS:   case NPTRA4DMOS:
1240
 
                case NPTRAPMOS:   case NPTRA4PMOS:
1241
 
                case NPTRADMES:   case NPTRA4DMES:
1242
 
                case NPTRAEMES:   case NPTRA4EMES:      
1243
 
                        return(TRUE);
1244
 
        }
1245
 
        return(FALSE);
1246
 
}
1247
 
 
1248
 
/*
1249
 
 * routine to determine the length and width of the primitive transistor
1250
 
 * node "ni" and return it in the reference integers "length" and "width".
1251
 
 * The value returned is in internal units.
1252
 
 * If the value cannot be determined, -1 is returned in the length and width.
1253
 
 * Mar. 1991 SRP: If the first character of *extra is not a digit or a
1254
 
 * sign, then do not call latoa.  This allows us to put a model name after
1255
 
 * the type string 'npn', etc. in SCHEM_transistortype that does not include
1256
 
 * any size data.
1257
 
 */
1258
 
void transistorsize(NODEINST *ni, INTBIG *length, INTBIG *width)
1259
 
{
1260
 
        INTBIG lx, ly, hx, hy;
1261
 
        REGISTER INTBIG count, i;
1262
 
        REGISTER INTBIG fx, fy, tx, ty, lambda;
1263
 
        char *pt;
1264
 
        REGISTER VARIABLE *var, *varl, *varw;
1265
 
 
1266
 
        *length = *width = -1;
1267
 
        switch ((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH)
1268
 
        {
1269
 
                case NPTRANMOS:   case NPTRA4NMOS:
1270
 
                case NPTRADMOS:   case NPTRA4DMOS:
1271
 
                case NPTRAPMOS:   case NPTRA4PMOS:
1272
 
                case NPTRANJFET:  case NPTRA4NJFET:
1273
 
                case NPTRAPJFET:  case NPTRA4PJFET:
1274
 
                case NPTRADMES:   case NPTRA4DMES:
1275
 
                case NPTRAEMES:   case NPTRA4EMES:
1276
 
                        var = gettrace(ni);
1277
 
                        if (var != NOVARIABLE)
1278
 
                        {
1279
 
                                /* serpentine transistor: compute path length */
1280
 
                                *width = 0;
1281
 
                                count = getlength(var) / 2;
1282
 
                                for(i=1; i<count; i++)
1283
 
                                {
1284
 
                                        fx = ((INTBIG *)var->addr)[i*2-2];
1285
 
                                        fy = ((INTBIG *)var->addr)[i*2-1];
1286
 
                                        tx = ((INTBIG *)var->addr)[i*2];
1287
 
                                        ty = ((INTBIG *)var->addr)[i*2+1];
1288
 
                                        *width += computedistance(fx,fy, tx,ty);
1289
 
                                }
1290
 
 
1291
 
                                var = getvalkey((INTBIG)ni, VNODEINST, VFRACT, el_transistor_width_key);
1292
 
                                if (var != NOVARIABLE) *length = var->addr * lambdaofnode(ni)/WHOLE; else
1293
 
                                {
1294
 
                                        nodesizeoffset(ni, &lx, &ly, &hx, &hy);
1295
 
                                        *length = ni->proto->highy-hy - (ni->proto->lowy+ly);
1296
 
                                }
1297
 
                        } else
1298
 
                        {
1299
 
                                /* normal transistor: subtract offset for active area */
1300
 
                                nodesizeoffset(ni, &lx, &ly, &hx, &hy);
1301
 
                                *length = ni->highy-hy - (ni->lowy+ly);
1302
 
                                *width = ni->highx-hx - (ni->lowx+lx);
1303
 
                        }
1304
 
                        break;
1305
 
 
1306
 
                case NPTRANS:
1307
 
                case NPTRANS4:
1308
 
                        lambda = lambdaofnode(ni);
1309
 
                        varl = getvalkey((INTBIG)ni, VNODEINST, -1, el_attrkey_length);
1310
 
                        varw = getvalkey((INTBIG)ni, VNODEINST, -1, el_attrkey_width);
1311
 
                        if (varl != NOVARIABLE || varw != NOVARIABLE)
1312
 
                        {
1313
 
                                if (varl != NOVARIABLE)
1314
 
                                {
1315
 
                                        pt = describevariable(varl, -1, -1);
1316
 
                                        if (*pt == '-' || *pt == '+' || isdigit(*pt))
1317
 
                                        {
1318
 
                                                *length = muldiv(atofr(pt), lambda, WHOLE);
1319
 
                                        }
1320
 
                                }
1321
 
                                if (varw != NOVARIABLE)
1322
 
                                {
1323
 
                                        pt = describevariable(varw, -1, -1);
1324
 
                                        if (*pt == '-' || *pt == '+' || isdigit(*pt))
1325
 
                                        {
1326
 
                                                *width = muldiv(atofr(pt), lambda, WHOLE);
1327
 
                                        }
1328
 
                                }
1329
 
                        } else
1330
 
                        {
1331
 
                                /* no length/width, look for area */
1332
 
                                var = getvalkey((INTBIG)ni, VNODEINST, -1, el_attrkey_area);
1333
 
                                if (var != NOVARIABLE)
1334
 
                                {
1335
 
                                        pt = describevariable(var, -1, -1);
1336
 
                                        if (*pt == '-' || *pt == '+' || isdigit(*pt))
1337
 
                                        {
1338
 
                                                *length = muldiv(atofr(pt), lambda, WHOLE);
1339
 
                                                *width = lambda;
1340
 
                                        }
1341
 
                                }
1342
 
                        }
1343
 
                        break;
1344
 
        }
1345
 
}
1346
 
 
1347
 
/*
1348
 
 * routine to return the ports of transistor "ni" in "gateleft", "gateright",
1349
 
 * "activetop", and "activebottom".  If "gateright" is NOPORTPROTO, there is only
1350
 
 * one gate port.
1351
 
 *
1352
 
 * This code is predicated upon the fact that all MOS transistors have four ports
1353
 
 * in the same sequence: gateleft, activetop, gateright, activebottom.  The schematic
1354
 
 * transistor, which has only three ports, is ordered: gate, source, drain.
1355
 
 * We have to allow for multiple ported transistors, so we will look at the
1356
 
 * nodefunction again (SRP)
1357
 
 */
1358
 
void transistorports(NODEINST *ni, PORTPROTO **gateleft, PORTPROTO **gateright,
1359
 
        PORTPROTO **activetop, PORTPROTO **activebottom)
1360
 
{
1361
 
        REGISTER INTBIG fun;
1362
 
 
1363
 
        fun = nodefunction(ni);
1364
 
        *activetop = *gateright = *activebottom = NOPORTPROTO;
1365
 
        *gateleft = ni->proto->firstportproto;
1366
 
        if (*gateleft == NOPORTPROTO) return;
1367
 
        *activetop = (*gateleft)->nextportproto;
1368
 
        if (*activetop == NOPORTPROTO) return;
1369
 
        *gateright = (*activetop)->nextportproto;
1370
 
        if ((*gateright)->nextportproto == NOPORTPROTO || fun == NPTRANPN ||
1371
 
                fun == NPTRAPNP || fun == NPTRA4NMOS || fun == NPTRA4DMOS ||
1372
 
                fun == NPTRA4PMOS || fun == NPTRA4NPN || fun == NPTRA4PNP ||
1373
 
                fun == NPTRA4NJFET || fun == NPTRA4PJFET ||
1374
 
                fun == NPTRA4DMES || fun == NPTRA4EMES)
1375
 
        {
1376
 
                *activebottom = *gateright;
1377
 
                *gateright = NOPORTPROTO;
1378
 
        } else
1379
 
                *activebottom = (*gateright)->nextportproto;
1380
 
}
1381
 
 
1382
 
/*
1383
 
 * routine to get the starting and ending angle of the arc described by node "ni".
1384
 
 * Sets "startoffset" to the fractional difference between the node rotation and the
1385
 
 * true starting angle of the arc (this will be less than a tenth of a degree, since
1386
 
 * node rotation is in tenths of a degree).  Sets "endangle" to the ending rotation
1387
 
 * of the arc (the true ending angle is this plus the node rotation and "startoffset").
1388
 
 * Both "startoffset" and "endangle" are in radians).
1389
 
 * If the node is not circular, both values are set to zero.
1390
 
 */
1391
 
void getarcdegrees(NODEINST *ni, double *startoffset, double *endangle)
1392
 
{
1393
 
        REGISTER VARIABLE *var;
1394
 
        float sof, eaf;
1395
 
 
1396
 
        *startoffset = *endangle = 0.0;
1397
 
        if (ni->proto != art_circleprim && ni->proto != art_thickcircleprim) return;
1398
 
        var = getvalkey((INTBIG)ni, VNODEINST, -1, art_degreeskey);
1399
 
        if (var == NOVARIABLE) return;
1400
 
        if ((var->type&VTYPE) == VINTEGER)
1401
 
        {
1402
 
                *startoffset = 0.0;
1403
 
                *endangle = (double)var->addr * EPI / 1800.0;
1404
 
                return;
1405
 
        }
1406
 
        if ((var->type&(VTYPE|VISARRAY)) == (VFLOAT|VISARRAY))
1407
 
        {
1408
 
                sof = ((float *)var->addr)[0];
1409
 
                eaf = ((float *)var->addr)[1];
1410
 
                *startoffset = (double)sof;
1411
 
                *endangle = (double)eaf;
1412
 
        }
1413
 
}
1414
 
 
1415
 
/*
1416
 
 * routine to set the starting and ending angle of the arc described by node "ni".
1417
 
 * Sets "startoffset" to the fractional difference between the node rotation and the
1418
 
 * true starting angle of the arc (this will be less than a tenth of a degree, since
1419
 
 * node rotation is in tenths of a degree).  Sets "endangle" to the ending rotation
1420
 
 * of the arc (the true ending angle is this plus the node rotation and "startoffset").
1421
 
 * Both "startoffset" and "endangle" are in radians).
1422
 
 * If the node is not circular, this call does nothing.
1423
 
 */
1424
 
void setarcdegrees(NODEINST *ni, double startoffset, double endangle)
1425
 
{
1426
 
        REGISTER INTBIG angle;
1427
 
        REGISTER double rangle;
1428
 
        float degs[2];
1429
 
 
1430
 
        if (ni->proto != art_circleprim && ni->proto != art_thickcircleprim) return;
1431
 
        if (startoffset == 0.0 && endangle == 0.0)
1432
 
        {
1433
 
                /* no arc on this circle: remove any data */
1434
 
                if (getvalkey((INTBIG)ni, VNODEINST, -1, art_degreeskey) == NOVARIABLE) return;
1435
 
                (void)delvalkey((INTBIG)ni, VNODEINST, art_degreeskey);
1436
 
        } else
1437
 
        {
1438
 
                /* put arc information on the circle */
1439
 
                angle = rounddouble(endangle * 1800.0 / EPI);
1440
 
                rangle = (double)angle * EPI / 1800.0;
1441
 
                if (startoffset == 0.0 && rangle == endangle)
1442
 
                {
1443
 
                        (void)setvalkey((INTBIG)ni, VNODEINST, art_degreeskey, angle, VINTEGER);
1444
 
                } else
1445
 
                {
1446
 
                        degs[0] = (float)startoffset;
1447
 
                        degs[1] = (float)endangle;
1448
 
                        (void)setvalkey((INTBIG)ni, VNODEINST, art_degreeskey, (INTBIG)degs,
1449
 
                                VFLOAT|VISARRAY|(2<<VLENGTHSH));
1450
 
                }
1451
 
        }
1452
 
        updategeom(ni->geom, ni->parent);
1453
 
        db_setchangefacet(ni->parent);
1454
 
}
1455
 
 
1456
 
/*
1457
 
 * Routine to return the endpoints of the arc on node "ni" that has a starting offset of
1458
 
 * "startoffset" and an ending angle of "endangle" (from "getarcdegrees()" above).  Returns
1459
 
 * the coordinates in (fx,fy) and (tx,ty).
1460
 
 */
1461
 
void getarcendpoints(NODEINST *ni, double startoffset, double endangle, INTBIG *fx, INTBIG *fy,
1462
 
        INTBIG *tx, INTBIG *ty)
1463
 
{
1464
 
        REGISTER INTBIG cx, cy, radius;
1465
 
 
1466
 
        cx = (ni->lowx + ni->highx) / 2;
1467
 
        cy = (ni->lowy + ni->highy) / 2;
1468
 
        radius = (ni->highx - ni->lowx) / 2;
1469
 
        startoffset += ((double)ni->rotation) * EPI / 1800.0;
1470
 
        if (ni->transpose != 0)
1471
 
        {
1472
 
                startoffset = 1.5 * EPI - startoffset - endangle;
1473
 
                if (startoffset < 0.0) startoffset += EPI * 2.0;
1474
 
        }
1475
 
        *fx = cx + rounddouble(cos(startoffset) * radius);
1476
 
        *fy = cy + rounddouble(sin(startoffset) * radius);
1477
 
        *tx = cx + rounddouble(cos(startoffset+endangle) * radius);
1478
 
        *ty = cy + rounddouble(sin(startoffset+endangle) * radius);
1479
 
}
1480
 
 
1481
 
/*
1482
 
 * Routine to get the primitive node in technology "tech" that is the pure-layer node
1483
 
 * for layer "layer" (if layer is negative, then look for the pure-layer node with
1484
 
 * function "function").  Returns NONODEPROTO if none is found.
1485
 
 */
1486
 
NODEPROTO *getpurelayernode(TECHNOLOGY *tech, INTBIG layer, INTBIG function)
1487
 
{
1488
 
        REGISTER NODEPROTO *np;
1489
 
        REGISTER NODEINST *ni;
1490
 
        REGISTER INTBIG i, fun;
1491
 
        static POLYGON *poly = NOPOLYGON;
1492
 
 
1493
 
        /* get polygon */
1494
 
        if (poly == NOPOLYGON) poly = allocstaticpolygon(4, db_cluster);
1495
 
 
1496
 
        ni = dummynode();
1497
 
        ni->lowx = ni->highx = 0;
1498
 
        ni->lowy = ni->highy = 0;
1499
 
        for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1500
 
        {
1501
 
                if (((np->userbits&NFUNCTION) >> NFUNCTIONSH) != NPNODE) continue;
1502
 
                ni->proto = np;
1503
 
                i = nodepolys(ni, 0, NOWINDOWPART);
1504
 
                if (i != 1) continue;
1505
 
                shapenodepoly(ni, 0, poly);
1506
 
                if (layer >= 0)
1507
 
                {
1508
 
                        if (poly->layer == layer) return(np);
1509
 
                } else
1510
 
                {
1511
 
                        fun = layerfunction(tech, poly->layer);
1512
 
                        if ((fun&(LFTYPE|LFPTYPE|LFNTYPE)) == function) return(np);
1513
 
                }
1514
 
        }
1515
 
        return(NONODEPROTO);
1516
 
}
1517
 
 
1518
 
/******************** PORT DESCRIPTION ********************/
1519
 
 
1520
 
/*
1521
 
 * routine to set polygon "poly" to the shape of port "pp" on nodeinst "ni".
1522
 
 * If "purpose" is false, the entire port is desired.  If "purpose" is true,
1523
 
 * the exact location of a new port is desired and that port should be
1524
 
 * optimally close to the co-ordinates in (poly->xv[0],poly->yv[0]).
1525
 
 */
1526
 
void shapeportpoly(NODEINST *ni, PORTPROTO *pp, POLYGON *poly, BOOLEAN purpose)
1527
 
{
1528
 
        REGISTER INTBIG pindex;
1529
 
        REGISTER TECH_NODES *thistn;
1530
 
        XARRAY localtran, tempt1, tempt2, *t1, *t2, *swapt;
1531
 
 
1532
 
        /* look down to the bottom level node/port */
1533
 
        t1 = (XARRAY *)tempt1;   t2 = (XARRAY *)tempt2;
1534
 
        if (ni->rotation == 0 && ni->transpose == 0) transid(*t1); else
1535
 
                makerot(ni, *t1);
1536
 
        while (ni->proto->primindex == 0)
1537
 
        {
1538
 
                maketrans(ni, localtran);
1539
 
                transmult(localtran, *t1, *t2);
1540
 
                swapt = t1;   t1 = t2;   t2 = swapt;
1541
 
                ni = pp->subnodeinst;
1542
 
                pp = pp->subportproto;
1543
 
                if (ni->rotation != 0 || ni->transpose != 0)
1544
 
                {
1545
 
                        makerot(ni, localtran);
1546
 
                        transmult(localtran, *t1, *t2);
1547
 
                        swapt = t1;   t1 = t2;   t2 = swapt;
1548
 
                }
1549
 
        }
1550
 
 
1551
 
        /* if the technology has its own routine, use it */
1552
 
        if (ni->proto->tech->shapeportpoly != 0)
1553
 
        {
1554
 
                (*(ni->proto->tech->shapeportpoly))(ni, pp, poly, *t1, purpose);
1555
 
                return;
1556
 
        }
1557
 
 
1558
 
        pindex = ni->proto->primindex;
1559
 
        thistn = ni->proto->tech->nodeprotos[pindex-1];
1560
 
        switch (thistn->special)
1561
 
        {
1562
 
                case SERPTRANS:
1563
 
                        tech_filltransport(ni, pp, poly, *t1, thistn, thistn->f2, thistn->f3,
1564
 
                                thistn->f4, thistn->f5, thistn->f6);
1565
 
                        break;
1566
 
 
1567
 
                default:
1568
 
                        tech_fillportpoly(ni, pp, poly, *t1, thistn, CLOSED);
1569
 
                        break;
1570
 
        }
1571
 
}
1572
 
 
1573
 
/*
1574
 
 * routine to set polygon "poly" to the shape of port "pp" on nodeinst "ni",
1575
 
 * given that the node transformation is already known and is "trans".
1576
 
 */
1577
 
void shapetransportpoly(NODEINST *ni, PORTPROTO *pp, POLYGON *poly, XARRAY trans)
1578
 
{
1579
 
        REGISTER INTBIG pindex;
1580
 
        REGISTER TECH_NODES *thistn;
1581
 
 
1582
 
        /* if the technology has its own routine, use it */
1583
 
        if (ni->proto->tech->shapeportpoly != 0)
1584
 
        {
1585
 
                (*(ni->proto->tech->shapeportpoly))(ni, pp, poly, trans, FALSE);
1586
 
                return;
1587
 
        }
1588
 
 
1589
 
        pindex = ni->proto->primindex;
1590
 
        thistn = ni->proto->tech->nodeprotos[pindex-1];
1591
 
        switch (thistn->special)
1592
 
        {
1593
 
                case SERPTRANS:
1594
 
                        tech_filltransport(ni, pp, poly, trans, thistn, thistn->f2, thistn->f3,
1595
 
                                thistn->f4, thistn->f5, thistn->f6);
1596
 
                        break;
1597
 
 
1598
 
                default:
1599
 
                        tech_fillportpoly(ni, pp, poly, trans, thistn, CLOSED);
1600
 
                        break;
1601
 
        }
1602
 
}
1603
 
 
1604
 
/*
1605
 
 * routine to compute the center of port "pp" in nodeinst "ni" (taking
1606
 
 * nodeinst position, transposition and rotation into account).  The location
1607
 
 * is placed in the reference integer parameters "x" and "y"
1608
 
 */
1609
 
void portposition(NODEINST *ni, PORTPROTO *pp, INTBIG *x, INTBIG *y)
1610
 
{
1611
 
        static POLYGON *poly = NOPOLYGON;
1612
 
 
1613
 
        /* make sure there is a polygon */
1614
 
        if (poly == NOPOLYGON) poly = allocstaticpolygon(4, db_cluster);
1615
 
 
1616
 
        /* get the polygon describing the port */
1617
 
        shapeportpoly(ni, pp, poly, FALSE);
1618
 
 
1619
 
        /* determine the center of the polygon */
1620
 
        getcenter(poly, x, y);
1621
 
}
1622
 
 
1623
 
/*
1624
 
 * routine to return true if port "pp" is a power port
1625
 
 */
1626
 
BOOLEAN portispower(PORTPROTO *pp)
1627
 
{
1628
 
        if ((pp->userbits&STATEBITS) == PWRPORT) return(TRUE);
1629
 
        if ((pp->userbits&STATEBITS) != 0) return(FALSE);
1630
 
        if (portisnamedpower(pp)) return(TRUE);
1631
 
        return(FALSE);
1632
 
}
1633
 
 
1634
 
/*
1635
 
 * routine to return true if port "pp" has a power port name
1636
 
 */
1637
 
BOOLEAN portisnamedpower(PORTPROTO *pp)
1638
 
{
1639
 
        REGISTER char *pt;
1640
 
        REGISTER INTBIG len;
1641
 
 
1642
 
        for(pt = pp->protoname; *pt != 0; pt++)
1643
 
        {
1644
 
                len = strlen(pt);
1645
 
                if (len >= 3)
1646
 
                {
1647
 
                        if (namesamen(pt, "vdd", 3) == 0) return(TRUE);
1648
 
                        if (namesamen(pt, "pwr", 3) == 0) return(TRUE);
1649
 
                        if (namesamen(pt, "vcc", 3) == 0) return(TRUE);
1650
 
                }
1651
 
                if (len >= 5)
1652
 
                {
1653
 
                        if (namesamen(pt, "power", 5) == 0) return(TRUE);
1654
 
                }
1655
 
        }
1656
 
        return(FALSE);
1657
 
}
1658
 
 
1659
 
/*
1660
 
 * routine to return true if port "pp" is a ground port
1661
 
 */
1662
 
BOOLEAN portisground(PORTPROTO *pp)
1663
 
{
1664
 
        if ((pp->userbits&STATEBITS) == GNDPORT) return(TRUE);
1665
 
        if ((pp->userbits&STATEBITS) != 0) return(FALSE);
1666
 
        if (portisnamedground(pp)) return(TRUE);
1667
 
        return(FALSE);
1668
 
}
1669
 
 
1670
 
/*
1671
 
 * routine to return true if port "pp" has a ground port name
1672
 
 */
1673
 
BOOLEAN portisnamedground(PORTPROTO *pp)
1674
 
{
1675
 
        REGISTER char *pt;
1676
 
        REGISTER INTBIG len;
1677
 
 
1678
 
        for(pt = pp->protoname; *pt != 0; pt++)
1679
 
        {
1680
 
                len = strlen(pt);
1681
 
                if (len >= 3)
1682
 
                {
1683
 
                        if (namesamen(pt, "gnd", 3) == 0) return(TRUE);
1684
 
                        if (namesamen(pt, "vss", 3) == 0) return(TRUE);
1685
 
                }
1686
 
                if (len >= 6)
1687
 
                {
1688
 
                        if (namesamen(pt, "ground", 6) == 0) return(TRUE);
1689
 
                }
1690
 
        }
1691
 
        return(FALSE);
1692
 
}
1693
 
 
1694
 
/******************** ARCINST DESCRIPTION ********************/
1695
 
 
1696
 
/*
1697
 
 * routine to report the number of distinct polygons used to compose
1698
 
 * primitive arcinst "ai".
1699
 
 */
1700
 
INTBIG arcpolys(ARCINST *ai, WINDOWPART *win)
1701
 
{
1702
 
        REGISTER INTBIG i;
1703
 
        REGISTER TECHNOLOGY *tech;
1704
 
 
1705
 
        /* if the technology has its own routine, use it */
1706
 
        tech = ai->proto->tech;
1707
 
        tech_curwindowpart = win;
1708
 
        if (tech->arcpolys != 0) return((*(tech->arcpolys))(ai, win));
1709
 
 
1710
 
        /* reset negated bit if set and not allowed */
1711
 
        if ((tech->userbits&NONEGATEDARCS) != 0 && (ai->userbits&ISNEGATED) != 0)
1712
 
                tech_resetnegated(ai);
1713
 
 
1714
 
        /* get number of polygons in the arc */
1715
 
        i = tech->arcprotos[ai->proto->arcindex]->laycount;
1716
 
 
1717
 
        /* add one layer if arc is directional and technology allows it */
1718
 
        if ((tech->userbits&NODIRECTIONALARCS) == 0 && (ai->userbits&ISDIRECTIONAL) != 0) i++;
1719
 
 
1720
 
        /* if zero-length, not end-extended, not directional, not negated, ignore all */
1721
 
        if (ai->end[0].xpos == ai->end[1].xpos && ai->end[0].ypos == ai->end[1].ypos &&
1722
 
                (ai->userbits&(NOEXTEND|ISNEGATED|ISDIRECTIONAL|NOTEND0|NOTEND1)) == NOEXTEND)
1723
 
                        i = 0;
1724
 
 
1725
 
        /* add in displayable variables */
1726
 
        tech_realpolys = i;
1727
 
        i += tech_displayableavars(ai, win);
1728
 
        return(i);
1729
 
}
1730
 
 
1731
 
/*
1732
 
 * routine to describe polygon number "box" of arcinst "ai".  The description
1733
 
 * is placed in the polygon "poly".
1734
 
 */
1735
 
void shapearcpoly(ARCINST *ai, INTBIG box, POLYGON *poly)
1736
 
{
1737
 
        REGISTER INTBIG pindex;
1738
 
        REGISTER ARCPROTO *ap;
1739
 
        REGISTER TECHNOLOGY *tech;
1740
 
        REGISTER TECH_ARCLAY *thista;
1741
 
 
1742
 
        /* if the technology has its own routine, use it */
1743
 
        ap = ai->proto;
1744
 
        tech = ap->tech;
1745
 
        poly->tech = tech;
1746
 
        if (tech->shapearcpoly != 0)
1747
 
        {
1748
 
                (*(tech->shapearcpoly))(ai, box, poly);
1749
 
                return;
1750
 
        }
1751
 
 
1752
 
        /* handle displayable variables */
1753
 
        if (box >= tech_realpolys)
1754
 
        {
1755
 
                (void)tech_filldisplayableavar(ai, poly, tech_curwindowpart, 0);
1756
 
                return;
1757
 
        }
1758
 
 
1759
 
        pindex = ap->arcindex;
1760
 
        if (box >= tech->arcprotos[pindex]->laycount) tech_makearrow(ai, poly); else
1761
 
        {
1762
 
                thista = &tech->arcprotos[pindex]->list[box];
1763
 
                makearcpoly(ai->length, ai->width-thista->off*lambdaofarc(ai)/WHOLE, ai, poly,
1764
 
                        thista->style);
1765
 
                poly->layer = thista->lay;
1766
 
                poly->desc = tech->layers[poly->layer];
1767
 
        }
1768
 
}
1769
 
 
1770
 
/*
1771
 
 * routine to fill polygon "poly" with the outline of the curved arc in
1772
 
 * "ai" whose width is "wid".  The style of the polygon is set to "style".
1773
 
 * If there is no curvature information in the arc, the routine returns true,
1774
 
 * otherwise it returns false.
1775
 
 */
1776
 
BOOLEAN curvedarcoutline(ARCINST *ai, POLYGON *poly, INTBIG style, INTBIG wid)
1777
 
{
1778
 
        REGISTER INTBIG i, points, anglebase, anglerange, pieces, a;
1779
 
        REGISTER INTBIG radius, centerx, centery, innerradius, outerradius, sin, cos;
1780
 
        INTBIG x1, y1, x2, y2;
1781
 
        REGISTER VARIABLE *var;
1782
 
 
1783
 
        /* get the radius information on the arc */
1784
 
        var = getvalkey((INTBIG)ai, VARCINST, VINTEGER, el_arc_radius_key);
1785
 
        if (var == NOVARIABLE) return(TRUE);
1786
 
        radius = var->addr;
1787
 
 
1788
 
        /* see if the radius can work with these arc ends */
1789
 
        if (abs(radius)*2 < ai->length) return(TRUE);
1790
 
 
1791
 
        /* determine the center of the circle */
1792
 
        if (findcenters(abs(radius), ai->end[0].xpos, ai->end[0].ypos,
1793
 
                ai->end[1].xpos, ai->end[1].ypos, ai->length, &x1,&y1, &x2,&y2)) return(TRUE);
1794
 
 
1795
 
        if (radius < 0)
1796
 
        {
1797
 
                radius = -radius;
1798
 
                centerx = x1;   centery = y1;
1799
 
        } else
1800
 
        {
1801
 
                centerx = x2;   centery = y2;
1802
 
        }
1803
 
 
1804
 
        /* determine the base and range of angles */
1805
 
        anglebase = figureangle(centerx,centery, ai->end[0].xpos,ai->end[0].ypos);
1806
 
        anglerange = figureangle(centerx, centery, ai->end[1].xpos, ai->end[1].ypos);
1807
 
        if ((ai->userbits&REVERSEEND) != 0)
1808
 
        {
1809
 
                i = anglebase;
1810
 
                anglebase = anglerange;
1811
 
                anglerange = i;
1812
 
        }
1813
 
        anglerange -= anglebase;
1814
 
        if (anglerange < 0) anglerange += 3600;
1815
 
 
1816
 
        /* determine the number of intervals to use for the arc */
1817
 
        pieces = anglerange;
1818
 
        while (pieces > 16) pieces /= 2;
1819
 
 
1820
 
        /* initialize the polygon */
1821
 
        points = (pieces+1) * 2;
1822
 
        if (poly->limit < points) (void)extendpolygon(poly, points);
1823
 
        poly->count = points;
1824
 
        poly->style = style;
1825
 
 
1826
 
        /* get the inner and outer radii of the arc */
1827
 
        outerradius = radius + wid / 2;
1828
 
        innerradius = outerradius - wid;
1829
 
 
1830
 
        /* fill the polygon */
1831
 
        for(i=0; i<=pieces; i++)
1832
 
        {
1833
 
                a = (anglebase + i * anglerange / pieces) % 3600;
1834
 
                sin = sine(a);   cos = cosine(a);
1835
 
                poly->xv[i] = mult(cos, innerradius) + centerx;
1836
 
                poly->yv[i] = mult(sin, innerradius) + centery;
1837
 
                poly->xv[points-1-i] = mult(cos, outerradius) + centerx;
1838
 
                poly->yv[points-1-i] = mult(sin, outerradius) + centery;
1839
 
        }
1840
 
        return(FALSE);
1841
 
}
1842
 
 
1843
 
/*
1844
 
 * routine to make a polygon that describes the arcinst "ai" which is "len"
1845
 
 * long and "wid" wide.  The polygon is in "poly", the style is set to "style".
1846
 
 */
1847
 
void makearcpoly(INTBIG len, INTBIG wid, ARCINST *ai, POLYGON *poly, INTBIG style)
1848
 
{
1849
 
        REGISTER INTBIG x1, y1, x2, y2, e1, e2, angle;
1850
 
 
1851
 
        x1 = ai->end[0].xpos;   y1 = ai->end[0].ypos;
1852
 
        x2 = ai->end[1].xpos;   y2 = ai->end[1].ypos;
1853
 
        poly->style = style;
1854
 
 
1855
 
        /* zero-width polygons are simply lines */
1856
 
        if (wid == 0)
1857
 
        {
1858
 
                if (poly->limit < 2) (void)extendpolygon(poly, 2);
1859
 
                poly->count = 2;
1860
 
                poly->xv[0] = x1;   poly->yv[0] = y1;
1861
 
                poly->xv[1] = x2;   poly->yv[1] = y2;
1862
 
                return;
1863
 
        }
1864
 
 
1865
 
        /* determine the end extension on each end */
1866
 
        e1 = e2 = wid/2;
1867
 
        if ((ai->userbits&NOEXTEND) != 0)
1868
 
        {
1869
 
                /* nonextension arc: set extension to zero for all included ends */
1870
 
                if ((ai->userbits&NOTEND0) == 0) e1 = 0;
1871
 
                if ((ai->userbits&NOTEND1) == 0) e2 = 0;
1872
 
        } else if ((ai->userbits&ASHORT) != 0)
1873
 
        {
1874
 
                /* shortened arc: compute variable extension */
1875
 
                e1 = tech_getextendfactor(wid, ai->endshrink&0xFFFF);
1876
 
                e2 = tech_getextendfactor(wid, (ai->endshrink>>16)&0xFFFF);
1877
 
        }
1878
 
 
1879
 
        /* make the polygon */
1880
 
        angle = (ai->userbits&AANGLE) >> AANGLESH;
1881
 
        tech_makeendpointpoly(len, wid, angle*10, x1,y1, e1, x2,y2, e2, poly);
1882
 
}
1883
 
 
1884
 
/*
1885
 
 * routine to return the offset between the nominal width of arcinst "ai"
1886
 
 * and the actual width.  This routine accesses the "arc_width_offset"
1887
 
 * variable on the technology objects.
1888
 
 */
1889
 
INTBIG arcwidthoffset(ARCINST *ai)
1890
 
{
1891
 
        REGISTER ARCPROTO *ap;
1892
 
 
1893
 
        /* if the technology has its own routine, use it */
1894
 
        ap = ai->proto;
1895
 
        if (ap->tech->nodesizeoffset != 0)
1896
 
                return((*(ap->tech->arcwidthoffset))(ai));
1897
 
 
1898
 
        return(tech_arcprotowidthoffset(ap, lambdaofarc(ai)));
1899
 
}
1900
 
 
1901
 
/*
1902
 
 * routine to return the offset between the nominal width of arcproto "ap"
1903
 
 * and the actual width.  This routine accesses the "arc_width_offset"
1904
 
 * variable on the technology objects.
1905
 
 */
1906
 
INTBIG arcprotowidthoffset(ARCPROTO *ap)
1907
 
{
1908
 
        return(tech_arcprotowidthoffset(ap, el_curlib->lambda[ap->tech->techindex]));
1909
 
}
1910
 
 
1911
 
/*
1912
 
 * support routine for "arcwidthoffset()" and "arcprotowidthoffset()" to return the offset
1913
 
 * between the nominal width of arcproto "ap" and the actual width.
1914
 
 */
1915
 
INTBIG tech_arcprotowidthoffset(ARCPROTO *ap, INTBIG lambda)
1916
 
{
1917
 
        REGISTER INTBIG *addr;
1918
 
 
1919
 
        /* make sure cache of information is valid */
1920
 
        if (tech_arc_widoff == 0)
1921
 
        {
1922
 
                tech_initarcwidthoffset();
1923
 
                if (tech_arc_widoff == 0) return(0);
1924
 
        }
1925
 
 
1926
 
        addr = tech_arc_widoff[ap->tech->techindex];
1927
 
        if (addr == 0) return(0);
1928
 
        return(addr[ap->arcindex]*lambda/WHOLE);
1929
 
}
1930
 
 
1931
 
/*
1932
 
 * routine to return the name of the arc with function "fun"
1933
 
 */
1934
 
char *arcfunctionname(INTBIG fun)
1935
 
{
1936
 
        static char *arcfunname[] =
1937
 
        {
1938
 
                N_("unknown"),                          /* APUNKNOWN */
1939
 
                N_("metal-1"),                          /* APMETAL1 */
1940
 
                N_("metal-2"),                          /* APMETAL2 */
1941
 
                N_("metal-3"),                          /* APMETAL3 */
1942
 
                N_("metal-4"),                          /* APMETAL4 */
1943
 
                N_("metal-5"),                          /* APMETAL5 */
1944
 
                N_("metal-6"),                          /* APMETAL6 */
1945
 
                N_("metal-7"),                          /* APMETAL7 */
1946
 
                N_("metal-8"),                          /* APMETAL8 */
1947
 
                N_("polysilicon-1"),            /* APPOLY1 */
1948
 
                N_("polysilicon-2"),            /* APPOLY2 */
1949
 
                N_("polysilicon-3"),            /* APPOLY3 */
1950
 
                N_("diffusion"),                        /* APDIFF */
1951
 
                N_("p-diffusion"),                      /* APDIFFP */
1952
 
                N_("n-diffusion"),                      /* APDIFFN */
1953
 
                N_("substrate-diffusion"),      /* APDIFFS */
1954
 
                N_("well-diffusion"),           /* APDIFFW */
1955
 
                N_("bus"),                                      /* APBUS */
1956
 
                N_("unrouted"),                         /* APUNROUTED */
1957
 
                N_("nonelectrical")                     /* APNONELEC */
1958
 
        };
1959
 
 
1960
 
        if (fun < 0 || fun > APNONELEC) return("");
1961
 
        return(_(arcfunname[fun]));
1962
 
}
1963
 
 
1964
 
/*
1965
 
 * Routine to find the arc that has layer "layer" in technology "tech".
1966
 
 * Returns NOARCPROTO if the layer doesn't have an arc.
1967
 
 */
1968
 
ARCPROTO *getarconlayer(INTBIG layer, TECHNOLOGY *tech)
1969
 
{
1970
 
        REGISTER ARCPROTO *ap;
1971
 
        REGISTER ARCINST *ai;
1972
 
        static POLYGON *poly = NOPOLYGON;
1973
 
 
1974
 
        /* get polygon */
1975
 
        if (poly == NOPOLYGON) poly = allocstaticpolygon(4, db_cluster);
1976
 
 
1977
 
        ai = dummyarc();
1978
 
        for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1979
 
        {
1980
 
                ai->proto = ap;
1981
 
                (void)arcpolys(ai, NOWINDOWPART);
1982
 
                shapearcpoly(ai, 0, poly);
1983
 
                if (poly->layer == layer) return(ap);
1984
 
        }
1985
 
        return(NOARCPROTO);
1986
 
}
1987
 
 
1988
 
/******************** LAYER DESCRIPTION ********************/
1989
 
 
1990
 
/*
1991
 
 * routine to return the full name of layer "layer" in technology "tech".
1992
 
 * This routine accesses the "layer_names" variable on the technology objects.
1993
 
 */
1994
 
char *layername(TECHNOLOGY *tech, INTBIG layer)
1995
 
{
1996
 
        REGISTER char **addr;
1997
 
 
1998
 
        if (layer < 0) return("");
1999
 
 
2000
 
        /* make sure cache of information is valid */
2001
 
        if (tech_layer_names == 0)
2002
 
        {
2003
 
                tech_initlayername();
2004
 
                if (tech_layer_names == 0) return("");
2005
 
        }
2006
 
 
2007
 
        addr = tech_layer_names[tech->techindex];
2008
 
        if (addr == 0) return("");
2009
 
        return(addr[layer]);
2010
 
}
2011
 
 
2012
 
/*
2013
 
 * routine to return the function of layer "layer" in technology "tech".
2014
 
 * This routine accesses the "layer_function" variable on the technology objects.
2015
 
 */
2016
 
INTBIG layerfunction(TECHNOLOGY *tech, INTBIG layer)
2017
 
{
2018
 
        REGISTER INTBIG *addr;
2019
 
 
2020
 
        if (layer < 0) return(LFUNKNOWN);
2021
 
 
2022
 
        /* make sure cache of information is valid */
2023
 
        if (tech_layer_function == 0)
2024
 
        {
2025
 
                tech_initlayerfunction();
2026
 
                if (tech_layer_function == 0) return(LFUNKNOWN);
2027
 
        }
2028
 
 
2029
 
        addr = tech_layer_function[tech->techindex];
2030
 
        if (addr == 0) return(LFUNKNOWN);
2031
 
        return(addr[layer]);
2032
 
}
2033
 
 
2034
 
/* Routine to return true if the layer function "fun" is metal  */
2035
 
BOOLEAN layerismetal(INTBIG fun)
2036
 
{
2037
 
        fun &= LFTYPE;
2038
 
        if (fun == LFMETAL1 || fun == LFMETAL2 || fun == LFMETAL3 ||
2039
 
                fun == LFMETAL4 || fun == LFMETAL5 || fun == LFMETAL6 ||
2040
 
                fun == LFMETAL7 || fun == LFMETAL8)  return(TRUE);
2041
 
        return(FALSE);
2042
 
}
2043
 
 
2044
 
/* Routine to return nonzero if the layer function "fun" is polysilicon  */
2045
 
BOOLEAN layerispoly(INTBIG fun)
2046
 
{
2047
 
        fun &= LFTYPE;
2048
 
        if (fun == LFPOLY1 || fun == LFPOLY2 || fun == LFPOLY3 || fun == LFGATE) return(TRUE);
2049
 
        return(FALSE);
2050
 
}
2051
 
 
2052
 
/* Routine to return nonzero if the layer function "fun" is a contact/via  */
2053
 
BOOLEAN layeriscontact(INTBIG fun)
2054
 
{
2055
 
        fun &= LFTYPE;
2056
 
        if (fun == LFCONTACT1 || fun == LFCONTACT2 || fun == LFCONTACT3 ||
2057
 
                fun == LFCONTACT4 || fun == LFCONTACT5 || fun == LFCONTACT6)  return(TRUE);
2058
 
        return(FALSE);
2059
 
}
2060
 
 
2061
 
/*
2062
 
 * routine to return the height of layer function "funct".
2063
 
 */
2064
 
INTBIG layerfunctionheight(INTBIG funct)
2065
 
{
2066
 
        switch (funct & LFTYPE)
2067
 
        {
2068
 
                case LFWELL:       return(0);
2069
 
                case LFSUBSTRATE:  return(1);
2070
 
                case LFIMPLANT:    return(2);
2071
 
                case LFTRANSISTOR: return(3);
2072
 
                case LFRESISTOR:   return(4);
2073
 
                case LFCAP:        return(5);
2074
 
                case LFEMITTER:    return(6);
2075
 
                case LFBASE:       return(7);
2076
 
                case LFCOLLECTOR:  return(8);
2077
 
                case LFGUARD:      return(9);
2078
 
                case LFISOLATION:  return(10);
2079
 
                case LFDIFF:       return(11);
2080
 
                case LFPOLY1:      return(12);
2081
 
                case LFPOLY2:      return(13);
2082
 
                case LFPOLY3:      return(14);
2083
 
                case LFGATE:       return(15);
2084
 
                case LFCONTACT1:   return(16);
2085
 
                case LFMETAL1:     return(17);
2086
 
                case LFCONTACT2:   return(18);
2087
 
                case LFMETAL2:     return(19);
2088
 
                case LFCONTACT3:   return(20);
2089
 
                case LFMETAL3:     return(21);
2090
 
                case LFCONTACT4:   return(22);
2091
 
                case LFMETAL4:     return(23);
2092
 
                case LFCONTACT5:   return(24);
2093
 
                case LFMETAL5:     return(25);
2094
 
                case LFCONTACT6:   return(26);
2095
 
                case LFMETAL6:     return(27);
2096
 
                case LFMETAL7:     return(28);
2097
 
                case LFMETAL8:     return(29);
2098
 
                case LFPLUG:       return(30);
2099
 
                case LFOVERGLASS:  return(31);
2100
 
                case LFBUS:        return(32);
2101
 
                case LFART:        return(33);
2102
 
                case LFCONTROL:    return(34);
2103
 
        }
2104
 
        return(35);
2105
 
}
2106
 
 
2107
 
/*
2108
 
 * Routine to return the non-pseudo layer associated with layer "layer" in
2109
 
 * technology "tech".
2110
 
 */
2111
 
INTBIG nonpseudolayer(INTBIG layer, TECHNOLOGY *tech)
2112
 
{
2113
 
        REGISTER INTBIG fun, ofun, i, j;
2114
 
 
2115
 
        if (tech != db_convertpseudotech)
2116
 
        {
2117
 
                if (db_convertpseudoarray != 0) efree((char *)db_convertpseudoarray);
2118
 
                db_convertpseudoarray = (INTBIG *)emalloc(tech->layercount * SIZEOFINTBIG, db_cluster);
2119
 
                if (db_convertpseudoarray == 0)
2120
 
                {
2121
 
                        db_convertpseudotech = NOTECHNOLOGY;
2122
 
                        return(layer);
2123
 
                }
2124
 
                for(i=0; i<tech->layercount; i++)
2125
 
                {
2126
 
                        db_convertpseudoarray[i] = i;
2127
 
                        fun = layerfunction(tech, i);
2128
 
                        if ((fun&LFPSEUDO) == 0) continue;
2129
 
                        for(j=0; j<tech->layercount; j++)
2130
 
                        {
2131
 
                                ofun = layerfunction(tech, j);
2132
 
                                if (ofun == (fun & ~LFPSEUDO)) break;
2133
 
                        }
2134
 
                        if (j < tech->layercount) db_convertpseudoarray[i] = j;
2135
 
                }
2136
 
                db_convertpseudotech = tech;
2137
 
        }
2138
 
        return(db_convertpseudoarray[layer]);
2139
 
}
2140
 
 
2141
 
/*
2142
 
 * Routine to obtain 3D information about layer "layer" in technology "tech".  The 3D
2143
 
 * height is stored in "height" and its thickness in "thickness".  Returns true on
2144
 
 * error.
2145
 
 */
2146
 
BOOLEAN get3dfactors(TECHNOLOGY *tech, INTBIG layer, INTBIG *height, INTBIG *thickness)
2147
 
{
2148
 
        static BOOLEAN heightsetup = FALSE;
2149
 
        REGISTER TECHNOLOGY *itech;
2150
 
        REGISTER VARIABLE *varh, *vart;
2151
 
 
2152
 
        /* make sure that every technology has layer height information */
2153
 
        if (!heightsetup)
2154
 
        {
2155
 
                heightsetup = TRUE;
2156
 
                tech_techlayer3dheightkey = makekey("TECH_layer_3dheight");
2157
 
                tech_techlayer3dthicknesskey = makekey("TECH_layer_3dthickness");
2158
 
                for(itech = el_technologies; itech != NOTECHNOLOGY; itech = itech->nexttechnology)
2159
 
                {
2160
 
                        varh = getvalkey((INTBIG)itech, VTECHNOLOGY, VINTEGER|VISARRAY, tech_techlayer3dheightkey);
2161
 
                        vart = getvalkey((INTBIG)itech, VTECHNOLOGY, VINTEGER|VISARRAY, tech_techlayer3dthicknesskey);
2162
 
                        if (varh == NOVARIABLE || vart == NOVARIABLE)
2163
 
                                tech_3ddefaultlayerheight(itech);
2164
 
                }
2165
 
        }
2166
 
 
2167
 
        if (tech != tech_3dcurtech)
2168
 
        {
2169
 
                tech_3dcurtech = tech;
2170
 
                varh = getvalkey((INTBIG)tech_3dcurtech, VTECHNOLOGY, VINTEGER|VISARRAY,
2171
 
                        tech_techlayer3dheightkey);
2172
 
                vart = getvalkey((INTBIG)tech_3dcurtech, VTECHNOLOGY, VINTEGER|VISARRAY,
2173
 
                        tech_techlayer3dthicknesskey);
2174
 
                if (varh == NOVARIABLE || vart == NOVARIABLE)
2175
 
                {
2176
 
                        tech_3dcurtech = NOTECHNOLOGY;
2177
 
                        return(TRUE);
2178
 
                }
2179
 
                tech_3dcurthicknessarray = (INTBIG *)vart->addr;
2180
 
                tech_3dcurheightarray = (INTBIG *)varh->addr;
2181
 
        }
2182
 
        if (layer < 0 || layer >= tech->layercount) return(TRUE);
2183
 
 
2184
 
        *thickness = tech_3dcurthicknessarray[layer];
2185
 
        *height = tech_3dcurheightarray[layer];
2186
 
        return(FALSE);
2187
 
}
2188
 
 
2189
 
void set3dheight(TECHNOLOGY *tech, INTBIG *depth)
2190
 
{
2191
 
        setvalkey((INTBIG)tech, VTECHNOLOGY, tech_techlayer3dheightkey, (INTBIG)depth,
2192
 
                VINTEGER|VISARRAY|(tech->layercount<<VLENGTHSH));
2193
 
        tech_3dcurtech = NOTECHNOLOGY;
2194
 
}
2195
 
 
2196
 
void set3dthickness(TECHNOLOGY *tech, INTBIG *thickness)
2197
 
{
2198
 
        setvalkey((INTBIG)tech, VTECHNOLOGY, tech_techlayer3dthicknesskey, (INTBIG)thickness,
2199
 
                VINTEGER|VISARRAY|(tech->layercount<<VLENGTHSH));
2200
 
        tech_3dcurtech = NOTECHNOLOGY;
2201
 
}
2202
 
 
2203
 
/*
2204
 
 * Routine to return true if layers "layer1" and "layer2" in technology "tech"
2205
 
 * should be considered equivalent for the purposes of cropping.
2206
 
 */
2207
 
BOOLEAN samelayer(TECHNOLOGY *tech, INTBIG layer1, INTBIG layer2)
2208
 
{
2209
 
        static TECHNOLOGY *layertabtech = NOTECHNOLOGY;
2210
 
        REGISTER INTBIG countsquared, i, first, second;
2211
 
        INTBIG *equivlist;
2212
 
 
2213
 
        if (layer1 == layer2) return(TRUE);
2214
 
        if (layer1 < 0 || layer2 < 0) return(FALSE);
2215
 
        if (tech == NOTECHNOLOGY) return(FALSE);
2216
 
        if (tech != layertabtech)
2217
 
        {
2218
 
                if (tech_equivtable != 0) efree((char *)tech_equivtable);
2219
 
                tech_equivtable = 0;
2220
 
                equivlist = (INTBIG *)asktech(tech, "get-layer-equivalences");
2221
 
                if (equivlist != 0)
2222
 
                {
2223
 
                        countsquared = tech->layercount * tech->layercount;
2224
 
                        tech_equivtable = (BOOLEAN *)emalloc(countsquared * (sizeof (BOOLEAN)),
2225
 
                                db_cluster);
2226
 
                        if (tech_equivtable == 0) return(FALSE);
2227
 
                        for(i=0; i<countsquared; i++) tech_equivtable[i] = FALSE;
2228
 
                        while (*equivlist >= 0)
2229
 
                        {
2230
 
                                first = *equivlist++;
2231
 
                                second = *equivlist++;
2232
 
                                tech_equivtable[first*tech->layercount + second] = TRUE;
2233
 
                                tech_equivtable[second*tech->layercount + first] = TRUE;
2234
 
                        }
2235
 
                }
2236
 
                layertabtech = tech;
2237
 
        }
2238
 
        if (tech_equivtable == 0) return(FALSE);
2239
 
        return(tech_equivtable[layer1*tech->layercount + layer2]);
2240
 
}
2241
 
 
2242
 
/*
2243
 
 * Routine to establish default layer height and thickness for
2244
 
 * technology "tech".
2245
 
 */
2246
 
void tech_3ddefaultlayerheight(TECHNOLOGY *tech)
2247
 
{
2248
 
        REGISTER INTBIG *layerheight, *layerthickness, i, funct;
2249
 
 
2250
 
        layerheight = (INTBIG *)emalloc(tech->layercount * SIZEOFINTBIG, el_tempcluster);
2251
 
        layerthickness = (INTBIG *)emalloc(tech->layercount * SIZEOFINTBIG, el_tempcluster);
2252
 
        for(i=0; i<tech->layercount; i++)
2253
 
        {
2254
 
                funct = layerfunction(tech, i) & LFTYPE;
2255
 
                layerheight[i] = layerfunctionheight(funct);
2256
 
                layerthickness[i] = 0;
2257
 
                if (layeriscontact(funct)) layerthickness[i] = 2;
2258
 
        }
2259
 
        setvalkey((INTBIG)tech, VTECHNOLOGY, tech_techlayer3dheightkey, (INTBIG)layerheight,
2260
 
                VINTEGER|VISARRAY|(tech->layercount<<VLENGTHSH)|VDONTSAVE);
2261
 
        setvalkey((INTBIG)tech, VTECHNOLOGY, tech_techlayer3dthicknesskey, (INTBIG)layerthickness,
2262
 
                VINTEGER|VISARRAY|(tech->layercount<<VLENGTHSH)|VDONTSAVE);
2263
 
        efree((char *)layerheight);
2264
 
        efree((char *)layerthickness);
2265
 
}
2266
 
 
2267
 
/*
2268
 
 * routine to tell the minimum distance between layers "layer1" and "layer2" in
2269
 
 * technology "tech".  If "connected" is false, the two layers are not connected,
2270
 
 * if it is true, they are connected electrically.  A negative return means
2271
 
 * that the two layers can overlap.  If the distance is an edge rule, "edge"
2272
 
 * is set nonzero.  If there is a rule associated with this
2273
 
 * it is returned in "rule".  This routine accesses the database
2274
 
 * variables "DRC_min_connected_distances" and "DRC_min_unconnected_distances"
2275
 
 * in the technologies.
2276
 
 */
2277
 
INTBIG tech_getdrcmindistance(TECHNOLOGY *tech, INTBIG layer1, INTBIG layer2,
2278
 
        BOOLEAN connected, INTBIG wide, BOOLEAN multicut, INTBIG *edge, char **rule)
2279
 
{
2280
 
        REGISTER INTBIG pindex, temp, *addr, *edgeaddr, *multiaddr, *wideaddr, ti, dist;
2281
 
        REGISTER char **rules, **edgerules, **multirules, **widerules;
2282
 
 
2283
 
        if (layer1 < 0 || layer2 < 0) return(XX);
2284
 
 
2285
 
        /* make sure cache of information is valid */
2286
 
        ti = tech->techindex;
2287
 
        multiaddr = wideaddr = 0;
2288
 
        if (connected)
2289
 
        {
2290
 
                if (tech_drcconndistance == 0)
2291
 
                {
2292
 
                        tech_initmaxdrcsurround();
2293
 
                        if (tech_drcconndistance == 0) return(XX);
2294
 
                }
2295
 
                addr = tech_drcconndistance[ti];
2296
 
                rules = tech_drccondistancerule[ti];
2297
 
                edgeaddr = 0;
2298
 
                if (wide != 0)
2299
 
                {
2300
 
                        wideaddr = tech_drcconndistancew[ti];
2301
 
                        widerules = tech_drccondistancewrule[ti];
2302
 
                }
2303
 
                if (multicut)
2304
 
                {
2305
 
                        multiaddr = tech_drcconndistancem[ti];
2306
 
                        multirules = tech_drccondistancemrule[ti];
2307
 
                }
2308
 
        } else
2309
 
        {
2310
 
                if (tech_drcuncondistance == 0)
2311
 
                {
2312
 
                        tech_initmaxdrcsurround();
2313
 
                        if (tech_drcuncondistance == 0) return(XX);
2314
 
                }
2315
 
                addr = tech_drcuncondistance[ti];
2316
 
                rules = tech_drcuncondistancerule[ti];
2317
 
                edgeaddr = tech_drcedgedistance[ti];
2318
 
                edgerules = tech_drcedgedistancerule[ti];
2319
 
                if (wide != 0)
2320
 
                {
2321
 
                        wideaddr = tech_drcuncondistancew[ti];
2322
 
                        widerules = tech_drcuncondistancewrule[ti];
2323
 
                }
2324
 
                if (multicut)
2325
 
                {
2326
 
                        multiaddr = tech_drcuncondistancem[ti];
2327
 
                        multirules = tech_drcuncondistancemrule[ti];
2328
 
                }
2329
 
        }
2330
 
        if (addr == 0 && edgeaddr == 0) return(XX);
2331
 
 
2332
 
        /* compute index into connectedness tables */
2333
 
        if (layer1 > layer2) { temp = layer1; layer1 = layer2;  layer2 = temp; }
2334
 
        pindex = (layer1+1) * (layer1/2) + (layer1&1) * ((layer1+1)/2);
2335
 
        pindex = layer2 + tech->layercount * layer1 - pindex;
2336
 
 
2337
 
        /* presume the standard rule */
2338
 
        *edge = 0;
2339
 
        dist = addr[pindex];
2340
 
        if (edgeaddr != 0 && edgeaddr[pindex] > dist)
2341
 
        {
2342
 
                dist = edgeaddr[pindex];
2343
 
                rules = edgerules;
2344
 
                *edge = 1;
2345
 
        }
2346
 
        if (rule != 0)
2347
 
        {
2348
 
                *rule = 0; 
2349
 
                if (rules != 0 && rules[pindex][0] != 0) 
2350
 
                        *rule = rules[pindex];
2351
 
        }
2352
 
 
2353
 
        /* see if the multi-rule is there and is worse */
2354
 
        if (multiaddr != 0 && multiaddr[pindex] > dist)
2355
 
        {
2356
 
                dist = multiaddr[pindex];
2357
 
                *edge = 0;
2358
 
                if (rule != 0)
2359
 
                {
2360
 
                        *rule = 0; 
2361
 
                        if (multirules != 0 && multirules[pindex][0] != 0) 
2362
 
                                *rule = multirules[pindex];
2363
 
                }
2364
 
        }
2365
 
 
2366
 
        /* see if the wide-rule is there and is worse */
2367
 
        if (wideaddr != 0 && wideaddr[pindex] > dist)
2368
 
        {
2369
 
                dist = wideaddr[pindex];
2370
 
                *edge = 0;
2371
 
                if (rule != 0)
2372
 
                {
2373
 
                        *rule = 0; 
2374
 
                        if (widerules != 0 && widerules[pindex][0] != 0) 
2375
 
                                *rule = widerules[pindex];
2376
 
                }
2377
 
        }
2378
 
 
2379
 
        return(dist);
2380
 
}
2381
 
 
2382
 
/*
2383
 
 * routine to tell the maximum distance around layer "layer" in
2384
 
 * technology "tech" that needs to be looked at for design-rule
2385
 
 * checking (using library "lib").  This routine accesses the
2386
 
 * database variable "DRC_max_distances" in the technologies.
2387
 
 */
2388
 
INTBIG maxdrcsurround(TECHNOLOGY *tech, LIBRARY *lib, INTBIG layer)
2389
 
{
2390
 
        REGISTER INTBIG i, *addr;
2391
 
 
2392
 
        if (layer < 0 || layer >= tech->layercount) return(XX);
2393
 
 
2394
 
        /* make sure cache of information is valid */
2395
 
        if (tech_drcmaxdistances == 0)
2396
 
        {
2397
 
                tech_initmaxdrcsurround();
2398
 
                if (tech_drcmaxdistances == 0) return(XX);
2399
 
        }
2400
 
 
2401
 
        addr = tech_drcmaxdistances[tech->techindex];
2402
 
        if (addr == 0) return(XX);
2403
 
        i = addr[layer];
2404
 
        if (i < 0) return(XX);
2405
 
        i = i*lib->lambda[tech->techindex]/WHOLE;
2406
 
        return(i);
2407
 
}
2408
 
 
2409
 
/*
2410
 
 * routine to tell the minimum distance between two layers "layer1" and
2411
 
 * "layer2" in technology "tech".  If "connected" is false, the two layers
2412
 
 * are not connected, if it is true, they are connected electrically.
2413
 
 * The layers reside in library "lib".
2414
 
 * A negative return means that the two layers can overlap.
2415
 
 */
2416
 
INTBIG drcmindistance(TECHNOLOGY *tech, LIBRARY *lib, INTBIG layer1, INTBIG size1,
2417
 
        INTBIG layer2, INTBIG size2, BOOLEAN connected, BOOLEAN multicut, INTBIG *edge, char **rule)
2418
 
{
2419
 
        REGISTER INTBIG i, widerules, widelimit, lambda;
2420
 
 
2421
 
        /* determine whether or not wide rules are to be used */
2422
 
        widerules = 0;
2423
 
        lambda = lib->lambda[tech->techindex];
2424
 
        widelimit = tech_drcwidelimit[tech->techindex] * lambda / WHOLE;
2425
 
        if (size1 > widelimit || size2 > widelimit) widerules = 1;
2426
 
 
2427
 
        /* get the un-scaled distance */
2428
 
        i = tech_getdrcmindistance(tech, layer1, layer2, connected, widerules, multicut, edge, rule);
2429
 
 
2430
 
        /* scale result for current lambda value */
2431
 
        if (i > 0) i = i * lambda / WHOLE;
2432
 
        return(i);
2433
 
}
2434
 
 
2435
 
/*
2436
 
 * routine to return the minimum width of layer "layer" in technology "tech", given
2437
 
 * that it appears in library "lib".  The rule that determines this is placed in "rule"
2438
 
 * (ignored if "rule" is zero, set to 0 if no rule).
2439
 
 */
2440
 
INTBIG drcminwidth(TECHNOLOGY *tech, LIBRARY *lib, INTBIG layer, char **rule)
2441
 
{
2442
 
        REGISTER INTBIG *addr;
2443
 
        REGISTER char **rules;
2444
 
 
2445
 
        /* make sure cache of information is valid */
2446
 
        if (tech_drcminwidth == 0)
2447
 
        {
2448
 
                tech_initmaxdrcsurround();
2449
 
                if (tech_drcminwidth == 0) return(0);
2450
 
        }
2451
 
 
2452
 
        addr = tech_drcminwidth[tech->techindex];
2453
 
        rules = tech_drcminwidthrule[tech->techindex];
2454
 
        if (addr == 0) return(XX);
2455
 
        if (rule != 0)
2456
 
        {
2457
 
                *rule = 0; 
2458
 
                if (rules != 0 && rules[layer][0] != 0) 
2459
 
                        *rule = rules[layer];
2460
 
        }
2461
 
        return(addr[layer]*lib->lambda[tech->techindex]/WHOLE);
2462
 
}
2463
 
 
2464
 
/*
2465
 
 * routine to return the minimum size of primitive node "np", given
2466
 
 * that it appears in library "lib".  The size is placed in "sizex/sizey" and the
2467
 
 * rule that determines this is placed in "rule" (ignored if "rule" is zero, set to 0 if no rule).
2468
 
 */
2469
 
void drcminnodesize(NODEPROTO *np, LIBRARY *lib, INTBIG *sizex, INTBIG *sizey, char **rule)
2470
 
{
2471
 
        REGISTER INTBIG *addr, index;
2472
 
        REGISTER char **rules;
2473
 
        REGISTER TECHNOLOGY *tech;
2474
 
 
2475
 
        /* default answers */
2476
 
        *sizex = *sizey = XX;
2477
 
        if (rule != 0) *rule = 0;
2478
 
 
2479
 
        /* make sure cache of information is valid */
2480
 
        if (tech_drcminnodesize == 0)
2481
 
        {
2482
 
                tech_initmaxdrcsurround();
2483
 
                if (tech_drcminnodesize == 0) return;
2484
 
        }
2485
 
 
2486
 
        tech = np->tech;
2487
 
        index = np->primindex - 1;
2488
 
        if (index < 0) return;
2489
 
        addr = tech_drcminnodesize[tech->techindex];
2490
 
        rules = tech_drcminnodesizerule[tech->techindex];
2491
 
        if (addr != 0)
2492
 
        {
2493
 
                if (rule != 0 && rules != 0 && rules[index][0] != 0) 
2494
 
                        *rule = rules[index];
2495
 
                *sizex = addr[index*2] * lib->lambda[tech->techindex] / WHOLE;
2496
 
                *sizey = addr[index*2+1] * lib->lambda[tech->techindex] / WHOLE;
2497
 
        }
2498
 
}
2499
 
 
2500
 
/******************** MATHEMATICS ********************/
2501
 
 
2502
 
/*
2503
 
 * The transformation that is done here is from one range specification
2504
 
 * to another.  The original range is from "low" to "high".  The computed
2505
 
 * area is from "newlow" to "newhigh".  The obvious way to do this is:
2506
 
 *   center = (low + high) / 2;
2507
 
 *   size = high - low;
2508
 
 *   *newlow = center + size*lowmul/WHOLE + lowsum*lambda/WHOLE;
2509
 
 *   *newhigh = center + size*highmul/WHOLE + highsum*lambda/WHOLE;
2510
 
 * where "center" is the center co-ordinate and the complex expression is
2511
 
 * the transformation factors.  However, this method is unstable for odd
2512
 
 * range extents because there is no correct integral co-ordinate for the
2513
 
 * center of the area.  Try it on a null transformation of (-1,0).  The
2514
 
 * correct code is more complex, but rounds the center computation twice
2515
 
 * in case it is not integral, adjusting the numerator to round properly.
2516
 
 * The negative test is basically an adjustment by the "sign extend" value.
2517
 
 *
2518
 
 */
2519
 
void subrange(INTBIG low, INTBIG high, INTBIG lowmul, INTBIG lowsum, INTBIG highmul,
2520
 
        INTBIG highsum, INTBIG *newlow, INTBIG *newhigh, INTBIG lambda)
2521
 
{
2522
 
        REGISTER INTBIG total, size;
2523
 
 
2524
 
        size = high - low;
2525
 
        if ((total = low + high) < 0) total--;
2526
 
 
2527
 
        /*
2528
 
         * Because the largest 32-bit number is 2147483647 and because WHOLE
2529
 
         * is 120, the value of "size" cannot be larger than 2147483647/120
2530
 
         * (which is 17895697) or there may be rounding problems.  For these large
2531
 
         * numbers, use "muldiv".
2532
 
         */
2533
 
        if (size > 17895697)
2534
 
        {
2535
 
                *newlow = total/2 + muldiv(size, lowmul, WHOLE) + lowsum*lambda/WHOLE;
2536
 
                *newhigh = (total+1)/2 + muldiv(size, highmul, WHOLE) + highsum*lambda/WHOLE;
2537
 
        } else
2538
 
        {
2539
 
                *newlow = total/2 + size*lowmul/WHOLE + lowsum*lambda/WHOLE;
2540
 
                *newhigh = (total+1)/2 + size*highmul/WHOLE + highsum*lambda/WHOLE;
2541
 
        }
2542
 
}
2543
 
 
2544
 
/*
2545
 
 * routine to perform a range calculation (similar to "subrange") but on
2546
 
 * only one value rather than two.  The extent of the range is from "low"
2547
 
 * to "high" and the value of lambda is "lambda".  The routine returns
2548
 
 * the value (low+high)/2 + (high-low)*mul/WHOLE + sum*lambda/WHOLE.
2549
 
 */
2550
 
INTBIG getrange(INTBIG low, INTBIG high, INTBIG mul,INTBIG sum, INTBIG lambda)
2551
 
{
2552
 
        REGISTER INTBIG total;
2553
 
 
2554
 
        total = low + high;
2555
 
        if (total < 0) total--;
2556
 
 
2557
 
        /*
2558
 
         * Because the largest 32-bit number is 2147483647 and because WHOLE
2559
 
         * is 120, the value of "high-low" cannot be larger than 2147483647/120
2560
 
         * (which is 17895697) or there may be rounding problems.  For these large
2561
 
         * numbers, use "muldiv".
2562
 
         */
2563
 
        if (high-low > 17895697)
2564
 
                return(total/2 + muldiv(high-low, mul, WHOLE) + sum*lambda/WHOLE);
2565
 
        return(total/2 + (high-low)*mul/WHOLE + sum*lambda/WHOLE);
2566
 
}