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