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