2
* Electric(tm) VLSI Design System
5
* Database technology helper routines
6
* Written by: Steven M. Rubin, Static Free Software
8
* Copyright (c) 2000 Static Free Software.
10
* Electric(tm) is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* Electric(tm) is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with Electric(tm); see the file COPYING. If not, write to
22
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23
* Boston, Mass 02111-1307, USA.
25
* Static Free Software
27
* Portola Valley, California 94028
28
* info@staticfreesoft.com
33
#include "egraphics.h"
39
#include "efunction.h"
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;
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" */
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;
86
#define NOROUTINELIST ((ROUTINELIST *)-1)
88
typedef struct Iroutinelist
90
void (*routine)(void);
93
struct Iroutinelist *nextroutinelist;
95
static ROUTINELIST *tech_firstcache = NOROUTINELIST;
97
/* shared prototypes */
98
void tech_initmaxdrcsurround(void);
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,
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);
112
* Routine to free all memory associated with this module.
114
void db_freetechnologymemory(void)
116
REGISTER ROUTINELIST *rl;
118
while (tech_firstcache != NOROUTINELIST)
120
rl = tech_firstcache;
121
if (rl->count > 0) efree((char *)rl->variablekeys);
122
tech_firstcache = tech_firstcache->nextroutinelist;
125
if (tech_equivtable != 0) efree((char *)tech_equivtable);
126
if (db_convertpseudoarray != 0) efree((char *)db_convertpseudoarray);
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);
154
/******************** TECHNOLOGY ALLOCATION ********************/
157
* routine to allocate a technology from memory cluster "cluster" and return its
158
* address. The routine returns NOTECHNOLOGY if allocation fails.
160
TECHNOLOGY *alloctechnology(CLUSTER *cluster)
162
REGISTER TECHNOLOGY *tech;
164
tech = (TECHNOLOGY *)emalloc((sizeof (TECHNOLOGY)), cluster);
165
if (tech == 0) return((TECHNOLOGY *)db_error(DBNOMEM|DBALLOCTECHNOLOGY));
166
tech->techname = NOSTRING;
168
tech->deflambda = 2000;
169
tech->firstnodeproto = NONODEPROTO;
170
tech->firstarcproto = NOARCPROTO;
171
tech->firstvar = NOVARIABLE;
173
tech->parse = NOCOMCOMP;
174
tech->cluster = cluster;
175
tech->techdescript = NOSTRING;
181
tech->nodeEpolys = 0;
182
tech->shapenodepoly = 0;
183
tech->shapeEnodepoly = 0;
184
tech->nodesizeoffset = 0;
185
tech->shapeportpoly = 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;
194
tech->arcprotocount = 0;
195
tech->arcprotos = NULL;
196
tech->nodeprotocount = 0;
197
tech->nodeprotos = NULL;
202
* routine to return technology "tech" to the pool of free technologies
204
void freetechnology(TECHNOLOGY *tech)
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;
213
if (tech == NOTECHNOLOGY) return;
214
for(np = tech->firstnodeproto; np != NONODEPROTO; np = nextnp)
216
nextnp = np->nextnodeproto;
217
for(pp = np->firstportproto; pp != NOPORTPROTO; pp = nextpp)
219
nextpp = pp->nextportproto;
220
efree((char *)pp->protoname);
223
efree((char *)np->primname);
226
for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = nextap)
228
nextap = ap->nextarcproto;
229
efree((char *)ap->protoname);
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)
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++)
242
efree((char *)tech->arcprotos[i]->arcname);
243
efree((char *)tech->arcprotos[i]->list);
244
efree((char *)tech->arcprotos[i]);
246
efree((char *)tech->arcprotos);
247
for(i=0; i<tech->nodeprotocount; i++)
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
257
efree((char *)tn->gra);
258
efree((char *)tn->ele);
262
efree((char *)tech->nodeprotos);
264
clus = tech->cluster;
270
* routine to insert technology "tech" into the global linked list and to
271
* announce this change to all cached routines.
273
void addtechnology(TECHNOLOGY *tech)
275
REGISTER TECHNOLOGY *t, *lastt;
276
REGISTER ROUTINELIST *rl;
277
REGISTER INTBIG *newlam;
279
REGISTER LIBRARY *lib;
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;
286
/* recount the number of technologies and renumber them */
288
for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
289
t->techindex = el_maxtech++;
291
/* adjust the "lambda" array in all libraries */
292
for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
294
newlam = emalloc(((el_maxtech+1) * SIZEOFINTBIG), db_cluster);
297
(void)db_error(DBNOMEM|DBADDTECHNOLOGY);
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;
307
/* announce the change to the number of technologies */
308
for(rl = tech_firstcache; rl != NOROUTINELIST; rl = rl->nextroutinelist)
313
* routine to delete technology "tech" from the global list. Returns
316
BOOLEAN killtechnology(TECHNOLOGY *tech)
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;
327
/* cannot kill the generic technology */
328
if (tech == gen_tech)
330
(void)db_error(DBLASTECH|DBKILLTECHNOLOGY);
334
/* make sure there are no objects from this technology */
335
for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
337
for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
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;
346
if (np != NONODEPROTO)
348
(void)db_error(DBTECINUSE|DBKILLTECHNOLOGY);
353
/* adjust the "lambda" array in all libraries */
354
for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
356
newlam = emalloc((el_maxtech * SIZEOFINTBIG), db_cluster);
359
(void)db_error(DBNOMEM|DBKILLTECHNOLOGY);
362
for(i = j = 0, t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology, j++)
364
if (t == tech) continue;
365
newlam[i++] = lib->lambda[j];
368
efree((char *)lib->lambda);
369
lib->lambda = newlam;
372
/* remove "tech" from linked list */
373
lastt = NOTECHNOLOGY;
374
for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
376
if (t == tech) break;
379
if (lastt == NOTECHNOLOGY) el_technologies = tech->nexttechnology; else
380
lastt->nexttechnology = tech->nexttechnology;
382
/* deallocate the technology */
383
if (tech->numvar != 0) db_freevars(&tech->firstvar, &tech->numvar);
384
freetechnology(tech);
386
/* recount the number of technologies and renumber them */
388
for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
389
t->techindex = el_maxtech++;
391
/* announce the change to the number of technologies */
392
for(rl = tech_firstcache; rl != NOROUTINELIST; rl = rl->nextroutinelist)
397
void telltech(TECHNOLOGY *tech, INTBIG count, char *par[])
399
if (tech->setmode == 0) return;
400
(*tech->setmode)(count, par);
403
INTBIG asktech(TECHNOLOGY *tech, char *command, ...)
408
if (tech->request == 0) return(0);
409
var_start(ap, command);
410
result = (*tech->request)(command, ap);
415
/******************** VARIABLE CACHING ********************/
417
/* this should be called whenever "DRC_min_unconnected_distances" changes!!! */
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.
424
void tech_initmaxdrcsurround(void)
426
REGISTER VARIABLE *var;
427
REGISTER TECHNOLOGY *t;
428
REGISTER INTBIG j, total, l, *dist, m;
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);
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;
493
for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
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;
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;
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;
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++)
564
for(j=0; j<total; j++)
565
m = maxi(m, tech_getdrcmindistance(t, l, j, FALSE, 1, FALSE, &edge, 0));
569
if (setvalkey((INTBIG)t, VTECHNOLOGY, dr_max_distanceskey, (INTBIG)dist,
570
VFRACT|VDONTSAVE|VISARRAY|(total<<VLENGTHSH)) != NOVARIABLE)
572
var = getvalkey((INTBIG)t, VTECHNOLOGY, VFRACT|VISARRAY, dr_max_distanceskey);
573
if (var != NOVARIABLE) tech_drcmaxdistances[t->techindex] = (INTBIG *)var->addr;
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.
583
void tech_initnodesizeoffset(void)
585
REGISTER VARIABLE *var;
586
REGISTER TECHNOLOGY *tech;
588
/* free the old cache list if it exists */
589
if (tech_node_widoff != 0) efree((char *)tech_node_widoff);
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;
595
/* load the cache list */
596
for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
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);
604
* routine to initialize the database variable "TECH_layer_function". This
605
* is called once at initialization and again whenever the array is changed.
607
void tech_initlayerfunction(void)
609
REGISTER VARIABLE *var;
610
REGISTER TECHNOLOGY *t;
612
if (tech_layer_function != 0) efree((char *)tech_layer_function);
614
tech_layer_function = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
615
if (tech_layer_function == 0) return;
617
for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
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);
625
* routine to initialize the database variable "TECH_layer_names". This
626
* is called once at initialization and again whenever the array is changed.
628
void tech_initlayername(void)
630
REGISTER VARIABLE *var;
631
REGISTER TECHNOLOGY *t;
633
if (tech_layer_names != 0) efree((char *)tech_layer_names);
635
tech_layer_names = (char ***)emalloc((el_maxtech * (sizeof (char **))), db_cluster);
636
if (tech_layer_names == 0) return;
638
for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
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);
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.
649
void tech_initarcwidthoffset(void)
651
REGISTER VARIABLE *var;
652
REGISTER TECHNOLOGY *tech;
654
if (tech_arc_widoff != 0) efree((char *)tech_arc_widoff);
656
tech_arc_widoff = (INTBIG **)emalloc((el_maxtech * (sizeof (INTBIG *))), db_cluster);
657
if (tech_arc_widoff == 0) return;
659
for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
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);
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
673
void registertechnologycache(void (*proc)(void), INTBIG count, INTBIG *variablekeys)
675
REGISTER ROUTINELIST *rl;
678
/* allocate a ROUTINELIST object */
679
rl = (ROUTINELIST *)emalloc(sizeof (ROUTINELIST), db_cluster);
682
/* put this object at the start */
683
rl->nextroutinelist = tech_firstcache;
684
tech_firstcache = rl;
686
/* insert the data and run the routine */
691
rl->variablekeys = (INTBIG *)emalloc(count * SIZEOFINTBIG, db_cluster);
692
for(i=0; i<count; i++) rl->variablekeys[i] = variablekeys[i];
698
* routine called once at initialization to register the database
699
* functions that cache technology-related variables
701
void db_inittechcache(void)
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;
726
registertechnologycache(tech_initmaxdrcsurround, 20, keys);
728
keys[0] = db_tech_node_width_offset_key;
729
registertechnologycache(tech_initnodesizeoffset, 1, keys);
731
keys[0] = db_tech_layer_function_key;
732
registertechnologycache(tech_initlayerfunction, 1, keys);
734
keys[0] = db_tech_layer_names_key;
735
registertechnologycache(tech_initlayername, 1, keys);
737
keys[0] = db_tech_arc_width_offset_key;
738
registertechnologycache(tech_initarcwidthoffset, 1, keys);
742
* Routine called when key "keyval" on a technology changes.
744
void changedtechnologyvariable(INTBIG keyval)
746
REGISTER ROUTINELIST *rl;
749
for(rl = tech_firstcache; rl != NOROUTINELIST; rl = rl->nextroutinelist)
751
for(i=0; i<rl->count; i++)
753
if (rl->variablekeys[i] == keyval)
762
/******************** NODEINST DESCRIPTION ********************/
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).
770
INTBIG nodepolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win)
772
REGISTER INTBIG pindex, count, reasonablecount, cutcount, displayablepolys;
775
REGISTER NODEPROTO *np;
778
tech_curwindowpart = win;
779
pindex = np->primindex;
782
if (reasonable != 0) *reasonable = 0;
786
/* if the technology has its own routine, use it */
787
if (np->tech->nodepolys != 0)
789
count = (*(np->tech->nodepolys))(ni, reasonable, win);
793
thistn = np->tech->nodeprotos[pindex-1];
794
reasonablecount = count = thistn->layercount;
795
switch (thistn->special)
798
cutcount = tech_moscutcount(ni, thistn->f1, thistn->f2, thistn->f3, thistn->f4, &fewer);
799
count += cutcount - 1;
800
reasonablecount += fewer - 1;
803
reasonablecount = count = tech_inittrans(count, ni);
807
/* zero the count if this node is not to be displayed */
808
if ((ni->userbits&WIPED) != 0) reasonablecount = count = 0; else
810
/* zero the count if this node erases when connected to 1 or 2 arcs */
811
if ((np->userbits&WIPEON1OR2) != 0)
813
if (tech_pinusecount(ni, win)) reasonablecount = count = 0;
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;
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).
832
INTBIG nodeEpolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win)
834
REGISTER INTBIG pindex, count, reasonablecount, cutcount;
836
REGISTER TECH_NODES *thistn;
838
pindex = ni->proto->primindex;
839
tech_curwindowpart = win;
842
if (reasonable != 0) *reasonable = 0;
846
/* if the technology has its own routine, use it */
847
if (ni->proto->tech->nodeEpolys != 0)
849
count = (*(ni->proto->tech->nodeEpolys))(ni, reasonable, win);
853
thistn = ni->proto->tech->nodeprotos[pindex-1];
854
reasonablecount = count = thistn->layercount;
855
switch (thistn->special)
858
cutcount = tech_moscutcount(ni, thistn->f1, thistn->f2, thistn->f3, thistn->f4, &fewer);
859
count += cutcount - 1;
860
reasonablecount += fewer - 1;
863
reasonablecount = count = tech_inittrans(thistn->f1, ni);
866
if (reasonable != 0) *reasonable = reasonablecount;
871
* routine to report the shape of graphical polygon "box" of primitive
872
* nodeinst "ni". The polygon is returned in "poly".
874
void shapenodepoly(NODEINST *ni, INTBIG box, POLYGON *poly)
877
REGISTER TECH_PORTS *p;
878
REGISTER INTBIG pindex, count;
879
REGISTER NODEPROTO *np;
880
REGISTER INTBIG lambda;
881
REGISTER TECH_NODES *thistn;
884
pindex = np->primindex;
885
if (pindex == 0) return;
886
poly->tech = np->tech;
888
/* if the technology has its own routine, use it */
889
if (np->tech->shapenodepoly != 0)
891
(*(np->tech->shapenodepoly))(ni, box, poly);
895
/* handle displayable variables */
896
if (box >= tech_realpolys)
898
(void)tech_filldisplayablenvar(ni, poly, tech_curwindowpart, 0);
902
thistn = np->tech->nodeprotos[pindex-1];
903
lambda = lambdaofnode(ni);
904
switch (thistn->special)
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);
913
count = thistn->layercount - 1;
916
lay = &thistn->layerlist[count];
917
tech_moscutpoly(ni, box-count, lay->points);
918
tech_fillpoly(poly, lay, ni, lambda, FILLED);
923
lay = &thistn->layerlist[box];
924
tech_fillpoly(poly, lay, ni, lambda, FILLED);
928
poly->desc = np->tech->layers[poly->layer];
932
* routine to report the shape of electrical polygon "box" of primitive
933
* nodeinst "ni". The polygon is returned in "poly".
935
void shapeEnodepoly(NODEINST *ni, INTBIG box, POLYGON *poly)
938
REGISTER INTBIG pindex, count;
939
REGISTER NODEPROTO *np;
940
REGISTER INTBIG lambda;
941
REGISTER TECH_NODES *thistn;
944
pindex = np->primindex;
945
if (pindex == 0) return;
946
poly->tech = np->tech;
948
/* if the technology has its own routine, use it */
949
if (np->tech->shapeEnodepoly != 0)
951
(*(np->tech->shapeEnodepoly))(ni, box, poly);
955
thistn = np->tech->nodeprotos[pindex-1];
956
lambda = lambdaofnode(ni);
957
switch (thistn->special)
960
lay = &((TECH_POLYGON *)thistn->ele)[box];
961
tech_fillpoly(poly, lay, ni, lambda, FILLED);
965
tech_filltrans(poly, &lay, thistn->ele, ni, lambda, box, (TECH_PORTS *)0);
969
count = thistn->layercount - 1;
972
lay = &thistn->layerlist[count];
973
tech_moscutpoly(ni, box-count, lay->points);
974
tech_fillpoly(poly, lay, ni, lambda, FILLED);
979
lay = &thistn->layerlist[box];
980
tech_fillpoly(poly, lay, ni, lambda, FILLED);
984
/* handle port prototype association */
985
if (lay->portnum < 0) poly->portproto = NOPORTPROTO; else
986
poly->portproto = thistn->portlist[lay->portnum].addr;
988
poly->desc = np->tech->layers[poly->layer];
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.
997
void nodesizeoffset(NODEINST *ni, INTBIG *lx, INTBIG *ly, INTBIG *hx, INTBIG *hy)
999
REGISTER NODEPROTO *np;
1002
if (np->primindex == 0) { *lx = *ly = *hx = *hy = 0; return; }
1004
/* if the technology has its own routine, use it */
1005
if (np->tech->nodesizeoffset != 0)
1007
(*(np->tech->nodesizeoffset))(ni, lx, ly, hx, hy);
1011
/* use value from prototype */
1012
tech_nodeprotosizeoffset(ni->proto, lx, ly, hx, hy, lambdaofnode(ni));
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.
1021
void nodeprotosizeoffset(NODEPROTO *np, INTBIG *lx, INTBIG *ly, INTBIG *hx, INTBIG *hy)
1023
tech_nodeprotosizeoffset(np, lx, ly, hx, hy, el_curlib->lambda[np->tech->techindex]);
1027
* support routine for "nodesizeoffset" and "nodeprotosizeoffset" to report
1028
* the acutal size offsets of a node prototype.
1030
void tech_nodeprotosizeoffset(NODEPROTO *np, INTBIG *lx, INTBIG *ly, INTBIG *hx, INTBIG *hy,
1033
REGISTER INTBIG *base, *addr;
1035
*lx = *ly = *hx = *hy = 0;
1036
if (np->primindex == 0) return;
1038
/* make sure cache of information is valid */
1039
if (tech_node_widoff == 0)
1041
tech_initnodesizeoffset();
1042
if (tech_node_widoff == 0) return;
1045
addr = tech_node_widoff[np->tech->techindex];
1046
if (addr == 0) return;
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;
1056
* routine to return the function code for nodeinst "ni" (see "efunction.h").
1058
INTBIG nodefunction(NODEINST *ni)
1060
REGISTER INTBIG type;
1062
if (ni->proto->primindex == 0) return(NPUNKNOWN);
1063
type = (ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH;
1066
case NPCAPAC: /* capacitor */
1067
switch (ni->userbits&NTECHBITS)
1069
case CAPACNORM: type = NPCAPAC; break; /* Capacitor is normal */
1070
case CAPACELEC: type = NPECAPAC; break; /* Capacitor is Electrolytic */
1074
case NPDIODE: /* diode */
1075
switch (ni->userbits&NTECHBITS)
1077
case DIODENORM: type = NPDIODE; break; /* Diode is normal */
1078
case DIODEZENER: type = NPDIODEZ; break; /* Diode is Zener */
1082
case NPTRANS: /* undefined transistor: look at its transistor type */
1083
switch (ni->userbits&NTECHBITS)
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 */
1097
case NPTRANS4: /* undefined 4-port-transistor: look at its transistor type */
1098
switch (ni->userbits&NTECHBITS)
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 */
1112
case NPTLINE: /* two-port device: look for more information */
1113
switch (ni->userbits&NTECHBITS)
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 */
1126
/* these must match the "define"s in "efunction.h" */
1129
char *nodefunname; /* node function name */
1130
char *shortfunname; /* short node function name */
1131
char *constantfunname; /* actual code name */
1134
static NODEFUNCTION db_nodefunname[] =
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 */
1194
* routine to return the name of node "ni" with function "fun"
1196
char *nodefunctionname(INTBIG fun, NODEINST *ni)
1198
if (fun == NPTRANSREF && ni != NONODEINST)
1201
(void)formatinfstr(_("Transistor-%s"), ni->proto->primname);
1202
return(returninfstr());
1204
if (fun < 0 || fun >= MAXNODEFUNCTION) return("");
1205
return(_(db_nodefunname[fun].nodefunname));
1209
* routine to return the short name of node function "fun"
1211
char *nodefunctionshortname(INTBIG fun)
1213
if (fun < 0 || fun >= MAXNODEFUNCTION) return("");
1214
return(_(db_nodefunname[fun].shortfunname));
1218
* routine to return the constant name of node function "fun"
1220
char *nodefunctionconstantname(INTBIG fun)
1222
if (fun < 0 || fun >= MAXNODEFUNCTION) return("");
1223
return(db_nodefunname[fun].constantfunname);
1227
* routine to tell whether geometry module "pos" points to a field-effect
1228
* transtor. Returns true if so.
1230
BOOLEAN isfet(GEOM *pos)
1232
REGISTER INTBIG fun;
1234
if (!pos->entryisnode) return(FALSE);
1235
fun = nodefunction(pos->entryaddr.ni);
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:
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
1258
void transistorsize(NODEINST *ni, INTBIG *length, INTBIG *width)
1260
INTBIG lx, ly, hx, hy;
1261
REGISTER INTBIG count, i;
1262
REGISTER INTBIG fx, fy, tx, ty, lambda;
1264
REGISTER VARIABLE *var, *varl, *varw;
1266
*length = *width = -1;
1267
switch ((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH)
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:
1277
if (var != NOVARIABLE)
1279
/* serpentine transistor: compute path length */
1281
count = getlength(var) / 2;
1282
for(i=1; i<count; i++)
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);
1291
var = getvalkey((INTBIG)ni, VNODEINST, VFRACT, el_transistor_width_key);
1292
if (var != NOVARIABLE) *length = var->addr * lambdaofnode(ni)/WHOLE; else
1294
nodesizeoffset(ni, &lx, &ly, &hx, &hy);
1295
*length = ni->proto->highy-hy - (ni->proto->lowy+ly);
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);
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)
1313
if (varl != NOVARIABLE)
1315
pt = describevariable(varl, -1, -1);
1316
if (*pt == '-' || *pt == '+' || isdigit(*pt))
1318
*length = muldiv(atofr(pt), lambda, WHOLE);
1321
if (varw != NOVARIABLE)
1323
pt = describevariable(varw, -1, -1);
1324
if (*pt == '-' || *pt == '+' || isdigit(*pt))
1326
*width = muldiv(atofr(pt), lambda, WHOLE);
1331
/* no length/width, look for area */
1332
var = getvalkey((INTBIG)ni, VNODEINST, -1, el_attrkey_area);
1333
if (var != NOVARIABLE)
1335
pt = describevariable(var, -1, -1);
1336
if (*pt == '-' || *pt == '+' || isdigit(*pt))
1338
*length = muldiv(atofr(pt), lambda, WHOLE);
1348
* routine to return the ports of transistor "ni" in "gateleft", "gateright",
1349
* "activetop", and "activebottom". If "gateright" is NOPORTPROTO, there is only
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)
1358
void transistorports(NODEINST *ni, PORTPROTO **gateleft, PORTPROTO **gateright,
1359
PORTPROTO **activetop, PORTPROTO **activebottom)
1361
REGISTER INTBIG fun;
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)
1376
*activebottom = *gateright;
1377
*gateright = NOPORTPROTO;
1379
*activebottom = (*gateright)->nextportproto;
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.
1391
void getarcdegrees(NODEINST *ni, double *startoffset, double *endangle)
1393
REGISTER VARIABLE *var;
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)
1403
*endangle = (double)var->addr * EPI / 1800.0;
1406
if ((var->type&(VTYPE|VISARRAY)) == (VFLOAT|VISARRAY))
1408
sof = ((float *)var->addr)[0];
1409
eaf = ((float *)var->addr)[1];
1410
*startoffset = (double)sof;
1411
*endangle = (double)eaf;
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.
1424
void setarcdegrees(NODEINST *ni, double startoffset, double endangle)
1426
REGISTER INTBIG angle;
1427
REGISTER double rangle;
1430
if (ni->proto != art_circleprim && ni->proto != art_thickcircleprim) return;
1431
if (startoffset == 0.0 && endangle == 0.0)
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);
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)
1443
(void)setvalkey((INTBIG)ni, VNODEINST, art_degreeskey, angle, VINTEGER);
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));
1452
updategeom(ni->geom, ni->parent);
1453
db_setchangefacet(ni->parent);
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).
1461
void getarcendpoints(NODEINST *ni, double startoffset, double endangle, INTBIG *fx, INTBIG *fy,
1462
INTBIG *tx, INTBIG *ty)
1464
REGISTER INTBIG cx, cy, radius;
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)
1472
startoffset = 1.5 * EPI - startoffset - endangle;
1473
if (startoffset < 0.0) startoffset += EPI * 2.0;
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);
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.
1486
NODEPROTO *getpurelayernode(TECHNOLOGY *tech, INTBIG layer, INTBIG function)
1488
REGISTER NODEPROTO *np;
1489
REGISTER NODEINST *ni;
1490
REGISTER INTBIG i, fun;
1491
static POLYGON *poly = NOPOLYGON;
1494
if (poly == NOPOLYGON) poly = allocstaticpolygon(4, db_cluster);
1497
ni->lowx = ni->highx = 0;
1498
ni->lowy = ni->highy = 0;
1499
for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1501
if (((np->userbits&NFUNCTION) >> NFUNCTIONSH) != NPNODE) continue;
1503
i = nodepolys(ni, 0, NOWINDOWPART);
1504
if (i != 1) continue;
1505
shapenodepoly(ni, 0, poly);
1508
if (poly->layer == layer) return(np);
1511
fun = layerfunction(tech, poly->layer);
1512
if ((fun&(LFTYPE|LFPTYPE|LFNTYPE)) == function) return(np);
1515
return(NONODEPROTO);
1518
/******************** PORT DESCRIPTION ********************/
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]).
1526
void shapeportpoly(NODEINST *ni, PORTPROTO *pp, POLYGON *poly, BOOLEAN purpose)
1528
REGISTER INTBIG pindex;
1529
REGISTER TECH_NODES *thistn;
1530
XARRAY localtran, tempt1, tempt2, *t1, *t2, *swapt;
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
1536
while (ni->proto->primindex == 0)
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)
1545
makerot(ni, localtran);
1546
transmult(localtran, *t1, *t2);
1547
swapt = t1; t1 = t2; t2 = swapt;
1551
/* if the technology has its own routine, use it */
1552
if (ni->proto->tech->shapeportpoly != 0)
1554
(*(ni->proto->tech->shapeportpoly))(ni, pp, poly, *t1, purpose);
1558
pindex = ni->proto->primindex;
1559
thistn = ni->proto->tech->nodeprotos[pindex-1];
1560
switch (thistn->special)
1563
tech_filltransport(ni, pp, poly, *t1, thistn, thistn->f2, thistn->f3,
1564
thistn->f4, thistn->f5, thistn->f6);
1568
tech_fillportpoly(ni, pp, poly, *t1, thistn, CLOSED);
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".
1577
void shapetransportpoly(NODEINST *ni, PORTPROTO *pp, POLYGON *poly, XARRAY trans)
1579
REGISTER INTBIG pindex;
1580
REGISTER TECH_NODES *thistn;
1582
/* if the technology has its own routine, use it */
1583
if (ni->proto->tech->shapeportpoly != 0)
1585
(*(ni->proto->tech->shapeportpoly))(ni, pp, poly, trans, FALSE);
1589
pindex = ni->proto->primindex;
1590
thistn = ni->proto->tech->nodeprotos[pindex-1];
1591
switch (thistn->special)
1594
tech_filltransport(ni, pp, poly, trans, thistn, thistn->f2, thistn->f3,
1595
thistn->f4, thistn->f5, thistn->f6);
1599
tech_fillportpoly(ni, pp, poly, trans, thistn, CLOSED);
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"
1609
void portposition(NODEINST *ni, PORTPROTO *pp, INTBIG *x, INTBIG *y)
1611
static POLYGON *poly = NOPOLYGON;
1613
/* make sure there is a polygon */
1614
if (poly == NOPOLYGON) poly = allocstaticpolygon(4, db_cluster);
1616
/* get the polygon describing the port */
1617
shapeportpoly(ni, pp, poly, FALSE);
1619
/* determine the center of the polygon */
1620
getcenter(poly, x, y);
1624
* routine to return true if port "pp" is a power port
1626
BOOLEAN portispower(PORTPROTO *pp)
1628
if ((pp->userbits&STATEBITS) == PWRPORT) return(TRUE);
1629
if ((pp->userbits&STATEBITS) != 0) return(FALSE);
1630
if (portisnamedpower(pp)) return(TRUE);
1635
* routine to return true if port "pp" has a power port name
1637
BOOLEAN portisnamedpower(PORTPROTO *pp)
1640
REGISTER INTBIG len;
1642
for(pt = pp->protoname; *pt != 0; pt++)
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);
1653
if (namesamen(pt, "power", 5) == 0) return(TRUE);
1660
* routine to return true if port "pp" is a ground port
1662
BOOLEAN portisground(PORTPROTO *pp)
1664
if ((pp->userbits&STATEBITS) == GNDPORT) return(TRUE);
1665
if ((pp->userbits&STATEBITS) != 0) return(FALSE);
1666
if (portisnamedground(pp)) return(TRUE);
1671
* routine to return true if port "pp" has a ground port name
1673
BOOLEAN portisnamedground(PORTPROTO *pp)
1676
REGISTER INTBIG len;
1678
for(pt = pp->protoname; *pt != 0; pt++)
1683
if (namesamen(pt, "gnd", 3) == 0) return(TRUE);
1684
if (namesamen(pt, "vss", 3) == 0) return(TRUE);
1688
if (namesamen(pt, "ground", 6) == 0) return(TRUE);
1694
/******************** ARCINST DESCRIPTION ********************/
1697
* routine to report the number of distinct polygons used to compose
1698
* primitive arcinst "ai".
1700
INTBIG arcpolys(ARCINST *ai, WINDOWPART *win)
1703
REGISTER TECHNOLOGY *tech;
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));
1710
/* reset negated bit if set and not allowed */
1711
if ((tech->userbits&NONEGATEDARCS) != 0 && (ai->userbits&ISNEGATED) != 0)
1712
tech_resetnegated(ai);
1714
/* get number of polygons in the arc */
1715
i = tech->arcprotos[ai->proto->arcindex]->laycount;
1717
/* add one layer if arc is directional and technology allows it */
1718
if ((tech->userbits&NODIRECTIONALARCS) == 0 && (ai->userbits&ISDIRECTIONAL) != 0) i++;
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)
1725
/* add in displayable variables */
1727
i += tech_displayableavars(ai, win);
1732
* routine to describe polygon number "box" of arcinst "ai". The description
1733
* is placed in the polygon "poly".
1735
void shapearcpoly(ARCINST *ai, INTBIG box, POLYGON *poly)
1737
REGISTER INTBIG pindex;
1738
REGISTER ARCPROTO *ap;
1739
REGISTER TECHNOLOGY *tech;
1740
REGISTER TECH_ARCLAY *thista;
1742
/* if the technology has its own routine, use it */
1746
if (tech->shapearcpoly != 0)
1748
(*(tech->shapearcpoly))(ai, box, poly);
1752
/* handle displayable variables */
1753
if (box >= tech_realpolys)
1755
(void)tech_filldisplayableavar(ai, poly, tech_curwindowpart, 0);
1759
pindex = ap->arcindex;
1760
if (box >= tech->arcprotos[pindex]->laycount) tech_makearrow(ai, poly); else
1762
thista = &tech->arcprotos[pindex]->list[box];
1763
makearcpoly(ai->length, ai->width-thista->off*lambdaofarc(ai)/WHOLE, ai, poly,
1765
poly->layer = thista->lay;
1766
poly->desc = tech->layers[poly->layer];
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.
1776
BOOLEAN curvedarcoutline(ARCINST *ai, POLYGON *poly, INTBIG style, INTBIG wid)
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;
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);
1788
/* see if the radius can work with these arc ends */
1789
if (abs(radius)*2 < ai->length) return(TRUE);
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);
1798
centerx = x1; centery = y1;
1801
centerx = x2; centery = y2;
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)
1810
anglebase = anglerange;
1813
anglerange -= anglebase;
1814
if (anglerange < 0) anglerange += 3600;
1816
/* determine the number of intervals to use for the arc */
1817
pieces = anglerange;
1818
while (pieces > 16) pieces /= 2;
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;
1826
/* get the inner and outer radii of the arc */
1827
outerradius = radius + wid / 2;
1828
innerradius = outerradius - wid;
1830
/* fill the polygon */
1831
for(i=0; i<=pieces; i++)
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;
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".
1847
void makearcpoly(INTBIG len, INTBIG wid, ARCINST *ai, POLYGON *poly, INTBIG style)
1849
REGISTER INTBIG x1, y1, x2, y2, e1, e2, angle;
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;
1855
/* zero-width polygons are simply lines */
1858
if (poly->limit < 2) (void)extendpolygon(poly, 2);
1860
poly->xv[0] = x1; poly->yv[0] = y1;
1861
poly->xv[1] = x2; poly->yv[1] = y2;
1865
/* determine the end extension on each end */
1867
if ((ai->userbits&NOEXTEND) != 0)
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)
1874
/* shortened arc: compute variable extension */
1875
e1 = tech_getextendfactor(wid, ai->endshrink&0xFFFF);
1876
e2 = tech_getextendfactor(wid, (ai->endshrink>>16)&0xFFFF);
1879
/* make the polygon */
1880
angle = (ai->userbits&AANGLE) >> AANGLESH;
1881
tech_makeendpointpoly(len, wid, angle*10, x1,y1, e1, x2,y2, e2, poly);
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.
1889
INTBIG arcwidthoffset(ARCINST *ai)
1891
REGISTER ARCPROTO *ap;
1893
/* if the technology has its own routine, use it */
1895
if (ap->tech->nodesizeoffset != 0)
1896
return((*(ap->tech->arcwidthoffset))(ai));
1898
return(tech_arcprotowidthoffset(ap, lambdaofarc(ai)));
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.
1906
INTBIG arcprotowidthoffset(ARCPROTO *ap)
1908
return(tech_arcprotowidthoffset(ap, el_curlib->lambda[ap->tech->techindex]));
1912
* support routine for "arcwidthoffset()" and "arcprotowidthoffset()" to return the offset
1913
* between the nominal width of arcproto "ap" and the actual width.
1915
INTBIG tech_arcprotowidthoffset(ARCPROTO *ap, INTBIG lambda)
1917
REGISTER INTBIG *addr;
1919
/* make sure cache of information is valid */
1920
if (tech_arc_widoff == 0)
1922
tech_initarcwidthoffset();
1923
if (tech_arc_widoff == 0) return(0);
1926
addr = tech_arc_widoff[ap->tech->techindex];
1927
if (addr == 0) return(0);
1928
return(addr[ap->arcindex]*lambda/WHOLE);
1932
* routine to return the name of the arc with function "fun"
1934
char *arcfunctionname(INTBIG fun)
1936
static char *arcfunname[] =
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 */
1960
if (fun < 0 || fun > APNONELEC) return("");
1961
return(_(arcfunname[fun]));
1965
* Routine to find the arc that has layer "layer" in technology "tech".
1966
* Returns NOARCPROTO if the layer doesn't have an arc.
1968
ARCPROTO *getarconlayer(INTBIG layer, TECHNOLOGY *tech)
1970
REGISTER ARCPROTO *ap;
1971
REGISTER ARCINST *ai;
1972
static POLYGON *poly = NOPOLYGON;
1975
if (poly == NOPOLYGON) poly = allocstaticpolygon(4, db_cluster);
1978
for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1981
(void)arcpolys(ai, NOWINDOWPART);
1982
shapearcpoly(ai, 0, poly);
1983
if (poly->layer == layer) return(ap);
1988
/******************** LAYER DESCRIPTION ********************/
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.
1994
char *layername(TECHNOLOGY *tech, INTBIG layer)
1996
REGISTER char **addr;
1998
if (layer < 0) return("");
2000
/* make sure cache of information is valid */
2001
if (tech_layer_names == 0)
2003
tech_initlayername();
2004
if (tech_layer_names == 0) return("");
2007
addr = tech_layer_names[tech->techindex];
2008
if (addr == 0) return("");
2009
return(addr[layer]);
2013
* routine to return the function of layer "layer" in technology "tech".
2014
* This routine accesses the "layer_function" variable on the technology objects.
2016
INTBIG layerfunction(TECHNOLOGY *tech, INTBIG layer)
2018
REGISTER INTBIG *addr;
2020
if (layer < 0) return(LFUNKNOWN);
2022
/* make sure cache of information is valid */
2023
if (tech_layer_function == 0)
2025
tech_initlayerfunction();
2026
if (tech_layer_function == 0) return(LFUNKNOWN);
2029
addr = tech_layer_function[tech->techindex];
2030
if (addr == 0) return(LFUNKNOWN);
2031
return(addr[layer]);
2034
/* Routine to return true if the layer function "fun" is metal */
2035
BOOLEAN layerismetal(INTBIG fun)
2038
if (fun == LFMETAL1 || fun == LFMETAL2 || fun == LFMETAL3 ||
2039
fun == LFMETAL4 || fun == LFMETAL5 || fun == LFMETAL6 ||
2040
fun == LFMETAL7 || fun == LFMETAL8) return(TRUE);
2044
/* Routine to return nonzero if the layer function "fun" is polysilicon */
2045
BOOLEAN layerispoly(INTBIG fun)
2048
if (fun == LFPOLY1 || fun == LFPOLY2 || fun == LFPOLY3 || fun == LFGATE) return(TRUE);
2052
/* Routine to return nonzero if the layer function "fun" is a contact/via */
2053
BOOLEAN layeriscontact(INTBIG fun)
2056
if (fun == LFCONTACT1 || fun == LFCONTACT2 || fun == LFCONTACT3 ||
2057
fun == LFCONTACT4 || fun == LFCONTACT5 || fun == LFCONTACT6) return(TRUE);
2062
* routine to return the height of layer function "funct".
2064
INTBIG layerfunctionheight(INTBIG funct)
2066
switch (funct & LFTYPE)
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);
2108
* Routine to return the non-pseudo layer associated with layer "layer" in
2109
* technology "tech".
2111
INTBIG nonpseudolayer(INTBIG layer, TECHNOLOGY *tech)
2113
REGISTER INTBIG fun, ofun, i, j;
2115
if (tech != db_convertpseudotech)
2117
if (db_convertpseudoarray != 0) efree((char *)db_convertpseudoarray);
2118
db_convertpseudoarray = (INTBIG *)emalloc(tech->layercount * SIZEOFINTBIG, db_cluster);
2119
if (db_convertpseudoarray == 0)
2121
db_convertpseudotech = NOTECHNOLOGY;
2124
for(i=0; i<tech->layercount; i++)
2126
db_convertpseudoarray[i] = i;
2127
fun = layerfunction(tech, i);
2128
if ((fun&LFPSEUDO) == 0) continue;
2129
for(j=0; j<tech->layercount; j++)
2131
ofun = layerfunction(tech, j);
2132
if (ofun == (fun & ~LFPSEUDO)) break;
2134
if (j < tech->layercount) db_convertpseudoarray[i] = j;
2136
db_convertpseudotech = tech;
2138
return(db_convertpseudoarray[layer]);
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
2146
BOOLEAN get3dfactors(TECHNOLOGY *tech, INTBIG layer, INTBIG *height, INTBIG *thickness)
2148
static BOOLEAN heightsetup = FALSE;
2149
REGISTER TECHNOLOGY *itech;
2150
REGISTER VARIABLE *varh, *vart;
2152
/* make sure that every technology has layer height information */
2156
tech_techlayer3dheightkey = makekey("TECH_layer_3dheight");
2157
tech_techlayer3dthicknesskey = makekey("TECH_layer_3dthickness");
2158
for(itech = el_technologies; itech != NOTECHNOLOGY; itech = itech->nexttechnology)
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);
2167
if (tech != tech_3dcurtech)
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)
2176
tech_3dcurtech = NOTECHNOLOGY;
2179
tech_3dcurthicknessarray = (INTBIG *)vart->addr;
2180
tech_3dcurheightarray = (INTBIG *)varh->addr;
2182
if (layer < 0 || layer >= tech->layercount) return(TRUE);
2184
*thickness = tech_3dcurthicknessarray[layer];
2185
*height = tech_3dcurheightarray[layer];
2189
void set3dheight(TECHNOLOGY *tech, INTBIG *depth)
2191
setvalkey((INTBIG)tech, VTECHNOLOGY, tech_techlayer3dheightkey, (INTBIG)depth,
2192
VINTEGER|VISARRAY|(tech->layercount<<VLENGTHSH));
2193
tech_3dcurtech = NOTECHNOLOGY;
2196
void set3dthickness(TECHNOLOGY *tech, INTBIG *thickness)
2198
setvalkey((INTBIG)tech, VTECHNOLOGY, tech_techlayer3dthicknesskey, (INTBIG)thickness,
2199
VINTEGER|VISARRAY|(tech->layercount<<VLENGTHSH));
2200
tech_3dcurtech = NOTECHNOLOGY;
2204
* Routine to return true if layers "layer1" and "layer2" in technology "tech"
2205
* should be considered equivalent for the purposes of cropping.
2207
BOOLEAN samelayer(TECHNOLOGY *tech, INTBIG layer1, INTBIG layer2)
2209
static TECHNOLOGY *layertabtech = NOTECHNOLOGY;
2210
REGISTER INTBIG countsquared, i, first, second;
2213
if (layer1 == layer2) return(TRUE);
2214
if (layer1 < 0 || layer2 < 0) return(FALSE);
2215
if (tech == NOTECHNOLOGY) return(FALSE);
2216
if (tech != layertabtech)
2218
if (tech_equivtable != 0) efree((char *)tech_equivtable);
2219
tech_equivtable = 0;
2220
equivlist = (INTBIG *)asktech(tech, "get-layer-equivalences");
2223
countsquared = tech->layercount * tech->layercount;
2224
tech_equivtable = (BOOLEAN *)emalloc(countsquared * (sizeof (BOOLEAN)),
2226
if (tech_equivtable == 0) return(FALSE);
2227
for(i=0; i<countsquared; i++) tech_equivtable[i] = FALSE;
2228
while (*equivlist >= 0)
2230
first = *equivlist++;
2231
second = *equivlist++;
2232
tech_equivtable[first*tech->layercount + second] = TRUE;
2233
tech_equivtable[second*tech->layercount + first] = TRUE;
2236
layertabtech = tech;
2238
if (tech_equivtable == 0) return(FALSE);
2239
return(tech_equivtable[layer1*tech->layercount + layer2]);
2243
* Routine to establish default layer height and thickness for
2244
* technology "tech".
2246
void tech_3ddefaultlayerheight(TECHNOLOGY *tech)
2248
REGISTER INTBIG *layerheight, *layerthickness, i, funct;
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++)
2254
funct = layerfunction(tech, i) & LFTYPE;
2255
layerheight[i] = layerfunctionheight(funct);
2256
layerthickness[i] = 0;
2257
if (layeriscontact(funct)) layerthickness[i] = 2;
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);
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.
2277
INTBIG tech_getdrcmindistance(TECHNOLOGY *tech, INTBIG layer1, INTBIG layer2,
2278
BOOLEAN connected, INTBIG wide, BOOLEAN multicut, INTBIG *edge, char **rule)
2280
REGISTER INTBIG pindex, temp, *addr, *edgeaddr, *multiaddr, *wideaddr, ti, dist;
2281
REGISTER char **rules, **edgerules, **multirules, **widerules;
2283
if (layer1 < 0 || layer2 < 0) return(XX);
2285
/* make sure cache of information is valid */
2286
ti = tech->techindex;
2287
multiaddr = wideaddr = 0;
2290
if (tech_drcconndistance == 0)
2292
tech_initmaxdrcsurround();
2293
if (tech_drcconndistance == 0) return(XX);
2295
addr = tech_drcconndistance[ti];
2296
rules = tech_drccondistancerule[ti];
2300
wideaddr = tech_drcconndistancew[ti];
2301
widerules = tech_drccondistancewrule[ti];
2305
multiaddr = tech_drcconndistancem[ti];
2306
multirules = tech_drccondistancemrule[ti];
2310
if (tech_drcuncondistance == 0)
2312
tech_initmaxdrcsurround();
2313
if (tech_drcuncondistance == 0) return(XX);
2315
addr = tech_drcuncondistance[ti];
2316
rules = tech_drcuncondistancerule[ti];
2317
edgeaddr = tech_drcedgedistance[ti];
2318
edgerules = tech_drcedgedistancerule[ti];
2321
wideaddr = tech_drcuncondistancew[ti];
2322
widerules = tech_drcuncondistancewrule[ti];
2326
multiaddr = tech_drcuncondistancem[ti];
2327
multirules = tech_drcuncondistancemrule[ti];
2330
if (addr == 0 && edgeaddr == 0) return(XX);
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;
2337
/* presume the standard rule */
2339
dist = addr[pindex];
2340
if (edgeaddr != 0 && edgeaddr[pindex] > dist)
2342
dist = edgeaddr[pindex];
2349
if (rules != 0 && rules[pindex][0] != 0)
2350
*rule = rules[pindex];
2353
/* see if the multi-rule is there and is worse */
2354
if (multiaddr != 0 && multiaddr[pindex] > dist)
2356
dist = multiaddr[pindex];
2361
if (multirules != 0 && multirules[pindex][0] != 0)
2362
*rule = multirules[pindex];
2366
/* see if the wide-rule is there and is worse */
2367
if (wideaddr != 0 && wideaddr[pindex] > dist)
2369
dist = wideaddr[pindex];
2374
if (widerules != 0 && widerules[pindex][0] != 0)
2375
*rule = widerules[pindex];
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.
2388
INTBIG maxdrcsurround(TECHNOLOGY *tech, LIBRARY *lib, INTBIG layer)
2390
REGISTER INTBIG i, *addr;
2392
if (layer < 0 || layer >= tech->layercount) return(XX);
2394
/* make sure cache of information is valid */
2395
if (tech_drcmaxdistances == 0)
2397
tech_initmaxdrcsurround();
2398
if (tech_drcmaxdistances == 0) return(XX);
2401
addr = tech_drcmaxdistances[tech->techindex];
2402
if (addr == 0) return(XX);
2404
if (i < 0) return(XX);
2405
i = i*lib->lambda[tech->techindex]/WHOLE;
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.
2416
INTBIG drcmindistance(TECHNOLOGY *tech, LIBRARY *lib, INTBIG layer1, INTBIG size1,
2417
INTBIG layer2, INTBIG size2, BOOLEAN connected, BOOLEAN multicut, INTBIG *edge, char **rule)
2419
REGISTER INTBIG i, widerules, widelimit, lambda;
2421
/* determine whether or not wide rules are to be used */
2423
lambda = lib->lambda[tech->techindex];
2424
widelimit = tech_drcwidelimit[tech->techindex] * lambda / WHOLE;
2425
if (size1 > widelimit || size2 > widelimit) widerules = 1;
2427
/* get the un-scaled distance */
2428
i = tech_getdrcmindistance(tech, layer1, layer2, connected, widerules, multicut, edge, rule);
2430
/* scale result for current lambda value */
2431
if (i > 0) i = i * lambda / WHOLE;
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).
2440
INTBIG drcminwidth(TECHNOLOGY *tech, LIBRARY *lib, INTBIG layer, char **rule)
2442
REGISTER INTBIG *addr;
2443
REGISTER char **rules;
2445
/* make sure cache of information is valid */
2446
if (tech_drcminwidth == 0)
2448
tech_initmaxdrcsurround();
2449
if (tech_drcminwidth == 0) return(0);
2452
addr = tech_drcminwidth[tech->techindex];
2453
rules = tech_drcminwidthrule[tech->techindex];
2454
if (addr == 0) return(XX);
2458
if (rules != 0 && rules[layer][0] != 0)
2459
*rule = rules[layer];
2461
return(addr[layer]*lib->lambda[tech->techindex]/WHOLE);
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).
2469
void drcminnodesize(NODEPROTO *np, LIBRARY *lib, INTBIG *sizex, INTBIG *sizey, char **rule)
2471
REGISTER INTBIG *addr, index;
2472
REGISTER char **rules;
2473
REGISTER TECHNOLOGY *tech;
2475
/* default answers */
2476
*sizex = *sizey = XX;
2477
if (rule != 0) *rule = 0;
2479
/* make sure cache of information is valid */
2480
if (tech_drcminnodesize == 0)
2482
tech_initmaxdrcsurround();
2483
if (tech_drcminnodesize == 0) return;
2487
index = np->primindex - 1;
2488
if (index < 0) return;
2489
addr = tech_drcminnodesize[tech->techindex];
2490
rules = tech_drcminnodesizerule[tech->techindex];
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;
2500
/******************** MATHEMATICS ********************/
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.
2519
void subrange(INTBIG low, INTBIG high, INTBIG lowmul, INTBIG lowsum, INTBIG highmul,
2520
INTBIG highsum, INTBIG *newlow, INTBIG *newhigh, INTBIG lambda)
2522
REGISTER INTBIG total, size;
2525
if ((total = low + high) < 0) total--;
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".
2533
if (size > 17895697)
2535
*newlow = total/2 + muldiv(size, lowmul, WHOLE) + lowsum*lambda/WHOLE;
2536
*newhigh = (total+1)/2 + muldiv(size, highmul, WHOLE) + highsum*lambda/WHOLE;
2539
*newlow = total/2 + size*lowmul/WHOLE + lowsum*lambda/WHOLE;
2540
*newhigh = (total+1)/2 + size*highmul/WHOLE + highsum*lambda/WHOLE;
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.
2550
INTBIG getrange(INTBIG low, INTBIG high, INTBIG mul,INTBIG sum, INTBIG lambda)
2552
REGISTER INTBIG total;
2555
if (total < 0) total--;
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".
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);