1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: network.cpp
6  * Network tool: module for maintenance of connectivity information
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 "network.h"
34 #include "database.h"
35 #include "egraphics.h"
36 #include "sim.h"
37 #include "tecschem.h"
38 #include "efunction.h"
39 #include "edialogs.h"
40 #include "usr.h"
41 #include "usrdiacom.h"
42 #include <math.h>
43 #include <ctype.h>
44 
45 /* variables */
46        TOOL       *net_tool;					/* the Network tool object */
47 static TOOL       *net_current_source;			/* the tool currently making changes */
48 static BOOLEAN     net_debug;					/* true for debugging */
49 static BOOLEAN     net_globalwork;				/* nonzero when doing major evaluation */
50 static INTBIG      net_optionskey;				/* key for "NET_options" */
51        INTBIG      net_node_abbrev_key;			/* key for "NET_node_abbreviations" */
52        INTBIG      net_node_abbrevlen_key;		/* key for "NET_node_abbreviation_length" */
53        INTBIG      net_unifystringskey;			/* key for "NET_unify_strings" */
54        INTBIG      net_options;					/* cached value for "NET_options" */
55        INTBIG      net_ncc_optionskey;			/* key for "NET_ncc_options" */
56        INTBIG      net_ncc_comptolerancekey;	/* key for "NET_ncc_component_tolerance" */
57        INTBIG      net_ncc_comptoleranceamtkey;	/* key for "NET_ncc_component_tolerance_amt" */
58        INTBIG      net_ncc_matchkey;			/* key for "NET_ncc_match" */
59        INTBIG      net_ncc_forcedassociationkey;/* key for "NET_ncc_forcedassociation" */
60        INTBIG      net_ncc_processors_key;		/* key for "NET_ncc_num_processors" */
61        INTBIG      net_ncc_function_key;		/* key for "NET_ncc_function" */
62        PNET       *net_pnetfree;
63        PCOMP      *net_pcompfree;
64 static INTBIG      net_mostj = 0;
65 static CHAR      **net_unifystrings;			/* list of string prefixes for unifying networks */
66 static INTBIG      net_unifystringcount;		/* number of strings in "net_unifystrings" */
67 static NETWORK   **net_primnetlist;
68 static void       *net_merge;					/* for polygon merging */
69 static BOOLEAN     net_checkresistorstate;		/* true to check for changes to resistor topology */
70 
71 /* obsolete variables */
72 static INTBIG      net_connect_power_groundkey;	/* key for "NET_connect_PandG" */
73 static INTBIG      net_connect_common_namekey;	/* key for "NET_connect_common" */
74 static INTBIG      net_found_obsolete_variables = 0;	/* nonzero if library had above variables */
75 
76 #define NUMBUSSTRINGBUFFERS 2
77 static INTBIG      net_busbufstringbufferpos = -1;
78 static CHAR      **net_busbufstringsarray[NUMBUSSTRINGBUFFERS];
79 static INTBIG      net_busbufstringcountarray[NUMBUSSTRINGBUFFERS];
80 
81        TRANSISTORINFO   net_transistor_p_gate;		/* info on P transistors connected at gate */
82        TRANSISTORINFO   net_transistor_n_gate;		/* info on N transistors connected at gate */
83        TRANSISTORINFO   net_transistor_p_active;	/* info on P transistors connected at active */
84        TRANSISTORINFO   net_transistor_n_active;	/* info on N transistors connected at active */
85 
86 /* working memory for "net_samenetworkname()" */
87 static INTBIG     net_namecompstringtotal = 0;
88 static CHAR     **net_namecompstrings;
89 
90 /* working memory for "net_nconnect()" */
91 static CHAR      *net_arrayedarcname = 0;
92 
93 /* working memory for "net_addnodename()" */
94 static INTBIG     net_nodenamelisttotal = 0;
95 static INTBIG     net_nodenamelistcount;
96 static CHAR     **net_nodenamelist;
97 
98 /* working memory for "net_addnettolist()" */
99 static INTBIG    net_highnetscount;
100 static INTBIG    net_highnetstotal = 0;
101 static NETWORK **net_highnets;
102 
103 static AREAPERIM *net_firstareaperim;
104 
105 typedef struct Ibuslist
106 {
107 	ARCINST         *ai;
108 	PORTPROTO       *pp;
109 	INTBIG           width;
110 } BUSLIST;
111 
112 static BUSLIST *net_buslists;
113 static INTBIG   net_buslistcount;
114 static INTBIG   net_buslisttotal = 0;
115 
116 
117 #define NOARCCHECK ((ARCCHECK *)-1)
118 
119 typedef struct Iarccheck
120 {
121 	ARCINST *ai;
122 	struct Iarccheck *nextarccheck;
123 } ARCCHECK;
124 
125 ARCCHECK *net_arccheckfree = NOARCCHECK;
126 ARCCHECK *net_firstarccheck;
127 
128 
129 #define NOCLEARNCC ((CLEARNCC *)-1)
130 
131 typedef struct Iclearncc
132 {
133 	NODEPROTO *np;
134 	struct Iclearncc *nextclearncc;
135 } CLEARNCC;
136 
137 CLEARNCC *net_clearnccfree = NOCLEARNCC;
138 CLEARNCC *net_firstclearncc;
139 
140 /*********************** CELL CONNECTIONS ***********************/
141 
142 #ifdef NEWRENUM
143 class NetCellConns;
144 
145 struct NetDrawn
146 {
147 	INTBIG _shallowRoot;
148 	INTBIG _busWidth;
149 	NETWORK *_network;
150 	INTBIG _deepbase;
151 	BOOLEAN _isBus;
152 };
153 
154 class NetCellConns
155 {
156 public:
157 	void* operator new( size_t size );
158 	void* operator new( size_t size, CLUSTER *cluster );
159 	void operator delete( void* obj );
160 #ifndef MACOS
161 	void operator delete( void *obj, CLUSTER *cluster );
162 #endif
163 	NetCellConns( NODEPROTO *np, CLUSTER *cluster );
164 	~NetCellConns();
complicated()165 	BOOLEAN complicated() { return _complicated; };
166 	void compare();
167 	void deepcompare();
168 	void schem();
169 	void makeNetworksSimple();
170 	void printf();
171 private:
172 	void shallowconnect( INTBIG a1, INTBIG a2 );
173 	void shallowfixup();
174 	INTBIG addGlobalname(CHAR *name);
175 	void makeDrawns();
176 	void deepconnectport( INTBIG drawnIndex, NODEINST *ni, NetCellShorts *shorts, INTBIG *pinmap, PORTPROTO *pp);
177 	void deepconnect( INTBIG a1, INTBIG a2 );
178 	void deepjoin( NODEINST *ni );
179 	void deepfixup();
180 	NODEPROTO *_np;
181 	INTBIG _portcount;
182 	INTBIG _arccount;
183 	INTBIG *_shallowmap;
184 	INTBIG _globalcount;
185 	CHAR **_globalnames;
186 	NetDrawn **_shallow2drawn;
187 	INTBIG _drawncount;
188 	NetDrawn *_drawns;
189 	INTBIG _deepmapcount;
190 	INTBIG *_deepmap;
191 	BOOLEAN _complicated;
192 };
193 #endif
194 
195 /*********************** COMMAND PARSING ***********************/
196 
197 #ifndef ALLCPLUSPLUS
198 extern "C"
199 {
200 #endif
201 
202 static COMCOMP net_networkcellp = {NOKEYWORD,topofcells,nextcells,NOPARAMS,
203 	INPUTOPT, x_(" \t"), M_("Cell to re-number (default is current cell)"), 0};
204 static COMCOMP networknodehp = {NOKEYWORD, topofnets, nextnets, NOPARAMS,
205 	INPUTOPT, x_(" \t"), M_("Net to highlight"), 0};
206 static COMCOMP networknodenp = {NOKEYWORD, topofnets, nextnets, NOPARAMS,
207 	INPUTOPT, x_(" \t"), M_("Net whose connections should be listed"), 0};
208 static COMCOMP networknodelp = {NOKEYWORD, topofnets, nextnets, NOPARAMS,
209 	INPUTOPT, x_(" \t"), M_("Net, ALL of whose ports should be listed"), 0};
210 static KEYWORD networkeqnopt[] =
211 {
212 	{x_("include-no-component-nets"),     0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
213 	{x_("check-export-names"),            0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
214 	{x_("check-node-sizes"),              0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
215 	{x_("flatten-hierarchy"),             0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
216 	{x_("recurse"),                       0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
217 	TERMKEY
218 };
219 static COMCOMP networkeqnp = {networkeqnopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
220 	INPUTOPT, x_(" \t"), M_("Network-compare negating option"), 0};
221 static KEYWORD networkeqopt[] =
222 {
223 	{x_("flatten-hierarchy"),             0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
224 	{x_("include-no-component-nets"),     0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
225 	{x_("recurse"),                       0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
226 	{x_("highlight-other"),               0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
227 	{x_("check-export-names"),            0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
228 	{x_("check-node-sizes"),              0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
229 	{x_("pre-analysis"),                  0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
230 #ifdef FORCESUNTOOLS
231 	{x_("analyze-cell"),                  0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
232 #endif
233 	{x_("not"),                           1,{&networkeqnp,NOKEY,NOKEY,NOKEY,NOKEY}},
234 	TERMKEY
235 };
236 COMCOMP net_networkeqp = {networkeqopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
237 	INPUTOPT, x_(" \t"), M_("Network comparing/equating option"), M_("do comparison")};
238 static KEYWORD networkpgopt[] =
239 {
240 	{x_("unify-all-networks"),            0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
241 	{x_("separate-unconnected-networks"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
242 	{x_("identify"),                      0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
243 	{x_("validate"),                      0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
244 	TERMKEY
245 };
246 static COMCOMP networkpgp = {networkpgopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
247 	INPUTOPT, x_(" \t"), M_("Network power and ground equating option"), 0};
248 static KEYWORD networkcnopt[] =
249 {
250 	{x_("unify-always"),             0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
251 	{x_("unify-only-in-schematics"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
252 	TERMKEY
253 };
254 static COMCOMP networkcnp = {networkcnopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
255 	INPUTOPT, x_(" \t"), M_("How to handle networks with the same name"), 0};
256 static KEYWORD networkunopt[] =
257 {
258 	{x_("ascend-numbering"),              0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
259 	{x_("descend-numbering"),             0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
260 	{x_("0-base"),                        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
261 	{x_("1-base"),                        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
262 	TERMKEY
263 };
264 static COMCOMP networkunp = {networkunopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
265 	INPUTOPT, x_(" \t"), M_("Option to handle unnamed busses"), 0};
266 static KEYWORD networkropt[] =
267 {
268 	{x_("ignore"),                        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
269 	{x_("include"),                       0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
270 	TERMKEY
271 };
272 static COMCOMP networkrp = {networkropt, NOTOPLIST, NONEXTLIST, NOPARAMS,
273 	INPUTOPT, x_(" \t"), M_("Option to handle reistors"), 0};
274 static KEYWORD networkopt[] =
275 {
276 	{x_("highlight"),                     1,{&networknodehp,NOKEY,NOKEY,NOKEY,NOKEY}},
277 	{x_("show-equivalent"),               1,{&networknodehp,NOKEY,NOKEY,NOKEY,NOKEY}},
278 	{x_("name-connections"),              1,{&networknodenp,NOKEY,NOKEY,NOKEY,NOKEY}},
279 	{x_("name-cell-objects"),             0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
280 	{x_("name-library-objects"),          0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
281 	{x_("show-geometry"),                 1,{&networknodenp,NOKEY,NOKEY,NOKEY,NOKEY}},
282 	{x_("list-hierarchical-ports"),       1,{&networknodelp,NOKEY,NOKEY,NOKEY,NOKEY}},
283 	{x_("list-ports-below"),              1,{&networknodelp,NOKEY,NOKEY,NOKEY,NOKEY}},
284 	{x_("compare"),                       1,{&net_networkeqp,NOKEY,NOKEY,NOKEY,NOKEY}},
285 	{x_("power-and-ground"),              1,{&networkpgp,NOKEY,NOKEY,NOKEY,NOKEY}},
286 	{x_("like-named-nets"),               1,{&networkcnp,NOKEY,NOKEY,NOKEY,NOKEY}},
287 	{x_("re-number"),                     1,{&net_networkcellp,NOKEY,NOKEY,NOKEY,NOKEY}},
288 	{x_("default-busses"),                1,{&networkunp,NOKEY,NOKEY,NOKEY,NOKEY}},
289 	{x_("resistors"),                     1,{&networkrp,NOKEY,NOKEY,NOKEY,NOKEY}},
290 	{x_("total-re-number"),               0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
291 	{x_("rip-bus"),                       0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
292 	{x_("debug-toggle"),                  0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
293 	{x_("extract"),                       0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
294 	TERMKEY
295 };
296 COMCOMP net_networkp = {networkopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
297 	0, x_(" \t"), M_("Network maintenance"), 0};
298 
299 #ifndef ALLCPLUSPLUS
300 }
301 #endif
302 
303 /* prototypes for local routines */
304 static NETWORK         *net_addglobalnet(NODEPROTO *subcell, INTBIG subindex, NODEPROTO *cell);
305 static INTBIG           net_addnametonet(CHAR*, INTBIG, NETWORK*, ARCINST*, PORTPROTO*, NODEPROTO*);
306 static void             net_addnettolist(NETWORK *net);
307 static BOOLEAN          net_addnodename(CHAR *name);
308 static void             net_addstring(CHAR*, INTBIG*, INTBIG*, CHAR***);
309 static void             net_addtobuslist(ARCINST *ai, PORTPROTO *pp, INTBIG width);
310 static void             net_addtotransistorinfo(TRANSISTORINFO *ti, INTBIG length, INTBIG width);
311 static ARCCHECK        *net_allocarccheck(void);
312 static CLEARNCC        *net_allocclearncc(void);
313 static int              net_buslistwidthascending(const void *e1, const void *e2);
314 static CHAR            *net_busnameofarc(ARCINST *ai);
315 static INTBIG           net_buswidthofarc(ARCINST *ai, NODEINST **ni, PORTPROTO **pp);
316 static void             net_checknetname(NETWORK *net, NetName *nn);
317 static void             net_checkvalidconnection(NODEINST*, ARCINST*);
318 static void             net_cleartransistorinfo(TRANSISTORINFO *ti);
319 static BOOLEAN          net_donconnect(ARCINST *ai, NETWORK *newnetwork, NODEPROTO *np);
320 #ifdef NEWRENUM
321 static void             net_ensurebusses(NETWORK*, NetName*, INTBIG);
322 #else
323 static void             net_ensurebusses(NETWORK*, INTBIG, CHAR**, INTBIG);
324 #endif
325 static void             net_ensuretempbusname(NETWORK *net);
326 static CHAR            *net_findnameinbus(CHAR *wantname, CHAR *busname);
327 static CHAR            *net_findnameofbus(ARCINST *ai, BOOLEAN justbus);
328 static void             net_findportsdown(NETWORK*, NODEPROTO*);
329 static void             net_findportsup(NETWORK*, NODEPROTO*);
330 static void             net_freearccheck(ARCCHECK *ac);
331 static void             net_freeclearncc(CLEARNCC *cn);
332 static void             net_geometrypolygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count);
333 static NETWORK         *net_getunifiednetwork(CHAR *name, NODEPROTO *cell, NETWORK *notthisnet);
334 static void             net_highlightnet(void*, NODEPROTO*, NETWORK*);
335 static void             net_highlightsubnet(void *infstr, NODEPROTO *topnp, NODEINST *ni, XARRAY trans, NETWORK *net);
336 static void             net_initnconnect(NODEPROTO *np);
337 static void             net_insertstring(CHAR *key, INTBIG index, INTBIG *count, INTBIG *stringcount, CHAR ***mystrings);
338 static BOOLEAN          net_isanumber(CHAR *name);
339 static void             net_joinnetworks(NODEINST *ni);
340 static void             net_killnetwork(NETWORK*, NODEPROTO*);
341 static BOOLEAN          net_mergebuswires(NODEINST*);
342 static BOOLEAN          net_mergenet(NETWORK*, NETWORK*);
343 static INTBIG           net_nameallnets(NODEPROTO *np);
344 static INTBIG           net_nameallnodes(NODEPROTO *np, BOOLEAN evenpins);
345 #ifdef NEWRENUM
346 static BOOLEAN          net_namenet(NetName*, NETWORK*);
347 #else
348 static BOOLEAN          net_namenet(CHAR*, NETWORK*);
349 #endif
350 static void             net_ncccellfunctiondlog(void);
351 static NODEPROTO       *net_nccdlgselectedcell(void *dia, INTBIG liblist, INTBIG celllist);
352 static void             net_nccoptionsdlog(void);
353 static BOOLEAN          net_nconnect(ARCINST*, NETWORK*, NODEPROTO*);
354 #ifdef NEWRENUM
355 static BOOLEAN          net_nethasname(NETWORK *net, NetName *netname);
356 #else
357 static BOOLEAN          net_nethasname(NETWORK *net, CHAR *name);
358 #endif
359 static NETWORK         *net_newnetwork(NODEPROTO*);
360 static CHAR            *net_nextcells(void);
361 static CHAR            *net_nextcellswithfunction(void);
362 static void             net_optionsdlog(void);
363 static NETWORK        **net_parsenetwork(CHAR*);
364 static BOOLEAN          net_pconnect(PORTPROTO*);
365 static void             net_propgeometry(NODEPROTO *cell, XARRAY trans, BOOLEAN recurse);
366 static void             net_putarclinkonnet(NETWORK*, ARCINST*);
367 static void             net_putarconnet(ARCINST*, NETWORK*);
368 static void             net_putportonnet(PORTPROTO*, NETWORK*);
369 static void             net_queueclearncc(NODEPROTO *np);
370 static void             net_recacheunifystrings(void);
371 static void             net_recursivelymarkabove(NODEPROTO*);
372 static BOOLEAN          net_recursivelyredo(NODEPROTO*);
373 static void             net_reevaluatecell(NODEPROTO*);
374 static void             net_removebuslinks(NETWORK*);
375 static void             net_removeclearncc(NODEPROTO *np);
376 static void             net_renamenet(CHAR*, CHAR*, NODEPROTO*);
377 static void             net_ripbus(void);
378 static void             net_setglobalnet(INTBIG *special, INTBIG newindex, CHAR *netname, NETWORK *net,
379 							INTBIG characteristics, NODEPROTO *cell);
380 static void             net_setnccoverrides(void *dia);
381 static void             net_showgeometry(NETWORK *net);
382 static void             net_startglobalwork(LIBRARY*);
383 static BOOLEAN          net_takearcfromnet(ARCINST*);
384 static void             net_takearclinkfromnet(ARCINST*, NETWORK*);
385 static BOOLEAN          net_takeportfromnet(PORTPROTO*);
386 static void             net_tellschematics(void);
387 static BOOLEAN          net_topofcells(CHAR **c);
388 static void             net_totalrenumber(LIBRARY*);
389 static INTBIG           net_nccdebuggingdlog(INTBIG options);
390 static void             net_listnccforcedmatches(void);
391 static void             net_removenccforcedmatches(void);
392 
393 /*********************** DATABASE INTERFACE ROUTINES ***********************/
394 
net_init(INTBIG * argc,CHAR1 * argv[],TOOL * thistool)395 void net_init(INTBIG *argc, CHAR1 *argv[], TOOL *thistool)
396 {
397 	Q_UNUSED( argc );
398 	Q_UNUSED( argv );
399 
400 	/* ignore pass 3 initialization */
401 	if (thistool == 0) return;
402 
403 	/* take tool pointer in pass 1 */
404 	if (thistool != NOTOOL)
405 	{
406 		net_tool = thistool;
407 		return;
408 	}
409 
410 	/* initialize flattened network representation */
411 	net_pcompfree = NOPCOMP;
412 	net_pnetfree = NOPNET;
413 
414 	/* debugging off */
415 	net_debug = FALSE;
416 
417 	/* set network options */
418 	net_optionskey = makekey(x_("NET_options"));
419 	nextchangequiet();
420 	net_options = NETDEFBUSBASEDESC;
421 	(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey, net_options, VINTEGER|VDONTSAVE);
422 	net_node_abbrev_key = makekey(x_("NET_node_abbreviations"));
423 	net_node_abbrevlen_key = makekey(x_("NET_node_abbreviation_length"));
424 	net_unifystringskey = makekey(x_("NET_unify_strings"));
425 	net_checkresistorstate = FALSE;
426 	net_unifystringcount = 0;
427 
428 	/* get obsolete variable names */
429 	net_connect_power_groundkey = makekey(x_("NET_connect_PandG"));
430 	net_connect_common_namekey = makekey(x_("NET_connect_common"));
431 
432 	/* set NCC options */
433 	net_ncc_optionskey = makekey(x_("NET_ncc_options"));
434 	nextchangequiet();
435 	(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey,
436 		NCCNOMERGEPARALLEL|NCCDISLOCAFTERMATCH, VINTEGER|VDONTSAVE);
437 	net_ncc_comptolerancekey = makekey(x_("NET_ncc_component_tolerance"));
438 	net_ncc_comptoleranceamtkey = makekey(x_("NET_ncc_component_tolerance_amt"));
439 	net_ncc_matchkey = makekey(x_("NET_ncc_match"));
440 	net_ncc_forcedassociationkey = makekey(x_("NET_ncc_forcedassociation"));
441 	net_ncc_function_key = makekey(x_("NET_ncc_function"));
442 	net_firstclearncc = NOCLEARNCC;
443 
444 	/* node-number primitive ports (now and when technologies change) */
445 	registertechnologycache(net_redoprim, 0, 0);
446 
447 	/* register options dialog */
448 	DiaDeclareHook(x_("nccopt"), &net_networkeqp, net_nccoptionsdlog);
449 	DiaDeclareHook(x_("netopt"), &net_networkp, net_optionsdlog);
450 	DiaDeclareHook(x_("netcelfun"), &net_networkcellp, net_ncccellfunctiondlog);
451 }
452 
net_done(void)453 void net_done(void)
454 {
455 #ifdef DEBUGMEMORY
456 	REGISTER INTBIG i, j, stringcount;
457 	REGISTER CHAR **mystrings;
458 	REGISTER ARCCHECK *ac;
459 	REGISTER CLEARNCC *cn;
460 
461 	if (net_mostj != 0)
462 	{
463 		for(j=0; j<net_mostj; j++) efree((CHAR *)net_primnetlist[j]);
464 		efree((CHAR *)net_primnetlist);
465 		net_mostj = 0;
466 	}
467 	if (net_unifystringcount > 0)
468 	{
469 		for(j=0; j<net_unifystringcount; j++) efree((CHAR *)net_unifystrings[j]);
470 		efree((CHAR *)net_unifystrings);
471 	}
472 
473 	if (net_busbufstringbufferpos >= 0)
474 	{
475 		for(i=0; i<NUMBUSSTRINGBUFFERS; i++)
476 		{
477 			mystrings = net_busbufstringsarray[i];
478 			stringcount = net_busbufstringcountarray[i];
479 			for(j=0; j<stringcount; j++) efree((CHAR *)mystrings[j]);
480 			if (stringcount > 0) efree((CHAR *)mystrings);
481 		}
482 	}
483 	while (net_arccheckfree != NOARCCHECK)
484 	{
485 		ac = net_arccheckfree;
486 		net_arccheckfree = ac->nextarccheck;
487 		efree((CHAR *)ac);
488 	}
489 	while (net_clearnccfree != NOCLEARNCC)
490 	{
491 		cn = net_clearnccfree;
492 		net_clearnccfree = cn->nextclearncc;
493 		efree((CHAR *)cn);
494 	}
495 
496 	if (net_buslisttotal > 0) efree((CHAR *)net_buslists);
497 	if (net_namecompstringtotal > 0) efree((CHAR *)net_namecompstrings);
498 	if (net_arrayedarcname != 0) efree(net_arrayedarcname);
499 	if (net_highnetstotal > 0) efree((CHAR *)net_highnets);
500 	if (net_nodenamelisttotal > 0)
501 	{
502 		for(i=0; i<net_nodenamelisttotal; i++)
503 			if (net_nodenamelist[i] != 0) efree(net_nodenamelist[i]);
504 		efree((CHAR *)net_nodenamelist);
505 	}
506 	net_freediffmemory();
507 	net_freeflatmemory();
508 #endif
509 }
510 
511 /*
512  * routine to associate the primitives ports in each technology with unique
513  * network objects according to connectivity within the node
514  */
net_redoprim(void)515 void net_redoprim(void)
516 {
517 	REGISTER INTBIG j, maxj;
518 	REGISTER PORTPROTO *pp, *spt;
519 	REGISTER TECHNOLOGY *tech;
520 	REGISTER NODEPROTO *np;
521 
522 	/* count the number of network objects that are needed */
523 	maxj = 0;
524 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
525 		for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
526 	{
527 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
528 		{
529 			if ((pp->userbits&PORTNET) == PORTNET)
530 			{
531 				maxj++;
532 				continue;
533 			}
534 			for(spt = np->firstportproto; spt != pp; spt = spt->nextportproto)
535 				if ((pp->userbits&PORTNET) == (spt->userbits&PORTNET))
536 			{
537 				pp->network = spt->network;
538 				break;
539 			}
540 			if (spt == pp) maxj++;
541 		}
542 	}
543 
544 	/* create an array of network objects for the primitives */
545 	if (maxj > net_mostj)
546 	{
547 		if (net_mostj != 0)
548 		{
549 			for(j=0; j<net_mostj; j++) efree((CHAR *)net_primnetlist[j]);
550 			efree((CHAR *)net_primnetlist);
551 			net_mostj = 0;
552 		}
553 		net_primnetlist = (NETWORK **)emalloc(((sizeof (NETWORK *)) * maxj),
554 			net_tool->cluster);
555 		if (net_primnetlist == 0) return;
556 		for(j=0; j<maxj; j++)
557 		{
558 			net_primnetlist[j] = (NETWORK *)emalloc(sizeof (NETWORK), net_tool->cluster);
559 			if (net_primnetlist[j] == 0) return;
560 			net_primnetlist[j]->namecount = 0;
561 			net_primnetlist[j]->tempname = 0;
562 			net_primnetlist[j]->globalnet = -1;
563 			net_primnetlist[j]->buswidth = 1;
564 			net_primnetlist[j]->nextnetwork = NONETWORK;
565 			net_primnetlist[j]->prevnetwork = NONETWORK;
566 			net_primnetlist[j]->networklist = (NETWORK **)NONETWORK;
567 			net_primnetlist[j]->parent = NONODEPROTO;
568 			net_primnetlist[j]->netnameaddr = 0; /* var examine does not check namecount */
569 			net_primnetlist[j]->arccount = 0;
570 			net_primnetlist[j]->refcount = 0;
571 			net_primnetlist[j]->portcount = 0;
572 			net_primnetlist[j]->buslinkcount = 0;
573 			net_primnetlist[j]->numvar = 0;
574 		}
575 		net_mostj = maxj;
576 	}
577 
578 	/* assign unique networks to unconnected primitive ports */
579 	j = 0;
580 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
581 		for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
582 	{
583 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
584 		{
585 			if ((pp->userbits&PORTNET) == PORTNET)
586 			{
587 				pp->network = net_primnetlist[j++];
588 				continue;
589 			}
590 			for(spt = np->firstportproto; spt != pp; spt = spt->nextportproto)
591 				if ((pp->userbits&PORTNET) == (spt->userbits&PORTNET))
592 			{
593 				pp->network = spt->network;
594 				break;
595 			}
596 			if (spt == pp) pp->network = net_primnetlist[j++];
597 		}
598 		if (!np->netd)
599 			np->netd = new (tech->cluster) NetCellPrivate( np, tech->cluster );
600 		np->netd->updateShorts();
601 	}
602 }
603 
net_slice(void)604 void net_slice(void)
605 {
606 	REGISTER VARIABLE *var;
607 	REGISTER CLEARNCC *cn, *nextcn;
608 
609 	if (net_found_obsolete_variables != 0)
610 	{
611 		net_found_obsolete_variables = 0;
612 		var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_connect_power_groundkey);
613 		if (var != NOVARIABLE)
614 			(void)delvalkey((INTBIG)net_tool, VTOOL, net_connect_power_groundkey);
615 		var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_connect_common_namekey);
616 		if (var != NOVARIABLE)
617 			(void)delvalkey((INTBIG)net_tool, VTOOL, net_connect_common_namekey);
618 	}
619 	if (net_checkresistorstate)
620 	{
621 		net_checkresistorstate = FALSE;
622 		net_tellschematics();
623 	}
624 
625 	/* clear NCC cache as requested */
626 	for(cn = net_firstclearncc; cn != NOCLEARNCC; cn = nextcn)
627 	{
628 		nextcn = cn->nextclearncc;
629 		net_nccremovematches(cn->np);
630 		net_freeclearncc(cn);
631 	}
632 	net_firstclearncc = NOCLEARNCC;
633 }
634 
net_examinenodeproto(NODEPROTO * np)635 void net_examinenodeproto(NODEPROTO *np)
636 {
637 	net_reevaluatecell(np);
638 }
639 
net_set(INTBIG count,CHAR * par[])640 void net_set(INTBIG count, CHAR *par[])
641 {
642 	REGISTER NODEPROTO *np;
643 	REGISTER PORTPROTO *pp, *opp;
644 	REGISTER ARCINST *ai;
645 	REGISTER LIBRARY *lib;
646 	REGISTER NETWORK *net, **netlist;
647 	REGISTER INTBIG i, l, total, fun, tr, options, *highsiglist;
648 	BOOLEAN showrequest;
649 	REGISTER CHAR *pt;
650 	REGISTER VARIABLE *var;
651 	NETWORK *mynet[2];
652 	INTBIG x, y, highsigcount;
653 	REGISTER WINDOWPART *w;
654 	REGISTER NODEINST *ni;
655 	REGISTER PORTARCINST *pi;
656 	static CHAR *message[1] = {x_("total-re-number")};
657 	REGISTER void *infstr;
658 
659 	if (count == 0)
660 	{
661 		count = ttygetparam(x_("NETWORK option:"), &net_networkp, MAXPARS, par);
662 		if (count == 0)
663 		{
664 			ttyputerr(M_("Aborted"));
665 			return;
666 		}
667 	}
668 	l = estrlen(pt = par[0]);
669 
670 
671 	if (namesamen(pt, x_("rip-bus"), l) == 0 && l >= 2)
672 	{
673 		net_ripbus();
674 		return;
675 	}
676 
677 	if (namesamen(pt, x_("highlight"), l) == 0 ||
678 		(namesamen(pt, x_("show-equivalent"), l) == 0 && l > 5))
679 	{
680 		/* if this was associated, show that */
681 		if (net_equate(0) == 0) return;
682 
683 		np = getcurcell();
684 		if (np == NONODEPROTO)
685 		{
686 			ttyputerr(_("No current cell"));
687 			return;
688 		}
689 		if (namesamen(pt, x_("show-equivalent"), l) == 0) showrequest = TRUE; else
690 			showrequest = FALSE;
691 		if (count < 2)
692 		{
693 			if (!showrequest)
694 			{
695 				netlist = net_gethighlightednets(FALSE);
696 				if (netlist[0] == NONETWORK) return;
697 			} else
698 			{
699 				netlist = net_gethighlightednets(showrequest);
700 				if (netlist[0] == NONETWORK) return;
701 			}
702 		} else
703 		{
704 			mynet[0] = getnetwork(par[1], np);
705 			if (mynet[0] == NONETWORK)
706 			{
707 				ttyputerr(_("No net called '%s'"), par[1]);
708 				return;
709 			}
710 			mynet[1] = NONETWORK;
711 			netlist = mynet;
712 		}
713 
714 		/* first highlight the arcs on this network */
715 		if (!showrequest)
716 		{
717 			infstr = initinfstr();
718 			for(i=0; netlist[i] != NONETWORK; i++)
719 			{
720 				net = netlist[i];
721 				ttyputverbose(M_("Network '%s'"), describenetwork(net));
722 				np = net->parent;
723 
724 				/* show the arcs on this network */
725 				net_highlightnet(infstr, np, net);
726 
727 				/* handle multi-page schematic */
728 				if ((np->cellview->viewstate&MULTIPAGEVIEW) != 0)
729 				{
730 					/* search for an export on this net */
731 					for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
732 						if (pp->network == net) break;
733 					if (pp != NOPORTPROTO)
734 					{
735 						/* search all other windows for another page of this schematic */
736 						for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
737 						{
738 							if (w->curnodeproto == NONODEPROTO) continue;
739 							if ((w->curnodeproto->cellview->viewstate&MULTIPAGEVIEW) == 0) continue;
740 							if (!insamecellgrp(w->curnodeproto, np)) continue;
741 							if (w->curnodeproto == np) continue;
742 
743 							/* find any equivalent ports in this cell */
744 							opp = getportproto(w->curnodeproto, pp->protoname);
745 							if (opp == NOPORTPROTO) continue;
746 
747 							/* show the arcs on this network */
748 							net_highlightnet(infstr, w->curnodeproto, opp->network);
749 						}
750 					}
751 				}
752 			}
753 			(void)asktool(us_tool, x_("show-multiple"), (INTBIG)returninfstr(infstr));
754 		}
755 
756 		/* if there are associated VHDL or simulation windows, show in them */
757 		for(i=0; netlist[i] != NONETWORK; i++)
758 		{
759 			net = netlist[i];
760 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
761 			{
762 				if (w == el_curwindowpart) continue;
763 				switch (w->state&WINDOWTYPE)
764 				{
765 					case TEXTWINDOW:
766 					case POPTEXTWINDOW:
767 						/* must be editing this cell */
768 						if (w->curnodeproto == NONODEPROTO) break;
769 						if (!insamecellgrp(w->curnodeproto, np)) break;
770 						if (net->namecount > 0) pt = networkname(net, 0); else
771 							pt = describenetwork(net);
772 						if (w->curnodeproto->cellview == el_vhdlview ||
773 							w->curnodeproto->cellview == el_verilogview)
774 						{
775 							/* special intelligence for finding the net name in VHDL */
776 							infstr = initinfstr();
777 							addstringtoinfstr(infstr, x_("entity "));
778 							addstringtoinfstr(infstr, w->curnodeproto->protoname);
779 							addstringtoinfstr(infstr, x_(" is port("));
780 							us_searchtext(w, returninfstr(infstr), 0, 1);
781 							if (net->portcount <= 0)
782 								us_searchtext(w, x_("signal "), 0, 0);
783 							us_searchtext(w, pt, 0, 0);
784 						} else
785 						{
786 							/* just look for the name, starting at the top */
787 							us_searchtext(w, pt, 0, 1);
788 						}
789 						break;
790 #if SIMTOOL
791 					case WAVEFORMWINDOW:
792 						if (w->curnodeproto == NONODEPROTO) break;
793 
794 						/* try converting this network to a HSPICE path */
795 						pt = sim_spice_signalname(net);
796 						highsiglist = sim_window_findtrace(pt, &highsigcount);
797 						if (highsigcount > 0)
798 						{
799 							sim_window_cleartracehighlight();
800 							for(l=0; l<highsigcount; l++)
801 								sim_window_addhighlighttrace(highsiglist[l]);
802 							sim_window_showhighlightedtraces();
803 							break;
804 						}
805 
806 						/* must be simulating this cell */
807 						tr = 0;
808 						if (insamecellgrp(w->curnodeproto, np))
809 						{
810 							if (net->namecount > 0) pt = networkname(net, 0); else
811 								pt = describenetwork(net);
812 							highsiglist = sim_window_findtrace(pt, &highsigcount);
813 							if (highsigcount > 0) tr = highsiglist[0];
814 						}
815 						if (tr != 0)
816 						{
817 							sim_window_cleartracehighlight();
818 							sim_window_addhighlighttrace(tr);
819 							sim_window_showhighlightedtraces();
820 						}
821 						break;
822 #endif
823 				}
824 			}
825 		}
826 		return;
827 	}
828 
829 	if (namesamen(pt, x_("show-geometry"), l) == 0 && l > 5)
830 	{
831 		if (count < 2)
832 		{
833 			netlist = net_gethighlightednets(FALSE);
834 			if (netlist[0] == NONETWORK) return;
835 		} else
836 		{
837 			np = getcurcell();
838 			if (np == NONODEPROTO)
839 			{
840 				ttyputerr(_("No current cell"));
841 				return;
842 			}
843 			mynet[0] = getnetwork(par[1], np);
844 			if (mynet[0] == NONETWORK)
845 			{
846 				ttyputerr(M_("No net called '%s'"), par[1]);
847 				return;
848 			}
849 			mynet[1] = NONETWORK;
850 			netlist = mynet;
851 		}
852 		for(i=0; netlist[i] != NONETWORK; i++)
853 		{
854 			net = netlist[i];
855 			net_showgeometry(net);
856 		}
857 		return;
858 	}
859 
860 	if (namesamen(pt, x_("extract"), l) == 0)
861 	{
862 		np = getcurcell();
863 		if (np == NONODEPROTO)
864 		{
865 			ttyputerr(_("No current cell to extract"));
866 			return;
867 		}
868 		net_conv_to_internal(np);
869 		return;
870 	}
871 
872 	if (namesamen(pt, x_("default-busses"), l) == 0 && l > 3)
873 	{
874 		if (count == 1)
875 		{
876 			ttyputusage(x_("telltool network default-busses OPTION"));
877 			return;
878 		}
879 		l = estrlen(pt = par[1]);
880 		if (namesamen(pt, x_("ascend-numbering"), l) == 0)
881 		{
882 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey,
883 				net_options & ~NETDEFBUSBASEDESC, VINTEGER|VDONTSAVE);
884 			ttyputverbose(M_("Default busses will be numbered in ascending order"));
885 			return;
886 		}
887 		if (namesamen(pt, x_("descend-numbering"), l) == 0)
888 		{
889 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey,
890 				net_options|NETDEFBUSBASEDESC, VINTEGER|VDONTSAVE);
891 			ttyputverbose(M_("Default busses will be numbered in descending order"));
892 			return;
893 		}
894 		if (namesamen(pt, x_("0-base"), l) == 0)
895 		{
896 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey,
897 				net_options & ~NETDEFBUSBASE1, VINTEGER|VDONTSAVE);
898 			ttyputverbose(M_("Default busses will be numbered starting at 0"));
899 			return;
900 		}
901 		if (namesamen(pt, x_("1-base"), l) == 0)
902 		{
903 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey,
904 				net_options|NETDEFBUSBASE1, VINTEGER|VDONTSAVE);
905 			ttyputverbose(M_("Default busses will be numbered starting at 1"));
906 			return;
907 		}
908 		ttyputbadusage(x_("telltool network default-busses"));
909 		return;
910 	}
911 
912 	if (namesamen(pt, x_("name-cell-objects"), l) == 0 && l >= 6)
913 	{
914 		np = getcurcell();
915 		if (np == NONODEPROTO)
916 		{
917 			ttyputerr(M_("No current cell"));
918 			return;
919 		}
920 
921 		(void)net_nameallnodes(np, TRUE);
922 		(void)net_nameallnets(np);
923 		return;
924 	}
925 
926 	if (namesamen(pt, x_("name-library-objects"), l) == 0 && l >= 6)
927 	{
928 		for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
929 		{
930 			(void)net_nameallnodes(np, TRUE);
931 			(void)net_nameallnets(np);
932 		}
933 		return;
934 	}
935 
936 	if (namesamen(pt, x_("name-connections"), l) == 0 && l >= 6)
937 	{
938 		if (count < 2)
939 		{
940 			netlist = net_gethighlightednets(FALSE);
941 			if (netlist[0] == NONETWORK)
942 			{
943 				ttyputerr(_("Cannot determine network from highlighting"));
944 				return;
945 			}
946 		} else
947 		{
948 			np = getcurcell();
949 			if (np == NONODEPROTO)
950 			{
951 				ttyputerr(M_("No current cell"));
952 				return;
953 			}
954 			mynet[0] = getnetwork(par[1], np);
955 			if (mynet[0] == NONETWORK)
956 			{
957 				ttyputerr(M_("No net called '%s'"), par[1]);
958 				return;
959 			}
960 			mynet[1] = NONETWORK;
961 			netlist = mynet;
962 		}
963 		for(i=0; netlist[i] != NONETWORK; i++)
964 		{
965 			net = netlist[i];
966 			ttyputmsg(_("Network '%s':"), describenetwork(net));
967 
968 			total = 0;
969 			for(ni = net->parent->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
970 			{
971 				np = ni->proto;
972 				if (np->primindex != 0)
973 				{
974 					opp = np->firstportproto;
975 					for(pp = opp->nextportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
976 					{
977 						if (pp->network != opp->network) break;
978 						opp = pp;
979 					}
980 					if (pp == NOPORTPROTO) continue;
981 				}
982 
983 				for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
984 					if (pi->conarcinst->network == net) break;
985 				if (pi == NOPORTARCINST) continue;
986 
987 				if (total == 0) ttyputmsg(_("  Connects to:"));
988 				portposition(ni, pi->proto, &x, &y);
989 				ttyputmsg(_("    Node %s, port %s at (%s,%s)"), describenodeinst(ni),
990 					pi->proto->protoname, latoa(x, 0), latoa(y, 0));
991 				total++;
992 			}
993 			if (total == 0) ttyputmsg(_("  Not connected"));
994 		}
995 		return;
996 	}
997 
998 	if (namesamen(pt, x_("power-and-ground"), l) == 0)
999 	{
1000 		if (count == 1)
1001 		{
1002 			ttyputusage(x_("telltool network power-and-ground OPTION"));
1003 			return;
1004 		}
1005 		l = estrlen(pt = par[1]);
1006 		if (namesamen(pt, x_("unify-all-networks"), l) == 0)
1007 		{
1008 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey,
1009 				net_options|NETCONPWRGND, VINTEGER|VDONTSAVE);
1010 			ttyputverbose(M_("Unconnected power and ground nets will be equated"));
1011 			telltool(net_tool, 1, message);
1012 			return;
1013 		}
1014 		if (namesamen(pt, x_("separate-unconnected-networks"), l) == 0)
1015 		{
1016 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey,
1017 				net_options & ~NETCONPWRGND, VINTEGER|VDONTSAVE);
1018 			ttyputverbose(M_("Unconnected power and ground nets will not be equated"));
1019 			telltool(net_tool, 1, message);
1020 			return;
1021 		}
1022 		if (namesamen(pt, x_("identify"), l) == 0)
1023 		{
1024 			np = getcurcell();
1025 			if (np == NONODEPROTO)
1026 			{
1027 				ttyputerr(_("No current cell"));
1028 				return;
1029 			}
1030 			for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1031 				net->temp1 = 0;
1032 			for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1033 			{
1034 				if (portispower(pp) || portisground(pp))
1035 					pp->network->temp1 = 1;
1036 			}
1037 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1038 			{
1039 				if (ni->proto->primindex == 0) continue;
1040 				fun = nodefunction(ni);
1041 				if (fun != NPCONPOWER && fun != NPCONGROUND) continue;
1042 				for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1043 				{
1044 					ai = pi->conarcinst;
1045 					ai->network->temp1 = 1;
1046 				}
1047 			}
1048 			infstr = initinfstr();
1049 			total = 0;
1050 			for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1051 			{
1052 				if (net->temp1 == 0) continue;
1053 				net_highlightnet(infstr, np, net);
1054 				total++;
1055 			}
1056 			(void)asktool(us_tool, x_("show-multiple"), (INTBIG)returninfstr(infstr));
1057 
1058 			if (total == 0)
1059 				ttyputmsg(_("This cell has no Power or Ground networks"));
1060 			return;
1061 		}
1062 		if (namesamen(pt, x_("validate"), l) == 0)
1063 		{
1064 			ttyputmsg(_("Validating power and ground networks"));
1065 			total = 0;
1066 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1067 			{
1068 				for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1069 				{
1070 					for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1071 					{
1072 						if (portisnamedground(pp) && (pp->userbits&STATEBITS) != GNDPORT)
1073 						{
1074 							ttyputmsg(_("Cell %s, export %s: does not have 'GROUND' characteristic"),
1075 								describenodeproto(np), pp->protoname);
1076 #if 0
1077 							pp->userbits = (pp->userbits & ~STATEBITS) | GNDPORT;
1078 							lib->userbits |= LIBCHANGEDMAJOR;
1079 #endif
1080 							total++;
1081 						}
1082 						if (portisnamedpower(pp) && (pp->userbits&STATEBITS) != PWRPORT)
1083 						{
1084 							ttyputmsg(_("Cell %s, export %s: does not have 'POWER' characteristic"),
1085 								describenodeproto(np), pp->protoname);
1086 #if 0
1087 							pp->userbits = (pp->userbits & ~STATEBITS) | PWRPORT;
1088 							lib->userbits |= LIBCHANGEDMAJOR;
1089 #endif
1090 							total++;
1091 						}
1092 					}
1093 				}
1094 			}
1095 			if (total == 0) ttyputmsg(_("No problems found")); else
1096 				ttyputmsg(_("Found %ld export problems"), total);
1097 			return;
1098 		}
1099 
1100 		ttyputbadusage(x_("telltool network power-and-ground"));
1101 		return;
1102 	}
1103 
1104 	if (namesamen(pt, x_("like-named-nets"), l) == 0)
1105 	{
1106 		if (count == 1)
1107 		{
1108 			ttyputusage(x_("telltool network like-named-nets OPTION"));
1109 			return;
1110 		}
1111 		l = estrlen(pt = par[1]);
1112 		if (namesamen(pt, x_("unify-always"), l) == 0)
1113 		{
1114 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey,
1115 				net_options|NETCONCOMMONNAME, VINTEGER|VDONTSAVE);
1116 			ttyputverbose(M_("Nets with the same name will always be equated"));
1117 			telltool(net_tool, 1, message);
1118 			return;
1119 		}
1120 		if (namesamen(pt, x_("unify-only-in-schematics"), l) == 0)
1121 		{
1122 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey,
1123 				net_options & ~NETCONCOMMONNAME, VINTEGER|VDONTSAVE);
1124 			ttyputverbose(M_("Nets with the same name will be equated only in schematics"));
1125 			telltool(net_tool, 1, message);
1126 			return;
1127 		}
1128 		ttyputbadusage(x_("telltool network like-named-nets"));
1129 		return;
1130 	}
1131 
1132 	if (namesamen(pt, x_("compare"), l) == 0)
1133 	{
1134 		if (count == 1)
1135 		{
1136 			net_compare(FALSE, TRUE, NONODEPROTO, NONODEPROTO);
1137 			return;
1138 		}
1139 		l = estrlen(pt = par[1]);
1140 		if (namesamen(pt, x_("highlight-other"), l) == 0)
1141 		{
1142 			net_equate(1);
1143 			return;
1144 		}
1145 		if (namesamen(pt, x_("pre-analysis"), l) == 0)
1146 		{
1147 			net_compare(TRUE, TRUE, NONODEPROTO, NONODEPROTO);
1148 			return;
1149 		}
1150 #ifdef FORCESUNTOOLS
1151 		if (namesamen(pt, x_("analyze-cell"), l) == 0)
1152 		{
1153 			(void)net_analyzecell();
1154 			return;
1155 		}
1156 #endif
1157 		if (namesamen(pt, x_("not"), l) == 0)
1158 		{
1159 			if (count <= 2)
1160 			{
1161 				ttyputusage(x_("telltool network compare not OPTION"));
1162 				return;
1163 			}
1164 			l = estrlen(pt = par[2]);
1165 			if (namesamen(pt, x_("include-no-component-nets"), l) == 0)
1166 			{
1167 				var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
1168 				if (var == NOVARIABLE) options = 0; else options = var->addr;
1169 				(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey,
1170 					options & ~NCCINCLUDENOCOMPNETS, VINTEGER|VDONTSAVE);
1171 				ttyputverbose(M_("Circuit comparison will include networks with no components on them"));
1172 				return;
1173 			}
1174 			if (namesamen(pt, x_("check-export-names"), l) == 0 && l >= 7)
1175 			{
1176 				var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
1177 				if (var == NOVARIABLE) options = 0; else options = var->addr;
1178 				(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey,
1179 					options & ~NCCCHECKEXPORTNAMES, VINTEGER|VDONTSAVE);
1180 				ttyputverbose(M_("Circuit comparison will not check export names"));
1181 				return;
1182 			}
1183 			if (namesamen(pt, x_("check-node-sizes"), l) == 0 && l >= 7)
1184 			{
1185 				var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
1186 				if (var == NOVARIABLE) options = 0; else options = var->addr;
1187 				(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey,
1188 					options & ~NCCCHECKSIZE, VINTEGER|VDONTSAVE);
1189 				ttyputverbose(M_("Circuit comparison will not check node sizes"));
1190 				return;
1191 			}
1192 			if (namesamen(pt, x_("flatten-hierarchy"), l) == 0)
1193 			{
1194 				var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
1195 				if (var == NOVARIABLE) options = 0; else options = var->addr;
1196 				(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey,
1197 					options & ~NCCHIERARCHICAL, VINTEGER|VDONTSAVE);
1198 				ttyputverbose(M_("Circuits will be compared without flattening hierarchy"));
1199 				return;
1200 			}
1201 			if (namesamen(pt, x_("recurse"), l) == 0)
1202 			{
1203 				var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
1204 				if (var == NOVARIABLE) options = 0; else options = var->addr;
1205 				(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey,
1206 					options & ~NCCRECURSE, VINTEGER|VDONTSAVE);
1207 				ttyputverbose(M_("Circuits will be compared without recursing through hierarchy"));
1208 				return;
1209 			}
1210 			ttyputbadusage(x_("telltool network compare not"));
1211 			return;
1212 		}
1213 		if (namesamen(pt, x_("include-no-component-nets"), l) == 0)
1214 		{
1215 			var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
1216 			if (var == NOVARIABLE) options = 0; else options = var->addr;
1217 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey,
1218 				options | NCCINCLUDENOCOMPNETS, VINTEGER|VDONTSAVE);
1219 			ttyputverbose(M_("Circuit comparison will exclude networks with no components on them"));
1220 			return;
1221 		}
1222 		if (namesamen(pt, x_("check-export-names"), l) == 0 && l >= 7)
1223 		{
1224 			var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
1225 			if (var == NOVARIABLE) options = 0; else options = var->addr;
1226 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey,
1227 				options | NCCCHECKEXPORTNAMES, VINTEGER|VDONTSAVE);
1228 			ttyputverbose(M_("Circuit comparison will check export names"));
1229 			return;
1230 		}
1231 		if (namesamen(pt, x_("check-node-sizes"), l) == 0 && l >= 7)
1232 		{
1233 			var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
1234 			if (var == NOVARIABLE) options = 0; else options = var->addr;
1235 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey,
1236 				options | NCCCHECKSIZE, VINTEGER|VDONTSAVE);
1237 			ttyputverbose(M_("Circuit comparison will check node sizes"));
1238 			return;
1239 		}
1240 		if (namesamen(pt, x_("flatten-hierarchy"), l) == 0)
1241 		{
1242 			var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
1243 			if (var == NOVARIABLE) options = 0; else options = var->addr;
1244 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey,
1245 				options | NCCHIERARCHICAL, VINTEGER|VDONTSAVE);
1246 			ttyputverbose(M_("Circuits will be compared with hierarchy flattened"));
1247 			return;
1248 		}
1249 		if (namesamen(pt, x_("recurse"), l) == 0)
1250 		{
1251 			var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
1252 			if (var == NOVARIABLE) options = 0; else options = var->addr;
1253 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey,
1254 				options | NCCRECURSE, VINTEGER|VDONTSAVE);
1255 			ttyputverbose(M_("Circuits will be compared recursing through hierarchy"));
1256 			return;
1257 		}
1258 		ttyputbadusage(x_("telltool network compare"));
1259 		return;
1260 	}
1261 
1262 	if (namesamen(pt, x_("list-ports-below"), l) == 0 && l >= 6)
1263 	{
1264 		/* get the currently highlighted network */
1265 		if (count < 2)
1266 		{
1267 			netlist = net_gethighlightednets(FALSE);
1268 			if (netlist[0] == NONETWORK) return;
1269 		} else
1270 		{
1271 			np = getcurcell();
1272 			if (np == NONODEPROTO)
1273 			{
1274 				ttyputerr(_("No current cell"));
1275 				return;
1276 			}
1277 			mynet[0] = getnetwork(par[1], np);
1278 			if (mynet[0] == NONETWORK)
1279 			{
1280 				ttyputerr(M_("No net called '%s'"), par[1]);
1281 				return;
1282 			}
1283 			mynet[1] = NONETWORK;
1284 			netlist = mynet;
1285 		}
1286 
1287 		for(i=0; netlist[i] != NONETWORK; i++)
1288 		{
1289 			net = netlist[i];
1290 			ttyputmsg(_("Network '%s':"), describenetwork(net));
1291 
1292 			/* find all exports on network "net" */
1293 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1294 				for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1295 					for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1296 						pp->temp1 = 0;
1297 			net_findportsdown(net, net->parent);
1298 		}
1299 		return;
1300 	}
1301 
1302 	if (namesamen(pt, x_("list-hierarchical-ports"), l) == 0 && l >= 6)
1303 	{
1304 		/* get the currently highlighted network */
1305 		if (count < 2)
1306 		{
1307 			netlist = net_gethighlightednets(FALSE);
1308 			if (netlist[0] == NONETWORK) return;
1309 		} else
1310 		{
1311 			np = getcurcell();
1312 			if (np == NONODEPROTO)
1313 			{
1314 				ttyputerr(_("No current cell"));
1315 				return;
1316 			}
1317 			mynet[0] = getnetwork(par[1], np);
1318 			if (mynet[0] == NONETWORK)
1319 			{
1320 				ttyputerr(M_("No net called '%s'"), par[1]);
1321 				return;
1322 			}
1323 			mynet[1] = NONETWORK;
1324 			netlist = mynet;
1325 		}
1326 
1327 		for(i=0; netlist[i] != NONETWORK; i++)
1328 		{
1329 			net = netlist[i];
1330 			ttyputmsg(_("Network '%s':"), describenetwork(net));
1331 
1332 			/* find all exports on network "net" */
1333 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1334 				for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1335 					for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1336 						pp->temp1 = 0;
1337 			net_findportsup(net, net->parent);
1338 			(void)ttyputmsg(_(" Going down the hierarchy from cell %s"), describenodeproto(net->parent));
1339 			net_findportsdown(net, net->parent);
1340 		}
1341 		return;
1342 	}
1343 
1344 	if (namesamen(pt, x_("debug-toggle"), l) == 0 && l > 3)
1345 	{
1346 		if (!net_debug)
1347 		{
1348 			net_debug = TRUE;
1349 			ttyputmsg(M_("Network debugging on"));
1350 		} else
1351 		{
1352 			net_debug = FALSE;
1353 			ttyputmsg(M_("Network debugging off"));
1354 		}
1355 		return;
1356 	}
1357 
1358 	if (namesamen(pt, x_("resistors"), l) == 0 && l >= 3)
1359 	{
1360 		if (count < 2)
1361 		{
1362 			ttyputusage(x_("telltool network resistors (ignore | include)"));
1363 			return;
1364 		}
1365 		l = estrlen(pt = par[1]);
1366 		if (namesamen(pt, x_("ignore"), l) == 0 && l >= 2)
1367 		{
1368 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey,
1369 				net_options | NETIGNORERESISTORS, VINTEGER|VDONTSAVE);
1370 			net_tellschematics();
1371 			return;
1372 		}
1373 		if (namesamen(pt, x_("include"), l) == 0 && l >= 2)
1374 		{
1375 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey,
1376 				net_options & ~NETIGNORERESISTORS, VINTEGER|VDONTSAVE);
1377 			net_tellschematics();
1378 			return;
1379 		}
1380 		ttyputbadusage(x_("telltool network resistors"));
1381 	}
1382 
1383 	if (namesamen(pt, x_("re-number"), l) == 0 && l >= 3)
1384 	{
1385 		if (count >= 2)
1386 		{
1387 			np = getnodeproto(par[1]);
1388 			if (np == NONODEPROTO)
1389 			{
1390 				ttyputerr(M_("No cell named %s"), par[1]);
1391 				return;
1392 			}
1393 			if (np->primindex != 0)
1394 			{
1395 				ttyputerr(M_("Can only renumber cells, not primitives"));
1396 				return;
1397 			}
1398 		} else
1399 		{
1400 			np = getcurcell();
1401 			if (np == NONODEPROTO)
1402 			{
1403 				ttyputerr(_("No current cell"));
1404 				return;
1405 			}
1406 		}
1407 
1408 		net_reevaluatecell(np);
1409 		ttyputverbose(M_("Cell %s re-numbered"), describenodeproto(np));
1410 		return;
1411 	}
1412 
1413 	if (namesamen(pt, x_("total-re-number"), l) == 0)
1414 	{
1415 		net_totalrenumber(NOLIBRARY);
1416 		ttyputverbose(M_("All libraries re-numbered"));
1417 		return;
1418 	}
1419 
1420 	ttyputbadusage(x_("telltool network"));
1421 }
1422 
1423 /*
1424  * make request of the network tool:
1425  * "total-re-number" renumbers all libraries
1426  * "library-re-number" TAKES: library to renumbers
1427  * "re-number" TAKES: the CELL to be renumbered
1428  * "rename" TAKES: old STRING name, new STRING name, CELL
1429  * "name-nodes" TAKES: CELL with nodes; RETURNS: number of nodes named
1430  * "name-all-nodes" TAKES: CELL with nodes; RETURNS: number of nodes named
1431  */
net_request(CHAR * command,va_list ap)1432 INTBIG net_request(CHAR *command, va_list ap)
1433 {
1434 	REGISTER NODEPROTO *np;
1435 	REGISTER LIBRARY *lib;
1436 	REGISTER INTBIG arg1, arg2, arg3;
1437 	REGISTER INTBIG retval;
1438 
1439 	if (namesame(command, x_("total-re-number")) == 0)
1440 	{
1441 		net_totalrenumber(NOLIBRARY);
1442 		return(0);
1443 	}
1444 	if (namesame(command, x_("library-re-number")) == 0)
1445 	{
1446 		/* get the arguments */
1447 		arg1 = va_arg(ap, INTBIG);
1448 
1449 		lib = (LIBRARY *)arg1;
1450 		net_totalrenumber(lib);
1451 		return(0);
1452 	}
1453 	if (namesame(command, x_("re-number")) == 0)
1454 	{
1455 		/* get the arguments */
1456 		arg1 = va_arg(ap, INTBIG);
1457 
1458 		np = (NODEPROTO *)arg1;
1459 		net_reevaluatecell(np);
1460 		return(0);
1461 	}
1462 	if (namesame(command, x_("name-nodes")) == 0)
1463 	{
1464 		/* get the arguments */
1465 		arg1 = va_arg(ap, INTBIG);
1466 
1467 		np = (NODEPROTO *)arg1;
1468 		retval = net_nameallnodes(np, FALSE);
1469 		return(retval);
1470 	}
1471 	if (namesame(command, x_("name-all-nodes")) == 0)
1472 	{
1473 		/* get the arguments */
1474 		arg1 = va_arg(ap, INTBIG);
1475 
1476 		np = (NODEPROTO *)arg1;
1477 		retval = net_nameallnodes(np, TRUE);
1478 		return(retval);
1479 	}
1480 	if (namesame(command, x_("name-nets")) == 0)
1481 	{
1482 		/* get the arguments */
1483 		arg1 = va_arg(ap, INTBIG);
1484 
1485 		np = (NODEPROTO *)arg1;
1486 		retval = net_nameallnets(np);
1487 		return(retval);
1488 	}
1489 	if (namesame(command, x_("rename")) == 0)
1490 	{
1491 		/* get the arguments */
1492 		arg1 = va_arg(ap, INTBIG);
1493 		arg2 = va_arg(ap, INTBIG);
1494 		arg3 = va_arg(ap, INTBIG);
1495 
1496 		net_renamenet((CHAR *)arg1, (CHAR *)arg2, (NODEPROTO *)arg3);
1497 		return(0);
1498 	}
1499 	return(-1);
1500 }
1501 
1502 /*********************** BROADCAST ROUTINES ***********************/
1503 
net_startbatch(TOOL * source,BOOLEAN undoredo)1504 void net_startbatch(TOOL *source, BOOLEAN undoredo)
1505 {
1506 	Q_UNUSED( undoredo );
1507 
1508 	/* code cannot be called by multiple procesors: uses globals */
1509 	NOT_REENTRANT;
1510 
1511 	net_globalwork = FALSE;
1512 	net_current_source = source;
1513 }
1514 
net_endbatch(void)1515 void net_endbatch(void)
1516 {
1517 	REGISTER NODEPROTO *np;
1518 	REGISTER LIBRARY *lib;
1519 	BOOLEAN advance;
1520 
1521 	if (!net_globalwork) return;
1522 
1523 	if (net_debug) ttyputmsg(M_("Network: doing entire cell rechecks"));
1524 
1525 	/* look for all cells that need to be renumbered */
1526 	do {
1527 		advance = FALSE;
1528 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1529 		{
1530 			if ((lib->userbits&REDOCELLLIB) == 0) continue;
1531 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1532 			{
1533 				if ((np->userbits&REDOCELLNET) == 0) continue;
1534 				advance = TRUE;
1535 				if (net_recursivelyredo(np))
1536 				{
1537 					ttyputmsg(_("Network information may be incorrect...should redo network numbering"));
1538 					net_globalwork = FALSE;
1539 					return;
1540 				}
1541 			}
1542 		}
1543 	} while (advance);
1544 	net_globalwork = FALSE;
1545 }
1546 
1547 /*
1548  * Routine to renumber all networks.
1549  */
net_totalrenumber(LIBRARY * lib)1550 void net_totalrenumber(LIBRARY *lib)
1551 {
1552 	REGISTER LIBRARY *olib;
1553 	REGISTER NODEPROTO *np;
1554 	REGISTER VARIABLE *var;
1555 
1556 	/* recache net_tool options */
1557 	var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_optionskey);
1558 	if (var != NOVARIABLE)
1559 		net_options = var->addr;
1560 	net_recacheunifystrings();
1561 
1562 	if (lib == NOLIBRARY)
1563 	{
1564 		/* renumber every library */
1565 		net_globalwork = TRUE;
1566 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
1567 		{
1568 			olib->userbits |= REDOCELLLIB;
1569 			for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1570 				np->userbits |= REDOCELLNET;
1571 		}
1572 	} else
1573 	{
1574 		/* renumber just this library */
1575 		net_startglobalwork(lib);
1576 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1577 			np->userbits |= REDOCELLNET;
1578 	}
1579 	net_endbatch();
1580 }
1581 
1582 /*
1583  * routine to redo the connectivity within cell "np" (and recursively,
1584  * all cells below that in need of renumbering).
1585  * Returns true if interrupted
1586  */
net_recursivelyredo(NODEPROTO * np)1587 BOOLEAN net_recursivelyredo(NODEPROTO *np)
1588 {
1589 	REGISTER NODEINST *ni;
1590 	REGISTER NODEPROTO *cnp, *subnp;
1591 
1592 	if (stopping(STOPREASONNETWORK) != 0)
1593 	{
1594 		return(TRUE);
1595 	}
1596 
1597 	/* renumber contents view if this is icon or skeleton */
1598 	cnp = contentsview(np);
1599 	if (cnp != NONODEPROTO && (cnp->userbits&REDOCELLNET) != 0)
1600 	{
1601 		if (net_recursivelyredo(cnp)) return(TRUE);
1602 	}
1603 
1604 	/* first see if any lower cells need to be renumbered */
1605 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1606 	{
1607 		/* ignore recursive references (showing icon in contents) */
1608 		subnp = ni->proto;
1609 		if (isiconof(subnp, np)) continue;
1610 
1611 		if (subnp->primindex == 0 && (subnp->userbits&REDOCELLNET) != 0)
1612 		{
1613 			if (net_recursivelyredo(subnp)) return(TRUE);
1614 		}
1615 	}
1616 	net_reevaluatecell(np);
1617 
1618 	/* mark this cell rechecked */
1619 	np->userbits &= ~REDOCELLNET;
1620 	return(FALSE);
1621 }
1622 
1623 /*
1624  * routine to redo the connectivity within cell "np".  The "network" fields
1625  * of the arcs and ports are set to be consistent.  This data and this routine
1626  * are used by other tools such as the design-rule checker and the simulator
1627  */
net_reevaluatecell(NODEPROTO * np)1628 void net_reevaluatecell(NODEPROTO *np)
1629 {
1630 	REGISTER ARCINST *ai;
1631 	REGISTER BUSLIST *bl;
1632 	REGISTER PORTPROTO *pp;
1633 	REGISTER VARIABLE *var;
1634 	REGISTER NETWORK *net, *nextnet;
1635 	REGISTER NODEPROTO *subnp, *onp;
1636 	REGISTER PORTARCINST *pi;
1637 	REGISTER INTBIG i, width;
1638 	NODEINST *ni;
1639 	PORTPROTO *cpp;
1640 	NETWORK *gnet, *cnet;
1641 	INTBIG j, k;
1642 
1643 	if (net_debug)
1644 		ttyputmsg(M_("Network: rechecking cell %s"), describenodeproto(np));
1645 
1646 	/* initialize net hash if necessary */
1647 	net_initnetprivate(np);
1648 
1649 	/* first delete all network objects in this cell */
1650 	for(net = np->firstnetwork; net != NONETWORK; net = nextnet)
1651 	{
1652 		nextnet = net->nextnetwork;
1653 		net_freenetwork(net, np);
1654 	}
1655 	np->firstnetwork = NONETWORK;
1656 	for(i=0; i<np->globalnetcount; i++)
1657 		np->globalnetworks[i] = NONETWORK;
1658 
1659 #ifdef NEWRENUM
1660 	/* handle non-complicated layout cells */
1661 	if (np->cellview == el_layoutview)
1662 	{
1663 		NetCellConns *conns = new (np->lib->cluster) NetCellConns(np, np->lib->cluster);
1664 		if (!conns->complicated())
1665 		{
1666 			conns->makeNetworksSimple();
1667 			delete conns;
1668 			goto simpleLayout;
1669 		} else
1670 		{
1671 			delete conns;
1672 			ttyputmsg(_("Layout cell %s is complicated"), describenodeproto(np));
1673 		}
1674 	}
1675 #endif
1676 
1677 	/* unmark all network data in the cell */
1678 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1679 		ai->network = NONETWORK;
1680 	for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1681 		pp->network = NONETWORK;
1682 
1683 	/* initialize for propagation */
1684 	net_initnconnect(np);
1685 
1686 	/* make a list of all named busses */
1687 	net_buslistcount = 0;
1688 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1689 	{
1690 		if (ai->proto != sch_busarc) continue;
1691 		var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
1692 		if (var == NOVARIABLE) continue;
1693 		width = net_buswidth((CHAR *)var->addr);
1694 		net_addtobuslist(ai, NOPORTPROTO, width);
1695 	}
1696 	for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1697 	{
1698 		width = net_buswidth(pp->protoname);
1699 		if (width <= 1) continue;
1700 		net_addtobuslist(NOARCINST, pp, width);
1701 	}
1702 
1703 	/* handle busses first */
1704 	if (net_buslistcount > 0)
1705 	{
1706 		/* sort by bus width */
1707 		esort(net_buslists, net_buslistcount, sizeof (BUSLIST), net_buslistwidthascending);
1708 
1709 		/* renumber arcs, starting with the narrowest */
1710 		for(i=0; i<net_buslistcount; i++)
1711 		{
1712 			bl = &net_buslists[i];
1713 			if (bl->ai != NOARCINST)
1714 			{
1715 				ai = bl->ai;
1716 				if (ai->network != NONETWORK) continue;
1717 				net = net_newnetwork(np);
1718 				(void)net_nconnect(ai, net, np);
1719 			} else
1720 			{
1721 				pp = bl->pp;
1722 				if (pp->network == NONETWORK) (void)net_pconnect(pp);
1723 			}
1724 		}
1725 	}
1726 
1727 	/* renumber all other bus arcs (on unnamed networks) */
1728 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1729 	{
1730 		if (ai->network != NONETWORK) continue;
1731 		if (ai->proto != sch_busarc) continue;
1732 		net = net_newnetwork(np);
1733 		(void)net_nconnect(ai, net, np);
1734 	}
1735 
1736 	/* finally renumber non-bus arcs */
1737 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1738 	{
1739 		if (ai->network != NONETWORK) continue;
1740 		if (ai->proto == sch_busarc) continue;
1741 #ifdef NEWRENUM
1742 		/* ignore arcs with no signals on them */
1743 		if (((ai->proto->userbits&AFUNCTION)>>AFUNCTIONSH) == APNONELEC) continue;
1744 #endif
1745 		net = net_newnetwork(np);
1746 		(void)net_nconnect(ai, net, np);
1747 	}
1748 
1749 	/* evaluate "wire_con" nodes which join nets */
1750 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1751 	{
1752 		if (ni->proto != sch_wireconprim) continue;
1753 		net_joinnetworks(ni);
1754 	}
1755 
1756 	/* update connectivity values on unconnected ports */
1757 	for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1758 		if (pp->network == NONETWORK) (void)net_pconnect(pp);
1759 
1760 	/* finally merge all individual signals connected in busses by subcells */
1761 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1762 	{
1763 		subnp = ni->proto;
1764 		if (subnp == NONODEPROTO) continue;
1765 		if (subnp->primindex != 0) continue;
1766 
1767 		/* ignore recursive references (showing icon in contents) */
1768 		if (isiconof(subnp, np)) continue;
1769 		if (net_mergebuswires(ni)) net_recursivelymarkabove(subnp);
1770 	}
1771 
1772 	/* do checks where arcs touch busses */
1773 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1774 	{
1775 		if (ni->proto == sch_buspinprim)
1776 		{
1777 			/* see if there is a wire arc on it */
1778 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1779 				if (pi->conarcinst->proto != sch_busarc) break;
1780 			if (pi != NOPORTARCINST)
1781 				net_checkvalidconnection(ni, pi->conarcinst);
1782 		}
1783 	}
1784 
1785 	/* gather global nets of instances */
1786 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1787 	{
1788 		/* ignore primitives and recursive references (showing icon in contents) */
1789 		if (ni->proto->primindex != 0) continue;
1790 		if (isiconof(ni->proto, np)) continue;
1791 		subnp = contentsview(ni->proto);
1792 		if (subnp == NONODEPROTO) subnp = ni->proto;
1793 		for(i=0; i<subnp->globalnetcount; i++)
1794 		{
1795 			if(subnp->globalnetworks[i] == NONETWORK) continue;
1796 			gnet = net_addglobalnet(subnp, i, np);
1797 
1798 			/* check if global net is connected to some export */
1799 			if (!ni->proto->netd->netshorts()->globalshort()) continue;
1800 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1801 			{
1802 				ai = pi->conarcinst;
1803 				cpp = equivalentport(ni->proto, pi->proto, subnp);
1804 				if (cpp == NOPORTPROTO) continue;
1805 				cnet = cpp->network;
1806 				for(j=0; j<cnet->buswidth; j++)
1807 				{
1808 					if((cnet->buswidth == 1 ? cnet : cnet->networklist[j])
1809 						!= subnp->globalnetworks[i]) continue;
1810 					if(ai->network->buswidth > 1)
1811 					{
1812 						if(ni->arraysize > 1 && cnet->buswidth*ni->arraysize == ai->network->buswidth)
1813 						{
1814 							for(k=0; k < ni->arraysize; k++)
1815 								net_mergenet(ai->network->networklist[j + k*cnet->buswidth], gnet);
1816 						} else net_mergenet(ai->network->networklist[j], gnet);
1817 					} else net_mergenet(ai->network, gnet);
1818 				}
1819 			}
1820 		}
1821 	}
1822 #ifdef NEWRENUM
1823 #  if 0
1824 	{
1825 		NetCellConns *conns = new (np->lib->cluster) NetCellConns(np, np->lib->cluster);
1826 		conns->schem();
1827 		delete conns;
1828 	}
1829 #  endif
1830 #  if 0
1831 	for (net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1832 	{
1833 		if (net->buswidth > 1 && net->namecount - net->portcount > 1)
1834 			::printf("Cell %s bus net %s has many names\n", describenodeproto(np), describenetwork(net));
1835 	}
1836 #  endif
1837 simpleLayout:
1838 #endif
1839 	if (!np->netd->updateShorts()) return;
1840 
1841 	/* if this cell has an icon, mark it  */
1842 	i = 0;
1843 	FOR_CELLGROUP(onp, np)
1844 	{
1845 		if (i++ > 1000)
1846 		{
1847 			db_correctcellgroups(np);
1848 			break;
1849 		}
1850 		if (contentsview(onp) != np) continue;
1851 		if ((onp->userbits&REDOCELLNET) != 0) continue;
1852 		if (net_debug)
1853 			ttyputmsg(M_("Network: icon %s is marked"), describenodeproto(onp));
1854 		onp->userbits |= REDOCELLNET;
1855 	}
1856 
1857 	/* mark instances */
1858 	for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
1859 	{
1860 		/* ignore recursive references (showing icon in contents) */
1861 		if (isiconof(ni->proto, ni->parent)) continue;
1862 
1863 		net_startglobalwork(ni->parent->lib);
1864 		if ((ni->parent->userbits&REDOCELLNET) != 0) continue;
1865 		if (net_debug)
1866 			ttyputmsg(M_("Network: parent cell %s is marked"), describenodeproto(ni->parent));
1867 		ni->parent->userbits |= REDOCELLNET;
1868 	}
1869 }
1870 
net_modifyportproto(PORTPROTO * pp,NODEINST * oldsubni,PORTPROTO * oldsubpp)1871 void net_modifyportproto(PORTPROTO *pp, NODEINST *oldsubni, PORTPROTO *oldsubpp)
1872 {
1873 #ifndef NEWRENUM
1874 	REGISTER NODEPROTO *np;
1875 #endif
1876 	Q_UNUSED( oldsubni );
1877 	Q_UNUSED( oldsubpp );
1878 
1879 	if (net_debug) ttyputmsg(M_("Network: port %s modified"), pp->protoname);
1880 
1881 #ifdef NEWRENUM
1882 	net_recursivelymarkabove(pp->parent);
1883 #else
1884 	/* stop now if the entire cell will be renumbered */
1885 	if (net_globalwork && (pp->parent->userbits&REDOCELLNET) != 0) return;
1886 
1887 	np = pp->parent;
1888 	net_initnconnect(np);
1889 	if (net_pconnect(pp))
1890 	{
1891 		if (net_debug) ttyputmsg(M_("Network: must recheck instances of %s"),
1892 			describenodeproto(np));
1893 		net_recursivelymarkabove(np);
1894 	}
1895 #endif
1896 }
1897 
net_newobject(INTBIG addr,INTBIG type)1898 void net_newobject(INTBIG addr, INTBIG type)
1899 {
1900 	REGISTER ARCINST *ai;
1901 	REGISTER PORTPROTO *pp;
1902 	REGISTER NODEPROTO *np;
1903 
1904 	if ((type&VTYPE) == VARCINST)
1905 	{
1906 		ai = (ARCINST *)addr;
1907 #ifdef NEWRENUM
1908 		net_recursivelymarkabove(ai->parent);
1909 #else
1910 		ai->network = NONETWORK;
1911 
1912 		/* stop now if the entire cell will be renumbered */
1913 		if (net_globalwork && (ai->parent->userbits&REDOCELLNET) != 0) return;
1914 
1915 		/* ignore nonelectrical arcs */
1916 		if (((ai->proto->userbits&AFUNCTION)>>AFUNCTIONSH) == APNONELEC) return;
1917 
1918 		if (net_debug)
1919 			ttyputmsg(M_("Network: arc %s created"), describearcinst(ai));
1920 
1921 		/* remove any former network information */
1922 		(void)net_takearcfromnet(ai);
1923 
1924 		/* create a new network and propagate it */
1925 		np = ai->parent;
1926 		net_initnconnect(np);
1927 		if (net_nconnect(ai, net_newnetwork(np), np))
1928 		{
1929 			if (net_debug)
1930 				ttyputmsg(M_("Network: must recheck instances of %s"),
1931 					describenodeproto(np));
1932 			net_recursivelymarkabove(np);
1933 		}
1934 #endif
1935 	} else if ((type&VTYPE) == VPORTPROTO)
1936 	{
1937 		pp = (PORTPROTO *)addr;
1938 #ifdef NEWRENUM
1939 		net_recursivelymarkabove(pp->parent);
1940 #else
1941 		pp->network = NONETWORK;
1942 
1943 		/* stop now if the entire cell will be renumbered */
1944 		if (net_globalwork && (pp->parent->userbits&REDOCELLNET) != 0) return;
1945 
1946 		if (net_debug) ttyputmsg(M_("Network: port %s created"), pp->protoname);
1947 
1948 		np = pp->parent;
1949 		net_initnconnect(np);
1950 		if (net_pconnect(pp))
1951 		{
1952 			if (net_debug)
1953 				ttyputmsg(M_("Network: must recheck instances of %s"),
1954 					describenodeproto(np));
1955 			net_recursivelymarkabove(np);
1956 		}
1957 #endif
1958 	} else if ((type&VTYPE) == VNODEPROTO)
1959 	{
1960 		np = (NODEPROTO *)addr;
1961 		if (net_debug) ttyputmsg(M_("Network: cell %s created"),
1962 				describenodeproto(np));
1963 #ifdef NEWRENUM
1964 		net_recursivelymarkabove(np);
1965 #else
1966 		/* queue this cell for renumbering */
1967 		net_startglobalwork(np->lib);
1968 
1969 		/* mark this cell to be renumbered */
1970 		np->userbits |= REDOCELLNET;
1971 #endif
1972 	}
1973 }
1974 
net_killobject(INTBIG addr,INTBIG type)1975 void net_killobject(INTBIG addr, INTBIG type)
1976 {
1977 #ifdef NEWRENUM
1978 	REGISTER ARCINST *ai;
1979 	REGISTER NODEPROTO *np;
1980 	REGISTER PORTPROTO *pp;
1981 	REGISTER NETWORK *net, *nextnet;
1982 #else
1983 	REGISTER PORTARCINST *pi;
1984 	REGISTER ARCINST *ai;
1985 	REGISTER NODEINST *ni;
1986 	REGISTER NODEPROTO *np;
1987 	REGISTER PORTPROTO *pp;
1988 	REGISTER PORTEXPINST *pe;
1989 	REGISTER INTBIG i;
1990 	REGISTER NETWORK *net, *onet, *nextnet;
1991 #endif
1992 
1993 	if ((type&VTYPE) == VARCINST)
1994 	{
1995 		ai = (ARCINST *)addr;
1996 		np = ai->parent;
1997 #ifdef NEWRENUM
1998 		net_recursivelymarkabove(np);
1999 #else
2000 		net = ai->network;
2001 
2002 		if (net_debug)
2003 			ttyputmsg(M_("Network: arc %s killed"), describearcinst(ai));
2004 
2005 		/* stop now if the entire cell will be renumbered */
2006 		if (net_globalwork && (np->userbits&REDOCELLNET) != 0) return;
2007 
2008 		if (ai->proto == sch_busarc)
2009 		{
2010 			/* for busses, must redo entire cell */
2011 			net_recursivelymarkabove(np);
2012 			return;
2013 		}
2014 
2015 		/* if arc connects to an export, renumber all above this cell */
2016 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2017 		{
2018 			onet = pp->network;
2019 			if (onet == net) break;
2020 			if (onet->buswidth <= 1) continue;
2021 			for(i=0; i<onet->buswidth; i++)
2022 				if (onet->networklist[i] == net) break;
2023 			if (i < onet->buswidth) break;
2024 		}
2025 		if (pp != NOPORTPROTO)
2026 		{
2027 			/* deleted arc connects to an export: must renumber above */
2028 			net_recursivelymarkabove(np);
2029 			return;
2030 		}
2031 
2032 		/* if this arc was on a multiply-named network, reevaluate the cell */
2033 		if (net != NONETWORK && net->namecount > 1)
2034 		{
2035 			net_startglobalwork(np->lib);
2036 			np->userbits |= REDOCELLNET;
2037 			return;
2038 		}
2039 
2040 		/* remove network pointers to this arc */
2041 		net = ai->network;
2042 		(void)net_takearcfromnet(ai);
2043 
2044 		net_initnconnect(np);
2045 
2046 		/* renumber both sides of now unconnected network */
2047 		for(i=0; i<2; i++)
2048 		{
2049 			ni = ai->end[i].nodeinst;
2050 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2051 			{
2052 				if ((pi->conarcinst->userbits&DEADA) != 0) continue;
2053 				if (pi->conarcinst->network != net) continue;
2054 
2055 				/* remove any former network information */
2056 				(void)net_takearcfromnet(pi->conarcinst);
2057 
2058 				/* create a new network and propagate it */
2059 				if (net_nconnect(pi->conarcinst, net_newnetwork(np), np))
2060 				{
2061 					if (net_debug)
2062 						ttyputmsg(M_("Network: must recheck instances of %s"), describenodeproto(ai->parent));
2063 					net_recursivelymarkabove(np);
2064 					return;
2065 				}
2066 				break;
2067 			}
2068 			if (pi == NOPORTARCINST)
2069 			for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
2070 			{
2071 				if (pe->exportproto->network != net) continue;
2072 				if (net_pconnect(pe->exportproto))
2073 				{
2074 					if (net_debug)
2075 						ttyputmsg(M_("Network: must recheck instances of %s"),
2076 							describenodeproto(np));
2077 					net_recursivelymarkabove(np);
2078 					return;
2079 				}
2080 				break;
2081 			}
2082 		}
2083 #endif
2084 	} else if ((type&VTYPE) == VPORTPROTO)
2085 	{
2086 		pp = (PORTPROTO *)addr;
2087 		np = pp->parent;
2088 		if (net_debug) ttyputmsg(M_("Network: port %s killed"), pp->protoname);
2089 
2090 #ifdef NEWRENUM
2091 		net_recursivelymarkabove(np);
2092 #else
2093 		/* stop now if the entire cell will be renumbered */
2094 		if (net_globalwork && (np->userbits&REDOCELLNET) != 0) return;
2095 
2096 		/* remove network pointers to this port */
2097 		(void)net_takeportfromnet(pp);
2098 
2099 		/* renumber all arcs connected to the node that this port used */
2100 		for(pi = pp->subnodeinst->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2101 		{
2102 			if ((pi->conarcinst->userbits&DEADA) != 0) continue;
2103 
2104 			/* remove any former network information */
2105 			(void)net_takearcfromnet(pi->conarcinst);
2106 
2107 			/* create a new network and propagate it */
2108 			net_initnconnect(np);
2109 			if (net_nconnect(pi->conarcinst, net_newnetwork(np), np))
2110 			{
2111 				if (net_debug)
2112 					ttyputmsg(M_("Network: must recheck instances of %s"),
2113 						describenodeproto(np));
2114 				net_recursivelymarkabove(np);
2115 				return;
2116 			}
2117 		}
2118 #endif
2119 	} else if ((type&VTYPE) == VNODEPROTO)
2120 	{
2121 		np = (NODEPROTO *)addr;
2122 
2123 		/* remove references to this cell in the clear-ncc list */
2124 		net_removeclearncc(np);
2125 
2126 		/* delete all network objects in this cell */
2127 		for(net = np->firstnetwork; net != NONETWORK; net = nextnet)
2128 		{
2129 			nextnet = net->nextnetwork;
2130 			net_freenetwork(net, np);
2131 		}
2132 		np->firstnetwork = NONETWORK;
2133 	}
2134 }
2135 
net_newvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG newtype)2136 void net_newvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG newtype)
2137 {
2138 #ifdef NEWRENUM
2139 	REGISTER VARIABLE *var;
2140 	REGISTER ARCINST *ai;
2141 	CHAR *netname;
2142 	REGISTER NODEINST *ni;
2143 	REGISTER NODEPROTO *np;
2144 	REGISTER PORTPROTO *pp;
2145 #else
2146 	REGISTER VARIABLE *var;
2147 	REGISTER NETWORK *net;
2148 	REGISTER ARCINST *ai;
2149 	CHAR **strings, *netname;
2150 	REGISTER NODEINST *ni;
2151 	REGISTER NODEPROTO *np;
2152 	REGISTER INTBIG count;
2153 	REGISTER PORTPROTO *pp, *subpp;
2154 #endif
2155 
2156 	if ((newtype&VCREF) != 0)
2157 	{
2158 		if ((type&VTYPE) == VPORTPROTO)
2159 		{
2160 			netname = changedvariablename(type, key, newtype);
2161 			if (namesame(netname, x_("userbits")) == 0)
2162 			{
2163 				/* changing characteristics on export invalidates NCC of cell */
2164 				pp = (PORTPROTO *)addr;
2165 				net_queueclearncc(pp->parent);
2166 				return;
2167 			}
2168 
2169 			if (namesame(netname, x_("protoname")) == 0)
2170 			{
2171 				if (net_debug)
2172 					ttyputmsg(M_("Network: export name %s created"), netname);
2173 
2174 				/* stop now if the entire cell will be renumbered */
2175 				pp = (PORTPROTO *)addr;
2176 #ifdef NEWRENUM
2177 				net_recursivelymarkabove(pp->parent);
2178 #else
2179 				subpp = pp;
2180 				ni = subpp->subnodeinst;
2181 				while (ni->proto->primindex == 0)
2182 				{
2183 					ni = subpp->subnodeinst;
2184 					subpp = subpp->subportproto;
2185 				}
2186 				if (ni->proto != sch_buspinprim) return;
2187 				if (net_globalwork && (pp->parent->userbits&REDOCELLNET) != 0) return;
2188 
2189 				/* check name for validity */
2190 				count = net_evalbusname(APBUS, pp->protoname, &strings, NOARCINST, pp->parent, 1);
2191 				if (count < 0)
2192 				{
2193 					ttyputerr(_("Warning (cell %s): invalid network name: '%s'"), describenodeproto(pp->parent),
2194 						pp->protoname);
2195 					return;
2196 				}
2197 
2198 				/* for busses, must redo entire cell */
2199 				if (pp->network->buswidth != count)
2200 				{
2201 					net_recursivelymarkabove(pp->parent);
2202 					return;
2203 				}
2204 #endif
2205 			}
2206 		}
2207 		return;
2208 	}
2209 
2210 	/* handle changes to variables on the network object */
2211 	if ((type&VTYPE) == VTOOL && (TOOL *)addr == net_tool)
2212 	{
2213 		if (key == net_optionskey)
2214 		{
2215 			var = getvalkey(addr, type, VINTEGER, key);
2216 			if (var != NOVARIABLE)
2217 			{
2218 				net_options = var->addr;
2219 				net_checkresistorstate = TRUE;
2220 			}
2221 			return;
2222 		}
2223 		if (key == net_unifystringskey)
2224 		{
2225 			net_recacheunifystrings();
2226 			return;
2227 		}
2228 		return;
2229 	}
2230 
2231 	/* handle changes to node variables */
2232 	if ((type&VTYPE) == VNODEINST)
2233 	{
2234 		/* handle changes to node name variable (look for arrays) */
2235 		if (key == el_node_name_key)
2236 		{
2237 			net_setnodewidth((NODEINST *)addr);
2238 			return;
2239 		}
2240 
2241 		/* changes to parameters on nodes invalidates NCC information */
2242 		var = getvalkeynoeval(addr, type, -1, key);
2243 		if (var != NOVARIABLE)
2244 		{
2245 			if (TDGETISPARAM(var->textdescript) != 0)
2246 			{
2247 				ni = (NODEINST *)addr;
2248 				net_queueclearncc(ni->parent);
2249 				return;
2250 			}
2251 		}
2252 
2253 		/* changes to transistor sizes invalidates NCC information */
2254 		if (key == el_attrkey_width || key == el_attrkey_length || key == el_attrkey_area)
2255 		{
2256 			ni = (NODEINST *)addr;
2257 			net_queueclearncc(ni->parent);
2258 			return;
2259 		}
2260 
2261 		return;
2262 	}
2263 
2264 	/* handle changes to an ARCINSTs "ARC_name" variable */
2265 	if (key != el_arc_name_key) return;
2266 	if ((type&(VTYPE|VISARRAY)) != VARCINST) return;
2267 	var = getvalkey(addr, type, VSTRING, key);
2268 	if (var == NOVARIABLE || *((CHAR *)var->addr) == 0) return;
2269 
2270 	if (net_debug)
2271 		ttyputmsg(M_("Network: arc name %s created"), (CHAR *)var->addr);
2272 
2273 	/* stop now if the entire cell will be renumbered */
2274 	ai = (ARCINST *)addr;
2275 	np = ai->parent;
2276 #ifdef NEWRENUM
2277 	net_recursivelymarkabove(np);
2278 #else
2279 	if (net_globalwork && (np->userbits&REDOCELLNET) != 0) return;
2280 
2281 	/* check name for validity */
2282 	count = net_evalbusname((ai->proto->userbits&AFUNCTION)>>AFUNCTIONSH,
2283 		(CHAR *)var->addr, &strings, ai, ai->parent, 1);
2284 	if (count < 0)
2285 	{
2286 		ttyputerr(_("Warning (cell %s): invalid network name: '%s'"),
2287 			describenodeproto(np), (CHAR *)var->addr);
2288 		return;
2289 	}
2290 
2291 	/* for busses, must redo entire cell */
2292 	if (ai->proto == sch_busarc)
2293 	{
2294 		net_recursivelymarkabove(np);
2295 		return;
2296 	}
2297 
2298 	/* if merging common net names, check this one */
2299 	net = NONETWORK;
2300 	if ((net_options&NETCONCOMMONNAME) != 0 || np->cellview == el_schematicview ||
2301 		ai->proto->tech == sch_tech)
2302 	{
2303 		/* see if network exists in this cell */
2304 		net = net_getunifiednetwork((CHAR *)var->addr, np, NONETWORK);
2305 	}
2306 	if (net == NONETWORK) net = net_newnetwork(np); else
2307 	{
2308 		if (net_current_source == us_tool)
2309 			ttyputmsg(_("Network '%s' extended to this arc"), describenetwork(net));
2310 	}
2311 
2312 	/* propagate the network through this cell */
2313 	net_initnconnect(np);
2314 	if (net_nconnect(ai, net, np))
2315 	{
2316 		if (net_debug) ttyputmsg(M_("Network: must recheck instances of %s"),
2317 			describenodeproto(np));
2318 		net_recursivelymarkabove(np);
2319 	}
2320 #endif
2321 }
2322 
net_killvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG oldaddr,INTBIG oldtype,UINTBIG * olddescript)2323 void net_killvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG oldaddr, INTBIG oldtype,
2324 	UINTBIG *olddescript)
2325 {
2326 	REGISTER ARCINST *ai;
2327 #ifndef NEWRENUM
2328 	REGISTER NODEPROTO *np;
2329 #endif
2330 	Q_UNUSED( olddescript );
2331 
2332 	/* handle changes to node name variable (look for arrays) */
2333 	if ((type&VTYPE) == VNODEINST)
2334 	{
2335 		if (key == el_node_name_key)
2336 		{
2337 			net_setnodewidth((NODEINST *)addr);
2338 		}
2339 		return;
2340 	}
2341 
2342 	/* only interested in the string variable "ARC_name" on ARCINSTs */
2343 	if (key != el_arc_name_key) return;
2344 	if ((type&(VTYPE|VISARRAY)) != VARCINST) return;
2345 	if ((oldtype&(VTYPE|VISARRAY|VCREF)) != VSTRING) return;
2346 	if (*((CHAR *)oldaddr) == 0) return;
2347 
2348 	if (net_debug)
2349 		ttyputmsg(M_("Network: arc name '%s' deleted"), (CHAR *)oldaddr);
2350 
2351 	/* get the arc being unnamed */
2352 	ai = (ARCINST *)addr;
2353 #ifdef NEWRENUM
2354 	net_recursivelymarkabove(ai->parent);
2355 #else
2356 	if (ai->network == NONETWORK) return;
2357 	np = ai->parent;
2358 
2359 	/* stop now if the entire cell will be renumbered */
2360 	if (net_globalwork && (np->userbits&REDOCELLNET) != 0) return;
2361 
2362 	/* no network functions on nonelectrical arcs */
2363 	if (((ai->proto->userbits&AFUNCTION)>>AFUNCTIONSH) == APNONELEC) return;
2364 
2365 	/* if this network is at all complex, must renumber cell */
2366 	if (ai->network->namecount != 1 || ai->network->arccount != 1 ||
2367 		ai->network->portcount != 0 || ai->network->buslinkcount != 0)
2368 	{
2369 		net_recursivelymarkabove(np);
2370 		return;
2371 	}
2372 
2373 	/* remove any former network information */
2374 	(void)net_takearcfromnet(ai);
2375 
2376 	/* create a new network and propagate it */
2377 	net_initnconnect(np);
2378 	if (net_nconnect(ai, net_newnetwork(np), np))
2379 	{
2380 		if (net_debug) ttyputmsg(M_("Network: must recheck instances of %s"),
2381 			describenodeproto(np));
2382 		net_recursivelymarkabove(np);
2383 	}
2384 #endif
2385 }
2386 
net_readlibrary(LIBRARY * lib)2387 void net_readlibrary(LIBRARY *lib)
2388 {
2389 	REGISTER VARIABLE *var;
2390 	Q_UNUSED( lib );
2391 
2392 	var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_optionskey);
2393 	if (var != NOVARIABLE)
2394 	{
2395 		net_options = var->addr;
2396 		net_checkresistorstate = TRUE;
2397 	}
2398 	net_recacheunifystrings();
2399 
2400 	/* handle obsolete flags */
2401 	var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_connect_power_groundkey);
2402 	if (var != NOVARIABLE)
2403 	{
2404 		if (var->addr != 0) net_options |= NETCONPWRGND; else
2405 			net_options &= ~NETCONPWRGND;
2406 		net_found_obsolete_variables = 1;
2407 	}
2408 	var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_connect_common_namekey);
2409 	if (var != NOVARIABLE)
2410 	{
2411 		if (var->addr != 0) net_options |= NETCONCOMMONNAME; else
2412 			net_options &= ~NETCONCOMMONNAME;
2413 		net_found_obsolete_variables = 1;
2414 	}
2415 }
2416 
net_eraselibrary(LIBRARY * lib)2417 void net_eraselibrary(LIBRARY *lib)
2418 {
2419 	Q_UNUSED( lib );
2420 }
2421 
2422 /*********************** NCC INVALIDATION ***********************/
2423 
2424 /*
2425  * Routine to allocate a "clear NCC" object.
2426  * Returns NOCLEARNCC on error.
2427  */
net_allocclearncc(void)2428 CLEARNCC *net_allocclearncc(void)
2429 {
2430 	REGISTER CLEARNCC *cn;
2431 
2432 	if (net_clearnccfree != NOCLEARNCC)
2433 	{
2434 		cn = net_clearnccfree;
2435 		net_clearnccfree = cn->nextclearncc;
2436 	} else
2437 	{
2438 		cn = (CLEARNCC *)emalloc(sizeof (CLEARNCC), net_tool->cluster);
2439 		if (cn == 0) return(NOCLEARNCC);
2440 	}
2441 	return(cn);
2442 }
2443 
2444 /*
2445  * Routine to free clear-NCC object "cn".
2446  */
net_freeclearncc(CLEARNCC * cn)2447 void net_freeclearncc(CLEARNCC *cn)
2448 {
2449 	cn->nextclearncc = net_clearnccfree;
2450 	net_clearnccfree = cn;
2451 }
2452 
2453 /*
2454  * Routine to queue cell "np" to have its NCC cache cleared.
2455  */
net_queueclearncc(NODEPROTO * np)2456 void net_queueclearncc(NODEPROTO *np)
2457 {
2458 	REGISTER CLEARNCC *cn;
2459 
2460 	/* ignore duplicates */
2461 	for(cn = net_firstclearncc; cn != NOCLEARNCC; cn = cn->nextclearncc)
2462 		if (cn->np == np) return;
2463 
2464 	/* create a clear-ncc object for this request */
2465 	cn = net_allocclearncc();
2466 	if (cn == NOCLEARNCC) return;
2467 	cn->np = np;
2468 
2469 	/* put this on the list */
2470 	cn->nextclearncc = net_firstclearncc;
2471 	net_firstclearncc = cn;
2472 }
2473 
2474 /*
2475  * Routine to remove references to cell "np" in the clear-ncc list because the cell has
2476  * been deleted.
2477  */
net_removeclearncc(NODEPROTO * np)2478 void net_removeclearncc(NODEPROTO *np)
2479 {
2480 	REGISTER CLEARNCC *cn, *lastcn;
2481 
2482 	lastcn = NOCLEARNCC;
2483 	for(cn = net_firstclearncc; cn != NOCLEARNCC; cn = cn->nextclearncc)
2484 	{
2485 		if (cn->np == np)
2486 		{
2487 			if (lastcn == NOCLEARNCC) net_firstclearncc->nextclearncc = cn->nextclearncc; else
2488 				lastcn->nextclearncc = cn->nextclearncc;
2489 			net_freeclearncc(cn);
2490 			return;
2491 		}
2492 		lastcn = cn;
2493 	}
2494 }
2495 
2496 /*********************** RECURSIVE NETWORK TRACING ***********************/
2497 
2498 /*
2499  * Routine to allocate an "arc check" object for network tracing.
2500  * Returns NOARCCHECK on error.
2501  */
net_allocarccheck(void)2502 ARCCHECK *net_allocarccheck(void)
2503 {
2504 	REGISTER ARCCHECK *ac;
2505 
2506 	if (net_arccheckfree != NOARCCHECK)
2507 	{
2508 		ac = net_arccheckfree;
2509 		net_arccheckfree = ac->nextarccheck;
2510 	} else
2511 	{
2512 		ac = (ARCCHECK *)emalloc(sizeof (ARCCHECK), net_tool->cluster);
2513 		if (ac == 0) return(NOARCCHECK);
2514 	}
2515 	return(ac);
2516 }
2517 
2518 /*
2519  * Routine to free arc check object "ac".
2520  */
net_freearccheck(ARCCHECK * ac)2521 void net_freearccheck(ARCCHECK *ac)
2522 {
2523 	ac->nextarccheck = net_arccheckfree;
2524 	net_arccheckfree = ac;
2525 }
2526 
2527 /*
2528  * routine to initialize for network renumbering done through "net_nconnect".
2529  */
net_initnconnect(NODEPROTO * np)2530 void net_initnconnect(NODEPROTO *np)
2531 {
2532 	REGISTER ARCINST *ai;
2533 
2534 	/* mark all arcs as un-checked */
2535 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
2536 		ai->temp2 = 0;
2537 }
2538 
2539 
2540 /*
2541  * routine to trace all electrical paths starting at the given arcinst "ai"
2542  * and set the network to "newnetwork".  The pointers "power" and "ground"
2543  * are the current power and ground networks in the cell.  Returns true
2544  * if the cell should be rechecked (because ports were modified).  Traces
2545  * contents ports in case of iconic connections.
2546  */
net_nconnect(ARCINST * ai,NETWORK * newnetwork,NODEPROTO * np)2547 BOOLEAN net_nconnect(ARCINST *ai, NETWORK *newnetwork, NODEPROTO *np)
2548 {
2549 	REGISTER ARCCHECK *ac;
2550 	BOOLEAN result;
2551 #if 0
2552 	REGISTER ARCINST *oai;
2553 
2554 	for(oai = np->firstarcinst; oai != NOARCINST; oai = oai->nextarcinst)
2555 		oai->temp2 = 0;
2556 #endif
2557 
2558 	/* create an arc-check object for this request */
2559 	ac = net_allocarccheck();
2560 	if (ac == NOARCCHECK) return(FALSE);
2561 	ac->ai = ai;
2562 	ai->temp2 = 1;
2563 
2564 	/* put this on the list */
2565 	ac->nextarccheck = NOARCCHECK;
2566 	net_firstarccheck = ac;
2567 
2568 	/* process everything on the list */
2569 	result = FALSE;
2570 	while (net_firstarccheck != NOARCCHECK)
2571 	{
2572 		/* remove the top of the list */
2573 		ac = net_firstarccheck;
2574 		net_firstarccheck = ac->nextarccheck;
2575 
2576 		/* process it */
2577 		if (net_donconnect(ac->ai, newnetwork, np)) result = TRUE;
2578 
2579 		/* free this list object */
2580 		net_freearccheck(ac);
2581 	}
2582 	return(result);
2583 }
2584 
net_donconnect(ARCINST * ai,NETWORK * newnetwork,NODEPROTO * np)2585 BOOLEAN net_donconnect(ARCINST *ai, NETWORK *newnetwork, NODEPROTO *np)
2586 {
2587 	REGISTER ARCINST *oai;
2588 	REGISTER NODEINST *ni;
2589 	NODEINST *arrayni;
2590 	PORTPROTO *arraypp;
2591 	REGISTER PORTARCINST *pi;
2592 	REGISTER PORTEXPINST *pe;
2593 	REGISTER PORTPROTO *cpp, *copp;
2594 	REGISTER NODEPROTO *cnp;
2595 	REGISTER VARIABLE *var;
2596 	REGISTER CHAR *pt, *base1, *base2, *arcname;
2597 	static CHAR arctag[50];
2598 	INTBIG special;
2599 	REGISTER INTBIG ret, i, j, tempname, fun, width, buswidth, len1, len2, base;
2600 	REGISTER BOOLEAN recheck;
2601 	REGISTER ARCCHECK *ac;
2602 
2603 	if (net_debug)
2604 		ttyputmsg(M_("Setting network %ld onto arc %s"), newnetwork, describearcinst(ai));
2605 
2606 	if (ai->network == newnetwork) return(FALSE);
2607 
2608 	/* ignore arcs with no signals on them */
2609 	if (((ai->proto->userbits&AFUNCTION)>>AFUNCTIONSH) == APNONELEC) return(FALSE);
2610 
2611 	/* ignore if two busses have different width */
2612 	var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
2613 	if (var == NOVARIABLE) arcname = 0; else
2614 		arcname = (CHAR *)var->addr;
2615 	if (ai->proto == sch_busarc && newnetwork->buswidth > 1 &&
2616 		((ai->network != NONETWORK && ai->network->buswidth > 1) || var != NOVARIABLE))
2617 	{
2618 		/* bus network */
2619 		if (var == NOVARIABLE) width = ai->network->buswidth; else
2620 		{
2621 			width = net_buswidth(arcname);
2622 			if (width == 1 && newnetwork->buswidth > 1)
2623 			{
2624 				/* name indicates one signal, see if it simply omitted any array specification */
2625 				for(pt = arcname; *pt != 0; pt++)
2626 					if (*pt == '[') break;
2627 				if (*pt == 0)
2628 				{
2629 					/* use the implied width */
2630 					if ((var->type & VDISPLAY) == 0)
2631 					{
2632 #if 0
2633 						ttyputmsg(_("Warning (cell %s): INVISIBLE unindexed arcname '%s' is used for bus"),
2634 							describenodeproto(np), arcname);
2635 #endif
2636 					} else
2637 					{
2638 						ttyputmsg(_("Warning (cell %s): unindexed arcname '%s' is used for bus"),
2639 							describenodeproto(np), arcname);
2640 					}
2641 					width = newnetwork->buswidth;
2642 				}
2643 			}
2644 		}
2645 		if (width != newnetwork->buswidth)
2646 		{
2647 			/* different width networks meet: see if it is sensible */
2648 			base1 = describenetwork(newnetwork);
2649 			if (var != NOVARIABLE) base2 = (CHAR *)var->addr; else
2650 				base2 = describenetwork(ai->network);
2651 			for(len1 = 0; base1[len1] != 0; len1++) if (base1[len1] == '[') break;
2652 			for(len2 = 0; base2[len2] != 0; len2++) if (base2[len2] == '[') break;
2653 			if (len1 != len2 || namesamen(base1, base2, len1) != 0)
2654 			{
2655 				ttyputmsg(_("Warning (cell %s): networks '%s' and '%s' connected with different lengths"),
2656 					describenodeproto(np), base1, base2);
2657 			}
2658 			return(TRUE);
2659 		}
2660 	}
2661 
2662 	/* presume that recheck of cell is not necessary */
2663 	recheck = FALSE;
2664 
2665 	/* free previous network information */
2666 	(void)net_takearcfromnet(ai);
2667 
2668 	/* add this arc to the network */
2669 	net_putarconnet(ai, newnetwork);
2670 
2671 	/* determine the width of bus arcs by looking at adjoining cell exports */
2672 	buswidth = net_buswidthofarc(ai, &arrayni, &arraypp);
2673 	if (buswidth > 1 && newnetwork->buswidth > 1)
2674 	{
2675 		if (arrayni->arraysize > 1 && buswidth / arrayni->arraysize == newnetwork->buswidth)
2676 			buswidth = newnetwork->buswidth;
2677 		if (buswidth != newnetwork->buswidth)
2678 		{
2679 			ttyputmsg(_("Warning: cell %s has %d-wide %s connected to node %s, port %s, which is %ld-wide"),
2680 				describenodeproto(np), newnetwork->buswidth, describearcinst(ai), describenodeinst(arrayni),
2681 					arraypp->protoname, buswidth);
2682 		}
2683 	}
2684 
2685 	/* if this arc has a name, establish it */
2686 	if (arcname != 0 && *arcname != 0)
2687 	{
2688 		/* add this arc name to the network */
2689 		if (net_debug)
2690 			ttyputmsg(M_("Adding name '%s' to network '%s'"), arcname, describenetwork(newnetwork));
2691 		if ((var->type&VDISPLAY) == 0) tempname = 1; else tempname = 0;
2692 		if (buswidth > 1)
2693 		{
2694 			/* be sure there is an array specification, create if not */
2695 			for(pt = arcname; *pt != 0; pt++) if (*pt == '[' || *pt == ',') break;
2696 			if (*pt == 0)
2697 			{
2698 				/* use the implied width */
2699 				if ((var->type & VDISPLAY) == 0)
2700 				{
2701 #if 0
2702 					ttyputmsg(_("Warning (cell %s): INVISIBLE unindexed arcname '%s' is used for bus"),
2703 						describenodeproto(np), arcname);
2704 #endif
2705 				} else
2706 				{
2707 					ttyputmsg(_("Warning (cell %s): unindexed arcname '%s' is used for bus"),
2708 						describenodeproto(np), arcname);
2709 				}
2710 				if (net_arrayedarcname != 0) efree(net_arrayedarcname);
2711 				if ((net_options&NETDEFBUSBASE1) == 0) base = 0; else base = 1;
2712 				if ((net_options&NETDEFBUSBASEDESC) == 0)
2713 				{
2714 					(void)esnprintf(arctag, 50, x_("[%ld:%ld]"), base, buswidth-1+base);
2715 				} else
2716 				{
2717 					(void)esnprintf(arctag, 50, x_("[%ld:%ld]"), buswidth-1+base, base);
2718 				}
2719 				net_arrayedarcname = (CHAR *)emalloc((estrlen(arcname)+estrlen(arctag)+2) * SIZEOFCHAR,
2720 					net_tool->cluster);
2721 				if (net_arrayedarcname == 0) return(FALSE);
2722 				estrcpy(net_arrayedarcname, arcname);
2723 				estrcat(net_arrayedarcname, arctag);
2724 				arcname = net_arrayedarcname;
2725 			}
2726 		}
2727 		ret = net_addnametonet(arcname, tempname, newnetwork, ai, NOPORTPROTO, np);
2728 		if (ret > 0) recheck = TRUE;
2729 		if (ret >= 0) net_putarclinkonnet(newnetwork, ai);
2730 	} else
2731 	{
2732 		if (buswidth > 1 && newnetwork->buswidth == 1)
2733 		{
2734 			/* unnamed bus: generate individual unnamed signals */
2735 			newnetwork->networklist = (NETWORK **)emalloc(((sizeof (NETWORK *)) * buswidth),
2736 				np->lib->cluster);
2737 			if (newnetwork->networklist != 0)
2738 			{
2739 				if (newnetwork->namecount > 0)
2740 				{
2741 					if (newnetwork->tempname)
2742 					{
2743 #if 0
2744 						ttyputmsg(_("Warning (cell %s): INVISIBLE unindexed netname '%s' is used for bus"),
2745 							describenodeproto(np), networkname(newnetwork, 0));
2746 #endif
2747 					} else
2748 					{
2749 						ttyputmsg(_("Warning (cell %s): unindexed netname '%s' is used for bus"),
2750 							describenodeproto(np), networkname(newnetwork, 0));
2751 					}
2752 				}
2753 				newnetwork->buswidth = (INTSML)buswidth;
2754 				net_ensuretempbusname(newnetwork);
2755 				for(i=0; i<buswidth; i++)
2756 				{
2757 					newnetwork->networklist[i] = net_newnetwork(np);
2758 					newnetwork->networklist[i]->buslinkcount++;
2759 				}
2760 			}
2761 			recheck = TRUE;
2762 		}
2763 	}
2764 
2765 	/* initialize the special information about this network */
2766 	special = newnetwork->globalnet;
2767 
2768 	/* recursively set all arcs and nodes touching this */
2769 	for(i=0; i<2; i++)
2770 	{
2771 		/* establish the contents relationships */
2772 		ni = ai->end[i].nodeinst;
2773 		if (ni == NONODEINST) continue;
2774 		if ((ni->proto->userbits&REDOCELLNET) != 0)
2775 		{
2776 			recheck = TRUE;
2777 			continue;
2778 		}
2779 		cnp = contentsview(ni->proto);
2780 		if (cnp == NONODEPROTO) cnp = ni->proto;
2781 		cpp = equivalentport(ni->proto, ai->end[i].portarcinst->proto, cnp);
2782 		if (cpp == NOPORTPROTO)
2783 		{
2784 			cpp = ai->end[i].portarcinst->proto;
2785 			if (cpp == NOPORTPROTO) continue;
2786 		}
2787 
2788 		/* if this network hit a "wire connection", must reevaluate the cell */
2789 		if (ni->proto == sch_wireconprim) recheck = TRUE;
2790 
2791 		/* if this arc end connects to an isolated port, ignore it */
2792 		if ((cpp->userbits&PORTISOLATED) != 0) continue;
2793 
2794 		/* do not follow nonbus wires onto a bus pin */
2795 		if (cnp == sch_buspinprim && ai->proto != sch_busarc) continue;
2796 
2797 		/* if this arc end is negated, ignore its node propagation */
2798 		if ((ai->userbits&ISNEGATED) != 0)
2799 		{
2800 			if ((ai->userbits&REVERSEEND) == 0)
2801 			{
2802 				if (i == 0) continue;
2803 			} else
2804 			{
2805 				if (i == 1) continue;
2806 			}
2807 		}
2808 
2809 		/* check out the node on the arc */
2810 		if (cnp == sch_globalprim)
2811 		{
2812 			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_globalnamekey);
2813 			if (var != NOVARIABLE)
2814 			{
2815 				net_setglobalnet(&special, -1, (CHAR *)var->addr, newnetwork,
2816 					((ni->userbits&NTECHBITS) >> NTECHBITSSH) << STATEBITSSH, np);
2817 				recheck = TRUE;
2818 			}
2819 		} else
2820 		{
2821 			fun = (cnp->userbits&NFUNCTION)>>NFUNCTIONSH;
2822 			if (fun == NPCONPOWER)
2823 			{
2824 				net_setglobalnet(&special, GLOBALNETPOWER, 0, newnetwork, PWRPORT, np);
2825 				recheck = TRUE;
2826 			} else if (fun == NPCONGROUND)
2827 			{
2828 				net_setglobalnet(&special, GLOBALNETGROUND, 0, newnetwork, GNDPORT, np);
2829 				recheck = TRUE;
2830 			}
2831 		}
2832 
2833 		if ((net_options&NETCONPWRGND) != 0)
2834 		{
2835 			/* see if subport on the node is power or ground */
2836 			if (portispower(cpp))
2837 			{
2838 				net_setglobalnet(&special, GLOBALNETPOWER, 0, newnetwork, PWRPORT, np);
2839 				recheck = TRUE;
2840 			} else if (portisground(cpp))
2841 			{
2842 				net_setglobalnet(&special, GLOBALNETGROUND, 0, newnetwork, GNDPORT, np);
2843 				recheck = TRUE;
2844 			}
2845 		}
2846 
2847 		/* numerate ports in "ni->proto" */
2848 		PORTPROTO *pp;
2849 		for (pp = ni->proto->firstportproto, j=0; pp != NOPORTPROTO; pp = pp->nextportproto, j++)
2850 			pp->temp1 = j;
2851 
2852 		/* get net number */
2853 		NetCellShorts *shorts = ni->proto->netd->netshorts();
2854 		INTBIG netnum = shorts->portshallowmap(ai->end[i].portarcinst->proto->temp1);
2855 		if (shorts->globalshort()) recheck = TRUE;
2856 
2857 		/* look at all other arcs connected to the node on this end of the arc */
2858 		for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2859 		{
2860 			if (shorts->portshallowmap(pi->proto->temp1) != netnum &&
2861 				(newnetwork->buswidth != 1 || pi->proto->network->buswidth <= 1))
2862 				continue;
2863 
2864 			/* select an arcinst that has not been examined */
2865 			oai = pi->conarcinst;
2866 			if (oai->temp2 != 0) continue;
2867 			if (oai == ai) continue;
2868 
2869 			if (oai->network == newnetwork) continue;
2870 
2871 			/* establish the contents connection for this portarcinst */
2872 			copp = equivalentport(ni->proto, pi->proto, cnp);
2873 			if (copp == NOPORTPROTO) copp = pi->proto;
2874 			if (copp->network == NONETWORK) continue;
2875 
2876 			/* do not follow nonbus wires from a bus pin */
2877 			if (cnp == sch_buspinprim && oai->proto != sch_busarc) continue;
2878 
2879 			/* see if the two ports connect electrically */
2880 			if (cpp->network != copp->network)
2881 			{
2882 				/* check for single signals ending up as part of another bus */
2883 				if (newnetwork->buswidth == 1 && copp->network->buswidth > 1)
2884 				{
2885 					for(j=0; j<copp->network->buswidth; j++)
2886 						if (cpp->network == copp->network->networklist[j]) break;
2887 					if (j < copp->network->buswidth)
2888 						recheck = TRUE;
2889 				}
2890 				continue;
2891 			}
2892 
2893 			/* if this arc end is negated, ignore its node propagation */
2894 			if ((oai->userbits&ISNEGATED) != 0)
2895 			{
2896 				if ((oai->userbits&REVERSEEND) == 0)
2897 				{
2898 					if (oai->end[0].portarcinst == pi) continue;
2899 				} else
2900 				{
2901 					if (oai->end[1].portarcinst == pi) continue;
2902 				}
2903 			}
2904 
2905 			/* recurse on the nodes of this arcinst */
2906 			if (net_debug)
2907 				ttyputmsg(M_("Propagating network %ld from node %s to arc %s"), newnetwork,
2908 					describenodeinst(ni), describearcinst(oai));
2909 
2910 			/* create an arc-check object for this request */
2911 			ac = net_allocarccheck();
2912 			if (ac == NOARCCHECK) return(FALSE);
2913 			ac->ai = oai;
2914 			oai->temp2 = 1;
2915 
2916 			/* put this on the list */
2917 			ac->nextarccheck = net_firstarccheck;
2918 			net_firstarccheck = ac;
2919 		}
2920 
2921 		/* set the port information for any exports */
2922 		for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
2923 		{
2924 			if (shorts->portshallowmap(pe->proto->temp1) != netnum) continue;
2925 
2926 			/* add this port name to the network */
2927 			net_addnametonet(pe->exportproto->protoname, 0, newnetwork,
2928 				NOARCINST, pe->exportproto, np);
2929 
2930 			/* network extends to export, set it */
2931 			(void)net_takeportfromnet(pe->exportproto);
2932 			net_putportonnet(pe->exportproto, newnetwork);
2933 
2934 			if ((net_options&NETCONPWRGND) != 0)
2935 			{
2936 				/* check for power or ground ports */
2937 				if (portispower(pe->exportproto))
2938 				{
2939 					net_setglobalnet(&special, GLOBALNETPOWER, 0, newnetwork, PWRPORT, np);
2940 				} else if (portisground(pe->exportproto))
2941 				{
2942 					net_setglobalnet(&special, GLOBALNETGROUND, 0, newnetwork, GNDPORT, np);
2943 				}
2944 			}
2945 			recheck = TRUE;
2946 			break;
2947 		}
2948 	}
2949 	return(recheck);
2950 }
2951 
2952 /*
2953  * routine to determine the network number of port "pp".  Returns true
2954  * if the network information has changed.
2955  */
net_pconnect(PORTPROTO * pp)2956 BOOLEAN net_pconnect(PORTPROTO *pp)
2957 {
2958 	REGISTER PORTARCINST *pi;
2959 	REGISTER PORTEXPINST *pe;
2960 	REGISTER NODEPROTO *np;
2961 	REGISTER NETWORK *oldnet, *net;
2962 	REGISTER BOOLEAN ret;
2963 	REGISTER INTBIG width;
2964 	INTBIG special;
2965 
2966 	/* throw away any existing network information */
2967 	oldnet = pp->network;
2968 	np = pp->parent;
2969 	if (oldnet != NONETWORK) (void)net_takeportfromnet(pp);
2970 
2971 	/* if port comes from an isolated subport, give it new number */
2972 	if ((pp->subportproto->userbits&PORTISOLATED) != 0)
2973 	{
2974 		net = net_newnetwork(np);
2975 		if (net_debug)
2976 			ttyputmsg(M_("Network: creating new network for isolated subport %s"),
2977 				pp->protoname);
2978 		(void)net_addnametonet(pp->protoname, 0, net, NOARCINST, pp, np);
2979 		net_putportonnet(pp, net);
2980 		return(TRUE);
2981 	}
2982 
2983 	/* next see if that port connects to an arc */
2984 	width = net_buswidth(pp->protoname);
2985 	for(pi = pp->subnodeinst->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2986 		if (pi->proto->network == pp->subportproto->network)
2987 	{
2988 		/* do not follow bus pins onto non-bus arcs */
2989 		if (pp->subnodeinst->proto == sch_buspinprim && pi->conarcinst->proto != sch_busarc)
2990 			continue;
2991 
2992 		net = pi->conarcinst->network;
2993 		if (width > 1) net = NONETWORK;
2994 		if (net == NONETWORK)
2995 		{
2996 			net = net_newnetwork(np);
2997 			if (net_debug)
2998 				ttyputmsg(M_("Network: creating new network for %s (on an arc with no net)"),
2999 					pp->protoname);
3000 		} else if (net_debug)
3001 			ttyputmsg(M_("Network: adding port %s to net %s"), pp->protoname,
3002 				describenetwork(net));
3003 		(void)net_addnametonet(pp->protoname, 0, net, pi->conarcinst, pp, np);
3004 		net_putportonnet(pp, net);
3005 		if (pp->network != oldnet) ret = TRUE; else ret = FALSE;
3006 		if (net_nconnect(pi->conarcinst, net, np)) ret = TRUE;
3007 		return(ret);
3008 	}
3009 
3010 	/* finally see if that port connects to another export */
3011 	for(pe = pp->subnodeinst->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
3012 	{
3013 		if (pe->exportproto == pp) continue;
3014 		if (pe->proto->network != pp->subportproto->network) continue;
3015 		net = pe->exportproto->network;
3016 		if (net == NONETWORK) continue;
3017 		net_putportonnet(pp, net);
3018 		(void)net_addnametonet(pp->protoname, 0, net, NOARCINST, pp, pp->parent);
3019 		if (pp->network != oldnet) return(TRUE);
3020 		return(FALSE);
3021 	}
3022 
3023 	/* give up and assign a new net number */
3024 	net = net_newnetwork(np);
3025 	if (net_debug)
3026 		ttyputmsg(M_("Network: creating new network for %s (gave up on all other tests)"),
3027 			pp->protoname);
3028 	(void)net_addnametonet(pp->protoname, 0, net, NOARCINST, pp, np);
3029 	net_putportonnet(pp, net);
3030 	if (np->cellview == el_schematicview || (np->cellview->viewstate&MULTIPAGEVIEW) != 0)
3031 	{
3032 		if (portispower(pp))
3033 		{
3034 			special = -1;
3035 			net_setglobalnet(&special, GLOBALNETPOWER, 0, net, PWRPORT, np);
3036 		} else if (portisground(pp))
3037 		{
3038 			special = -1;
3039 			net_setglobalnet(&special, GLOBALNETGROUND, 0, net, GNDPORT, np);
3040 		}
3041 	}
3042 	return(TRUE);
3043 }
3044 
3045 /*
3046  * Routine to update the array information on node "ni" (its name has changed).
3047  */
net_setnodewidth(NODEINST * ni)3048 void net_setnodewidth(NODEINST *ni)
3049 {
3050 	REGISTER INTBIG newarraysize;
3051 	REGISTER VARIABLE *var;
3052 
3053 	/* see if this node can be arrayed */
3054 	if (!isschematicview(ni->parent)) newarraysize = 0; else
3055 	{
3056 		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
3057 		if (var == NOVARIABLE)
3058 		{
3059 			newarraysize = 0;
3060 		} else
3061 		{
3062 			newarraysize = net_buswidth((CHAR *)var->addr);
3063 		}
3064 	}
3065 	if (newarraysize != ni->arraysize)
3066 	{
3067 		ni->arraysize = newarraysize;
3068 	}
3069 }
3070 
3071 /*
3072  * routine to add the name "name" to network "newnetwork", assuming that it
3073  * is connected to arc "ai" (which may be NOARCINST if it is not connected)
3074  * or port "pp" (which may be NOPORTPROTO if it is not an export) in cell
3075  * "cell".  If this addition causes a merging of networks, the routine
3076  * returns a positive value.  If the network name is invalid, the routine
3077  * returns a negative value.
3078  */
net_addnametonet(CHAR * name,INTBIG tempname,NETWORK * newnetwork,ARCINST * ai,PORTPROTO * pp,NODEPROTO * cell)3079 INTBIG net_addnametonet(CHAR *name, INTBIG tempname, NETWORK *newnetwork, ARCINST *ai,
3080 	PORTPROTO *pp, NODEPROTO *cell)
3081 {
3082 	REGISTER NETWORK *net, *subnet;
3083 	INTBIG wid, busexists;
3084 	REGISTER INTBIG count, i, bits, dontname;
3085 	REGISTER BOOLEAN recheck;
3086 	REGISTER CHAR *pt, *opt;
3087 #ifdef NEWRENUM
3088 	CHAR *netname;
3089 #else
3090 	CHAR **strings, *netname;
3091 #endif
3092 
3093 	/* special case if this is a temporary name */
3094 	if (tempname != 0)
3095 	{
3096 		/* if the net already has a real name, check it out */
3097 		if (newnetwork->namecount > 0)
3098 		{
3099 			/* if the existing network name isn't temporary, ignore this temp one */
3100 			if (newnetwork->tempname == 0) return(-1);
3101 
3102 			/* if the new name is arrayed and the old isn't, use the new */
3103 			for(pt = name; *pt != 0; pt++) if (*pt == '[') break;
3104 			for(opt = networkname(newnetwork, 0); *opt != 0; opt++) if (*opt == '[') break;
3105 			if (*opt == '[' || *pt == 0) return(-1);
3106 			((NetName*)newnetwork->netnameaddr)->removeNet(newnetwork);
3107 			newnetwork->namecount = 0;
3108 		}
3109 
3110 		/* mark the network as having a temporary name */
3111 		newnetwork->tempname = 1;
3112 	} else
3113 	{
3114 		/* this is a real name: if the net has a temporary one, kill it */
3115 		if (newnetwork->tempname != 0 && newnetwork->namecount == 1)
3116 		{
3117 			((NetName*)newnetwork->netnameaddr)->removeNet(newnetwork);
3118 			newnetwork->namecount = 0;
3119 			newnetwork->tempname = 0;
3120 		}
3121 	}
3122 
3123 	/* see if the network already has this name */
3124 #ifdef NEWRENUM
3125 	NetName *nn = cell->netd->findNetName(name, TRUE);
3126 	if (!net_nethasname(newnetwork, nn))
3127 #else
3128 	if (!net_nethasname(newnetwork, name))
3129 #endif
3130 	{
3131 		/* see if the net can be a bus */
3132 		bits = APUNKNOWN;
3133 		if (pp != NOPORTPROTO)
3134 		{
3135 			/* determine whether this port can be a bus */
3136 			for(i=0; pp->connects[i] != NOARCPROTO; i++)
3137 			{
3138 				bits = (pp->connects[i]->userbits&AFUNCTION) >> AFUNCTIONSH;
3139 				if (bits == APBUS) break;
3140 			}
3141 		} else if (ai != NOARCINST)
3142 		{
3143 			/* determine whether this arc can be a bus */
3144 			bits = (ai->proto->userbits&AFUNCTION) >> AFUNCTIONSH;
3145 		}
3146 
3147 		/* check net name for validity */
3148 		recheck = FALSE;
3149 #ifdef NEWRENUM
3150 		count = nn->busWidth();
3151 		if (bits != APBUS && count != 1)
3152 		{
3153 			ttyputerr(_("Warning (cell %s): network '%s' cannot name a single wire"),
3154 				describenodeproto(cell), name);
3155 			return(-1);
3156 		}
3157 #else
3158 		count = net_evalbusname(bits, name, &strings, ai, cell, 1);
3159 		if (count < 0)
3160 		{
3161 			ttyputerr(_("Warning (cell %s): network name '%s' is invalid"), describenodeproto(cell), name);
3162 			return(-1);
3163 		}
3164 #endif
3165 
3166 		/* check width for consistency */
3167 		busexists = 0;
3168 		if (newnetwork->namecount > 0)
3169 		{
3170 			wid = net_buswidth(networkname(newnetwork, 0));
3171 			if (count != wid)
3172 			{
3173 				ttyputerr(_("Warning (cell %s): networks '%s' and '%s' cannot connect (different width)"),
3174 					describenodeproto(cell), name, networkname(newnetwork, 0));
3175 				return(-1);
3176 			}
3177 		}
3178 		if (count > 1 && count == newnetwork->buswidth)
3179 		{
3180 			/* add new names of signals in the bus to those already on the network */
3181 			for(i=0; i<count; i++)
3182 			{
3183 #ifdef NEWRENUM
3184 				(void)allocstring(&netname, nn->subName(i)->name(), el_tempcluster);
3185 #else
3186 				(void)allocstring(&netname, strings[i], el_tempcluster);
3187 #endif
3188 				subnet = newnetwork->networklist[i];
3189 				net = NONETWORK;
3190 				if ((net_options&NETCONCOMMONNAME) != 0 || cell->cellview == el_schematicview ||
3191 					(ai != NOARCINST && ai->proto->tech == sch_tech) ||
3192 						(pp != NOPORTPROTO && pp->parent->primindex != 0 && pp->parent->tech == sch_tech))
3193 							net = net_getunifiednetwork(netname, cell, subnet);
3194 
3195 				/* special case if this is a temporary name */
3196 				dontname = 0;
3197 				if (tempname != 0)
3198 				{
3199 					/* this is a temp name: ignore if already a real one */
3200 					if (subnet->namecount > 0) dontname = 1; else
3201 						subnet->tempname = 1;
3202 				} else
3203 				{
3204 					/* this is a real name: if the net has a temporary one, kill it */
3205 					if (subnet->tempname != 0 && subnet->namecount == 1)
3206 					{
3207 						((NetName*)subnet->netnameaddr)->removeNet(subnet);
3208 						subnet->namecount = 0;
3209 						subnet->tempname = 0;
3210 					}
3211 				}
3212 
3213 #ifdef NEWRENUM
3214 				if (dontname == 0) (void)net_namenet(nn->subName(i), subnet);
3215 #else
3216 				if (dontname == 0) (void)net_namenet(netname, subnet);
3217 #endif
3218 				if (net != NONETWORK && net != subnet)
3219 				{
3220 					if (net_mergenet(net, subnet)) recheck = TRUE;
3221 				}
3222 				efree(netname);
3223 			}
3224 			busexists++;
3225 		}
3226 
3227 		/* for busses, name the network and install appropriate bus links */
3228 		if (count > 1)
3229 		{
3230 #ifdef NEWRENUM
3231 			if (!net_namenet(nn, newnetwork))
3232 				if (busexists == 0)
3233 					net_ensurebusses(newnetwork, nn, tempname);
3234 #else
3235 			if (!net_namenet(name, newnetwork))
3236 				if (busexists == 0)
3237 					net_ensurebusses(newnetwork, count, strings, tempname);
3238 #endif
3239 		} else
3240 		{
3241 #ifdef NEWRENUM
3242 			(void)net_namenet(nn, newnetwork);
3243 #else
3244 			(void)net_namenet(strings[0], newnetwork);
3245 #endif
3246 		}
3247 
3248 		/* reset "tempname" field since "net_namenet" wipes it out */
3249 		if (tempname != 0) newnetwork->tempname = 1;
3250 
3251 		/* see if this net name is in use */
3252 		net = NONETWORK;
3253 		if ((net_options&NETCONCOMMONNAME) != 0 || cell->cellview == el_schematicview ||
3254 			(ai != NOARCINST && ai->proto->tech == sch_tech) ||
3255 				(pp != NOPORTPROTO && pp->parent->primindex != 0 && pp->parent->tech == sch_tech))
3256 					net = net_getunifiednetwork(name, cell, newnetwork);
3257 
3258 		/* merge the new network with an old one of the same name, if it exists */
3259 		if (net != NONETWORK && net != newnetwork)
3260 		{
3261 			if (net_mergenet(net, newnetwork)) recheck = TRUE;
3262 		}
3263 
3264 		if (recheck) return(1);
3265 	}
3266 	return(0);
3267 }
3268 
3269 /*
3270  * recursive routine to re-do connectivity of entire library starting
3271  * at highest level cell.  Current point for re-doing connectivity is "np".
3272  * This routine is called when the node of a port has changed and all
3273  * instances of the cell need to be renumbered.  The "REDOCELLNET" flag on
3274  * cells prevents them from being checked multiple times.
3275  */
net_recursivelymarkabove(NODEPROTO * np)3276 void net_recursivelymarkabove(NODEPROTO *np)
3277 {
3278 	net_startglobalwork(np->lib);
3279 
3280 	/* skip this if already done */
3281 	if ((np->userbits&REDOCELLNET) != 0) return;
3282 
3283 	/* mark this cell to be renumbered */
3284 	if (net_debug)
3285 		ttyputmsg(M_("Network: cell %s is marked"), describenodeproto(np));
3286 	np->userbits |= REDOCELLNET;
3287 
3288 }
3289 
3290 /*********************** NETLIST MAINTENANCE ROUTINES ***********************/
3291 
3292 /*
3293  * routine to add network "net" to arc "ai"
3294  */
net_putarconnet(ARCINST * ai,NETWORK * net)3295 void net_putarconnet(ARCINST *ai, NETWORK *net)
3296 {
3297 	if (net == NONETWORK) return;
3298 	ai->network = net;
3299 	net->refcount++;
3300 }
3301 
3302 /*
3303  * routine to remove the network link from arc "ai".  Returns true if
3304  * the network has been deleted
3305  */
net_takearcfromnet(ARCINST * ai)3306 BOOLEAN net_takearcfromnet(ARCINST *ai)
3307 {
3308 	REGISTER NETWORK *net;
3309 
3310 	net = ai->network;
3311 	if (net == NONETWORK) return(FALSE);
3312 	ai->network = NONETWORK;
3313 	net_takearclinkfromnet(ai, net);
3314 	net->refcount--;
3315 
3316 	/* delete the network if all counts are zero */
3317 	if (net->portcount <= 0 && net->refcount <= 0 && net->arccount <= 0 && net->buslinkcount <= 0)
3318 	{
3319 		net_killnetwork(net, ai->parent);
3320 		return(TRUE);
3321 	}
3322 	return(FALSE);
3323 }
3324 
3325 /*
3326  * routine to add network "net" to port "pp"
3327  */
net_putportonnet(PORTPROTO * pp,NETWORK * net)3328 void net_putportonnet(PORTPROTO *pp, NETWORK *net)
3329 {
3330 	if (net == NONETWORK) return;
3331 	pp->network = net;
3332 	net->portcount++;
3333 }
3334 
3335 /*
3336  * routine to remove the network link from port "pp".  Returns true
3337  * if the network has been deleted
3338  */
net_takeportfromnet(PORTPROTO * pp)3339 BOOLEAN net_takeportfromnet(PORTPROTO *pp)
3340 {
3341 	REGISTER NETWORK *net;
3342 
3343 	net = pp->network;
3344 	if (net == NONETWORK) return(FALSE);
3345 	pp->network = NONETWORK;
3346 	net->portcount--;
3347 
3348 	/* delete the network if all counts are zero */
3349 	if (net->portcount <= 0 && net->refcount <= 0 && net->arccount <= 0 && net->buslinkcount <= 0)
3350 	{
3351 		net_killnetwork(net, pp->parent);
3352 		return(TRUE);
3353 	}
3354 	return(FALSE);
3355 }
3356 
3357 /*
3358  * routine to add arc "ai" to the list of named arcs on network "net".
3359  */
net_putarclinkonnet(NETWORK * net,ARCINST * ai)3360 void net_putarclinkonnet(NETWORK *net, ARCINST *ai)
3361 {
3362 	REGISTER ARCINST **arclist;
3363 	REGISTER INTBIG i, newsize;
3364 
3365 	if (net == NONETWORK) return;
3366 
3367 	/* if there are no arcs on the net, add this */
3368 	if (net->arccount <= 0)
3369 	{
3370 		if (net->arctotal == 0) net->arcaddr = (INTBIG)ai; else
3371 			((ARCINST **)net->arcaddr)[0] = ai;
3372 		net->arccount = 1;
3373 		return;
3374 	}
3375 
3376 	/* check that the arc isn't already on the list */
3377 	if (net->arctotal == 0)
3378 	{
3379 		if (net->arccount == 1 && (ARCINST *)net->arcaddr == ai) return;
3380 	} else
3381 	{
3382 		for(i=0; i<net->arccount; i++)
3383 			if (((ARCINST **)net->arcaddr)[i] == ai) return;
3384 	}
3385 
3386 	/* make sure there is space for the new arc pointer */
3387 	if (net->arccount >= net->arctotal)
3388 	{
3389 		newsize = net->arctotal * 2;
3390 		if (net->arccount >= newsize) newsize = net->arccount + 8;
3391 		arclist = (ARCINST **)emalloc(((sizeof (ARCINST *)) * newsize),
3392 			net->parent->lib->cluster);
3393 		if (arclist == 0) return;
3394 
3395 		/* load the array */
3396 		for(i=0; i<net->arccount; i++)
3397 		{
3398 			if (net->arctotal == 0) arclist[i] = (ARCINST *)net->arcaddr; else
3399 				arclist[i] = ((ARCINST **)net->arcaddr)[i];
3400 		}
3401 		if (net->arctotal > 0) efree((CHAR *)net->arcaddr);
3402 		net->arctotal = (INTSML)newsize;
3403 		net->arcaddr = (INTBIG)arclist;
3404 	}
3405 
3406 	/* add this arc and place the array on the net */
3407 	((ARCINST **)net->arcaddr)[net->arccount] = ai;
3408 	net->arccount++;
3409 }
3410 
3411 /*
3412  * routine to remove mention of arc "ai" on network "net"
3413  */
net_takearclinkfromnet(ARCINST * ai,NETWORK * net)3414 void net_takearclinkfromnet(ARCINST *ai, NETWORK *net)
3415 {
3416 	REGISTER INTBIG i;
3417 
3418 	if (net == NONETWORK) return;
3419 	if (net->arccount <= 0) return;
3420 
3421 	/* special check if the network has no array of arcs */
3422 	if (net->arctotal == 0)
3423 	{
3424 		if ((ARCINST *)net->arcaddr == ai) net->arccount--;
3425 		return;
3426 	}
3427 
3428 	for(i=0; i<net->arccount; i++)
3429 		if (((ARCINST **)net->arcaddr)[i] == ai)
3430 	{
3431 		/* network found in the list: remove it */
3432 		((ARCINST **)net->arcaddr)[i] = ((ARCINST **)net->arcaddr)[net->arccount-1];
3433 		net->arccount--;
3434 		return;
3435 	}
3436 }
3437 
3438 #ifdef NEWRENUM
3439 /*
3440  * routine to ensure that there are networks with the names of each
3441  * individual bus member described by subnames of net name "nn".
3442  * They are all part of the network "net"
3443  */
net_ensurebusses(NETWORK * net,NetName * nn,INTBIG tempname)3444 void net_ensurebusses(NETWORK *net, NetName *nn, INTBIG tempname)
3445 {
3446 	REGISTER INTBIG i, dontname;
3447 	REGISTER NETWORK *singlenet;
3448 	CHAR *subnetname;
3449 	INTBIG count = nn->busWidth();
3450 
3451 	if (net->buswidth == count)
3452 	{
3453 		/* already have signals in place: name them */
3454 		for(i=0; i<count; i++)
3455 		{
3456 			singlenet = getnetwork(nn->subName(i)->name(), net->parent);
3457 			if (singlenet == NONETWORK)
3458 			{
3459 				singlenet = net->networklist[i];
3460 
3461 				/* special case if this is a temporary name */
3462 				dontname = 0;
3463 				if (tempname != 0)
3464 				{
3465 					/* this is a temp name: ignore if already a real one */
3466 					if (singlenet->namecount > 0) dontname = 1; else
3467 						singlenet->tempname = 1;
3468 				} else
3469 				{
3470 					/* this is a real name: if the net has a temporary one, kill it */
3471 					if (singlenet->tempname != 0 && singlenet->namecount > 0)
3472 					{
3473 						((NetName*)singlenet->netnameaddr)->removeNet(singlenet);
3474 						singlenet->namecount = 0;
3475 						singlenet->tempname = 0;
3476 					}
3477 				}
3478 				if (dontname == 0)
3479 					(void)net_namenet(nn->subName(i), net->networklist[i]);
3480 			}
3481 		}
3482 		return;
3483 	}
3484 
3485 	net->buswidth = (INTSML)count;
3486 	net_ensuretempbusname(net);
3487 	net->networklist = (NETWORK **)emalloc(((sizeof (NETWORK *)) * count),
3488 		net->parent->lib->cluster);
3489 	if (net->networklist == 0) return;
3490 
3491 	/* generate network names for each array member */
3492 	for(i=0; i<count; i++)
3493 	{
3494 		(void)allocstring(&subnetname, nn->subName(i)->name(), el_tempcluster);
3495 		net->networklist[i] = getnetwork(subnetname, net->parent);
3496 		efree(subnetname);
3497 		if (net->networklist[i] == NONETWORK)
3498 		{
3499 			net->networklist[i] = net_newnetwork(net->parent);
3500 			(void)net_namenet(nn->subName(i), net->networklist[i]);
3501 		}
3502 		net->networklist[i]->buslinkcount++;
3503 		net->networklist[i]->tempname = (INTSML)tempname;
3504 	}
3505 }
3506 
3507 #else
3508 /*
3509  * routine to ensure that there are networks with the names of each
3510  * individual bus member described by the "count" signals in "strings".
3511  * They are all part of the network "net"
3512  */
net_ensurebusses(NETWORK * net,INTBIG count,CHAR ** strings,INTBIG tempname)3513 void net_ensurebusses(NETWORK *net, INTBIG count, CHAR **strings, INTBIG tempname)
3514 {
3515 	REGISTER INTBIG i, dontname;
3516 	REGISTER NETWORK *singlenet;
3517 	CHAR *subnetname;
3518 
3519 	if (net->buswidth == count)
3520 	{
3521 		/* already have signals in place: name them */
3522 		for(i=0; i<count; i++)
3523 		{
3524 			singlenet = getnetwork(strings[i], net->parent);
3525 			if (singlenet == NONETWORK)
3526 			{
3527 				singlenet = net->networklist[i];
3528 
3529 				/* special case if this is a temporary name */
3530 				dontname = 0;
3531 				if (tempname != 0)
3532 				{
3533 					/* this is a temp name: ignore if already a real one */
3534 					if (singlenet->namecount > 0) dontname = 1; else
3535 						singlenet->tempname = 1;
3536 				} else
3537 				{
3538 					/* this is a real name: if the net has a temporary one, kill it */
3539 					if (singlenet->tempname != 0 && singlenet->namecount > 0)
3540 					{
3541 						((NetName*)singlenet->netnameaddr)->removeNet(singlenet);
3542 						singlenet->namecount = 0;
3543 						singlenet->tempname = 0;
3544 					}
3545 				}
3546 				if (dontname == 0)
3547 					(void)net_namenet(strings[i], net->networklist[i]);
3548 			}
3549 		}
3550 		return;
3551 	}
3552 
3553 	net->buswidth = (INTSML)count;
3554 	net_ensuretempbusname(net);
3555 	net->networklist = (NETWORK **)emalloc(((sizeof (NETWORK *)) * count),
3556 		net->parent->lib->cluster);
3557 	if (net->networklist == 0) return;
3558 
3559 	/* generate network names for each array member */
3560 	for(i=0; i<count; i++)
3561 	{
3562 		(void)allocstring(&subnetname, strings[i], el_tempcluster);
3563 		net->networklist[i] = getnetwork(subnetname, net->parent);
3564 		efree(subnetname);
3565 		if (net->networklist[i] == NONETWORK)
3566 		{
3567 			net->networklist[i] = net_newnetwork(net->parent);
3568 			(void)net_namenet(strings[i], net->networklist[i]);
3569 		}
3570 		net->networklist[i]->buslinkcount++;
3571 		net->networklist[i]->tempname = (INTSML)tempname;
3572 	}
3573 }
3574 
3575 #endif
3576 
3577 /*
3578  * routine to get "i"th name of network "net". Returns 0 if there is no "i"th name
3579  */
networkname(NETWORK * net,INTBIG i)3580 CHAR *networkname(NETWORK *net, INTBIG i)
3581 {
3582 	if (i < 0 || i >= net->namecount) return(0);
3583 	NetName *nn = (net->namecount > 1 ? ((NetName**)net->netnameaddr)[i] : (NetName*)net->netnameaddr);
3584 	return(nn->name());
3585 }
3586 
3587 /*
3588  * routine to find network "netname" in cell "cell".  Returns NONETWORK
3589  * if it cannot be found
3590  */
net_getnetwork(CHAR * netname,NODEPROTO * cell)3591 NETWORK *net_getnetwork(CHAR *netname, NODEPROTO *cell)
3592 {
3593 	REGISTER NETWORK *net;
3594 	NetName *nn = cell->netd->findNetName( netname, FALSE );
3595 	if (nn)
3596 	{
3597 		net = nn->firstNet();
3598 		if (net != NONETWORK) return(net);
3599 	}
3600 	return(NONETWORK);
3601 }
3602 
3603 #ifdef NEWRENUM
3604 /*
3605  * routine to give network "net" the name "nn".  Returns true if the network
3606  * already has the name.
3607  */
net_namenet(NetName * nn,NETWORK * net)3608 BOOLEAN net_namenet(NetName *nn, NETWORK *net)
3609 #else
3610 /*
3611  * routine to give network "net" the name "name".  Returns true if the network
3612  * already has the name.
3613  */
3614 BOOLEAN net_namenet(CHAR *name, NETWORK *net)
3615 #endif
3616 {
3617 	REGISTER INTBIG i, j, match;
3618 
3619 	if (net->tempname != 0)
3620 	{
3621 		/* remove temporary name */
3622 		if (net->namecount > 0) ((NetName*)net->netnameaddr)->removeNet(net);
3623 		net->namecount = 0;
3624 		net->tempname = 0;
3625 	}
3626 #ifdef NEWRENUM
3627 	CHAR *name = nn->name();
3628 #else
3629 	NetName *nn = net->parent->netd->findNetName( name, TRUE );
3630 #endif
3631 	if (net->namecount == 0)
3632 	{
3633 		/* network is unnamed: name it */
3634 		nn->addNet( net );
3635 		net->namecount++;
3636 		net->netnameaddr = (INTBIG)nn;
3637 		return(FALSE);
3638 	}
3639 
3640 	/* see if the network already has this name */
3641 	for(i=0; i<net->namecount; i++)
3642 	{
3643 		match = namesame(name, networkname(net, i));
3644 		if (match == 0) return(TRUE);
3645 		if (match < 0) break;
3646 	}
3647 	nn->addNet( net );
3648 	NetName **newnameaddr = (NetName**)emalloc((net->namecount + 1)*sizeof(NetName*), net->parent->lib->cluster);
3649 	newnameaddr[i] = nn;
3650 	if (net->namecount == 1)
3651 	{
3652 		newnameaddr[1 - i] = (NetName*)net->netnameaddr;
3653 	} else
3654 	{
3655 		NetName **oldnameaddr = (NetName**)net->netnameaddr;
3656 		for(j=0; j < i; j++)
3657 			newnameaddr[j] = oldnameaddr[j];
3658 		for(j=i; j < net->namecount; j++)
3659 			newnameaddr[j+1] = oldnameaddr[j];
3660 		efree((CHAR *)oldnameaddr);
3661 	}
3662 	net->netnameaddr = (INTBIG)newnameaddr;
3663 	net->namecount++;
3664 	return(FALSE);
3665 }
3666 
3667 /*
3668  * routine to get a new network object from cell "cell" and return the
3669  * address.  Returns NONETWORK on error.
3670  */
net_newnetwork(NODEPROTO * cell)3671 NETWORK *net_newnetwork(NODEPROTO *cell)
3672 {
3673 	REGISTER NETWORK *net;
3674 
3675 	if (cell->lib->freenetwork != NONETWORK)
3676 	{
3677 		/* take from list of unused networks objects in the cell */
3678 		net = cell->lib->freenetwork;
3679 		cell->lib->freenetwork = net->nextnetwork;
3680 	} else
3681 	{
3682 		/* allocate a new network object */
3683 		net = (NETWORK *)emalloc(sizeof(NETWORK), cell->lib->cluster);
3684 		if (net == 0) return(NONETWORK);
3685 		net->arctotal = 0;
3686 	}
3687 	net->netnameaddr = 0;
3688 	net->namecount = 0;
3689 	net->tempname = 0;
3690 	net->arccount = net->refcount = net->portcount = net->buslinkcount = 0;
3691 	net->parent = cell;
3692 	net->globalnet = -1;
3693 	net->buswidth = 1;
3694 	net->firstvar = NOVARIABLE;
3695 	net->numvar = 0;
3696 
3697 	/* link the network into the cell */
3698 	net->nextnetwork = cell->firstnetwork;
3699 	net->prevnetwork = NONETWORK;
3700 	if (cell->firstnetwork != NONETWORK) cell->firstnetwork->prevnetwork = net;
3701 	cell->firstnetwork = net;
3702 	return(net);
3703 }
3704 
3705 /*
3706  * routine to return network "net" to cell "cell"
3707  */
net_killnetwork(NETWORK * net,NODEPROTO * cell)3708 void net_killnetwork(NETWORK *net, NODEPROTO *cell)
3709 {
3710 	if (net->prevnetwork == NONETWORK) cell->firstnetwork = net->nextnetwork; else
3711 		net->prevnetwork->nextnetwork = net->nextnetwork;
3712 	if (net->nextnetwork != NONETWORK)
3713 		net->nextnetwork->prevnetwork = net->prevnetwork;
3714 
3715 	/* if this is a global network, mark the global signal "available" */
3716 	if (net->globalnet >= 0)
3717 	{
3718 		if (net->globalnet < cell->globalnetcount)
3719 		{
3720 			cell->globalnetworks[net->globalnet] = NONETWORK;
3721 			if (net_debug)
3722 				ttyputmsg(M_("Global network '%s' deleted from %s"), cell->globalnetnames[net->globalnet],
3723 					describenodeproto(cell));
3724 			/* don't mark above if the entire cell will be renumbered */
3725 			if (!net_globalwork || (cell->userbits&REDOCELLNET) == 0)
3726 				net_recursivelymarkabove(cell);
3727 		}
3728 	}
3729 
3730 	/* routine to remove bus links */
3731 	net_removebuslinks(net);
3732 
3733 	/* delete the network */
3734 	net_freenetwork(net, cell);
3735 }
3736 
3737 /*
3738  * routine to remove bus links to network "net"
3739  */
net_removebuslinks(NETWORK * net)3740 void net_removebuslinks(NETWORK *net)
3741 {
3742 	REGISTER NETWORK *subnet;
3743 	REGISTER INTBIG i;
3744 
3745 	if (net->buswidth <= 1) return;
3746 
3747 	for(i=0; i<net->buswidth; i++)
3748 	{
3749 		subnet = net->networklist[i];
3750 		if (subnet == NONETWORK) continue;
3751 		subnet->buslinkcount--;
3752 		if (subnet->portcount <= 0 && subnet->refcount <= 0 &&
3753 			subnet->arccount <= 0 && subnet->buslinkcount <= 0)
3754 				net_killnetwork(subnet, subnet->parent);
3755 	}
3756 	efree((CHAR *)net->networklist);
3757 	net->buswidth = 1;
3758 }
3759 
net_freenetwork(NETWORK * net,NODEPROTO * cell)3760 void net_freenetwork(NETWORK *net, NODEPROTO *cell)
3761 {
3762 	if (net->namecount == 1)
3763 	{
3764 		((NetName*)net->netnameaddr)->removeNet(net);
3765 	} else if (net->namecount > 1)
3766 	{
3767 		NetName **netnames = (NetName**)net->netnameaddr;
3768 		for (INTBIG i = 0; i < net->namecount; i++)
3769 			netnames[i]->removeNet(net);
3770 		efree((CHAR*)netnames);
3771 	}
3772 	net->namecount = 0;
3773 	net->netnameaddr = 0;
3774 	if (net->buswidth > 1) efree((CHAR *)net->networklist);
3775 	net->buswidth = 1;
3776 	if (net->numvar != 0) db_freevars(&net->firstvar, &net->numvar);
3777 
3778 	/* insert in linked list of free networks in the cell */
3779 	net->nextnetwork = cell->lib->freenetwork;
3780 	cell->lib->freenetwork = net;
3781 }
3782 
3783 /*
3784  * routine to replace all occurrences of "oldnet" with "newnet".  Returns
3785  * true if ports were changed.  NOTE: merged busses must have same width
3786  * and this routine cannot handle that error condition properly.  Shouldn't
3787  * ever happen.
3788  */
net_mergenet(NETWORK * oldnet,NETWORK * newnet)3789 BOOLEAN net_mergenet(NETWORK *oldnet, NETWORK *newnet)
3790 {
3791 	REGISTER INTBIG i;
3792 	REGISTER BOOLEAN ret;
3793 	REGISTER BOOLEAN portschanged;
3794 	REGISTER ARCINST *ai;
3795 	REGISTER PORTPROTO *pp;
3796 	REGISTER NETWORK *net;
3797 
3798 	if (net_debug)
3799 		ttyputmsg(M_("Merging old network %ld into %ld"), oldnet, newnet);
3800 
3801 	/* merging is easy if the nets are already the same */
3802 	if (oldnet == newnet) return(FALSE);
3803 
3804 	/* cannot merge busses of dissimilar width (system error) */
3805 	if (oldnet->buswidth != newnet->buswidth)
3806 	{
3807 		ttyputerr(_("Warning (cell %s): cannot connect net '%s' (%d wide) and net '%s' (%d wide)"),
3808 			describenodeproto(newnet->parent), describenetwork(oldnet), oldnet->buswidth,
3809 				describenetwork(newnet), newnet->buswidth);
3810 		return(TRUE);
3811 	}
3812 
3813 	/* if one of the nets has a temporary name, drop it */
3814 	if (newnet->tempname != 0 && newnet->namecount > 0 && oldnet->namecount > 0)
3815 	{
3816 		/* new network has temporary name, old has real name */
3817 		((NetName*)newnet->netnameaddr)->removeNet(newnet);
3818 		newnet->namecount = 0;
3819 		newnet->tempname = 0;
3820 	}
3821 	if (oldnet->tempname == 0 || newnet->namecount == 0)
3822 	{
3823 		/* add the names of old network on the new one */
3824 #ifdef NEWRENUM
3825 		if (oldnet->namecount == 1)
3826 		{
3827 			NetName *nn = (NetName*)oldnet->netnameaddr;
3828 			(void)net_namenet(nn, newnet);
3829 		} else if (oldnet->namecount > 1)
3830 		{
3831 			NetName **netnames = (NetName**)oldnet->netnameaddr;
3832 			for(i=0; i<oldnet->namecount; i++)
3833 			{
3834 				(void)net_namenet(netnames[i], newnet);
3835 			}
3836 		}
3837 #else
3838 		for(i=0; i<oldnet->namecount; i++)
3839 		{
3840 			(void)net_namenet(networkname(oldnet, i), newnet);
3841 		}
3842 #endif
3843 	}
3844 
3845 	/* if old net is global, set that on new net */
3846 	if (oldnet->globalnet >= 0)
3847 	{
3848 		newnet->globalnet = oldnet->globalnet;
3849 		newnet->parent->globalnetworks[oldnet->globalnet] = newnet;
3850 		oldnet->globalnet = -1;
3851 	}
3852 
3853 	/* if there are bus links on the old network, switch it to the new one */
3854 	if (oldnet->buslinkcount != 0)
3855 	{
3856 		for(net = oldnet->parent->firstnetwork; net != NONETWORK; net = net->nextnetwork)
3857 		{
3858 			if (net->buswidth <= 1) continue;
3859 			for(i=0; i<net->buswidth; i++)
3860 			{
3861 				if (net->networklist[i] != oldnet) continue;
3862 				net->networklist[i] = newnet;
3863 				newnet->buslinkcount++;
3864 				oldnet->buslinkcount--;
3865 
3866 				/* delete the network if all counts are zero */
3867 				if (oldnet->portcount <= 0 && oldnet->refcount <= 0 &&
3868 					oldnet->arccount <= 0 && oldnet->buslinkcount <= 0)
3869 				{
3870 					net_killnetwork(oldnet, oldnet->parent);
3871 					return(FALSE);
3872 				}
3873 			}
3874 			if (oldnet->buslinkcount == 0) break;
3875 		}
3876 	}
3877 #if 0
3878 	/* place arc links on new network */
3879 	for(i=0; i<oldnet->arccount; i++)
3880 	{
3881 		if (oldnet->arctotal == 0)
3882 			net_putarclinkonnet(newnet, (ARCINST *)oldnet->arcaddr); else
3883 				net_putarclinkonnet(newnet, ((ARCINST **)oldnet->arcaddr)[i]);
3884 	}
3885 #endif
3886 	/* replace arc references to the old network with the new one */
3887 	for(ai = oldnet->parent->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3888 	{
3889 		if (ai->network == oldnet)
3890 		{
3891 			ret = net_takearcfromnet(ai);
3892 			net_putarconnet(ai, newnet);
3893 			if (ret) return(FALSE);
3894 		}
3895 	}
3896 
3897 	/* replace port references to the old network with the new one */
3898 	portschanged = FALSE;
3899 	for(pp = oldnet->parent->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
3900 	{
3901 		if (pp->network != oldnet) continue;
3902 		ret = net_takeportfromnet(pp);
3903 		net_putportonnet(pp, newnet);
3904 		if (ret) return(TRUE);
3905 		portschanged = TRUE;
3906 	}
3907 
3908 	/* handle globals inside subcells */
3909 	if (oldnet->refcount > 0)
3910 	{
3911 		newnet->refcount += oldnet->refcount;
3912 		oldnet->refcount = 0;
3913 
3914 		/* delete the network if all counts are zero */
3915 		if (oldnet->portcount <= 0 && oldnet->refcount <= 0 &&
3916 			oldnet->arccount <= 0 && oldnet->buslinkcount <= 0)
3917 		{
3918 			net_killnetwork(oldnet, oldnet->parent);
3919 			return(TRUE);
3920 		}
3921 	} else
3922 	{
3923 		ttyputmsg(M_("Network tool internal error in net_mergenet cell %s: Why oldnet '%s' hasn't been deleted yet ?"),
3924 			describenodeproto(newnet->parent), describenetwork(newnet));
3925 	}
3926 
3927 	return(portschanged);
3928 }
3929 
3930 /*
3931  * routine to initialize global evaluation
3932  */
net_startglobalwork(LIBRARY * lib)3933 void net_startglobalwork(LIBRARY *lib)
3934 {
3935 	REGISTER NODEPROTO *np;
3936 	REGISTER LIBRARY *olib;
3937 
3938 	/* if this is not the first request for global evaluation, quit */
3939 	if (!net_globalwork)
3940 	{
3941 		/* clear all library flags */
3942 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3943 			olib->userbits &= ~REDOCELLLIB;
3944 		net_globalwork = TRUE;
3945 	}
3946 
3947 	/* if this library hasn't been started, do so */
3948 	if ((lib->userbits&REDOCELLLIB) == 0)
3949 	{
3950 		lib->userbits |= REDOCELLLIB;
3951 
3952 		/* clear all flags in this library */
3953 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3954 			np->userbits &= ~REDOCELLNET;
3955 	}
3956 }
3957 
3958 /*
3959  * rename network "oldname" to "newname" in cell "np"
3960  */
net_renamenet(CHAR * oldname,CHAR * newname,NODEPROTO * np)3961 void net_renamenet(CHAR *oldname, CHAR *newname, NODEPROTO *np)
3962 {
3963 	REGISTER CHAR *pt, *arcname, *startpt;
3964 	CHAR *netname;
3965 	REGISTER INTBIG k, found, len;
3966 	UINTBIG descript[TEXTDESCRIPTSIZE];
3967 	REGISTER NETWORK *net;
3968 	REGISTER ARCINST *ai;
3969 	REGISTER PORTPROTO *pp;
3970 	REGISTER VARIABLE *var;
3971 	REGISTER void *infstr;
3972 
3973 	/* check for duplicate name */
3974 	if (namesame(oldname, newname) == 0)
3975 	{
3976 		ttyputmsg(_("Network name has not changed in cell %s"), describenodeproto(np));
3977 		return;
3978 	}
3979 
3980 	/* validate the names */
3981 	for(pt = oldname; *pt != 0; pt++) if (*pt == '[') break;
3982 	if (*pt == '[')
3983 	{
3984 		ttyputerr(_("Must rename unqualified networks (without the '[') in cell %s"),
3985 			describenodeproto(np));
3986 		return;
3987 	}
3988 	for(pt = newname; *pt != 0; pt++) if (*pt == '[') break;
3989 	if (*pt == '[')
3990 	{
3991 		ttyputerr(_("New name must be unqualified (without the '[') in cell %s"),
3992 			describenodeproto(np));
3993 		return;
3994 	}
3995 
3996 	/* make sure new name is not in use */
3997 	for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
3998 	{
3999 		for(k=0; k<net->namecount; k++)
4000 		{
4001 			startpt = net_findnameinbus(newname, networkname(net, k));
4002 			if (startpt != 0)
4003 			{
4004 				ttyputerr(_("Network name '%s' already exists in cell %s"), newname,
4005 					describenodeproto(np));
4006 				return;
4007 			}
4008 		}
4009 	}
4010 
4011 	/* substitute in all arcs */
4012 	len = estrlen(oldname);
4013 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
4014 	{
4015 		/* see if the arc has a name */
4016 		var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
4017 		if (var == NOVARIABLE) continue;
4018 
4019 		/* parse the network name */
4020 		arcname = (CHAR *)var->addr;
4021 		found = 0;
4022 		for(;;)
4023 		{
4024 			startpt = net_findnameinbus(oldname, arcname);
4025 			if (startpt == 0) break;
4026 			infstr = initinfstr();
4027 			for(pt = arcname; pt < startpt; pt++)
4028 				addtoinfstr(infstr, *pt);
4029 			addstringtoinfstr(infstr, newname);
4030 			pt += len;
4031 			addstringtoinfstr(infstr, pt);
4032 			arcname = returninfstr(infstr);
4033 			found++;
4034 		}
4035 		if (found > 0)
4036 		{
4037 			/* rename the arc */
4038 			(void)allocstring(&netname, arcname, el_tempcluster);
4039 			TDCOPY(descript, var->textdescript);
4040 			startobjectchange((INTBIG)ai, VARCINST);
4041 			var = setvalkey((INTBIG)ai, VARCINST, el_arc_name_key, (INTBIG)netname, VSTRING|VDISPLAY);
4042 			if (var == NOVARIABLE) continue;
4043 			modifydescript((INTBIG)ai, VARCINST, var, descript);
4044 			endobjectchange((INTBIG)ai, VARCINST);
4045 			efree((CHAR *)netname);
4046 		}
4047 	}
4048 
4049 	/* substitute in all exports */
4050 	for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
4051 	{
4052 		if (namesamen(pp->protoname, oldname, len) != 0) continue;
4053 		if (pp->protoname[len] != 0 && pp->protoname[len] != '[') continue;
4054 		if (pp->protoname[len] == 0)
4055 		{
4056 			startobjectchange((INTBIG)pp->subnodeinst, VNODEINST);
4057 			setval((INTBIG)pp, VPORTPROTO, x_("protoname"), (INTBIG)newname, VSTRING);
4058 			endobjectchange((INTBIG)pp->subnodeinst, VNODEINST);
4059 		} else
4060 		{
4061 			infstr = initinfstr();
4062 			addstringtoinfstr(infstr, newname);
4063 			addstringtoinfstr(infstr, &pp->protoname[len]);
4064 			startobjectchange((INTBIG)pp->subnodeinst, VNODEINST);
4065 			setval((INTBIG)pp, VPORTPROTO, x_("protoname"), (INTBIG)returninfstr(infstr), VSTRING);
4066 			endobjectchange((INTBIG)pp->subnodeinst, VNODEINST);
4067 		}
4068 	}
4069 
4070 	ttyputmsg(_("Network '%s' renamed to '%s'"), oldname, newname);
4071 }
4072 
4073 /*
4074  * Routine to find the name "wantname" in the bus name "busname".
4075  * Returns the character position where the name starts (0 if not found).
4076  */
net_findnameinbus(CHAR * wantname,CHAR * busname)4077 CHAR *net_findnameinbus(CHAR *wantname, CHAR *busname)
4078 {
4079 	REGISTER CHAR *pt;
4080 	REGISTER INTBIG len;
4081 
4082 	len = estrlen(wantname);
4083 	for(pt = busname; *pt != 0; pt++)
4084 	{
4085 		if (namesamen(pt, wantname, len) == 0)
4086 		{
4087 			if (pt[len] == 0 || pt[len] == '[' || pt[len] == ',')
4088 				return(pt);
4089 		}
4090 		while (*pt != 0 && *pt != '[' && *pt != ',') pt++;
4091 		while (*pt == '[')
4092 		{
4093 			pt++;
4094 			while (*pt != 0 && *pt != ']') pt++;
4095 			if (*pt == ']') pt++;
4096 		}
4097 		if (*pt == 0) break;
4098 	}
4099 	return(0);
4100 }
4101 
4102 /*********************** NetCellPrivate class ***********************/
4103 
operator new(size_t size)4104 void* NetCellPrivate::operator new( size_t size )
4105 {
4106 	ttyputerr(M_("operator NetCellPrivate(size,cluster) should be used"));
4107 	Q_UNUSED( size );
4108 	return (void*)0;
4109 }
4110 
operator new(size_t size,CLUSTER * cluster)4111 void* NetCellPrivate::operator new( size_t size, CLUSTER *cluster )
4112 {
4113 	return (void*)emalloc( size, cluster );
4114 }
4115 
operator delete(void * obj)4116 void NetCellPrivate::operator delete( void* obj )
4117 {
4118 	if(obj) efree((CHAR *)obj);
4119 }
4120 
4121 #ifndef MACOS
operator delete(void * obj,CLUSTER * cluster)4122 void NetCellPrivate::operator delete( void* obj, CLUSTER *cluster )
4123 {
4124 	Q_UNUSED( cluster );
4125 	if(obj) efree((CHAR *)obj);
4126 }
4127 #endif
4128 
NetCellPrivate(NODEPROTO * np,CLUSTER * cluster)4129 NetCellPrivate::NetCellPrivate( NODEPROTO *np, CLUSTER *cluster )
4130 	: _np( np ), _cluster( cluster ), _netnamecount( 0 ), _netshorts( 0 )
4131 {
4132 	_netnametotal = 5;
4133 	_netnamehash = (NetName**)emalloc(_netnametotal*sizeof(NetName*), _cluster);
4134 	for (INTBIG i = 0; i < _netnametotal; i++)
4135 		_netnamehash[i] = 0;
4136 }
4137 
net_initnetprivate(NODEPROTO * np)4138 void net_initnetprivate(NODEPROTO *np)
4139 {
4140 	if (np->netd) return;
4141 	np->netd = new (np->lib->cluster)NetCellPrivate(np, np->lib->cluster);
4142 }
4143 
~NetCellPrivate()4144 NetCellPrivate::~NetCellPrivate()
4145 {
4146 	if ( _netshorts ) delete _netshorts;
4147 	if (_netnamehash)
4148 	{
4149 		for (INTBIG i = 0; i < _netnametotal; i++)
4150 		{
4151 			if (_netnamehash[i]) delete _netnamehash[i];
4152 		}
4153 		efree((CHAR *)_netnamehash);
4154 	}
4155 }
4156 
net_freenetprivate(NODEPROTO * np)4157 void net_freenetprivate(NODEPROTO *np)
4158 {
4159 	if (np != NONODEPROTO && np->netd)
4160 	{
4161 		delete np->netd;
4162 		np->netd = 0;
4163 	}
4164 }
4165 
updateShorts()4166 BOOLEAN NetCellPrivate::updateShorts()
4167 {
4168 	if (_netshorts && _netshorts->isConsistent()) return FALSE;
4169 	if (_netshorts) delete _netshorts;
4170 	_netshorts = new (_cluster) NetCellShorts(_np, _cluster);
4171 	return TRUE;
4172 }
4173 
4174 #ifdef NEWRENUM
4175 /* for some reason, using "this" in the NetName constructor tickles a compiler bug */
newNetName(CLUSTER * cluster,NetCellPrivate * ncp,CHAR * name)4176 static NetName *newNetName( CLUSTER *cluster, NetCellPrivate *ncp, CHAR *name)
4177 {
4178     return new (cluster) NetName( ncp, name );
4179 }
4180 
findNetName(CHAR * name,BOOLEAN insert)4181 NetName *NetCellPrivate::findNetName( CHAR *name, BOOLEAN insert )
4182 {
4183 	NetName *nn;
4184 	CHAR *normname, *pt, **strings;
4185 	INTBIG i, j, hash, count;
4186 
4187 	/* find exactly */
4188 	hash = db_namehash(name);
4189 	i = hash % _netnametotal;
4190 	for(j=1; j<=_netnametotal; j += 2)
4191 	{
4192 		nn = _netnamehash[i];
4193 		if (!nn) break;
4194 		if (namesame(name, nn->_name) == 0) return(nn);
4195 		i += j;
4196 		if (i >= _netnametotal) i -= _netnametotal;
4197 	}
4198 
4199 	/* clean blanks, if any */
4200 	for (pt = name; *pt != 0; pt++)
4201 	{
4202 		if (*pt == ' ' || *pt == '\t') break;
4203 	}
4204 	if (*pt != 0)
4205 	{
4206 		normname = (CHAR*)emalloc( (estrlen(name) + 1) * sizeof(CHAR), _cluster);
4207 		for (pt = name, j = 0; *pt != 0; pt++)
4208 		{
4209 			if (*pt == ' ' || *pt == '\t') continue;
4210 			normname[j++] = *pt;
4211 		}
4212 		normname[j] = 0;
4213 		ttyputmsg(M_("normalizeNetName {%s} -> {%s}"), name, normname);
4214 		nn = findNetName( normname, insert );
4215 		efree(normname);
4216 		return (nn);
4217 	}
4218 
4219 	/* not found */
4220 	if (!insert) return(0);
4221 
4222 	/* Evaluate busname */
4223 	count = net_evalbusname(APBUS, name, &strings, NOARCINST, _np, TRUE);
4224 
4225 	/* Error in name - use patched */
4226 	if (count == 1 && estrcmp(strings[0], name) != 0)
4227 	{
4228 		ttyputmsg(M_("patchNetName {%s} -> {%s}"), name, strings[0]);
4229 		return findNetName( strings[0], TRUE );
4230 	}
4231 
4232 	/* for some reason, using "this" in the NetName constructor tickles a compiler bug */
4233 	nn = newNetName( _cluster, this, name );
4234 	insertNetName( nn, hash );
4235 	if (count > 1)
4236 		nn->setBusWidth( count, strings );
4237 	return(nn);
4238 }
4239 
4240 #else
findNetName(CHAR * name,BOOLEAN insert)4241 NetName *NetCellPrivate::findNetName( CHAR *name, BOOLEAN insert )
4242 {
4243 	NetName *nn;
4244 	NetCellPrivate *thisone;
4245 
4246 	INTBIG hash = db_namehash(name);
4247 	INTBIG i = hash % _netnametotal;
4248 	for(INTBIG j=1; j<=_netnametotal; j += 2)
4249 	{
4250 		nn = _netnamehash[i];
4251 		if (!nn) break;
4252 		if (namesame(name, nn->_name) == 0) return(nn);
4253 		i += j;
4254 		if (i >= _netnametotal) i -= _netnametotal;
4255 	}
4256 	if (!insert) return(0);
4257 
4258 	/* for some reason, using "this" in the NetName constructor tickles a compiler bug */
4259 	thisone = this;
4260 	nn = new (_cluster) NetName( thisone, name );
4261 	insertNetName( nn, hash );
4262 	return(nn);
4263 }
4264 #endif
4265 
insertNetName(NetName * nn,INTBIG hash)4266 void NetCellPrivate::insertNetName( NetName *nn, INTBIG hash )
4267 {
4268 	/* resize and rehash if necessary */
4269 	if ((_netnamecount+1) >= _netnametotal/2)
4270 		rehashNetNames();
4271 
4272 	/* insert new name */
4273 	INTBIG i = hash % _netnametotal;
4274 	for(INTBIG j=1; j<=_netnametotal; j += 2)
4275 	{
4276 		if (_netnamehash[i] == 0)
4277 		{
4278 			_netnamehash[i] = nn;
4279 			_netnamecount++;
4280 			return;
4281 		}
4282 		i += j;
4283 		if (i >= _netnametotal) i -= _netnametotal;
4284 	}
4285 	ttyputmsg(M_("Error in NetCellPrivate::insertNetName"));
4286 }
4287 
4288 #ifdef NEWRENUM
addNetName(CHAR * name)4289 NetName *NetCellPrivate::addNetName( CHAR *name )
4290 {
4291 	NetName *nn;
4292 	NetCellPrivate *thisone;
4293 
4294 	INTBIG hash = db_namehash(name);
4295 	INTBIG i = hash % _netnametotal;
4296 	for(INTBIG j=1; j<=_netnametotal; j += 2)
4297 	{
4298 		nn = _netnamehash[i];
4299 		if (!nn) break;
4300 		if (namesame(name, nn->_name) == 0) return(nn);
4301 		i += j;
4302 		if (i >= _netnametotal) i -= _netnametotal;
4303 	}
4304 
4305 	/* for some reason, using "this" in the NetName constructor tickles a compiler bug */
4306 	thisone = this;
4307 	nn = new (_cluster) NetName( thisone, name );
4308 	insertNetName( nn, hash );
4309 	return(nn);
4310 }
4311 #endif
4312 
rehashNetNames()4313 void NetCellPrivate::rehashNetNames()
4314 {
4315 	INTBIG i, j, k;
4316 	INTBIG oldnetnametotal = _netnametotal;
4317 	NetName **oldnetnamehash = _netnamehash;
4318 	_netnametotal = pickprime((_netnamecount + 1)*4);
4319 	_netnamehash = (NetName**)emalloc(_netnametotal*sizeof(NetName*), _cluster);
4320 	for (k = 0; k < _netnametotal; k++) _netnamehash[k] = 0;
4321 	for (k = 0; k < oldnetnametotal; k++)
4322 	{
4323 		if (oldnetnamehash[k] == 0) continue;
4324 		i = db_namehash(oldnetnamehash[k]->_name) % _netnametotal;
4325 		for(j=1; j<=_netnametotal; j += 2)
4326 		{
4327 			if (_netnamehash[i] == 0)
4328 			{
4329 				_netnamehash[i] = oldnetnamehash[k];
4330 				break;
4331 			}
4332 			i += j;
4333 			if (i >= _netnametotal) i -= _netnametotal;
4334 		}
4335 	}
4336 	if (oldnetnamehash) efree((CHAR *)oldnetnamehash);
4337 }
4338 
docheck()4339 void NetCellPrivate::docheck()
4340 {
4341 	INTBIG i, count;
4342 	NETWORK *net;
4343 
4344 	if (_netnamecount >= _netnametotal/2)
4345 		ttyputmsg(M_("Network hash table of faceet %s is too dense"), describenodeproto(_np));
4346 	count = 0;
4347 	INTBIG totalnetcount = 0;
4348 	INTBIG totalbaserefcount = 0;
4349 	for (i = 0; i < _netnametotal; i++)
4350 	{
4351 		NetName *nn = _netnamehash[i];
4352 		if (!nn) continue;
4353 		nn->docheck();
4354 		count++;
4355 		if (nn->_baseNetName)
4356 			totalnetcount += nn->_netcount;
4357 		totalbaserefcount += nn->_baseRefCount;
4358 	}
4359 	if (count != _netnamecount)
4360 		ttyputmsg(M_("Network hash table of cell %s: netcount is incorrect"), describenodeproto(_np));
4361 	if (totalnetcount != totalbaserefcount)
4362 		ttyputmsg(M_("In cell %s totalnetcount=%ld totalbaserefcount=%ld"), describenodeproto(_np),
4363 			totalnetcount, totalbaserefcount);
4364 	for (net = _np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
4365 	{
4366 		if (net->namecount > 1)
4367 		{
4368 			if (net->tempname)
4369 				ttyputmsg(M_("Network with temporary name has other names in cell %s"), describenodeproto(_np));
4370 			NetName **netnames = (NetName**)net->netnameaddr;
4371 			for (i = 0; i < net->namecount; i++)
4372 			{
4373 				NetName *nn = netnames[i];
4374 				if (i > 0 && namesame(netnames[i-1]->name(), nn->name()) >= 0)
4375 						ttyputmsg(M_("Network has wrong sorting of names in cell %s: %s %s"), describenodeproto(_np),
4376 							netnames[i-1]->name(), nn->name());
4377 				nn->checkNet(net);
4378 			}
4379 		}
4380 		else if (net->namecount == 1)
4381 		{
4382 			NetName *nn = (NetName*)net->netnameaddr;
4383 			nn->checkNet(net);
4384 		}
4385 	}
4386 }
4387 
4388 #ifdef NEWRENUM
clearConns()4389 void NetCellPrivate::clearConns()
4390 {
4391 	for (INTBIG i = 0; i < _netnametotal; i++)
4392 	{
4393 		NetName *nn = _netnamehash[i];
4394 		if (nn == 0) continue;
4395 		nn->_conn = 0;
4396 	}
4397 }
4398 
calcConns(INTBIG * count)4399 void NetCellPrivate::calcConns(INTBIG *count)
4400 {
4401 	for (INTBIG i = 0; i < _netnametotal; i++)
4402 	{
4403 		NetName *nn = _netnamehash[i];
4404 		if (nn == 0) continue;
4405 		if (nn->_conn <= 0) continue; /* ???????? maybe wrong when count == 0 */
4406 		nn->_conn = (*count)++;
4407 	}
4408 }
4409 
showConns(INTBIG * deepmap)4410 void NetCellPrivate::showConns(INTBIG *deepmap)
4411 {
4412 	for (INTBIG i = 0; i < _netnametotal; i++)
4413 	{
4414 		NetName *nn = _netnamehash[i];
4415 		if (nn == 0) continue;
4416 		if (nn->_conn <= 0) continue;
4417 		::printf("%ld %ld\t%s\n", nn->_conn, deepmap[nn->_conn], nn->name());
4418 	}
4419 }
4420 #endif
4421 
net_checknetprivate(NODEPROTO * np)4422 void net_checknetprivate(NODEPROTO *np)
4423 {
4424 	np->netd->docheck();
4425 }
4426 
4427 /*********************** NetName class ***********************/
4428 
operator new(size_t size)4429 void* NetName::operator new( size_t size )
4430 {
4431 	ttyputerr(M_("operator NetName(size,cluster) should be used"));
4432 	Q_UNUSED( size );
4433 	return (void*)0;
4434 }
4435 
operator new(size_t size,CLUSTER * cluster)4436 void* NetName::operator new( size_t size, CLUSTER *cluster )
4437 {
4438 	return (void*)emalloc( size, cluster );
4439 }
4440 
operator delete(void * obj)4441 void NetName::operator delete( void* obj )
4442 {
4443 	if(obj) efree((CHAR *)obj);
4444 }
4445 
4446 #ifndef MACOS
operator delete(void * obj,CLUSTER * cluster)4447 void NetName::operator delete( void* obj, CLUSTER *cluster )
4448 {
4449 	Q_UNUSED( cluster );
4450 	if(obj) efree((CHAR *)obj);
4451 }
4452 #endif
4453 
NetName(NetCellPrivate * npd,CHAR * name)4454 NetName::NetName( NetCellPrivate *npd, CHAR *name )
4455 	: _npd( npd ), _netcount( 0 ), _netaddr( (INTBIG)NONETWORK )
4456 	  , _baseNetName( 0 ), _baseRefCount( 0 )
4457 #ifdef NEWRENUM
4458 	  , _busWidth( 1 ), _netNameList( 0 )
4459 #endif
4460 {
4461 	allocstring(&_name, name, _npd->_cluster);
4462 	if (estrchr(_name, ',') != 0 || estrchr(name, ':') != 0) return;
4463 	CHAR *pt = estrchr(_name, '[');
4464 	if (pt == 0) return;
4465 	*pt = 0;
4466 #  ifdef NEWRENUM
4467 	_baseNetName = npd->addNetName( _name );
4468 #  else
4469 	_baseNetName = npd->findNetName( _name, TRUE );
4470 #  endif
4471 	*pt = '[';
4472 }
4473 
~NetName()4474 NetName::~NetName()
4475 {
4476 	efree(_name);
4477 	if (_netcount > 1)
4478 		efree((CHAR *)_netaddr);
4479 #ifdef NEWRENUM
4480 	if (_busWidth > 1)
4481 		efree((CHAR *)_netNameList);
4482 #endif
4483 }
4484 
4485 
firstNet()4486 NETWORK *NetName::firstNet()
4487 {
4488 	return (_netcount <= 1 ? (NETWORK*)_netaddr : ((NETWORK**)_netaddr)[0]);
4489 }
4490 
addNet(NETWORK * net)4491 void NetName::addNet(NETWORK *net)
4492 {
4493 	NETWORK **newaddr;
4494 
4495 	if (_netcount == 0)
4496 	{
4497 		_netaddr = (INTBIG)net;
4498 		_netcount = 1;
4499 		if (_baseRefCount != 0)
4500 			checkArity();
4501 		if (_baseNetName)
4502 		{
4503 			_baseNetName->_baseRefCount++;
4504 			if (_baseNetName->_baseRefCount == 1)
4505 				_baseNetName->checkArity();
4506 		}
4507 		return;
4508 	}
4509 	if (_netcount == 1)
4510 	{
4511 		NETWORK *onet = (NETWORK*)_netaddr;
4512 		if (onet == net)
4513 		{
4514 			ttyputmsg(M_("NetName::addNet : netname %s already assigned"), _name);
4515 			return;
4516 		}
4517 		newaddr = (NETWORK**)emalloc(2*sizeof(NETWORK*), _npd->_cluster);
4518 		newaddr[0] = (NETWORK*)_netaddr;
4519 	} else
4520 	{
4521 		INTBIG i;
4522 		NETWORK **oldaddr = (NETWORK**)_netaddr;
4523 		for (i = 0; i < _netcount; i++)
4524 			if(oldaddr[i] == net)
4525 			{
4526 				ttyputmsg(M_("NetName::addNet : netname %s already assigned"), _name);
4527 				return;
4528 			}
4529 		newaddr = (NETWORK**)emalloc((_netcount+1)*sizeof(NETWORK*), _npd->_cluster);
4530 		for (i = 0; i < _netcount; i++)
4531 			newaddr[i] = oldaddr[i];
4532 		efree((CHAR *)oldaddr);
4533 	}
4534 	newaddr[_netcount] = net;
4535 	_netcount++;
4536 	_netaddr = (INTBIG)newaddr;
4537 	if (_baseNetName)
4538 	{
4539 		_baseNetName->_baseRefCount++;
4540 		if (_baseNetName->_baseRefCount == 1)
4541 			_baseNetName->checkArity();
4542 	}
4543 }
4544 
removeNet(NETWORK * net)4545 void NetName::removeNet(NETWORK *net)
4546 {
4547 	if (_netcount == 1)
4548 	{
4549 		if (net != (NETWORK*)_netaddr)
4550 		{
4551 			ttyputmsg(M_("Netame::removeNet : netname %s is not connected with this"), _name);
4552 			return;
4553 		}
4554 		_netaddr = (INTBIG)NONETWORK;
4555 		_netcount = 0;
4556 		if (_baseNetName) _baseNetName->_baseRefCount--;
4557 		return;
4558 	}
4559 	if (_netcount == 0)
4560 	{
4561 		ttyputmsg(M_("Netname::removeNet : netname %s not connected"), _name);
4562 		return;
4563 	}
4564 
4565 	INTBIG i;
4566 	NETWORK **oldaddr = (NETWORK**)_netaddr;
4567 
4568 	for (i = 0; i < _netcount; i++)
4569 		if (oldaddr[i] == net) break;
4570 	if (i >= _netcount)
4571 	{
4572 		ttyputmsg(M_("Netame::removeNet : netname %s is not connected with this"), _name);
4573 		return;
4574 	}
4575 	if (_netcount == 2)
4576 	{
4577 		_netaddr = (INTBIG)oldaddr[1-i];
4578 		efree((CHAR *)oldaddr);
4579 		_netcount = 1;
4580 		if (_baseNetName) _baseNetName->_baseRefCount--;
4581 		return;
4582 	}
4583 	NETWORK **newaddr = (NETWORK**)emalloc((_netcount-1)*sizeof(NETWORK*), _npd->_cluster);
4584 	for (INTBIG j=0; j < i; j++)
4585 		newaddr[j] = oldaddr[j];
4586 	i++;
4587 	for (; i < _netcount; i++)
4588 		newaddr[i-1] = oldaddr[i];
4589 	_netaddr = (INTBIG)newaddr;
4590 	efree((CHAR *)oldaddr);
4591 	_netcount--;
4592 	if (_baseNetName) _baseNetName->_baseRefCount--;
4593 }
4594 
docheck()4595 void NetName::docheck()
4596 {
4597 	INTBIG i, j;
4598 
4599 	if (_netcount > 1)
4600 	{
4601 		NETWORK **netaddr = (NETWORK**)_netaddr;
4602 		for (i = 0; i < _netcount; i++)
4603 		{
4604 			NETWORK *net = netaddr[i];
4605 			if (net == NONETWORK)
4606 			{
4607 				ttyputmsg(M_("NetName::docheck : netname %s has null connections"), _name);
4608 			}
4609 			for (j = 0; j < i; j++)
4610 			{
4611 				if (netaddr[j] == net)
4612 				{
4613 					ttyputmsg(M_("NetName::docheck : netname %s has connected to duplicate nets"), _name);
4614 				}
4615 			}
4616 			net_checknetname(net, this);
4617 		}
4618 	}
4619 	else if (_netcount == 1)
4620 	{
4621 		NETWORK *net = (NETWORK*)_netaddr;;
4622 		if (net == NONETWORK)
4623 		{
4624 			ttyputmsg(M_("NetName::docheck : netname %s has null connections"), _name);
4625 		}
4626 		net_checknetname(net, this);
4627 	}
4628 	else if (_netaddr != (INTBIG)NONETWORK)
4629 		ttyputmsg(M_("NetName::docheck : netname %s with zero _netcount has bad _netaddr"), _name);
4630 	checkArity();
4631 }
4632 
checkArity()4633 void NetName::checkArity()
4634 {
4635 	if (_baseRefCount != 0 && _netcount != 0)
4636 		ttyputerr(_("Warning (cell %s): bus network '%s' used ambiguously"),
4637 			describenodeproto(_npd->_np), _name);
4638 }
4639 
net_checknetname(NETWORK * net,NetName * nn)4640 static void net_checknetname(NETWORK *net, NetName *nn)
4641 {
4642 	if (net->namecount == 1)
4643 	{
4644 		if ((NetName*)net->netnameaddr == nn) return;
4645 	}
4646 	else if (net->namecount > 1)
4647 	{
4648 		NetName **netnames = (NetName**)net->netnameaddr;
4649 		INTBIG i;
4650 		for(i = 0; i < net->namecount; i++)
4651 			if (netnames[i] == nn) return;
4652 	}
4653 	ttyputmsg(M_("net_checknetname : netname %s is not found in namelist"), nn->name());
4654 }
4655 
checkNet(NETWORK * net)4656 void NetName::checkNet(NETWORK *net)
4657 {
4658 	if (_netcount == 1)
4659 	{
4660 		if ((NETWORK*)_netaddr == net) return;
4661 	}
4662 	else if (_netcount > 1)
4663 	{
4664 		NETWORK **nets = (NETWORK**)_netaddr;
4665 		for (INTBIG i = 0; i < _netcount; i++)
4666 			if (nets[i] == net) return;
4667 	} else if ((NETWORK*)_netaddr == NONETWORK) return;
4668 	ttyputmsg(M_("NetName::checkNet : %s net is not found in namelist"), _name);
4669 }
4670 
4671 #ifdef NEWRENUM
setBusWidth(INTBIG busWidth,CHAR ** strings)4672 void NetName::setBusWidth( INTBIG busWidth, CHAR **strings )
4673 {
4674 	_netNameList = (NetName **)emalloc( busWidth * sizeof(NetName *), _npd->_cluster );
4675 	_busWidth = busWidth;
4676 	for (INTBIG i = 0; i < busWidth; i++)
4677 	{
4678 		_netNameList[i] = _npd->addNetName( strings[i] );
4679 	}
4680 }
4681 
markConn()4682 void NetName::markConn()
4683 {
4684 	if (_busWidth <= 1)
4685 	{
4686 		_conn++;
4687 		return;
4688 	}
4689 	for (INTBIG i = 0; i < _busWidth; i++)
4690 		_netNameList[i]->_conn++;
4691 }
4692 #endif
4693 
4694 /*********************** NetCellShorts class ***********************/
4695 
operator new(size_t size)4696 void* NetCellShorts::operator new( size_t size )
4697 {
4698 	ttyputerr(M_("operator NetCellShorts(size,cluster) should be used"));
4699 	Q_UNUSED( size );
4700 	return (void*)0;
4701 }
4702 
operator new(size_t size,CLUSTER * cluster)4703 void* NetCellShorts::operator new( size_t size, CLUSTER *cluster )
4704 {
4705 	return (void*)emalloc( size, cluster );
4706 }
4707 
operator delete(void * obj)4708 void NetCellShorts::operator delete( void* obj )
4709 {
4710 	if(obj) efree((CHAR *)obj);
4711 }
4712 
4713 #ifndef MACOS
operator delete(void * obj,CLUSTER * cluster)4714 void NetCellShorts::operator delete( void* obj, CLUSTER *cluster )
4715 {
4716 	Q_UNUSED( cluster );
4717 	if(obj) efree((CHAR *)obj);
4718 }
4719 #endif
4720 
NetCellShorts(NODEPROTO * np,CLUSTER * cluster)4721 NetCellShorts::NetCellShorts( NODEPROTO *np, CLUSTER *cluster )
4722 	: _np( np ), _portbeg( 0 ),
4723 #ifdef NEWRENUM
4724 	  _isolated( 0 ),
4725 #endif
4726 	  _globalnames( 0 ), _portshallowmap( 0 ), _portdeepmap( 0 ), _globalshort(FALSE)
4727 {
4728 	NODEPROTO *cnp;
4729 	PORTPROTO *pp,*cpp;
4730 	NETWORK *net;
4731 	INTBIG index, i, k;
4732 
4733 	/* find number of ports */
4734     index = 0;
4735     for (pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
4736 		index++;
4737     _portbeg = (INTBIG *)emalloc( (index + 1) * sizeof(INTBIG), cluster );
4738 #ifdef NEWRENUM
4739     _isolated = (BOOLEAN *)emalloc( (index + 1) * sizeof(BOOLEAN), cluster );
4740 #endif
4741 	_portshallowmap = (INTBIG *)emalloc( index * sizeof(INTBIG), cluster );
4742 	_portcount = index;
4743 
4744 	/* get contentsview */
4745 	cnp = contentsview(_np);
4746 	if (cnp == NONODEPROTO) cnp = _np;
4747 
4748 	/* calculate globalcount() */
4749     index = 0;
4750 	for (i = 0; i < cnp->globalnetcount; i++)
4751 		if (cnp->globalnetworks[i] != NONETWORK)
4752 			index++;
4753 	_portbeg[0] = index;
4754 	if (globalcount() > 0)
4755 		_globalnames = (CHAR **)emalloc( globalcount() * sizeof(CHAR*), cluster);
4756 
4757 	/* fill _portbeg and _portshallowmap */
4758 	clearNetworks(cnp);
4759     index = 0;
4760     for (pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
4761     {
4762 		INTBIG width;
4763 		cpp = equivalentport(_np, pp, cnp);
4764 #ifdef NEWRENUM
4765 		_isolated[index] = (cpp != NOPORTPROTO && (cpp->userbits&PORTISOLATED) != 0);
4766 #endif
4767 		if (cpp == NOPORTPROTO || cpp->network == NONETWORK)
4768 		{
4769 			ttyputmsg("Cell %s: equivalent port %s not found in %s", describenodeproto(_np), pp->protoname, describenodeproto(cnp));
4770 			_portshallowmap[index] = index;
4771 			width = pp->network->buswidth;
4772 		} else
4773 		{
4774 			net = cpp->network;
4775 			if (net->temp1 < 0)
4776 				net->temp1 = index;
4777 			_portshallowmap[index] = net->temp1;
4778 			width = net->buswidth;
4779 		}
4780 		_portbeg[index + 1] = _portbeg[index] + width;
4781 		index++;
4782     }
4783 
4784 	/* fill _portdeepmap */
4785 	_portdeepmap = (INTBIG *) emalloc( _portbeg[_portcount] * sizeof(INTBIG), cluster );
4786 	clearNetworks(cnp);
4787 	index = 0;
4788 	for (i = 0; i < cnp->globalnetcount; i++)
4789 	{
4790 		net = cnp->globalnetworks[i];
4791 		if (net == NONETWORK) continue;
4792 		(void)allocstring(&_globalnames[index], cnp->globalnetnames[i], cluster);
4793 		if (net->temp1 < 0)
4794 			net->temp1 = index;
4795 		_portdeepmap[index] = net->temp1;
4796 		index++;
4797 	}
4798 	index = 0;
4799     for(pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto, index++)
4800     {
4801 		cpp = equivalentport(_np, pp, cnp);
4802 		if (cpp == NOPORTPROTO || cpp->network == NONETWORK)
4803 		{
4804 			for (k = _portbeg[index]; k < _portbeg[index+1]; k++)
4805 				_portdeepmap[k] = k;
4806 			continue;
4807 		}
4808 		net = cpp->network;
4809 		for (k = _portbeg[index]; k < _portbeg[index+1]; k++)
4810 		{
4811 			NETWORK *netk = (net->buswidth <= 1 ? net : net->networklist[k-_portbeg[index]]);
4812 			if (netk->temp1 < 0)
4813 				netk->temp1 = k;
4814 			_portdeepmap[k] = netk->temp1;
4815 		}
4816     }
4817 
4818 	/* calculate globalshort() */
4819 	for (i=0; i < globalcount(); i++)
4820 		if (_portdeepmap[i] != i)
4821 			_globalshort = TRUE;
4822 	for(i=globalcount(); i < _portbeg[_portcount]; i++)
4823 		if (_portdeepmap[i] < globalcount())
4824 			_globalshort = TRUE;
4825 }
4826 
~NetCellShorts()4827 NetCellShorts::~NetCellShorts()
4828 {
4829 	INTBIG i;
4830 
4831 	if (_globalnames != 0)
4832 	{
4833 		for (i=0; i < globalcount(); i++)
4834 		{
4835 			if (_globalnames[i] != 0) efree(_globalnames[i]);
4836 		}
4837 		efree((CHAR*)_globalnames);
4838 	}
4839     if (_portbeg != 0) efree((CHAR *)_portbeg);
4840     if (_portshallowmap != 0) efree((CHAR *)_portshallowmap);
4841     if (_portdeepmap != 0) efree((CHAR *)_portdeepmap);
4842 }
4843 
isConsistent()4844 BOOLEAN NetCellShorts::isConsistent()
4845 {
4846     NETWORK *net;
4847 	NODEPROTO *cnp;
4848     PORTPROTO *pp, *cpp;
4849     INTBIG index, i, k;
4850 
4851 	/* check number of ports */
4852     index = 0;
4853     for (pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
4854 		index++;
4855 	if (portcount() != index) return FALSE;
4856 
4857 	/* get contentsview */
4858 	cnp = contentsview(_np);
4859 	if (cnp == NONODEPROTO) cnp = _np;
4860 
4861 	/* check globalcount() */
4862     index = 0;
4863 	for (i = 0; i < cnp->globalnetcount; i++)
4864 		if (cnp->globalnetworks[i] != NONETWORK)
4865 		{
4866 			if (index >= globalcount()) return FALSE;
4867 			if (namesame(_globalnames[index], cnp->globalnetnames[i]) != 0) return FALSE;
4868 			index++;
4869 		}
4870 	if (globalcount() != index) return FALSE;
4871 
4872 	/* check portwidth and _portshallowmap */
4873 	clearNetworks(cnp);
4874     index = 0;
4875     for(pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto, index++)
4876     {
4877 		cpp = equivalentport(_np, pp, cnp);
4878 		if (cpp == NOPORTPROTO || cpp->network == NONETWORK)
4879 		{
4880 			if (portwidth(index) != 1) return FALSE;
4881 			if (_portshallowmap[index] != index) return FALSE;
4882 			continue;
4883 		}
4884 		net = cpp->network;
4885 		if (portwidth(index) != net->buswidth) return FALSE;
4886 		if (net->temp1 < 0)
4887 			net->temp1 = index;
4888 		if (_portshallowmap[index] != net->temp1) return FALSE;
4889     }
4890 
4891 	/* check _portdeepmap */
4892 	clearNetworks(cnp);
4893 	index = 0;
4894 	for (i = 0; i < cnp->globalnetcount; i++)
4895 	{
4896 		net = cnp->globalnetworks[i];
4897 		if (net == NONETWORK) continue;
4898 		if (net->temp1 < 0)
4899 			net->temp1 = index;
4900 		if (_portdeepmap[index] != net->temp1) return FALSE;
4901 		index++;
4902 	}
4903     index = 0;
4904     for(pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto, index++)
4905     {
4906 		cpp = equivalentport(_np, pp, cnp);
4907 		if (cpp == NOPORTPROTO || cpp->network == NONETWORK)
4908 		{
4909 			for (k = _portbeg[index]; k < _portbeg[index+1]; k++)
4910 				if (_portdeepmap[k] != k) return FALSE;
4911 			continue;
4912 		}
4913 		net = cpp->network;
4914 		for (k = _portbeg[index]; k < _portbeg[index+1]; k++)
4915 		{
4916 			NETWORK *netk = (net->buswidth <= 1 ? net : net->networklist[k-_portbeg[index]]);
4917 			if (netk->temp1 < 0)
4918 				netk->temp1 = k;
4919 			if (_portdeepmap[k] != netk->temp1) return FALSE;
4920 		}
4921     }
4922 
4923     return TRUE;
4924 }
4925 
printf()4926 void NetCellShorts::printf()
4927 {
4928 	NODEPROTO *cnp;
4929     PORTPROTO *pp;
4930     INTBIG index, i;
4931 
4932 	cnp = contentsview(_np);
4933 	if (cnp == NONODEPROTO) cnp = _np;
4934 	efprintf(stdout, "Cell %s (%ld) contents %s globalshort=%d\n", describenodeproto(_np), portcount(),
4935 		describenodeproto(cnp), globalshort());
4936 	for (i = 0; i < globalcount(); i++)
4937 		efprintf(stdout, "\tGlobal %ld %s %ld %s\n", i, _globalnames[i], _portdeepmap[i], _portdeepmap[i] != i ? "!" : "");
4938 
4939 	/* check portwidth and _portshallowmap */
4940 	index = 0;
4941     for(pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto, index++)
4942     {
4943 #ifdef NEWRENUM
4944 		efprintf(stdout, "\tPort %ld %s (%ld) %ld %s %s\n", index, pp->protoname, portwidth(index), _portshallowmap[index],
4945 			_portshallowmap[index] != index ? "!" : "", isolated(index) ? "isolated" : "");
4946 #else
4947 		efprintf(stdout, "\tPort %ld %s (%ld) %ld %s\n", index, pp->protoname, portwidth(index), _portshallowmap[index], _portshallowmap[index] != index ? "!" : "");
4948 #endif
4949 		for (i = _portbeg[index]; i < _portbeg[index+1]; i++)
4950 			efprintf(stdout, "\t\t%ld %ld %s\n", i, _portdeepmap[i], _portdeepmap[i] != i ? "!" : "");
4951     }
4952 }
4953 
portwidth(INTBIG portno)4954 INTBIG NetCellShorts::portwidth( INTBIG portno )
4955 {
4956     if (portno < 0 || portno >= _portcount) return -1;
4957     return _portbeg[portno + 1] - _portbeg[portno];
4958 }
4959 
clearNetworks(NODEPROTO * np)4960 void NetCellShorts::clearNetworks(NODEPROTO *np)
4961 {
4962 	if (np->primindex == 0)
4963 	{
4964 		for(NETWORK *net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
4965 			net->temp1 = -1;
4966 	} else
4967 	{
4968 		for(INTBIG i = 0; i < net_mostj; i++)
4969 			net_primnetlist[i]->temp1 = -1;
4970 	}
4971 }
4972 
4973 /****************************************************/
4974 
4975 #ifdef NEWRENUM
operator new(size_t size)4976 void* NetCellConns::operator new( size_t size )
4977 {
4978 	ttyputerr(M_("operator NetCellConns(size,cluster) should be used"));
4979 	Q_UNUSED( size );
4980 	return (void*)0;
4981 }
4982 
operator new(size_t size,CLUSTER * cluster)4983 void* NetCellConns::operator new( size_t size, CLUSTER *cluster )
4984 {
4985 	return (void*)emalloc( size, cluster );
4986 }
4987 
operator delete(void * obj)4988 void NetCellConns::operator delete( void* obj )
4989 {
4990 	if(obj) efree((CHAR *)obj);
4991 }
4992 
4993 #ifndef MACOS
operator delete(void * obj,CLUSTER * cluster)4994 void NetCellConns::operator delete( void* obj, CLUSTER *cluster )
4995 {
4996 	Q_UNUSED( cluster );
4997 	if(obj) efree((CHAR *)obj);
4998 }
4999 #endif
5000 
NetCellConns(NODEPROTO * np,CLUSTER * cluster)5001 NetCellConns::NetCellConns( NODEPROTO *np, CLUSTER *cluster )
5002 	: _np( np ), _shallowmap( 0 ), _globalcount(0), _globalnames(0),
5003 	  _shallow2drawn( 0 ), _drawns( 0 ), _deepmapcount( 0 ), _deepmap( 0 ),
5004 	  _complicated( FALSE )
5005 {
5006 	PORTPROTO *pp;
5007 	ARCINST *ai;
5008 	INTBIG index, i, j;
5009 	INTBIG *pinmap;
5010 	VARIABLE *var;
5011 	INTBIG netnum;
5012 	NetName *nn;
5013 
5014 	/* find number of ports */
5015     index = 0;
5016     for (pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
5017 	{
5018 		pp->temp1 = index++;
5019 		/* check bussed ports */
5020 		nn = np->netd->findNetName( pp->protoname, TRUE );
5021 		if (nn->busWidth() > 1)
5022 			_complicated = TRUE;
5023 	}
5024 	_portcount = index;
5025 
5026     for (ai = _np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
5027 	{
5028 		/* ignore arcs with no signals on them */
5029 		if (((ai->proto->userbits&AFUNCTION)>>AFUNCTIONSH) == APNONELEC)
5030 		{
5031 			ai->temp1 = -1;
5032 			continue;
5033 		}
5034 		ai->temp1 = index++;
5035 
5036 		/* check bus arc */
5037 		VARIABLE *var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
5038 		if (var != NOVARIABLE)
5039 		{
5040 			CHAR *arcname = (CHAR *)var->addr;
5041 			if (arcname[0] != 0)
5042 			{
5043 				nn = np->netd->findNetName( arcname, TRUE );
5044 				if (nn->busWidth() > 1)
5045 					_complicated = TRUE;
5046 			}
5047 		}
5048 		/* if this arc end is negated, ignore its node propagation */
5049 		if ((ai->userbits&ISNEGATED) != 0)
5050 			_complicated = TRUE;
5051 	}
5052 	_arccount = index - _portcount;
5053 	_shallowmap = (INTBIG *)emalloc( (_portcount + _arccount) * sizeof(INTBIG), cluster );
5054 	for (i = 0; i < _portcount + _arccount; i++)
5055 		_shallowmap[i] = i;
5056 
5057 	/* fill _shallowmap */
5058 	//efprintf(stdout, "Cell %s\n", describenodeproto(np));
5059 	for (NODEINST *ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
5060 	{
5061 		//efprintf(stdout, "\tNode %s (%ld)\n", describenodeinst(ni), ni->arraysize);
5062 		if (insamecellgrp(ni->proto, _np)) continue;
5063 		for (pp = ni->proto->firstportproto, j=0; pp != NOPORTPROTO; pp = pp->nextportproto, j++)
5064 			pp->temp1 = j;
5065 		if (ni->arraysize > 1)
5066 		{
5067 			_complicated = TRUE;
5068 			continue;
5069 		}
5070 		NetCellShorts *shorts = ni->proto->netd->netshorts();
5071 		if (shorts->globalcount() > 0)
5072 		{
5073 			for (i = 0; i < shorts->globalcount(); i++)
5074 			{
5075 				addGlobalname(shorts->globalname(i));
5076 			}
5077 			_complicated = TRUE;
5078 		}
5079 		if (ni->proto == sch_wireconprim || ni->proto == sch_buspinprim)
5080 			_complicated = TRUE;
5081 		if (ni->proto == sch_globalprim)
5082 		{
5083 			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_globalnamekey);
5084 			if (var != NOVARIABLE)
5085 			{
5086 				addGlobalname((CHAR *)var->addr);
5087 			}
5088 			_complicated = TRUE;
5089 		}
5090 		INTBIG fun = (ni->proto->userbits&NFUNCTION)>>NFUNCTIONSH;
5091 		if (fun == NPCONPOWER)
5092 		{
5093 			addGlobalname(_("Power"));
5094 			_complicated = TRUE;
5095 		} else if (fun == NPCONGROUND)
5096 		{
5097 			addGlobalname(_("Ground"));
5098 			_complicated = TRUE;
5099 		}
5100 
5101 		pinmap = (INTBIG*)emalloc( shorts->portcount()*sizeof(INTBIG), cluster );
5102 		for (i = 0; i < shorts->portcount(); i++)
5103 			pinmap[i] = -1;
5104 
5105 		for(PORTEXPINST *pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
5106 		{
5107 			if (shorts->isolated(pe->proto->temp1)) continue;
5108 			netnum = shorts->portshallowmap(pe->proto->temp1);
5109 			//efprintf(stdout, M_("\t\tPortExpInst %s %ld %ld\n"), pe->proto->protoname, netnum, pe->exportproto->temp1);
5110 			if (pinmap[netnum] < 0)
5111 			{
5112 				pinmap[netnum] = pe->exportproto->temp1;
5113 			} else
5114 			{
5115 				shallowconnect( pinmap[netnum], pe->exportproto->temp1);
5116 			}
5117 		}
5118 		for (PORTARCINST *pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
5119 		{
5120 			/* if port is isolated, ignore it */
5121 			if (shorts->isolated(pi->proto->temp1)) continue;
5122 
5123 			/* do not follow nonbus wires onto a bus pin */
5124 			if (ni->proto == sch_buspinprim && pi->conarcinst->proto != sch_busarc) continue;
5125 
5126 			netnum = shorts->portshallowmap(pi->proto->temp1);
5127 			if (pi->conarcinst->temp1 < 0) continue;
5128 			//efprintf(stdout, M_("\t\tPortArcInst %s %ld %ld\n"), pi->proto->protoname, netnum, pi->conarcinst->temp1);
5129 			if (pinmap[netnum] < 0)
5130 			{
5131 				pinmap[netnum] = pi->conarcinst->temp1;
5132 			} else
5133 			{
5134 				shallowconnect( pinmap[netnum], pi->conarcinst->temp1);
5135 			}
5136 		}
5137 		efree((CHAR *)pinmap);
5138 	}
5139 	shallowfixup();
5140 	makeDrawns();
5141 }
5142 
~NetCellConns()5143 NetCellConns::~NetCellConns()
5144 {
5145 	INTBIG i;
5146 
5147     if (_shallowmap != 0) efree((CHAR *)_shallowmap);
5148 	for (i = 0; i < _globalcount; i++)
5149 		efree(_globalnames[i]);
5150 	if (_globalnames != 0) efree((CHAR *)_globalnames);
5151 	if (_shallow2drawn != 0 ) efree((CHAR *)_shallow2drawn);
5152 	if (_drawns != 0 ) efree((CHAR *)_drawns);
5153 	if (_deepmap != 0 ) efree((CHAR *)_deepmap);
5154 }
5155 
compare()5156 void NetCellConns::compare()
5157 {
5158 	PORTPROTO *pp;
5159 	ARCINST *ai;
5160 	NETWORK *net, **netmap;
5161 	INTBIG *portcount, *refcount, *arccount;
5162 	INTBIG index, i, netnum;
5163 
5164 	for(net = _np->firstnetwork, i = 0; net != NONETWORK; net = net->nextnetwork)
5165 		net->temp1 = -1;
5166 	netmap = (NETWORK **)emalloc((_portcount + _arccount) * sizeof(NETWORK *), _np->netd->cluster());
5167 	portcount = (INTBIG *)emalloc((_portcount + _arccount) * sizeof(INTBIG), _np->netd->cluster());
5168 	refcount = (INTBIG *)emalloc((_portcount + _arccount) * sizeof(INTBIG), _np->netd->cluster());
5169 	arccount = (INTBIG *)emalloc((_portcount + _arccount) * sizeof(INTBIG), _np->netd->cluster());
5170 	for (i = 0; i < _portcount + _arccount; i++)
5171 	{
5172 		netmap[i] = NONETWORK;
5173 		portcount[i] = 0;
5174 		refcount[i] = 0;
5175 		arccount[i] = 0;
5176 	}
5177 
5178 	/* check number of ports */
5179     index = 0;
5180     for (pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
5181 	{
5182 		net = pp->network;
5183 		if (net == NONETWORK)
5184 		{
5185 			ttyputmsg(M_("WARNING:: NetCellConns::compare port %s of cell %s has no network"),
5186 				pp->protoname, describenodeproto(_np));
5187 			return;
5188 		}
5189 		if (index >= _portcount + _arccount)
5190 		{
5191 			ttyputmsg(M_("WARNING:: NetCellConns::compare cell %s has too many ports portcount=%ld"),
5192 				describenodeproto(_np), _portcount);
5193 			return;
5194 		}
5195 		pp->temp1 = index++;
5196 		netmap[pp->temp1] = net;
5197 	}
5198 	if (index != _portcount)
5199 	{
5200 		ttyputmsg(M_("WARNING:: NetCellConns::compare cell %s portcount != index portcount=%ld index=%ld"),
5201 			describenodeproto(_np), _portcount, index);
5202 		return;
5203 	}
5204 
5205     for (ai = _np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
5206 	{
5207 		net = ai->network;
5208 		/* ignore arcs with no signals on them */
5209 		if (((ai->proto->userbits&AFUNCTION)>>AFUNCTIONSH) == APNONELEC)
5210 		{
5211 			ai->temp1 = -1;
5212 			if (net != NONETWORK)
5213 			{
5214 				ttyputmsg(M_("WARNING:: NetCellConns::compare nonelectrical arc %s of cell %s has network %s"),
5215 					describearcinst(ai), describenodeproto(_np), describenetwork(net));
5216 				return;
5217 
5218 			}
5219 			continue;
5220 		}
5221 		if (net == NONETWORK)
5222 		{
5223 			ttyputmsg(M_("WARNING:: NetCellConns::compare arcinst %s of cell %s has no network"),
5224 				describearcinst(ai), describenodeproto(_np));
5225 			return;
5226 		}
5227 		if (index >= _portcount + _arccount)
5228 		{
5229 			ttyputmsg(M_("WARNING:: NetCellConns::compare cell %s has too many arcs portcount=%ld arccount=%ld"),
5230 				describenodeproto(_np), _portcount, _arccount);
5231 			return;
5232 		}
5233 		ai->temp1 = index++;
5234 		netmap[ai->temp1] = net;
5235 	}
5236 	if (_arccount != index - _portcount)
5237 	{
5238 		ttyputmsg(M_("WARNING:: NetCellConns::compare cell %s arccount != index arccount=%ld index=%ld"),
5239 			describenodeproto(_np), _arccount, index - _portcount);
5240 		return;
5241 	}
5242 
5243 	for (i = 0; i < _portcount + _arccount; i++)
5244 	{
5245 		netnum = _shallowmap[i];
5246 		net = netmap[i];
5247 		if (netnum == i)
5248 		{
5249 			if (net->temp1 != -1)
5250 				ttyputmsg(M_("WARNING:: NetCellConns::compare net %s of cell %s already assigned"),
5251 					describenetwork(net), describenodeproto(_np));
5252 			net->temp1 = i;
5253 		} else {
5254 			if (net->temp1 != netnum)
5255 				ttyputmsg(M_("WARNING:: NetCellConns::compare net %s of cell %s net->temp1=%ld netnum=%ld i=%ld"),
5256 					describenetwork(net), describenodeproto(_np), net->temp1, netnum, i);
5257 		}
5258 		if (i < _portcount)
5259 			portcount[netnum]++;
5260 		else
5261 			refcount[netnum]++;
5262 	}
5263 
5264     for (ai = _np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
5265 	{
5266 		if (ai->temp1 < 0) continue;
5267 		net = ai->network;
5268 		/* check bus arc */
5269 		VARIABLE *var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
5270 		if (var != NOVARIABLE)
5271 		{
5272 			CHAR *arcname = (CHAR *)var->addr;
5273 			if (arcname[0] != 0)
5274 			{
5275 				//::printf("Cell %s arc %s on net %s\n", describenodeproto(_np), arcname, describenetwork(net));
5276 				arccount[net->temp1]++;
5277 			}
5278 		}
5279 	}
5280 
5281 	for(net = _np->firstnetwork, i = 0; net != NONETWORK; net = net->nextnetwork)
5282 	{
5283 		if (net->temp1 == -1)
5284 		{
5285 			ttyputmsg(M_("WARNING:: NetCellConns::compare net %s of cell %s has net->temp1=-1"),
5286 				describenetwork(net), describenodeproto(_np));
5287 		}
5288 		if (net->portcount != portcount[net->temp1])
5289 		{
5290 			ttyputmsg(M_("WARNING:: NetCellConns::compare net %s of cell %s has invalid portcount"),
5291 				describenetwork(net), describenodeproto(_np));
5292 		}
5293 		if (net->refcount != refcount[net->temp1])
5294 		{
5295 			ttyputmsg(M_("WARNING:: NetCellConns::compare net %s of cell %s has invalid refcount"),
5296 				describenetwork(net), describenodeproto(_np));
5297 		}
5298 #if 0
5299 		if (net->arccount != arccount[net->temp1])
5300 		{
5301 			ttyputmsg(M_("WARNING:: NetCellConns::compare net %s of cell %s has invalid arccount net->arccount=%ld arccount=%ld"),
5302 				describenetwork(net), describenodeproto(_np), net->arccount, arccount[net->temp1]);
5303 		}
5304 #endif
5305 		if (net->buslinkcount != 0)
5306 		{
5307 			ttyputmsg(M_("WARNING:: NetCellConns::compare net %s of cell %s has invalid buslinkcountcount"),
5308 				describenetwork(net), describenodeproto(_np));
5309 		}
5310 		if (net->globalnet != -1)
5311 		{
5312 			ttyputmsg(M_("WARNING:: NetCellConns::compare net %s of cell %s has invalid globalnet"),
5313 				describenetwork(net), describenodeproto(_np));
5314 		}
5315 		if (net->buswidth != 1)
5316 		{
5317 			ttyputmsg(M_("WARNING:: NetCellConns::compare net %s of cell %s has invalid buswidth"),
5318 				describenetwork(net), describenodeproto(_np));
5319 		}
5320 		if (net->numvar != 0)
5321 		{
5322 			ttyputmsg(M_("WARNING:: NetCellConns::compare net %s of cell %s has invalid numvar"),
5323 				describenetwork(net), describenodeproto(_np));
5324 		}
5325 	}
5326 
5327 	efree((CHAR*) netmap);
5328 	efree((CHAR*) portcount);
5329 	efree((CHAR*) refcount);
5330 	efree((CHAR*) arccount);
5331 }
5332 
deepcompare()5333 void NetCellConns::deepcompare()
5334 {
5335 	NETWORK *net, **netmap;
5336 	NetDrawn *nd;
5337 	INTBIG i, k, m;
5338 
5339 	for(net = _np->firstnetwork, i = 0; net != NONETWORK; net = net->nextnetwork)
5340 		net->temp1 = -1;
5341 	netmap = (NETWORK **)emalloc(_deepmapcount * sizeof(NETWORK *), _np->netd->cluster());
5342 	for (i = 0; i < _deepmapcount; i++)
5343 	{
5344 		netmap[i] = NONETWORK;
5345 	}
5346 	for (i = 0; i < _globalcount; i++)
5347 	{
5348 		m = _deepmap[i];
5349 		k = net_findglobalnet(_np, _globalnames[i]);
5350 #if 0
5351 		ttyputmsg(_("NetCellConns::deepcompare global %ld(%ld) %s %ld)"), i, m, _globalnames[i], k);
5352 #endif
5353 		net = k >= 0 ? _np->globalnetworks[k] : NONETWORK;
5354 		if (i == m)
5355 		{
5356 			netmap[i] = net;
5357 			if (net == NONETWORK) continue;
5358 			if (net->temp1 != -1)
5359 			{
5360 				ttyputmsg(M_("NetCellConns::deepcompare in %s: global net %s not fully connected"),
5361 					describenodeproto(_np), describenetwork(net));
5362 			}
5363 			net->temp1 = m;
5364 		} else if (netmap[m] != net)
5365 		{
5366 			ttyputmsg(M_("NetCellConns::deepcompare in %s: not connected %s and %s"),
5367 				describenodeproto(_np), describenetwork(netmap[m]), describenetwork(net));
5368 		}
5369 	}
5370 	for (i = 0; i < _drawncount; i++)
5371 	{
5372 		nd = &_drawns[i];
5373 		if (nd->_busWidth != nd->_network->buswidth)
5374 		{
5375 			ttyputmsg(M_("NetCellConns::deepcompare in %s: buswidth mismatch in %s"),
5376 				describenodeproto(_np), describenetwork(nd->_network));
5377 		}
5378 		for (k = 0; k < nd->_busWidth; k++)
5379 		{
5380 			m = _deepmap[nd->_deepbase + k];
5381 			net = nd->_network;
5382 			net = net->buswidth > 1 ? net->networklist[k] : net;
5383 			if (m == nd->_deepbase + k)
5384 			{
5385 				netmap[m] = net;
5386 				if (net->temp1 != -1)
5387 				{
5388 					ttyputmsg(M_("NetCellConns::deepcompare in %s: net %s not fully connected"),
5389 						describenodeproto(_np), describenetwork(net));
5390 				}
5391 				net->temp1 = m;
5392 			} else if (netmap[m] != net)
5393 			{
5394 				ttyputmsg(M_("NetCellConns::depcompare in %s: not connected %s and %s"),
5395 					describenodeproto(_np), describenetwork(netmap[m]), describenetwork(net));
5396 			}
5397 		}
5398 	}
5399 	efree((CHAR*) netmap);
5400 	for(net = _np->firstnetwork, i = 0; net != NONETWORK; net = net->nextnetwork)
5401 	{
5402 		if (net->buswidth == 1 && net->temp1 == -1)
5403 		{
5404 			ttyputmsg(M_("WARNING:: NetCellConns::deepcompare net %s of cell %s has net->temp1=-1"),
5405 				describenetwork(net), describenodeproto(_np));
5406 		}
5407 	}
5408 }
5409 
schem()5410 void NetCellConns::schem()
5411 {
5412 	PORTPROTO *pp;
5413 	ARCINST *ai;
5414 	NODEINST *ni;
5415 	PORTEXPINST *pe;
5416 	PORTARCINST *pi;
5417 	VARIABLE *var;
5418 	NetName *nn, *subn;
5419 	NetDrawn *nd;
5420 	INTBIG i, j, m;
5421 	NETWORK *net;
5422 
5423 	_np->netd->clearConns();
5424 
5425 	for(net = _np->firstnetwork, i = 0; net != NONETWORK; net = net->nextnetwork)
5426 		net->temp1 = -1;
5427 	/* find number of ports */
5428     for (pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
5429 	{
5430 		/* check bussed ports */
5431 		nn = _np->netd->findNetName( pp->protoname, TRUE );
5432 		nn->markConn();
5433 		/* give a number */
5434 		m = _shallowmap[pp->temp1];
5435 		nd = _shallow2drawn[m];
5436 		if (nn->busWidth() > 1) nd->_isBus = TRUE;
5437 		if (nd->_busWidth != 0 && nd->_busWidth != nn->busWidth())
5438 		{
5439 			ttyputmsg(M_("NetCellConns::schem in %s: net %s has different bus width %ld and %ld"),
5440 				describenodeproto(_np), describenetwork(nd->_network), nd->_busWidth, nn->busWidth());
5441 		}
5442 		nd->_busWidth = nn->busWidth();
5443 		if (m == pp->temp1)
5444 		{
5445 			nd->_network = pp->network;
5446 #if 0
5447 			net = pp->network;
5448 			if (net->buswidth > 1 && net->temp1 != -1)
5449 			{
5450 				ttyputmsg(M_("NetCellConns::schem in %s: net %s not fully connected"),
5451 					describenodeproto(_np), describenetwork(net));
5452 			}
5453 			net->temp1 = m;
5454 #endif
5455 		} else if (nd->_network != pp->network)
5456 		{
5457 			ttyputmsg(M_("NetCellConns::schem strange port %s of cell %s"),
5458 				pp->protoname, describenodeproto(_np));
5459 		}
5460 	}
5461 
5462     for (ai = _np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
5463 	{
5464 		/* ignore arcs with no signals on them */
5465 		if (ai->temp1 < 0) continue;
5466 
5467 		/* give a number */
5468 		m = _shallowmap[ai->temp1];
5469 		nd = _shallow2drawn[m];
5470 
5471 		/* check bus arc */
5472 		if (ai->proto == sch_busarc)
5473 			nd->_isBus = TRUE;
5474 		else if (nd->_busWidth != 1)
5475 		{
5476 			if (nd->_busWidth != 0)
5477 			{
5478 				ttyputmsg(M_("NetCellConns::schem in %s: bus net %s has nonbus arc"),
5479 					describenodeproto(_np), describenetwork(nd->_network), nd->_busWidth);
5480 			} else
5481 			{
5482 				nd->_busWidth = 1;
5483 			}
5484 		}
5485 		var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
5486 		if (var != NOVARIABLE && (var->type&VDISPLAY) != 0)
5487 		{
5488 			CHAR *arcname = (CHAR *)var->addr;
5489 			if (arcname[0] != 0)
5490 			{
5491 				nn = _np->netd->findNetName( arcname, TRUE );
5492 				nn->markConn();
5493 				if (nd->_busWidth != 0 && nd->_busWidth != nn->busWidth())
5494 				{
5495 					ttyputmsg(M_("NetCellConns::schem in %s: net %s has different bus width %ld and %ld"),
5496 						describenodeproto(_np), describenetwork(nd->_network), nd->_busWidth, nn->busWidth());
5497 				}
5498 				nd->_busWidth = nn->busWidth();
5499 			}
5500 		}
5501 
5502 		if (m == ai->temp1)
5503 		{
5504 			nd->_network = ai->network;
5505 #if 0
5506 			net = ai->network;
5507 			if (net->buswidth > 1 && net->temp1 != -1)
5508 			{
5509 				ttyputmsg(M_("NetCellConns::schem in %s: net %s not fully connected"),
5510 					describenodeproto(_np), describenetwork(net));
5511 			}
5512 			net->temp1 = m;
5513 #endif
5514 		} else if (nd->_network != ai->network)
5515 		{
5516 			ttyputmsg(M_("NetCellConns::sschem strange arc %s of cell %s"),
5517 				describearcinst(ai), describenodeproto(_np));
5518 		}
5519 	}
5520 
5521 	/* find bus width of unnamed busses */
5522 	for (ni = _np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
5523 	{
5524 		//efprintf(stdout, "\tNode %s (%ld)\n", describenodeinst(ni), ni->arraysize);
5525 		if (insamecellgrp(ni->proto, _np)) continue;
5526 
5527 		if (ni->proto->primindex != 0) continue;
5528 
5529 		for (pp = ni->proto->firstportproto, j=0; pp != NOPORTPROTO; pp = pp->nextportproto, j++)
5530 			pp->temp1 = j;
5531 		NetCellShorts *shorts = ni->proto->netd->netshorts();
5532 		INTBIG nodewidth = ni->arraysize;
5533 		if (nodewidth < 1) nodewidth = 1;
5534 
5535 		for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
5536 		{
5537 			nd = _shallow2drawn[pe->exportproto->temp1];
5538 			if (nd->_busWidth == 0)
5539 			{
5540 				nd->_busWidth = shorts->portwidth( pe->proto->temp1 ) * nodewidth;
5541 			}
5542 		}
5543 		for (pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
5544 		{
5545 			if (pi->conarcinst->temp1 < 0) continue;
5546 			nd = _shallow2drawn[pi->conarcinst->temp1];
5547 			if (nd->_busWidth == 0)
5548 			{
5549 				nd->_busWidth = shorts->portwidth( pi->proto->temp1 ) * nodewidth;
5550 			}
5551 		}
5552 	}
5553 
5554 	_deepmapcount = _globalcount;
5555 	for (i = 0; i < _drawncount; i++)
5556 	{
5557 		nd = &_drawns[i];
5558 		if (_np->cellview == el_iconview && nd->_busWidth == 0)
5559 		{
5560 			/* sometimes there are unnamed unconnected busses in icons */
5561 			nd->_busWidth = 1;
5562 		}
5563 		net = nd->_network;
5564 		if (nd->_busWidth != net->buswidth)
5565 		{
5566 			ttyputmsg(M_("NetCellConns::schem in %s: net %s has different bus width from newrenum %ld and from NETWORK %ld"),
5567 				describenodeproto(_np), describenetwork(net), nd->_busWidth, nd->_network->buswidth);
5568 		}
5569 		nd->_busWidth = net->buswidth;
5570 		nd->_deepbase = _deepmapcount;
5571 		_deepmapcount += nd->_busWidth;
5572 	}
5573 
5574 	_np->netd->calcConns(&_deepmapcount);
5575 	_deepmap = (INTBIG *)emalloc(_deepmapcount * sizeof(INTBIG), _np->netd->cluster());
5576 	for (i = 0; i < _deepmapcount; i++)
5577 		_deepmap[i] = i;
5578 
5579 	/* find number of ports */
5580     for (pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
5581 	{
5582 		/* check bussed ports */
5583 		nn = _np->netd->findNetName( pp->protoname, TRUE );
5584 		nd = _shallow2drawn[pp->temp1];
5585 		for (i = 0; i < nd->_busWidth; i++)
5586 		{
5587 			subn = nn->busWidth() > 1 ? nn->subName(i) : nn;
5588 			deepconnect(nd->_deepbase + i, subn->conn());
5589 		}
5590 	}
5591     for (ai = _np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
5592 	{
5593 		/* ignore arcs with no signals on them */
5594 		if (ai->temp1 < 0) continue;
5595 
5596 		/* check bus arc */
5597 		VARIABLE *var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
5598 		if (var != NOVARIABLE && (var->type&VDISPLAY) != 0)
5599 		{
5600 			CHAR *arcname = (CHAR *)var->addr;
5601 			if (arcname[0] != 0)
5602 			{
5603 				nn = _np->netd->findNetName( arcname, TRUE );
5604 				nd = _shallow2drawn[ai->temp1];
5605 				for (i = 0; i < nd->_busWidth; i++)
5606 				{
5607 					subn = nn->busWidth() > 1 ? nn->subName(i) : nn;
5608 					deepconnect(nd->_deepbase + i, subn->conn());
5609 				}
5610 			}
5611 		}
5612 	}
5613 
5614 	/* fill _shallowmap */
5615 	//efprintf(stdout, "Cell %s\n", describenodeproto(_np));
5616 	for (ni = _np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
5617 	{
5618 		//efprintf(stdout, "\tNode %s (%ld)\n", describenodeinst(ni), ni->arraysize);
5619 		if (insamecellgrp(ni->proto, _np)) continue;
5620 		for (pp = ni->proto->firstportproto, j=0; pp != NOPORTPROTO; pp = pp->nextportproto, j++)
5621 			pp->temp1 = j;
5622 		NetCellShorts *shorts = ni->proto->netd->netshorts();
5623 #if 0
5624 		if (ni->proto == sch_wireconprim || ni->proto == sch_buspinprim)
5625 			continue; // ????????????????????????
5626 #endif
5627 		INTBIG nodewidth = ni->arraysize;
5628 		if (nodewidth < 1) nodewidth = 1;
5629 		INTBIG pinmapcount = shorts->globalcount() + shorts->portdeepcount()*nodewidth;
5630 		INTBIG *pinmap = (INTBIG*)emalloc( pinmapcount*sizeof(INTBIG), _np->netd->cluster() );
5631 		for (i = 0; i < pinmapcount; i++)
5632 			pinmap[i] = -1;
5633 
5634 		INTBIG fun = (ni->proto->userbits&NFUNCTION)>>NFUNCTIONSH;
5635 		if (fun == NPCONPOWER || fun == NPCONGROUND || ni->proto == sch_globalprim)
5636 		{
5637 			INTBIG glob = -1;
5638 			if (ni->proto == sch_globalprim)
5639 			{
5640 				var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_globalnamekey);
5641 				if (var != NOVARIABLE)
5642 				{
5643 					glob = addGlobalname((CHAR *)var->addr);
5644 				}
5645 			} else if (fun == NPCONGROUND)
5646 				glob = addGlobalname(_("Ground"));
5647 			else if (fun == NPCONPOWER)
5648 				glob = addGlobalname(_("Power"));
5649 			if (glob == -1)
5650 			{
5651 				ttyputmsg(M_("NetCellShorts::schem in %s global instance %s not found"),
5652 					describenodeproto(_np), describenodeinst(ni));
5653 				if (ni->proto == sch_globalprim)
5654 				{
5655 					ttyputmsg(M_("NetCellShorts::schem in %s global instance %s not found name %s"),
5656 						describenodeproto(_np), describenodeinst(ni), (CHAR*)var->addr);
5657 				}
5658 			}
5659 			for (i = 0; i < pinmapcount; i++)
5660 				pinmap[i] = glob;
5661 		} else if (ni->proto == sch_wireconprim)
5662 		{
5663 			deepjoin(ni);
5664 			continue;
5665 		} else if (ni->proto->primindex != 0)
5666 		{
5667 			continue;
5668 		}
5669 		for (i = 0; i < shorts->globalcount(); i++)
5670 		{
5671 			INTBIG globalnet = addGlobalname(shorts->globalname(i));
5672 			if (globalnet < 0)
5673 			{
5674 				ttyputmsg(M_("NetCellShorts::schem in %s global net %s not found"),
5675 					describenodeproto(_np), shorts->globalname(i));
5676 				continue;
5677 			}
5678 			pinmap[i] = globalnet;
5679 			m = shorts->portdeepmap(i);
5680 			if (i != m)
5681 			{
5682 				ttyputmsg(M_("NetCellShorts::schem in %s global nets %s and %s are connected"),
5683 					describenodeproto(_np), shorts->globalname(m), shorts->globalname(i));
5684 				deepconnect(pinmap[i], pinmap[m]);
5685 			}
5686 		}
5687 
5688 		for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
5689 		{
5690 			deepconnectport(pe->exportproto->temp1, ni, shorts, pinmap, pe->proto);
5691 		}
5692 		for (pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
5693 		{
5694 			/* do not follow nonbus wires onto a bus pin */
5695 			if (ni->proto == sch_buspinprim && pi->conarcinst->proto != sch_busarc) continue;
5696 
5697 			deepconnectport(pi->conarcinst->temp1, ni, shorts, pinmap, pi->proto);
5698 		}
5699 		efree((CHAR *)pinmap);
5700 	}
5701 
5702 	deepfixup();
5703 
5704 	//::printf("ShowConns %s\n", describenodeproto(_np));
5705 	deepcompare();
5706 #if 0
5707 	for (i = 0; i < _drawncount; i++)
5708 	{
5709 		nd = &_drawns[i];
5710 		::printf("%ld\tDrawn %s %ld\n", nd->_deepbase, describenetwork(nd->_network), nd->_busWidth);
5711 		for (INTBIG k = 0; k < nd->_busWidth; k++)
5712 			::printf("\t%ld %ld\n", nd->_deepbase + k, _deepmap[nd->_deepbase + k]);
5713 	}
5714 
5715 	_np->netd->showConns(_deepmap);
5716 #endif
5717 }
5718 
deepconnectport(INTBIG drawnIndex,NODEINST * ni,NetCellShorts * shorts,INTBIG * pinmap,PORTPROTO * pp)5719 void NetCellConns::deepconnectport( INTBIG drawnIndex, NODEINST *ni, NetCellShorts *shorts, INTBIG *pinmap, PORTPROTO *pp)
5720 {
5721 	INTBIG k, l;
5722 
5723 	INTBIG nodewidth = ni->arraysize;
5724 	if (nodewidth < 1) nodewidth = 1;
5725 
5726 	/* if port is isolated, ignore it */
5727 	if (shorts->isolated(pp->temp1)) return;
5728 	INTBIG portbeg = shorts->portbeg(pp->temp1);
5729 	INTBIG portwidth = shorts->portwidth(pp->temp1);
5730 
5731 	if (drawnIndex < 0) return;
5732 	NetDrawn *nd = _shallow2drawn[drawnIndex];
5733 	BOOLEAN deepstep = portwidth != nd->_busWidth;
5734 	if (deepstep && nd->_busWidth != portwidth*nodewidth)
5735 	{
5736 		if (nodewidth > 1)
5737 		{
5738 			ttyputmsg(_("Warning (cell %s): bus %s cannot connect to port %s of %ld-wide node %s (different width)"),
5739 				describenodeproto(_np), describenetwork(nd->_network), pp->protoname,
5740 				nodewidth, describenodeinst(ni));
5741 		} else
5742 		{
5743 			ttyputmsg(_("Warning (cell %s): bus %s cannot connect to port %s of node %s (different width)"),
5744 				describenodeproto(_np), describenetwork(nd->_network), pp->protoname,
5745 				describenodeinst(ni));
5746 		}
5747 		return;
5748 	}
5749 	for (k = 0; k < portwidth; k++)
5750 	{
5751 		INTBIG netnum = shorts->portdeepmap(portbeg + k);
5752 		INTBIG deepnum = nd->_deepbase + k;
5753 		for (l = 0; l < nodewidth; l++) {
5754 			if (pinmap[netnum] < 0)
5755 			{
5756 				pinmap[netnum] = deepnum;
5757 			} else
5758 			{
5759 				deepconnect( pinmap[netnum], deepnum);
5760 			}
5761 			if (netnum >= shorts->globalcount())
5762 				netnum += shorts->portdeepcount();
5763 			if (deepstep)
5764 				deepnum += portwidth;
5765 		}
5766 	}
5767 }
5768 
5769 /*
5770  * Routine to implement the "wire_con" primitive which joins two arcs and attaches
5771  * busses of unequal length (by repeating signals on the shorter bus until fully
5772  * attached to the larger bus).
5773  */
deepjoin(NODEINST * ni)5774 void NetCellConns::deepjoin(NODEINST *ni)
5775 {
5776 	REGISTER ARCINST *ai;
5777 	NetDrawn *smallnd, *largend;
5778 	REGISTER INTBIG smallnum, largenum, num, wirecount, i;
5779 	REGISTER PORTARCINST *pi;
5780 
5781 	/* find the narrow and wide busses on this connector */
5782 	smallnd = largend = 0;
5783 	smallnum = largenum = 0;
5784 	wirecount = 0;
5785 	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
5786 	{
5787 		ai = pi->conarcinst;
5788 		wirecount++;
5789 		if (ai->temp1 < 0) continue;
5790 		NetDrawn *nd = _shallow2drawn[ai->temp1];
5791 		num = nd->_busWidth;
5792 		if (smallnd == 0 || num <= smallnum)
5793 		{
5794 			smallnd = nd;
5795 			smallnum = num;
5796 		}
5797 		if (largend == 0 || num > largenum)
5798 		{
5799 			largend = nd;
5800 			largenum = num;
5801 		}
5802 	}
5803 	if (wirecount < 2) return;
5804 	if (wirecount > 2)
5805 	{
5806 		ttyputmsg(_("Cell %s, connector %s can only merge two arcs (has %ld)"),
5807 			describenodeproto(ni->parent), describenodeinst(ni), wirecount);
5808 		return;
5809 	}
5810 
5811 	for(i=0; i<largenum; i++)
5812 	{
5813 		deepconnect( smallnd->_deepbase + i % smallnd->_busWidth, largend->_deepbase + i );
5814 	}
5815 #if 0
5816 	/* also merge the busses if they are the same length */
5817 	if (smallnum == largenum && smallnum > 1)
5818 	{
5819 		(void)net_mergenet(smallai->network, largeai->network);
5820 	}
5821 #endif
5822 }
5823 
makeNetworksSimple()5824 void NetCellConns::makeNetworksSimple()
5825 {
5826 	PORTPROTO *pp;
5827 	ARCINST *ai;
5828 	NETWORK *net, **netmap;
5829 	INTBIG i, netnum;
5830 	CHAR *arcname;
5831 	NetName *nn;
5832 
5833 	/* first delete all network objects in this cell */
5834 	while (_np->firstnetwork != NONETWORK)
5835 	{
5836 		net = _np->firstnetwork;
5837 		_np->firstnetwork = net->nextnetwork;
5838 		net_freenetwork(net, _np);
5839 	}
5840 	for(i=0; i<_np->globalnetcount; i++)
5841 		_np->globalnetworks[i] = NONETWORK;
5842 
5843 	/* create network objects for every equivalence class */
5844 	netmap = (NETWORK **)emalloc((_portcount + _arccount) * sizeof(NETWORK *), _np->netd->cluster());
5845 	for (i = 0; i < _portcount + _arccount; i++)
5846 	{
5847 		if (_shallowmap[i] == i)
5848 			netmap[i] = net_newnetwork(_np);
5849 		else
5850 			netmap[i] = NONETWORK;
5851 	}
5852 
5853 	/* mark ports */
5854     for (pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
5855 	{
5856 		netnum = _shallowmap[pp->temp1];
5857 		net = netmap[netnum];
5858 		net_putportonnet(pp, net);
5859 		nn = _np->netd->findNetName(pp->protoname, TRUE);
5860 		net_namenet(nn, net);
5861 
5862 	}
5863 	/* mark arcs */
5864     for (ai = _np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
5865 	{
5866 		/* ignore arcs with no signals on them */
5867 		if (ai->temp1 < 0)
5868 		{
5869 			ai->network = NONETWORK;
5870 			continue;
5871 		}
5872 		netnum = _shallowmap[ai->temp1];
5873 		net = netmap[netnum];
5874 		ai->network = net;
5875 		net->refcount++;
5876 		/* check arc name */
5877 		VARIABLE *var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
5878 		if (var == NOVARIABLE) continue;
5879 		/* ignore tempnames */
5880 		if ((var->type&VDISPLAY) == 0) continue;
5881 		arcname = (CHAR *)var->addr;
5882 		if (arcname[0] == 0) continue;
5883 		nn = _np->netd->findNetName( arcname, TRUE );
5884 		net_namenet(nn, net);
5885 		net_putarclinkonnet(net, ai);
5886 	}
5887 	/* temporary arc names */
5888     for (ai = _np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
5889 	{
5890 		net = ai->network;
5891 		if (net == NONETWORK || net->namecount > 0) continue;
5892 		/* check arc name */
5893 		VARIABLE *var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
5894 		if (var == NOVARIABLE) continue;
5895 		arcname = (CHAR *)var->addr;
5896 		if (arcname[0] == 0) continue;
5897 		nn = _np->netd->findNetName( arcname, TRUE );
5898 		net_namenet(nn, net);
5899 		net->tempname = TRUE;
5900 		if (net->arccount <= 0)
5901 			net_putarclinkonnet(net, ai);
5902 	}
5903 	efree((CHAR*) netmap);
5904 }
5905 
printf()5906 void NetCellConns::printf()
5907 {
5908 	NETWORK *net, **netmap;
5909 	INTBIG i, j;
5910 	PORTPROTO *pp;
5911 	CLUSTER *cluster = _np->netd->cluster();
5912 	BOOLEAN err = _complicated;
5913 
5914 	efprintf(stdout, "Cell %s complicated=%d\n", describenodeproto(_np), complicated());
5915 	for(net = _np->firstnetwork, i = 0; net != NONETWORK; net = net->nextnetwork)
5916 		net->temp1 = -1;
5917 	netmap = (NETWORK **)emalloc((_portcount + _arccount) * sizeof(NETWORK *), cluster);
5918 	for (i = 0; i < _portcount + _arccount; i++) netmap[i] = NONETWORK;
5919 	for (pp = _np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
5920 	{
5921 		net = pp->network;
5922 		if (_shallowmap[pp->temp1] == pp->temp1)
5923 			netmap[pp->temp1] = net;
5924 		else if (netmap[_shallowmap[pp->temp1]] != net)
5925 		{
5926 			efprintf(stdout, M_("\t!!!!!!!!!!!!!!!!!!!!!! %s %s are not connected in map\n"),
5927 				describenetwork(netmap[_shallowmap[pp->temp1]]),
5928 				describenetwork(net));
5929 			ttyputmsg(M_("\t!!!!!!!!!!!!!!!!!!!!!! %s %s are not connected in map"),
5930 				describenetwork(netmap[_shallowmap[pp->temp1]]),
5931 				describenetwork(net));
5932 			err = TRUE;
5933 		}
5934 		if (net->temp1 < 0)
5935 			net->temp1 = _shallowmap[pp->temp1];
5936 		else if (net->temp1 != _shallowmap[pp->temp1])
5937 		{
5938 			err = TRUE;
5939 		}
5940 #if 0
5941 		efprintf(stdout, "\t%ld\tPort %ld%s %s net %s %ld (%d)\n", pp->temp1, _shallowmap[pp->temp1],
5942 			pp->temp1 != _shallowmap[pp->temp1] ? "!" : "",
5943 			pp->protoname, describenetwork(pp->network), net->temp1, pp->network->buswidth);
5944 #endif
5945 	}
5946 	for (ARCINST *ai = _np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
5947 	{
5948 		net = ai->network;
5949 		if (net == NONETWORK || ai->temp1 < 0)
5950 		{
5951 			if (net != NONETWORK)
5952 			{
5953 				err = TRUE;
5954 				efprintf(stdout, "\tNonelectric arc %s has network %s\n", describearcinst(ai), describenetwork(net));
5955 			}
5956 			if (ai->temp1 != -1)
5957 			{
5958 				err = TRUE;
5959 				efprintf(stdout, "!!!!!!!!! -1 !!!!!!!!!\n");
5960 			}
5961 			continue;
5962 		}
5963 		if (_shallowmap[ai->temp1] == ai->temp1)
5964 			netmap[ai->temp1] = net;
5965 		else if (netmap[_shallowmap[ai->temp1]] != net)
5966 		{
5967 			efprintf(stdout, M_("\t!!!!!!!!!!!!!!!!!!!!!! %s %s are not connected in map\n"),
5968 				describenetwork(netmap[_shallowmap[ai->temp1]]),
5969 				describenetwork(net));
5970 			ttyputmsg(M_("\t!!!!!!!!!!!!!!!!!!!!!! %s %s are not connected in map"),
5971 				describenetwork(netmap[_shallowmap[ai->temp1]]),
5972 				describenetwork(net));
5973 			err = TRUE;
5974 		}
5975 		if (net->temp1 < 0)
5976 			net->temp1 = _shallowmap[ai->temp1];
5977 		else if (net->temp1 != _shallowmap[ai->temp1])
5978 			err = TRUE;
5979 #if 0
5980 		efprintf(stdout, "\t%ld\tArc %ld%s %s net %s %ld (%d)\n", ai->temp1, _shallowmap[ai->temp1],
5981 			ai->temp1 != _shallowmap[ai->temp1] ? "!" : "",
5982 			describearcinst(ai), describenetwork(ai->network), net->temp1, ai->network->buswidth);
5983 #endif
5984 	}
5985 	for (i = 0, j = 0; i < _portcount + _arccount; i++)
5986 		if (_shallowmap[i] == i) j++;
5987 	for(net = _np->firstnetwork, i = 0; net != NONETWORK; net = net->nextnetwork)
5988 	{
5989 		if (net->temp1 < 0)
5990 		{
5991 			efprintf(stdout, "\tUnknown network %s portcount=%d refcount=%d buslinkcount=%d arccount=%d globalnet=%d\n",
5992 				describenetwork(net),
5993 				net->portcount, net->refcount, net->buslinkcount, net->arccount, net->globalnet);
5994 			err = TRUE;
5995 		}
5996 		i++;
5997 	}
5998 	fprintf(stdout, "Networks count %ld shallow %ld\n\n", i, j);
5999 	if (i != j) err = TRUE;
6000 	if (_np->cellview == el_layoutview && err)
6001 	{
6002 		fprintf(stdout, "!!!!!!!!!!!!! Strange cell %s\n", describenodeproto(_np));
6003 		ttyputmsg(M_("!!!!!!!!!!!!! Strange cell %s"), describenodeproto(_np));
6004 	}
6005 	efree((CHAR*)netmap);
6006 }
6007 
shallowconnect(INTBIG a1,INTBIG a2)6008 void NetCellConns::shallowconnect( INTBIG a1, INTBIG a2 )
6009 {
6010 	INTBIG m1, m2, m;
6011 
6012 	for (m1 = a1; _shallowmap[m1] != m1; m1 = _shallowmap[m1]);
6013 	for (m2 = a2; _shallowmap[m2] != m2; m2 = _shallowmap[m2]);
6014 	m = m1 < m2 ? m1 : m2;
6015 	//efprintf(stdout, M_("\t\tShallowConnect %ld %ld -> %ld\n"), a1, a2, m);
6016 	for (;;)
6017 	{
6018 		m1 = _shallowmap[a1];
6019 		_shallowmap[a1] = m;
6020 		if (a1 == m1) break;
6021 		a1 = m1;
6022 	}
6023 	for (;;)
6024 	{
6025 		m2 = _shallowmap[a2];
6026 		_shallowmap[a2] = m;
6027 		if (a2 == m2) break;
6028 		a2 = m2;
6029 	}
6030 }
6031 
shallowfixup()6032 void NetCellConns::shallowfixup()
6033 {
6034 	INTBIG i;
6035 
6036 	for (i = 0; i < _portcount + _arccount; i++)
6037 	{
6038 		INTBIG m = _shallowmap[i];
6039 		if (m == i)
6040 			_drawncount++;
6041 		else
6042 			_shallowmap[i] = _shallowmap[m];
6043 	}
6044 }
6045 
addGlobalname(CHAR * name)6046 INTBIG NetCellConns::addGlobalname(CHAR *name)
6047 {
6048 	CLUSTER *cluster = _np->netd->cluster();
6049 	INTBIG i;
6050 	CHAR **newglobalnames;
6051 
6052 	if (_globalcount == 0)
6053 	{
6054 		_globalcount = 1;
6055 		_globalnames = (CHAR**)emalloc(sizeof(CHAR*)*1, cluster);
6056 		allocstring(&_globalnames[0], name, cluster);
6057 		return 0;
6058 	}
6059 	for (i = 0; i < _globalcount; i++)
6060 	{
6061 		if (namesame(name, _globalnames[i]) == 0) return i;
6062 	}
6063 	newglobalnames = (CHAR**)emalloc(sizeof(CHAR*)*(_globalcount + 1), cluster);
6064 	for (i = 0; i < _globalcount; i++)
6065 	{
6066 		newglobalnames[i] = _globalnames[i];
6067 	}
6068 	allocstring(&newglobalnames[_globalcount], name, cluster);
6069 	efree((CHAR *)_globalnames);
6070 	_globalnames = newglobalnames;
6071 	return _globalcount++;
6072 }
6073 
makeDrawns()6074 void NetCellConns::makeDrawns()
6075 {
6076 	INTBIG i;
6077 	CLUSTER *cluster = _np->netd->cluster();
6078 
6079 	_drawncount = 0;
6080 	for (i = 0; i < _portcount + _arccount; i++)
6081 	{
6082 		if (_shallowmap[i] == i)
6083 			_drawncount++;
6084 	}
6085 	_shallow2drawn = (NetDrawn **)emalloc((_portcount + _arccount)*sizeof(NetDrawn *), cluster);
6086 	_drawns = (NetDrawn *)emalloc(_drawncount*sizeof(NetDrawn), cluster);
6087 	NetDrawn *p = _drawns;
6088 	for (i = 0; i < _portcount + _arccount; i++)
6089 	{
6090 		INTBIG m = _shallowmap[i];
6091 		if (m == i)
6092 		{
6093 			_shallow2drawn[i] = p;
6094 			p->_shallowRoot = i;
6095 			p->_isBus = FALSE;
6096 			p->_busWidth = 0;
6097 			p->_network = NONETWORK;
6098 			p++;
6099 		} else
6100 		{
6101 			_shallow2drawn[i] = _shallow2drawn[m];
6102 		}
6103 	}
6104 }
6105 
deepconnect(INTBIG a1,INTBIG a2)6106 void NetCellConns::deepconnect( INTBIG a1, INTBIG a2 )
6107 {
6108 	INTBIG m1, m2, m;
6109 
6110 	for (m1 = a1; _deepmap[m1] != m1; m1 = _deepmap[m1]);
6111 	for (m2 = a2; _deepmap[m2] != m2; m2 = _deepmap[m2]);
6112 	m = m1 < m2 ? m1 : m2;
6113 	//efprintf(stdout, M_("\t\tShallowConnect %ld %ld -> %ld\n"), a1, a2, m);
6114 	for (;;)
6115 	{
6116 		m1 = _deepmap[a1];
6117 		_deepmap[a1] = m;
6118 		if (a1 == m1) break;
6119 		a1 = m1;
6120 	}
6121 	for (;;)
6122 	{
6123 		m2 = _deepmap[a2];
6124 		_deepmap[a2] = m;
6125 		if (a2 == m2) break;
6126 		a2 = m2;
6127 	}
6128 }
6129 
deepfixup()6130 void NetCellConns::deepfixup()
6131 {
6132 	for (INTBIG i = 0; i < _deepmapcount; i++)
6133 	{
6134 		INTBIG m = _deepmap[i];
6135 		_deepmap[i] = _deepmap[m];
6136 	}
6137 }
6138 #endif
6139 
6140 /*********************** BUS NAME ROUTINES ***********************/
6141 
6142 #define MULTIDIMENSIONALBUS 1
6143 
6144 /*
6145  * routine to parse the bus name "name" found on an arc that has function
6146  * "funct" in cell "cell".  Returns the number of signals described by the
6147  * name (returns 1 dummy signal on error).  The pointer at "strings" is filled with an
6148  * array of individual bus names.
6149  */
net_evalbusname(INTBIG funct,CHAR * name,CHAR *** strings,ARCINST * thisai,NODEPROTO * cell,INTBIG showerrors)6150 INTBIG net_evalbusname(INTBIG funct, CHAR *name, CHAR ***strings,
6151 	ARCINST *thisai, NODEPROTO *cell, INTBIG showerrors)
6152 {
6153 	REGISTER CHAR *key, *cindex, *endindex, *errorstring, *busname;
6154 	CHAR *ptin, *savekey, ***mystrings;
6155 	INTBIG count, *stringcount;
6156 	REGISTER INTBIG ch1, ch2, perfect, dimension, dimstart, dimend, dimlen;
6157 	REGISTER INTBIG indexval, endindexval, origfunct, i, index, range;
6158 	REGISTER void *infstr;
6159 
6160 	/* initialize */
6161 	if (net_busbufstringbufferpos < 0)
6162 	{
6163 		net_busbufstringbufferpos = 0;
6164 		for(i=0; i<NUMBUSSTRINGBUFFERS; i++) net_busbufstringcountarray[i] = 0;
6165 	}
6166 	mystrings = &net_busbufstringsarray[net_busbufstringbufferpos];
6167 	stringcount = &net_busbufstringcountarray[net_busbufstringbufferpos];
6168 	net_busbufstringbufferpos++;
6169 	if (net_busbufstringbufferpos >= NUMBUSSTRINGBUFFERS)
6170 		net_busbufstringbufferpos = 0;
6171 
6172 	count = 0;
6173 	ptin = name;
6174 	perfect = 0;
6175 	savekey = 0;
6176 	for(;;)
6177 	{
6178 		key = getkeyword(&ptin, x_("[],"));
6179 		if (key == NOSTRING) break;
6180 		ch1 = tonextchar(&ptin);
6181 		if (ch1 == ']')
6182 		{
6183 			if (showerrors != 0)
6184 				ttyputmsg(_("Cell %s, network '%s': unmatched ']' in name"),
6185 					describenodeproto(cell), name);
6186 			break;
6187 		}
6188 		if (ch1 == ',' || ch1 == 0)
6189 		{
6190 			/* add unindexed network name "key" to list */
6191 			if (*key == 0)
6192 			{
6193 				if (showerrors != 0)
6194 					ttyputmsg(_("Cell %s, network '%s': empty network name"),
6195 						describenodeproto(cell), name);
6196 				break;
6197 			}
6198 			net_addstring(key, &count, stringcount, mystrings);
6199 			if (ch1 == 0) { perfect = 1;   break; }
6200 			continue;
6201 		}
6202 
6203 		/* '[' encountered: process array entries */
6204 		if (savekey != 0) efree(savekey);
6205 		if (*key != 0) (void)allocstring(&savekey, key, el_tempcluster); else
6206 		{
6207 			/* no name before the '[', look for an assumed bus name */
6208 			if (thisai == NOARCINST)
6209 			{
6210 				(void)allocstring(&savekey, x_(""), el_tempcluster);
6211 			} else
6212 			{
6213 				busname = net_busnameofarc(thisai);
6214 				if (busname == 0)
6215 				{
6216 					ttyputmsg(_("Cell %s, network '%s': cannot determine bus name to use"),
6217 						describenodeproto(cell), name);
6218 					busname = x_("XXX");
6219 				}
6220 				(void)allocstring(&savekey, busname, el_tempcluster);
6221 			}
6222 		}
6223 
6224 		/* loop through the indexed entries */
6225 		dimension = 0;
6226 		dimstart = count;
6227 		dimend = dimlen = 0; /* valid only if dimension > 0 */
6228 		for(;;)
6229 		{
6230 			cindex = getkeyword(&ptin, x_(",:]"));
6231 			ch2 = tonextchar(&ptin);
6232 			if (cindex == NOSTRING) break;
6233 			if (*cindex == 0)
6234 			{
6235 				if (showerrors != 0)
6236 					ttyputmsg(_("Cell %s, network '%s': empty network index"),
6237 						describenodeproto(cell), name);
6238 				break;
6239 			}
6240 			if (net_isanumber(cindex))
6241 			{
6242 				indexval = myatoi(cindex);
6243 				if (indexval < 0)
6244 				{
6245 					if (showerrors != 0)
6246 						ttyputmsg(_("Cell %s, network '%s': array indices cannot be negative"),
6247 							describenodeproto(cell), name);
6248 					break;
6249 				}
6250 			} else indexval = -1;
6251 			if (ch2 == ']' || ch2 == ',')
6252 			{
6253 				/* add entry "indexval" in the array with name "key" */
6254 				if (dimension > 0)
6255 				{
6256 					for(i=dimstart; i<dimend; i++)
6257 					{
6258 						infstr = initinfstr();
6259 						formatinfstr(infstr, x_("%s[%s]"), (*mystrings)[i], cindex);
6260 						net_insertstring(returninfstr(infstr), dimend + dimlen + (i-dimstart)*(dimlen+1),
6261 							&count, stringcount, mystrings);
6262 					}
6263 					dimlen++;
6264 				} else
6265 				{
6266 					infstr = initinfstr();
6267 					formatinfstr(infstr, x_("%s[%s]"), savekey, cindex);
6268 					net_addstring(returninfstr(infstr), &count, stringcount, mystrings);
6269 				}
6270 			} else
6271 			{
6272 				/* ':' found, handle range of values */
6273 				if (indexval < 0)
6274 				{
6275 					if (showerrors != 0)
6276 						ttyputerr(_("Warning (cell %s): network '%s' has nonnumeric start of index range"),
6277 							describenodeproto(cell), name);
6278 					break;
6279 				}
6280 				endindex = getkeyword(&ptin, x_(",]"));
6281 				ch2 = tonextchar(&ptin);
6282 				if (endindex == NOSTRING) break;
6283 				if (*endindex == 0)
6284 				{
6285 					if (showerrors != 0)
6286 						ttyputmsg(_("Warning (cell %s): network '%s' has missing end of index range"),
6287 							describenodeproto(cell), name);
6288 					break;
6289 				}
6290 				if (!net_isanumber(endindex))
6291 				{
6292 					if (showerrors != 0)
6293 						ttyputmsg(_("Warning (cell %s): network '%s' has nonnumeric end of index range"),
6294 							describenodeproto(cell), name);
6295 					break;
6296 				}
6297 				endindexval = myatoi(endindex);
6298 				if (endindexval < 0)
6299 				{
6300 					if (showerrors != 0)
6301 						ttyputmsg(_("Warning (cell %s): network '%s' has negative end of index range"),
6302 							describenodeproto(cell), name);
6303 					break;
6304 				}
6305 				if (endindexval == indexval)
6306 				{
6307 					if (showerrors != 0)
6308 						ttyputmsg(_("Warning (cell %s): network '%s' has equal start and end indices"),
6309 							describenodeproto(cell), name);
6310 					break;
6311 				}
6312 
6313 				/* add an array from "indexval" to "endindexval" */
6314 				if (indexval < endindexval)
6315 				{
6316 					for(index=indexval; index<=endindexval; index++)
6317 					{
6318 						if (dimension > 0)
6319 						{
6320 							for(i=dimstart; i<dimend; i++)
6321 							{
6322 								infstr = initinfstr();
6323 								formatinfstr(infstr, x_("%s[%ld]"), (*mystrings)[dimstart+i], index);
6324 								net_insertstring(returninfstr(infstr), dimend + dimlen + i*(dimlen+1),
6325 									&count, stringcount, mystrings);
6326 							}
6327 							dimlen++;
6328 						} else
6329 						{
6330 							infstr = initinfstr();
6331 							formatinfstr(infstr, x_("%s[%ld]"), savekey, index);
6332 							net_addstring(returninfstr(infstr), &count, stringcount, mystrings);
6333 						}
6334 					}
6335 				} else
6336 				{
6337 					for(index=indexval; index>=endindexval; index--)
6338 					{
6339 						if (dimension > 0)
6340 						{
6341 							for(i=dimstart; i<dimend; i++)
6342 							{
6343 								infstr = initinfstr();
6344 								formatinfstr(infstr, x_("%s[%ld]"), (*mystrings)[dimstart+i], index);
6345 								net_insertstring(returninfstr(infstr), dimend + dimlen + i*(dimlen+1),
6346 									&count, stringcount, mystrings);
6347 							}
6348 							dimlen++;
6349 						} else
6350 						{
6351 							infstr = initinfstr();
6352 							formatinfstr(infstr, x_("%s[%ld]"), savekey, index);
6353 							net_addstring(returninfstr(infstr), &count, stringcount, mystrings);
6354 						}
6355 					}
6356 				}
6357 			}
6358 			if (ch2 == ',') continue;
6359 
6360 			/* at the "]", clean up multidimensional array */
6361 			if (dimension > 0)
6362 			{
6363 				range = dimend - dimstart;
6364 				for(i=dimend; i<count; i++)
6365 				{
6366 					key = (*mystrings)[i-range];
6367 					(*mystrings)[i-range] = (*mystrings)[i];
6368 					(*mystrings)[i] = key;
6369 				}
6370 				count-= range;
6371 			}
6372 
6373 			/* see if a "[" follows it for a multidimensional array */
6374 			if (*ptin != '[')
6375 			{
6376 				perfect = 1;
6377 				break;
6378 			}
6379 			ptin++;
6380 			dimend = count;
6381 			dimension++;
6382 			dimlen = 0;
6383 #ifdef MULTIDIMENSIONALBUS
6384 			continue;
6385 #else
6386 			break;
6387 #endif
6388 		}
6389 
6390 		if (!perfect) break;
6391 		perfect = 0;
6392 		/* see what follows the ']' */
6393 		key = getkeyword(&ptin, x_(","));
6394 		if (key == NOSTRING) break;
6395 		ch1 = tonextchar(&ptin);
6396 		if (*key != 0)
6397 		{
6398 			if (showerrors != 0)
6399 				ttyputmsg(_("Cell %s, network '%s': missing comma between names"),
6400 					describenodeproto(cell), name);
6401 			break;
6402 		}
6403 		if (ch1 == 0) { perfect = 1;   break; }
6404 	}
6405 	if (savekey != 0) efree(savekey);
6406 
6407 	/* if no strings were extracted, treat as wire */
6408 	origfunct = funct;
6409 	if (count == 0) funct = APUNKNOWN;
6410 
6411 	/* see if multiple signals were found on single-signal arc */
6412 	if ((count != 1 && funct != APBUS) || perfect == 0)
6413 	{
6414 		errorstring = (CHAR *)emalloc((estrlen(name)+1) * SIZEOFCHAR, el_tempcluster);
6415 		(void)estrcpy(errorstring, name);
6416 		for(ptin = errorstring; *ptin != 0; ptin++)
6417 			if (*ptin == ',' || *ptin == ':' || *ptin == '[' || *ptin == ']')
6418 				*ptin = 'X';
6419 		if (showerrors != 0)
6420 		{
6421 			if (origfunct != APBUS)
6422 				ttyputerr(_("Warning (cell %s): network '%s' cannot name a single wire, using '%s'"),
6423 					describenodeproto(cell), name, errorstring); else
6424 						ttyputerr(_("Warning (cell %s): network name '%s' is unintelligible, using '%s'"),
6425 							describenodeproto(cell), name, errorstring);
6426 		}
6427 		count = 0;
6428 		net_addstring(errorstring, &count, stringcount, mystrings);
6429 		*strings = *mystrings;
6430 		efree(errorstring);
6431 		return(count);
6432 	}
6433 
6434 	/* if there are errors, build what is available */
6435 	if (showerrors != 0)
6436 	{
6437 		if (perfect == 0)
6438 			ttyputerr(_("Warning (cell %s): network name '%s' is unintelligible"),
6439 				describenodeproto(cell), name);
6440 	}
6441 
6442 	*strings = *mystrings;
6443 	return(count);
6444 }
6445 
6446 /*
6447  * Routine to follow arc "ai" and find a bus with a unique name.  This is the name to
6448  * use for the arc (which has been named with an empty bus name and just an index).
6449  */
net_busnameofarc(ARCINST * ai)6450 CHAR *net_busnameofarc(ARCINST *ai)
6451 {
6452 	REGISTER ARCINST *oai;
6453 	REGISTER CHAR *ch;
6454 
6455 	if (ai != NOARCINST)
6456 	{
6457 		for(oai = ai->parent->firstarcinst; oai != NOARCINST; oai = oai->nextarcinst)
6458 			oai->temp1 = 0;
6459 		ch = net_findnameofbus(ai, TRUE);
6460 		if (ch != 0) return(ch);
6461 		ch = net_findnameofbus(ai, FALSE);
6462 		if (ch != 0) return(ch);
6463 	}
6464 	return(0);
6465 }
6466 
6467 /*
6468  * Routine to determine the name of the bus on arc "ai".  The assumption is that
6469  * the bus has been partially named (i.e. "[0:2]") and that some other bus has
6470  * a more full name.  Only searches bus arcs if "justbus" is true.
6471  */
net_findnameofbus(ARCINST * ai,BOOLEAN justbus)6472 CHAR *net_findnameofbus(ARCINST *ai, BOOLEAN justbus)
6473 {
6474 	REGISTER NODEINST *ni;
6475 	REGISTER ARCINST *oai;
6476 	REGISTER PORTARCINST *pi;
6477 	REGISTER PORTEXPINST *pe;
6478 	REGISTER INTBIG i, fun;
6479 	REGISTER CHAR *ch;
6480 	REGISTER void *infstr;
6481 
6482 	if (ai->proto == sch_busarc)
6483 	{
6484 		if (ai->network != NONETWORK)
6485 		{
6486 			if (ai->network->namecount > 0)
6487 			{
6488 				infstr = initinfstr();
6489 				for(ch = networkname(ai->network, 0); *ch != 0;  ch++)
6490 				{
6491 					if (*ch == '[') break;
6492 					addtoinfstr(infstr, *ch);
6493 				}
6494 				return(returninfstr(infstr));
6495 			}
6496 		}
6497 	}
6498 	ai->temp1 = 1;
6499 	for(i=0; i<2; i++)
6500 	{
6501 		ni = ai->end[i].nodeinst;
6502 		fun = (ni->proto->userbits & NFUNCTION) >> NFUNCTIONSH;
6503 		if (fun != NPPIN && fun != NPCONTACT && fun != NPNODE && fun != NPCONNECT) continue;
6504 
6505 		/* follow arcs out of this node */
6506 		for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
6507 		{
6508 			if ((pi->proto->userbits&PORTISOLATED) != 0) continue;
6509 			oai = pi->conarcinst;
6510 			if (oai->temp1 != 0) continue;
6511 			if (justbus && oai->proto != sch_busarc) continue;
6512 
6513 			ch = net_findnameofbus(oai, justbus);
6514 			if (ch != 0) return(ch);
6515 		}
6516 
6517 		/* look at exports for array names */
6518 		for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
6519 		{
6520 			if (net_buswidth(pe->exportproto->protoname) > 1)
6521 			{
6522 				infstr = initinfstr();
6523 				for(ch = pe->exportproto->protoname; *ch != 0;  ch++)
6524 				{
6525 					if (*ch == '[') break;
6526 					addtoinfstr(infstr, *ch);
6527 				}
6528 				return(returninfstr(infstr));
6529 			}
6530 		}
6531 	}
6532 	return(0);
6533 }
6534 
net_insertstring(CHAR * key,INTBIG index,INTBIG * count,INTBIG * stringcount,CHAR *** mystrings)6535 void net_insertstring(CHAR *key, INTBIG index, INTBIG *count, INTBIG *stringcount, CHAR ***mystrings)
6536 {
6537 	REGISTER CHAR **newstrings, *lastone;
6538 	REGISTER INTBIG i;
6539 
6540 	if (*count >= *stringcount)
6541 	{
6542 		newstrings = (CHAR **)emalloc(((sizeof (CHAR *)) * (*count + 1)), net_tool->cluster);
6543 		if (newstrings == 0) return;
6544 		for(i=0; i < *stringcount; i++)
6545 			newstrings[i] = (*mystrings)[i];
6546 		for(i = *stringcount; i < *count + 1; i++)
6547 			(void)allocstring(&newstrings[i], x_(""), net_tool->cluster);
6548 		if (*stringcount != 0)
6549 			efree((CHAR *)*mystrings);
6550 		*stringcount = *count + 1;
6551 		*mystrings = newstrings;
6552 	}
6553 
6554 	/* rearrange */
6555 	lastone = (*mystrings)[*count];
6556 	for(i = *count; i > index; i--)
6557 		(*mystrings)[i] = (*mystrings)[i-1];
6558 	(*mystrings)[index] = lastone;
6559 
6560 	(void)reallocstring(&(*mystrings)[index], key, net_tool->cluster);
6561 	(*count)++;
6562 }
6563 
net_addstring(CHAR * key,INTBIG * count,INTBIG * stringcount,CHAR *** mystrings)6564 void net_addstring(CHAR *key, INTBIG *count, INTBIG *stringcount, CHAR ***mystrings)
6565 {
6566 	REGISTER CHAR **newstrings;
6567 	REGISTER INTBIG i;
6568 
6569 	if (*count >= *stringcount)
6570 	{
6571 		newstrings = (CHAR **)emalloc(((sizeof (CHAR *)) * (*count + 1)), net_tool->cluster);
6572 		if (newstrings == 0) return;
6573 		for(i=0; i < *stringcount; i++)
6574 			newstrings[i] = (*mystrings)[i];
6575 		for(i = *stringcount; i < *count + 1; i++)
6576 			(void)allocstring(&newstrings[i], x_(""), net_tool->cluster);
6577 		if (*stringcount != 0)
6578 			efree((CHAR *)*mystrings);
6579 		*stringcount = *count + 1;
6580 		*mystrings = newstrings;
6581 	}
6582 	(void)reallocstring(&(*mystrings)[*count], key, net_tool->cluster);
6583 	(*count)++;
6584 }
6585 
6586 /*
6587  * routine to ensure that single-wire arc "ai" properly connects to the bus
6588  * running through bus-pin "ni".  Prints a warning message if error found.
6589  */
net_checkvalidconnection(NODEINST * ni,ARCINST * ai)6590 void net_checkvalidconnection(NODEINST *ni, ARCINST *ai)
6591 {
6592 	REGISTER PORTARCINST *pi;
6593 	REGISTER ARCINST *oai;
6594 	REGISTER INTBIG j, found;
6595 	REGISTER PORTEXPINST *pe;
6596 	REGISTER PORTPROTO *pp;
6597 
6598 	/* find a bus arc on this node */
6599 	if (ai->network == NONETWORK) return;
6600 	found = 0;
6601 	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
6602 	{
6603 		oai = pi->conarcinst;
6604 		if (oai->proto != sch_busarc) continue;
6605 		if (oai->network == NONETWORK) continue;
6606 		if (oai->network->buswidth <= 1) continue;
6607 
6608 		/* make sure the bus has this network on it */
6609 		for(j=0; j<oai->network->buswidth; j++)
6610 			if (oai->network->networklist[j] == ai->network) return;
6611 		found++;
6612 	}
6613 
6614 	/* now check exported bus pins */
6615 	for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
6616 	{
6617 		pp = pe->exportproto;
6618 		if (pp->network == NONETWORK) continue;
6619 		if (pp->network->buswidth <= 1) continue;
6620 
6621 		/* make sure the bus has this network on it */
6622 		for(j=0; j<pp->network->buswidth; j++)
6623 			if (pp->network->networklist[j] == ai->network) return;
6624 		found++;
6625 	}
6626 
6627 	if (found > 0)
6628 	{
6629 		ttyputmsg(_("Warning (cell %s): network '%s' not a part of connected busses"),
6630 			describenodeproto(ai->parent), describenetwork(ai->network));
6631 		if (ai->network->namecount == 0)
6632 			ttyputmsg(_("   (Set a network name on the '%s' arc)"), describearcinst(ai));
6633 	}
6634 }
6635 
6636 /*
6637  * Routine to ensure that network "net" (a bus) has a proper bus name if it is named temporarily.
6638  */
net_ensuretempbusname(NETWORK * net)6639 void net_ensuretempbusname(NETWORK *net)
6640 {
6641 	INTBIG count, base;
6642 	REGISTER void *infstr;
6643 	CHAR *netname;
6644 
6645 	if (net->buswidth <= 1) return;
6646 	if (net->tempname == 0) return;
6647 	if (net->namecount != 1) return;
6648 	netname = networkname(net, 0);
6649 	count = net_buswidth(netname);
6650 	if (count != 1) return;
6651 	infstr = initinfstr();
6652 	addstringtoinfstr(infstr, netname);
6653 	if ((net_options&NETDEFBUSBASE1) == 0) base = 0; else base = 1;
6654 	if ((net_options&NETDEFBUSBASEDESC) == 0)
6655 	{
6656 		formatinfstr(infstr, x_("[%ld:%ld]"), base, net->buswidth-1+base);
6657 	} else
6658 	{
6659 		formatinfstr(infstr, x_("[%ld:%ld]"), net->buswidth-1+base, base);
6660 	}
6661 	((NetName*)net->netnameaddr)->removeNet(net);
6662 	net->namecount = 0;
6663 #ifdef NEWRENUM
6664 	NetName *nn = net->parent->netd->findNetName(returninfstr(infstr), TRUE);
6665 	(void)net_namenet(nn, net);
6666 #else
6667 	(void)net_namenet(returninfstr(infstr), net);
6668 #endif
6669 }
6670 
6671 /*
6672  * Routine to evaluate the implied bus width of the string 'name'
6673  */
net_buswidth(CHAR * name)6674 INTBIG net_buswidth(CHAR *name)
6675 {
6676 	REGISTER INTBIG count;
6677 	CHAR **strings;
6678 
6679 	count = net_evalbusname(APBUS, name, &strings, NOARCINST, NONODEPROTO, 0);
6680 	return(count);
6681 }
6682 
6683 /*
6684  * Routine to implement the "wire_con" primitive which joins two arcs and attaches
6685  * busses of unequal length (by repeating signals on the shorter bus until fully
6686  * attached to the larger bus).
6687  */
net_joinnetworks(NODEINST * ni)6688 void net_joinnetworks(NODEINST *ni)
6689 {
6690 	REGISTER ARCINST *ai, *smallai, *largeai;
6691 	REGISTER INTBIG smallnum, largenum, num, wirecount, i;
6692 	REGISTER PORTARCINST *pi;
6693 	REGISTER NETWORK *net, *smallnet, *largenet;
6694 
6695 	/* find the narrow and wide busses on this connector */
6696 	smallai = largeai = NOARCINST;
6697 	smallnum = largenum = 0;
6698 	wirecount = 0;
6699 	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
6700 	{
6701 		ai = pi->conarcinst;
6702 		wirecount++;
6703 		net = ai->network;
6704 		if (net == NONETWORK) continue;
6705 		num = net->buswidth;
6706 		if (smallai == NOARCINST || num <= smallnum)
6707 		{
6708 			smallai = ai;
6709 			smallnum = num;
6710 		}
6711 		if (largeai == NOARCINST || num > largenum)
6712 		{
6713 			largeai = ai;
6714 			largenum = num;
6715 		}
6716 	}
6717 	if (wirecount < 2) return;
6718 	if (wirecount > 2)
6719 	{
6720 		ttyputmsg(_("Cell %s, connector %s can only merge two arcs (has %ld)"),
6721 			describenodeproto(ni->parent), describenodeinst(ni), wirecount);
6722 		return;
6723 	}
6724 	if (smallai == largeai) return;
6725 
6726 	for(i=0; i<largenum; i++)
6727 	{
6728 		if (smallnum == 1) smallnet = smallai->network; else
6729 		{
6730 			smallnet = smallai->network->networklist[i % smallnum];
6731 		}
6732 		if (largenum == 1) largenet = largeai->network; else
6733 		{
6734 			largenet = largeai->network->networklist[i];
6735 		}
6736 		if (smallnet == largenet) continue;
6737 		(void)net_mergenet(smallnet, largenet);
6738 	}
6739 
6740 	/* also merge the busses if they are the same length */
6741 	if (smallnum == largenum && smallnum > 1)
6742 	{
6743 		(void)net_mergenet(smallai->network, largeai->network);
6744 	}
6745 }
6746 
6747 /*
6748  * Routine to determine the width of bus arc "ai" by looking at cell instances that
6749  * connect to it.  Returns the node and port that was used to determine the size (if
6750  * a bus).
6751  */
net_buswidthofarc(ARCINST * ai,NODEINST ** arrayni,PORTPROTO ** arraypp)6752 INTBIG net_buswidthofarc(ARCINST *ai, NODEINST **arrayni, PORTPROTO **arraypp)
6753 {
6754 	REGISTER INTBIG buswidth, width;
6755 	REGISTER NODEINST *ni;
6756 
6757 	if (ai->proto != sch_busarc) return(1);
6758 	ni = ai->end[0].nodeinst;
6759 	if (ni->proto->primindex != 0) buswidth = 1; else
6760 	{
6761 		buswidth = ai->end[0].portarcinst->proto->network->buswidth;
6762 		if (ni->arraysize > 1) buswidth *= ni->arraysize;
6763 		if (buswidth > 1)
6764 		{
6765 			*arrayni = ai->end[0].nodeinst;
6766 			*arraypp = ai->end[0].portarcinst->proto;
6767 		}
6768 	}
6769 
6770 	ni = ai->end[1].nodeinst;
6771 	if (ni->proto->primindex == 0)
6772 	{
6773 		width = ai->end[1].portarcinst->proto->network->buswidth;
6774 		if (ni->arraysize > 1) width *= ni->arraysize;
6775 		if (width > 1)
6776 		{
6777 			*arrayni = ai->end[1].nodeinst;
6778 			*arraypp = ai->end[1].portarcinst->proto;
6779 		}
6780 		if (buswidth == 1) buswidth = width; else
6781 			if (buswidth != width) buswidth = 1;
6782 	}
6783 	return(buswidth);
6784 }
6785 
6786 #define FINDINTERBUSSHORT 1
6787 
6788 /*
6789  * Routine to locate individual signals contained within busses in
6790  * node instance ni which are connected inside of the contentsview
6791  * of ni->proto, and then to merge the two individual networks.
6792  */
net_mergebuswires(NODEINST * ni)6793 BOOLEAN net_mergebuswires(NODEINST *ni)
6794 {
6795 	REGISTER NODEPROTO *np, *cnp;
6796 	REGISTER PORTPROTO *pp, *opp, *cpp, *ocpp;
6797 	REGISTER NETWORK *net, *onet, *cnet, *ocnet, *cmnet, *ocmnet, *topnet, *otopnet;
6798 	REGISTER INTBIG j, k, a, nodewidth;
6799 	REGISTER BOOLEAN recheck;
6800 
6801 	/* primitives do not connect individual signals in busses */
6802 	if (ni->proto->primindex != 0) return(FALSE);
6803 
6804 	/* establish connections to contents nodeproto */
6805 	np = ni->proto;
6806 	nodewidth = ni->arraysize;
6807 	if (nodewidth < 1) nodewidth = 1;
6808 	cnp = contentsview(np);
6809 	if (cnp == NONODEPROTO) cnp = np;
6810 
6811 	/* presume no checking above is required */
6812 	recheck = FALSE;
6813 
6814 	for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
6815 	{
6816 		/* see if this port can connect to a bus */
6817 		for(j=0; pp->connects[j] != NOARCPROTO; j++)
6818 			if (pp->connects[j] == sch_busarc) break;
6819 		if (pp->connects[j] == NOARCPROTO) continue;
6820 
6821 		/* make sure this port has a network attached to it at the current level */
6822 		net = getnetonport(ni, pp);
6823 		if (net == NONETWORK) continue;
6824 
6825 		/* nothing to do if the network is a single wire */
6826 		if (net->buswidth <= 1) continue;
6827 
6828 		/* find the network inside of the contents */
6829 		cpp = equivalentport(np, pp, cnp);
6830 		if (cpp == NOPORTPROTO) continue;
6831 		cnet = cpp->network;
6832 
6833 		/* make sure the networks match width, inside and out */
6834 		if (net->buswidth != cnet->buswidth && net->buswidth != cnet->buswidth * nodewidth)
6835 		{
6836 			if (nodewidth > 1)
6837 			{
6838 				ttyputmsg(_("Warning (cell %s): bus %s cannot connect to port %s of %ld-wide node %s (different width)"),
6839 					describenodeproto(ni->parent), describenetwork(net), pp->protoname,
6840 						nodewidth, describenodeinst(ni));
6841 			} else
6842 			{
6843 				ttyputmsg(_("Warning (cell %s): bus %s cannot connect to port %s of node %s (different width)"),
6844 					describenodeproto(ni->parent), describenetwork(net), pp->protoname,
6845 						describenodeinst(ni));
6846 			}
6847 			continue;
6848 		}
6849 
6850 		/* now find another network attached to this node instance */
6851 		for (opp = np->firstportproto; opp != NOPORTPROTO; opp = opp->nextportproto)
6852 		{
6853 #ifndef FINDINTERBUSSHORT
6854 			if (opp == pp) continue;
6855 #endif
6856 
6857 			/* make sure this port has a different network attached to it at the current level */
6858 			onet = getnetonport(ni, opp);
6859 			if (onet == NONETWORK) continue;
6860 #ifndef FINDINTERBUSSHORT
6861 			if (onet == net) continue;
6862 #endif
6863 
6864 			/* find the network inside of the contents */
6865 			ocpp = equivalentport(np, opp, cnp);
6866 			if (ocpp == NOPORTPROTO) continue;
6867 			ocnet = ocpp->network;
6868 
6869 			/* make sure the networks match width, inside and out */
6870 			if (onet->buswidth != ocnet->buswidth && onet->buswidth != ocnet->buswidth * nodewidth)
6871 			{
6872 				if (nodewidth > 1)
6873 				{
6874 					ttyputmsg(_("Warning (cell %s): bus %s cannot connect to port %s of %ld-wide node %s (different width)"),
6875 						describenodeproto(ni->parent), describenetwork(onet), opp->protoname,
6876 							nodewidth, describenodeinst(ni));
6877 				} else
6878 				{
6879 					ttyputmsg(_("Warning (cell %s): bus %s cannot connect to port %s of node %s (different width)"),
6880 						describenodeproto(ni->parent), describenetwork(onet), opp->protoname,
6881 							describenodeinst(ni));
6882 				}
6883 				continue;
6884 			}
6885 
6886 #ifdef FINDINTERBUSSHORT
6887 			/* when the same net, check for shorts that are internal to a bus */
6888 			if (ocnet == cnet)
6889 			{
6890 				if (cnet->buswidth <= 1) continue;
6891 				for(j=0; j<cnet->buswidth; j++)
6892 				{
6893 					cmnet = cnet->networklist[j];
6894 					for (k=j+1; k<ocnet->buswidth; k++)
6895 					{
6896 						ocmnet = ocnet->networklist[k];
6897 						if (cmnet != ocmnet) continue;
6898 
6899 						/* merge found: propagate it to the top level */
6900 						for(a=0; a<nodewidth; a++)
6901 						{
6902 							if (net->buswidth > cnet->buswidth)
6903 								topnet = net->networklist[j + a*cnet->buswidth]; else
6904 							{
6905 								if (net->buswidth == 1) topnet = net; else
6906 									topnet = net->networklist[j];
6907 							}
6908 							if (onet->buswidth > ocnet->buswidth)
6909 								otopnet = onet->networklist[k + a*ocnet->buswidth]; else
6910 							{
6911 								if (onet->buswidth == 1) otopnet = onet; else
6912 									otopnet = onet->networklist[k];
6913 							}
6914 							(void)net_mergenet(topnet, otopnet);
6915 
6916 							/* if neither arc is arrayed with the node, stop after 1 merge */
6917 							if (net->buswidth == cnet->buswidth && onet->buswidth == ocnet->buswidth) break;
6918 						}
6919 					}
6920 				}
6921 				continue;
6922 			}
6923 #endif
6924 
6925 			/* look for merges inside of the cell */
6926 			for(j=0; j<cnet->buswidth; j++)
6927 			{
6928 				if (cnet->buswidth == 1) cmnet = cnet; else
6929 					cmnet = cnet->networklist[j];
6930 
6931 				for (k=0; k<ocnet->buswidth; k++)
6932 				{
6933 					if (ocnet->buswidth == 1) ocmnet = ocnet; else
6934 						ocmnet = ocnet->networklist[k];
6935 					if (cmnet != ocmnet) continue;
6936 
6937 					/* merge found: propagate it to the top level */
6938 					for(a=0; a<nodewidth; a++)
6939 					{
6940 						if (net->buswidth > cnet->buswidth)
6941 							topnet = net->networklist[j + a*cnet->buswidth]; else
6942 						{
6943 							if (net->buswidth == 1) topnet = net; else
6944 								topnet = net->networklist[j];
6945 						}
6946 						if (onet->buswidth > ocnet->buswidth)
6947 							otopnet = onet->networklist[k + a*ocnet->buswidth]; else
6948 						{
6949 							if (onet->buswidth == 1) otopnet = onet; else
6950 								otopnet = onet->networklist[k];
6951 						}
6952 						(void)net_mergenet(topnet, otopnet);
6953 
6954 						/* if neither arc is arrayed with the node, stop after 1 merge */
6955 						if (net->buswidth == cnet->buswidth && onet->buswidth == ocnet->buswidth) break;
6956 					}
6957 				}
6958 			}
6959 		}
6960 	}
6961 	return(recheck);
6962 }
6963 
6964 /*
6965  * Routine to examine the network names on networks "net1" and "net2" and return
6966  * true if they share a common name.
6967  */
net_samenetworkname(NETWORK * net1,NETWORK * net2)6968 BOOLEAN net_samenetworkname(NETWORK *net1, NETWORK *net2)
6969 {
6970 	REGISTER CHAR *pt1, *pt2;
6971 	CHAR **strings;
6972 	REGISTER INTBIG n1, n2, wid1, wid2, i1, i2;
6973 
6974 	for(n1 = 0; n1 < net1->namecount; n1++)
6975 	{
6976 		pt1 = networkname(net1, n1);
6977 		wid1 = net_evalbusname(APBUS, pt1, &strings, NOARCINST, net1->parent, 0);
6978 		if (wid1 > net_namecompstringtotal)
6979 		{
6980 			if (net_namecompstringtotal > 0) efree((CHAR *)net_namecompstrings);
6981 			net_namecompstringtotal = 0;
6982 			net_namecompstrings = (CHAR **)emalloc(wid1 * (sizeof (CHAR *)), net_tool->cluster);
6983 			if (net_namecompstrings == 0) return(TRUE);
6984 			net_namecompstringtotal = wid1;
6985 		}
6986 		if (wid1 == 1) net_namecompstrings[0] = pt1; else
6987 		{
6988 			for(i1=0; i1<wid1; i1++)
6989 				(void)allocstring(&net_namecompstrings[i1], strings[i1], net_tool->cluster);
6990 		}
6991 
6992 		for(n2 = 0; n2 < net2->namecount; n2++)
6993 		{
6994 			pt2 = networkname(net2, n2);
6995 			wid2 = net_evalbusname(APBUS, pt2, &strings, NOARCINST, net2->parent, 0);
6996 			for(i1=0; i1<wid1; i1++)
6997 			{
6998 				for(i2=0; i2<wid2; i2++)
6999 				{
7000 					if (namesame(net_namecompstrings[i1], strings[i2]) == 0) return(TRUE);
7001 				}
7002 			}
7003 		}
7004 		if (wid1 > 1)
7005 		{
7006 			for(i1=0; i1<wid1; i1++)
7007 				efree((CHAR *)net_namecompstrings[i1]);
7008 		}
7009 	}
7010 	return(FALSE);
7011 }
7012 
7013 /*
7014  * Routine to add arc "ai", export "pp" and width "width" to the list of busses.
7015  */
net_addtobuslist(ARCINST * ai,PORTPROTO * pp,INTBIG width)7016 void net_addtobuslist(ARCINST *ai, PORTPROTO *pp, INTBIG width)
7017 {
7018 	REGISTER INTBIG newtotal, i;
7019 	REGISTER BUSLIST *newbuslists;
7020 
7021 	if (net_buslistcount >= net_buslisttotal)
7022 	{
7023 		newtotal = net_buslisttotal * 2;
7024 		if (newtotal <= net_buslistcount) newtotal = net_buslistcount + 5;
7025 		newbuslists = (BUSLIST *)emalloc(newtotal * (sizeof (BUSLIST)), net_tool->cluster);
7026 		if (newbuslists == 0) return;
7027 		for(i=0; i<net_buslistcount; i++)
7028 			newbuslists[i] = net_buslists[i];
7029 		if (net_buslisttotal > 0) efree((CHAR *)net_buslists);
7030 		net_buslists = newbuslists;
7031 		net_buslisttotal = newtotal;
7032 	}
7033 	net_buslists[net_buslistcount].ai = ai;
7034 	net_buslists[net_buslistcount].pp = pp;
7035 	net_buslists[net_buslistcount].width = width;
7036 	net_buslistcount++;
7037 }
7038 
7039 /*********************** NETLIST GEOMETRY ROUTINES ***********************/
7040 
7041 /*
7042  * Routine to show the geometry on network "net".
7043  */
net_showgeometry(NETWORK * net)7044 void net_showgeometry(NETWORK *net)
7045 {
7046 	REGISTER NODEPROTO *np;
7047 	REGISTER INTBIG i, j, widest, len, lambda, total, fun, totalWire;
7048 	REGISTER CHAR *lname, *pad;
7049 	REGISTER AREAPERIM *arpe, *firstarpe, **arpelist;
7050 	TRANSISTORINFO *p_gate, *n_gate, *p_active, *n_active;
7051 	float ratio;
7052 	REGISTER void *infstr;
7053 
7054 	/* gather geometry on this network */
7055 	np = net->parent;
7056 	firstarpe = net_gathergeometry(net, &p_gate, &n_gate, &p_active, &n_active, TRUE);
7057 
7058 	/* copy the linked list to an array for sorting */
7059 	total = 0;
7060 	for(arpe = firstarpe; arpe != NOAREAPERIM; arpe = arpe->nextareaperim)
7061 		if (arpe->layer >= 0) total++;
7062 	if (total == 0)
7063 	{
7064 		ttyputmsg(_("No geometry on network '%s' in cell %s"), describenetwork(net),
7065 			describenodeproto(np));
7066 		return;
7067 	}
7068 	arpelist = (AREAPERIM **)emalloc(total * (sizeof (AREAPERIM *)), net_tool->cluster);
7069 	if (arpelist == 0) return;
7070 	i = 0;
7071 	for(arpe = firstarpe; arpe != NOAREAPERIM; arpe = arpe->nextareaperim)
7072 		if (arpe->layer >= 0) arpelist[i++] = arpe;
7073 
7074 	/* sort the layers */
7075 	esort(arpelist, total, sizeof (AREAPERIM *), net_areaperimdepthascending);
7076 
7077 	ttyputmsg(_("For network '%s' in cell %s:"), describenetwork(net),
7078 		describenodeproto(np));
7079 	lambda = lambdaofcell(np);
7080 	widest = 0;
7081 	for(i=0; i<total; i++)
7082 	{
7083 		arpe = arpelist[i];
7084 		lname = layername(arpe->tech, arpe->layer);
7085 		len = estrlen(lname);
7086 		if (len > widest) widest = len;
7087 	}
7088 	totalWire = 0;
7089 	for(i=0; i<total; i++)
7090 	{
7091 		arpe = arpelist[i];
7092 		lname = layername(arpe->tech, arpe->layer);
7093 		infstr = initinfstr();
7094 		for(j=estrlen(lname); j<widest; j++) addtoinfstr(infstr, ' ');
7095 		pad = returninfstr(infstr);
7096 		if (arpe->perimeter == 0)
7097 		{
7098 			ttyputmsg(_("Layer %s:%s area=%7g  half-perimeter=%s"), lname, pad,
7099 				arpe->area/(float)lambda/(float)lambda, latoa(arpe->perimeter/2, 0));
7100 		} else
7101 		{
7102 			ratio = (arpe->area / (float)lambda) / (float)(arpe->perimeter/2);
7103 			ttyputmsg(_("Layer %s:%s area=%7g  half-perimeter=%s ratio=%g"), lname,
7104 				pad, arpe->area/(float)lambda/(float)lambda,
7105 					latoa(arpe->perimeter/2, lambda), ratio);
7106 
7107 			/* accumulate total wire length on all metal/poly layers */
7108 			fun = layerfunction(arpe->tech, arpe->layer);
7109 			if ((layerispoly(fun) && !layerisgatepoly(fun)) || layerismetal(fun))
7110 				totalWire += arpe->perimeter / 2;
7111 		}
7112 		efree((CHAR *)arpelist[i]);
7113 	}
7114 	if (totalWire > 0.0) ttyputmsg(_("Total wire length = %s"), latoa(totalWire,lambda));
7115 	efree((CHAR *)arpelist);
7116 }
7117 
7118 /*
7119  * Helper routine for "net_showgeometry()" to sort AREAPERIM objects by depth
7120  */
net_areaperimdepthascending(const void * e1,const void * e2)7121 int net_areaperimdepthascending(const void *e1, const void *e2)
7122 {
7123 	REGISTER AREAPERIM *ap1, *ap2;
7124 	REGISTER INTBIG fun1, fun2, depth1, depth2;
7125 
7126 	ap1 = *((AREAPERIM **)e1);
7127 	ap2 = *((AREAPERIM **)e2);
7128 	fun1 = layerfunction(ap1->tech, ap1->layer);
7129 	depth1 = layerfunctionheight(fun1);
7130 	if (layeriscontact(fun1)) depth1 -= 1000;
7131 	fun2 = layerfunction(ap2->tech, ap2->layer);
7132 	depth2 = layerfunctionheight(fun2);
7133 	if (layeriscontact(fun2)) depth2 -= 1000;
7134 	return(depth2 - depth1);
7135 }
7136 
7137 /*
7138  * Helper routine for "net_reevaluatecell()" to sort BUSLIST objects by width
7139  */
net_buslistwidthascending(const void * e1,const void * e2)7140 int net_buslistwidthascending(const void *e1, const void *e2)
7141 {
7142 	REGISTER BUSLIST *b1, *b2;
7143 
7144 	b1 = (BUSLIST *)e1;
7145 	b2 = (BUSLIST *)e2;
7146 	return(b1->width - b2->width);
7147 }
7148 
7149 /*
7150  * Routine to gather the geometry on network "net".  Must deallocate all of the AREAPERIM
7151  * objects created by this routine.
7152  */
net_gathergeometry(NETWORK * net,TRANSISTORINFO ** p_gate,TRANSISTORINFO ** n_gate,TRANSISTORINFO ** p_active,TRANSISTORINFO ** n_active,BOOLEAN recurse)7153 AREAPERIM *net_gathergeometry(NETWORK *net, TRANSISTORINFO **p_gate, TRANSISTORINFO **n_gate,
7154 	TRANSISTORINFO **p_active, TRANSISTORINFO **n_active, BOOLEAN recurse)
7155 {
7156 	REGISTER NODEPROTO *np;
7157 	REGISTER NETWORK *onet;
7158 
7159 	np = net->parent;
7160 
7161 	/* initialize polygon merging */
7162 	net_merge = mergenew(net_tool->cluster);
7163 
7164 	/* mark the networks in this cell that are of interest */
7165 	for(onet = np->firstnetwork; onet != NONETWORK; onet = onet->nextnetwork)
7166 		onet->temp1 = 0;
7167 	net->temp1 = 1;
7168 	net_cleartransistorinfo(&net_transistor_p_gate);
7169 	net_cleartransistorinfo(&net_transistor_n_gate);
7170 	net_cleartransistorinfo(&net_transistor_p_active);
7171 	net_cleartransistorinfo(&net_transistor_n_active);
7172 	net_firstareaperim = NOAREAPERIM;
7173 
7174 	/* examine circuit recursively */
7175 	net_propgeometry(np, el_matid, recurse);
7176 
7177 	/* get back the total geometry */
7178 	mergeextract(net_merge, net_geometrypolygon);
7179 	mergedelete(net_merge);
7180 
7181 	/* store the transistor area information in the parameters */
7182 	if (p_gate != 0) *p_gate = &net_transistor_p_gate;
7183 	if (n_gate != 0) *n_gate = &net_transistor_n_gate;
7184 	if (p_active != 0) *p_active = &net_transistor_p_active;
7185 	if (n_active != 0) *n_active = &net_transistor_n_active;
7186 	return(net_firstareaperim);
7187 }
7188 
7189 /*
7190  * Helper routine to gather the geometry in cell "cell" and below where the network's
7191  * "temp1" is nonzero.  Appropriate polygons are merged.  "trans" is the transformation
7192  * to this point in the hierarchy.
7193  */
net_propgeometry(NODEPROTO * cell,XARRAY trans,BOOLEAN recurse)7194 void net_propgeometry(NODEPROTO *cell, XARRAY trans, BOOLEAN recurse)
7195 {
7196 	static POLYGON *poly = NOPOLYGON;
7197 	REGISTER ARCINST *ai;
7198 	REGISTER NODEINST *ni;
7199 	REGISTER NODEPROTO *subnp;
7200 	XARRAY rot, trn, rottrn, subrot;
7201 	REGISTER NETWORK *net;
7202 	REGISTER PORTARCINST *pi;
7203 	REGISTER PORTEXPINST *pe;
7204 	REGISTER PORTPROTO *pp;
7205 	REGISTER INTBIG fun, nfun, ignorelayer, height, highest, polys, diffs;
7206 	REGISTER INTBIG total, i, found;
7207 	INTBIG length, width;
7208 
7209 	/* get polygon */
7210 	(void)needstaticpolygon(&poly, 4, db_cluster);
7211 
7212 	/* include all arcs on desired networks */
7213 	for(ai = cell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
7214 	{
7215 		if (ai->network == NONETWORK || ai->network->temp1 == 0) continue;
7216 		total = arcpolys(ai, NOWINDOWPART);
7217 		for(i=0; i<total; i++)
7218 		{
7219 			shapearcpoly(ai, i, poly);
7220 			xformpoly(poly, trans);
7221 			mergeaddpolygon(net_merge, poly->layer, ai->proto->tech, poly);
7222 		}
7223 	}
7224 	for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
7225 	{
7226 		/* ignore recursive references (showing icon in contents) */
7227 		subnp = ni->proto;
7228 		if (isiconof(subnp, cell)) continue;
7229 
7230 		/* see if any selected networks touch this node */
7231 		if (subnp->primindex == 0 && recurse == TRUE)
7232 		{
7233 			for(net = subnp->firstnetwork; net != NONETWORK; net = net->nextnetwork)
7234 				net->temp1 = 0;
7235 		} else
7236 		{
7237 			for(pp = subnp->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
7238 				pp->network->temp1 = 0;
7239 		}
7240 		found = 0;
7241 		for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
7242 		{
7243 			if (pi->conarcinst->network == NONETWORK || pi->conarcinst->network->temp1 == 0) continue;
7244 			pi->proto->network->temp1 = 1;
7245 			found = 1;
7246 		}
7247 		for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
7248 		{
7249 			if (pe->exportproto->network->temp1 == 0) continue;
7250 			pe->proto->network->temp1 = 1;
7251 			found = 1;
7252 		}
7253 		if (found == 0) continue;
7254 
7255 		if (subnp->primindex == 0 && recurse == TRUE)
7256 		{
7257 			/* cell instance: recurse */
7258 			if (subnp->cellview != el_iconview)
7259 			{
7260 				makerot(ni, rot);
7261 				maketrans(ni, trn);
7262 				transmult(trn, rot, rottrn);
7263 				transmult(rottrn, trans, subrot);
7264 				net_propgeometry(subnp, subrot, recurse);
7265 			}
7266 		} else
7267 		{
7268 			/* primitive: include layers that touch desired networks */
7269 			makerot(ni, rot);
7270 			transmult(rot, trans, subrot);
7271 			ignorelayer = -1;
7272 			nfun = nodefunction(ni);
7273 			if (nfun == NPCONTACT)
7274 			{
7275 				/* find highest layer and ignore it */
7276 				total = nodeEpolys(ni, 0, NOWINDOWPART);
7277 				highest = -1;
7278 				for(i=0; i<total; i++)
7279 				{
7280 					shapeEnodepoly(ni, i, poly);
7281 					fun = layerfunction(ni->proto->tech, poly->layer);
7282 					if ((fun&LFPSEUDO) != 0) continue;
7283 					height = layerfunctionheight(fun);
7284 					if (height > highest)
7285 					{
7286 						highest = height;
7287 						ignorelayer = poly->layer;
7288 					}
7289 				}
7290 			}
7291 			polys = diffs = 0;
7292 			total = nodeEpolys(ni, 0, NOWINDOWPART);
7293 			for(i=0; i<total; i++)
7294 			{
7295 				shapeEnodepoly(ni, i, poly);
7296 				if (poly->layer == ignorelayer) continue;
7297 				fun = layerfunction(subnp->tech, poly->layer);
7298 				if (poly->portproto == NOPORTPROTO) continue;
7299 				if (poly->portproto->network->temp1 == 0) continue;
7300 				if ((fun&LFPSEUDO) != 0) continue;
7301 				if (layerispoly(fun)) polys++;
7302 				if ((fun&LFTYPE) == LFDIFF) diffs++;
7303 				xformpoly(poly, subrot);
7304 				mergeaddpolygon(net_merge, poly->layer, subnp->tech, poly);
7305 			}
7306 			if (nfun == NPTRANMOS)
7307 			{
7308 				transistorsize(ni, &length, &width);
7309 				if (polys > 0)
7310 					net_addtotransistorinfo(&net_transistor_n_gate, length, width);
7311 				if (diffs > 0)
7312 					net_addtotransistorinfo(&net_transistor_n_active, length, width);
7313 			}
7314 			if (nfun == NPTRAPMOS)
7315 			{
7316 				transistorsize(ni, &length, &width);
7317 				if (polys > 0)
7318 					net_addtotransistorinfo(&net_transistor_p_gate, length, width);
7319 				if (diffs > 0)
7320 					net_addtotransistorinfo(&net_transistor_p_active, length, width);
7321 			}
7322 		}
7323 	}
7324 }
7325 
7326 /*
7327  * Helper routine to clear the TRANSISTORINFO structure "ti".
7328  */
net_cleartransistorinfo(TRANSISTORINFO * ti)7329 void net_cleartransistorinfo(TRANSISTORINFO *ti)
7330 {
7331 	ti->count = 0;
7332 	ti->area = 0;
7333 	ti->width = 0;
7334 	ti->length = 0;
7335 }
7336 
7337 /*
7338  * Helper routine to add a "length" and "width" transistor to the TRANSISTORINFO structure "ti".
7339  */
net_addtotransistorinfo(TRANSISTORINFO * ti,INTBIG length,INTBIG width)7340 void net_addtotransistorinfo(TRANSISTORINFO *ti, INTBIG length, INTBIG width)
7341 {
7342 	INTBIG area;
7343 
7344 	area = length * width;
7345 	ti->count++;
7346 	ti->area += area;
7347 	ti->length += length;
7348 	ti->width += width;
7349 }
7350 
7351 /*
7352  * Helper routine that is given merged geometry from the "network geometry" command.
7353  */
net_geometrypolygon(INTBIG layer,TECHNOLOGY * tech,INTBIG * x,INTBIG * y,INTBIG count)7354 void net_geometrypolygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count)
7355 {
7356 	REGISTER INTBIG per, seglen, i,  lastx, lasty, thisx, thisy;
7357 	float area, side1, side2;
7358 	REGISTER AREAPERIM *ap;
7359 
7360 	/* compute the perimeter */
7361 	per = 0;
7362 	for(i=0; i<count; i++)
7363 	{
7364 		if (i == 0)
7365 		{
7366 			lastx = x[count-1];   lasty = y[count-1];
7367 		} else
7368 		{
7369 			lastx = x[i-1];   lasty = y[i-1];
7370 		}
7371 		seglen = computedistance(lastx, lasty, x[i], y[i]);
7372 		per += seglen;
7373 	}
7374 
7375 	/* compute the area */
7376 	area = 0.0;
7377 	lastx = x[0];
7378 	lasty = y[0];
7379 	for (i=1; i<count; i++)
7380 	{
7381 		thisx = x[i];
7382 		thisy = y[i];
7383 
7384 		/* triangulate around the polygon */
7385 		side1 = (float)(thisx - lastx);
7386 		side2 = (float)(lasty + thisy);
7387 		area += (side1 * side2) / 2.0f;
7388 		lastx = thisx;
7389 		lasty = thisy;
7390 	}
7391 	side1 = (float)(x[0] - lastx);
7392 	side2 = (float)(y[0] + lasty);
7393 	area += (side1 * side2) / 2.0f;
7394 	area = (float)fabs(area);
7395 
7396 	/* find an AREAPERIM with this information */
7397 	for(ap = net_firstareaperim; ap != NOAREAPERIM; ap = ap->nextareaperim)
7398 		if (layer == ap->layer && tech == ap->tech) break;
7399 	if (ap == NOAREAPERIM)
7400 	{
7401 		ap = (AREAPERIM *)emalloc(sizeof (AREAPERIM), net_tool->cluster);
7402 		if (ap == 0) return;
7403 		ap->nextareaperim = net_firstareaperim;
7404 		net_firstareaperim = ap;
7405 		ap->area = 0.0;
7406 		ap->perimeter = 0;
7407 		ap->tech = tech;
7408 		ap->layer = layer;
7409 	}
7410 
7411 	/* accumulate area and perimeter */
7412 	ap->area += area;
7413 	ap->perimeter += per;
7414 }
7415 
7416 /*********************** NETLIST SEARCH ROUTINES ***********************/
7417 
7418 /*
7419  * helper routine for "telltool network list-hierarchical-ports" to print all
7420  * ports connected to net "net" in cell "cell", and recurse up the hierarchy
7421  */
net_findportsup(NETWORK * net,NODEPROTO * cell)7422 void net_findportsup(NETWORK *net, NODEPROTO *cell)
7423 {
7424 	REGISTER NODEINST *ni;
7425 	REGISTER PORTPROTO *pp;
7426 	REGISTER PORTEXPINST *pe;
7427 	REGISTER PORTARCINST *pi;
7428 
7429 	if (stopping(STOPREASONPORT)) return;
7430 
7431 	/* look at every node in the cell */
7432 	for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
7433 	{
7434 		if (pp->network != net) continue;
7435 		if (pp->temp1 != 0) continue;
7436 		pp->temp1 = 1;
7437 		(void)ttyputmsg(_("  Export %s in cell %s"), pp->protoname,
7438 			describenodeproto(cell));
7439 
7440 		/* ascend to higher cell and continue */
7441 		for(ni = cell->firstinst; ni != NONODEINST; ni = ni->nextinst)
7442 		{
7443 			/* see if there is an arc connected to this port */
7444 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
7445 				if (pi->proto->network == pp->network)
7446 			{
7447 				net_findportsup(pi->conarcinst->network, ni->parent);
7448 				break;
7449 			}
7450 			if (pi != NOPORTARCINST) continue;
7451 
7452 			/* try further exporting of ports */
7453 			for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
7454 				if (pe->proto->network == pp->network)
7455 			{
7456 				net_findportsup(pe->exportproto->network, ni->parent);
7457 				break;
7458 			}
7459 		}
7460 	}
7461 }
7462 
7463 /*
7464  * helper routine for "telltool network list-hierarchical-ports" to print all
7465  * ports connected to net "net" in cell "cell", and recurse down the hierarchy
7466  */
net_findportsdown(NETWORK * net,NODEPROTO * cell)7467 void net_findportsdown(NETWORK *net, NODEPROTO *cell)
7468 {
7469 	REGISTER NODEINST *ni;
7470 	REGISTER PORTARCINST *pi;
7471 	REGISTER NODEPROTO *cnp, *subnp;
7472 	REGISTER PORTPROTO *cpp;
7473 
7474 	if (stopping(STOPREASONPORT)) return;
7475 
7476 	/* look at every node in the cell */
7477 	for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
7478 	{
7479 		/* only want complex nodes */
7480 		subnp = ni->proto;
7481 		if (subnp->primindex != 0) continue;
7482 
7483 		/* ignore recursive references (showing icon in contents) */
7484 		if (isiconof(subnp, cell)) continue;
7485 
7486 		/* look at all wires connected to the node */
7487 		for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
7488 		{
7489 			/* ignore arc if not connected to net */
7490 			if (pi->conarcinst->network != net) continue;
7491 
7492 			if ((cnp = contentsview(pi->proto->parent)) == NONODEPROTO)
7493 				cnp = pi->proto->parent;
7494 			if ((cpp = equivalentport(pi->proto->parent, pi->proto, cnp)) == NOPORTPROTO)
7495 				cpp = pi->proto;
7496 
7497 			if (cpp->temp1 != 0) continue;
7498 			cpp->temp1 = 1;
7499 			(void)ttyputmsg(_("  Export %s in cell %s"), cpp->protoname, describenodeproto(cnp));
7500 
7501 			/* descend to lower contents cell and continue */
7502 			net_findportsdown(cpp->network, cnp);
7503 		}
7504 	}
7505 }
7506 
7507 /*
7508  * Routine to return an array of selected networks, terminated by NONETWORK.
7509  */
net_gethighlightednets(BOOLEAN disperror)7510 NETWORK **net_gethighlightednets(BOOLEAN disperror)
7511 {
7512 	static NETWORK *nonet[1];
7513 	REGISTER INTBIG i, len, fun, cursimtrace, line, fromchar, tochar;
7514 	REGISTER CHAR *netname;
7515 	REGISTER NODEINST *ni;
7516 	REGISTER ARCINST *ai;
7517 	REGISTER EDITOR *e;
7518 	REGISTER GEOM **geom;
7519 	CHAR selected[50];
7520 
7521 	nonet[0] = NONETWORK;
7522 	if (el_curwindowpart == NOWINDOWPART) return(nonet);
7523 
7524 #if SIMTOOL
7525 	/* if current window is simulation, invade structures and find highlighted net */
7526 	if ((el_curwindowpart->state&WINDOWTYPE) == WAVEFORMWINDOW)
7527 	{
7528 		cursimtrace = sim_window_gethighlighttrace();
7529 		if (cursimtrace == 0) return(nonet);
7530 		netname = sim_window_gettracename(cursimtrace);
7531 		return(net_parsenetwork(netname));
7532 	}
7533 #endif
7534 
7535 	/* if current window is text, invade structures and find highlighted net name */
7536 	if ((el_curwindowpart->state&WINDOWTYPE) == TEXTWINDOW ||
7537 		(el_curwindowpart->state&WINDOWTYPE) == POPTEXTWINDOW)
7538 	{
7539 		/* only understand selection of net name in Point-and-Click editor */
7540 		e = el_curwindowpart->editor;
7541 		if ((e->state&EDITORTYPE) != PACEDITOR) return(nonet);
7542 
7543 		/* copy and count the number of selected characters */
7544 		len = 0;
7545 		selected[0] = 0;
7546 		for(line = e->curline; line <= e->endline; line++)
7547 		{
7548 			if (line == e->curline) fromchar = e->curchar; else fromchar = 0;
7549 			if (line == e->endline) tochar = e->endchar; else
7550 				tochar = estrlen(e->textarray[line])+1;
7551 			len += tochar - fromchar;
7552 			if (len >= 50) return(nonet);
7553 			(void)estrncat(selected, &e->textarray[line][fromchar], tochar - fromchar);
7554 		}
7555 		if (selected[0] == 0) return(nonet);
7556 
7557 		/* turn this string into a network name */
7558 		return(net_parsenetwork(selected));
7559 	}
7560 
7561 	geom = (GEOM **)asktool(us_tool, x_("get-all-objects"));
7562 	if (geom[0] == NOGEOM)
7563 	{
7564 		if (disperror) ttyputerr(_("Find some objects first"));
7565 		return(nonet);
7566 	}
7567 
7568 	/* gather all networks connected to selected objects */
7569 	net_highnetscount = 0;
7570 	for(i=0; geom[i] != NOGEOM; i++)
7571 	{
7572 		if (!geom[i]->entryisnode)
7573 		{
7574 			ai = geom[i]->entryaddr.ai;
7575 			net_addnettolist(ai->network);
7576 		} else
7577 		{
7578 			ni = geom[i]->entryaddr.ni;
7579 			fun = nodefunction(ni);
7580 			if (fun == NPPIN || fun == NPCONTACT ||
7581 				fun == NPCONNECT || fun == NPNODE)
7582 			{
7583 				if (ni->firstportarcinst != NOPORTARCINST)
7584 				{
7585 					ai = ni->firstportarcinst->conarcinst;
7586 					net_addnettolist(ai->network);
7587 				}
7588 			}
7589 		}
7590 	}
7591 	net_addnettolist(NONETWORK);
7592 	return(net_highnets);
7593 }
7594 
7595 /*
7596  * Routine to add network "net" to the global list of networks in "net_highnets".
7597  */
net_addnettolist(NETWORK * net)7598 void net_addnettolist(NETWORK *net)
7599 {
7600 	REGISTER INTBIG i, newtotal;
7601 	REGISTER NETWORK **newlist;
7602 
7603 	/* stop if already in the list */
7604 	for(i=0; i<net_highnetscount; i++)
7605 		if (net == net_highnets[i]) return;
7606 
7607 	/* ensure room in the list */
7608 	if (net_highnetscount >= net_highnetstotal)
7609 	{
7610 		newtotal = net_highnetstotal * 2;
7611 		if (net_highnetscount >= newtotal) newtotal = net_highnetscount + 5;
7612 		newlist = (NETWORK **)emalloc(newtotal * (sizeof (NETWORK *)), net_tool->cluster);
7613 		if (newlist == 0) return;
7614 		for(i=0; i<net_highnetscount; i++)
7615 			newlist[i] = net_highnets[i];
7616 		if (net_highnetstotal > 0) efree((CHAR *)net_highnets);
7617 		net_highnets = newlist;
7618 		net_highnetstotal = newtotal;
7619 	}
7620 	net_highnets[net_highnetscount] = net;
7621 	net_highnetscount++;
7622 }
7623 
7624 /*
7625  * routine to convert the network name "name" to a valid network.
7626  * Returns a list of associated networks (terminated by NONETWORK).
7627  */
net_parsenetwork(CHAR * name)7628 NETWORK **net_parsenetwork(CHAR *name)
7629 {
7630 	REGISTER NETWORK *net, *guessnet;
7631 	REGISTER WINDOWPART *w;
7632 	REGISTER NODEPROTO *np;
7633 	REGISTER CHAR *pt;
7634 	static NETWORK *retnetwork[2];
7635 
7636 	retnetwork[0] = retnetwork[1] = NONETWORK;
7637 	while (*name != 0 && *name <= ' ') name++;
7638 	if (*name == 0) return(retnetwork);
7639 
7640 	/* handle network names encoded as "NETxxxxx" */
7641 	if (name[0] == 'N' && name[1] == 'E' && name[2] == 'T')
7642 	{
7643 		guessnet = (NETWORK *)myatoi(&name[3]);
7644 
7645 		/* validate against all possible networks */
7646 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
7647 		{
7648 			if ((w->state&WINDOWTYPE) == WAVEFORMWINDOW || (w->state&WINDOWTYPE) == DISPWINDOW ||
7649 				(w->state&WINDOWTYPE) == DISP3DWINDOW)
7650 			{
7651 				np = w->curnodeproto;
7652 				if (np == NONODEPROTO) continue;
7653 
7654 				/* does this cell have the network? */
7655 				for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
7656 				{
7657 					if (net == guessnet)
7658 					{
7659 						retnetwork[0] = net;
7660 						return(retnetwork);
7661 					}
7662 				}
7663 			}
7664 		}
7665 	}
7666 
7667 	/* if there are dots in the name, check for HSPICE network specification */
7668 	for(pt = name; *pt != 0; pt++) if (*pt == '.') break;
7669 	if (*pt == '.')
7670 	{
7671 		net = sim_spice_networkfromname(name);
7672 		if (net != NONETWORK)
7673 		{
7674 			retnetwork[0] = net;
7675 			return(retnetwork);
7676 		}
7677 	}
7678 
7679 	/* see if it matches a network name in the current cell */
7680 	np = getcurcell();
7681 	if (np != NONODEPROTO)
7682 	{
7683 		if ((np->cellview->viewstate&TEXTVIEW) != 0)
7684 		{
7685 			np = layoutview(np);
7686 			if (np == NONODEPROTO) return(retnetwork);
7687 		}
7688 		return(getcomplexnetworks(name, np));
7689 	}
7690 
7691 	/* not found */
7692 	return(retnetwork);
7693 }
7694 
7695 /*
7696  * Routine to specify highlighting of the arcs on network "net" in cell "np".
7697  * The highlighting is added to the infinite string.
7698  */
net_highlightnet(void * infstr,NODEPROTO * np,NETWORK * net)7699 void net_highlightnet(void *infstr, NODEPROTO *np, NETWORK *net)
7700 {
7701 	REGISTER ARCINST *ai;
7702 	REGISTER NODEINST *ni;
7703 	REGISTER NODEPROTO *subnp;
7704 	REGISTER PORTPROTO *pp;
7705 	REGISTER INTBIG i, j, fun;
7706 
7707 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
7708 	{
7709 		if (ai->network == NONETWORK) continue;
7710 		if (ai->network == net)
7711 		{
7712 			formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
7713 				describenodeproto(np), (INTBIG)ai->geom);
7714 			continue;
7715 		}
7716 
7717 		/* handle busses according to the nature of the network being highlighted */
7718 		if (net->buswidth <= 1)
7719 		{
7720 			/* network is single wire: look for its presence on a bus arc */
7721 			if (ai->network->buswidth > 1)
7722 			{
7723 				for (i=0; i<ai->network->buswidth; i++)
7724 					if (ai->network->networklist[i] == net)
7725 				{
7726 					formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
7727 						describenodeproto(np), (INTBIG)ai->geom);
7728 					break;
7729 				}
7730 			}
7731 		} else
7732 		{
7733 			/* network is a bus: check the nature of this arc */
7734 			if (ai->network->buswidth <= 1)
7735 			{
7736 				/* arc is single wire: see if it is on the network bus */
7737 				for (i=0; i<net->buswidth; i++)
7738 					if (net->networklist[i] == ai->network)
7739 				{
7740 					formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
7741 						describenodeproto(np), (INTBIG)ai->geom);
7742 					break;
7743 				}
7744 			} else
7745 			{
7746 				/* arc is bus: see if any of its signals are on network bus */
7747 				for (i=0; i<net->buswidth; i++)
7748 				{
7749 					for (j=0; j<ai->network->buswidth; j++)
7750 						if (ai->network->networklist[j] == net->networklist[i]) break;
7751 					if (j < ai->network->buswidth) break;
7752 				}
7753 				if (i < net->buswidth)
7754 				{
7755 					formatinfstr(infstr, x_("CELL=%s LINE=%ld,%ld,%ld,%ld\n"),
7756 						describenodeproto(np), ai->end[0].xpos, ai->end[1].xpos,
7757 							ai->end[0].ypos, ai->end[1].ypos);
7758 				}
7759 			}
7760 		}
7761 	}
7762 
7763 	/* now highlight all pin-type nodes on the network */
7764 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
7765 	{
7766 		subnp = ni->proto;
7767 		if (subnp->primindex == 0)
7768 		{
7769 			/* show network where it travels through a subcell (layout only) */
7770 			if (subnp->cellview == el_iconview) continue;
7771 
7772 			/* see if the network hits the instance */
7773 			net_highlightsubnet(infstr, np, ni, el_matid, net);
7774 			continue;
7775 		}
7776 		fun = nodefunction(ni);
7777 		if (fun != NPPIN && fun != NPCONTACT && fun != NPNODE && fun != NPCONNECT)
7778 			continue;
7779 		if (ni->firstportarcinst == NOPORTARCINST) continue;
7780 		if (ni->firstportarcinst->conarcinst->network != net) continue;
7781 		formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
7782 			describenodeproto(np), (INTBIG)ni->geom);
7783 	}
7784 
7785 	/* finally highlight all exports on the network */
7786 	for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
7787 	{
7788 		if (pp->network == net)
7789 		{
7790 			formatinfstr(infstr, x_("CELL=%s TEXT=0%lo;0%lo;-\n"),
7791 				describenodeproto(np), (INTBIG)pp->subnodeinst->geom, (INTBIG)pp);
7792 		}
7793 		if (net->buswidth <= 1)
7794 		{
7795 			/* network is single wire: look for its presence on a bus export */
7796 			if (pp->network->buswidth > 1)
7797 			{
7798 				for (i=0; i<pp->network->buswidth; i++)
7799 					if (pp->network->networklist[i] == net)
7800 				{
7801 					formatinfstr(infstr, x_("CELL=%s TEXT=0%lo;0%lo;-\n"),
7802 						describenodeproto(np), (INTBIG)pp->subnodeinst->geom, (INTBIG)pp);
7803 					break;
7804 				}
7805 			}
7806 		} else
7807 		{
7808 			/* network is a bus: check the nature of this export */
7809 			if (pp->network->buswidth <= 1)
7810 			{
7811 				/* export is single wire: see if it is on the network bus */
7812 				for (i=0; i<net->buswidth; i++)
7813 					if (net->networklist[i] == pp->network)
7814 				{
7815 					formatinfstr(infstr, x_("CELL=%s TEXT=0%lo;0%lo;-\n"),
7816 						describenodeproto(np), (INTBIG)pp->subnodeinst->geom, (INTBIG)pp);
7817 					break;
7818 				}
7819 			} else
7820 			{
7821 				/* export is bus: see if any of its signals are on network bus */
7822 				for (i=0; i<net->buswidth; i++)
7823 				{
7824 					for (j=0; j<pp->network->buswidth; j++)
7825 						if (pp->network->networklist[j] == net->networklist[i]) break;
7826 					if (j < pp->network->buswidth) break;
7827 				}
7828 				if (i < net->buswidth)
7829 				{
7830 					formatinfstr(infstr, x_("CELL=%s TEXT=0%lo;0%lo;-\n"),
7831 						describenodeproto(np), (INTBIG)pp->subnodeinst->geom, (INTBIG)pp);
7832 				}
7833 			}
7834 		}
7835 	}
7836 }
7837 
7838 /*
7839  * Routine to recursively highlight a subnet in a layout cell instance and add it to the infinite
7840  * string "infstr".  The top cell is "topnp" and the instance that is being expanded is "ni" (with
7841  * network "net" on that instance being highlighted).  The transformation matrix to that instance
7842  * (not including the instance) is "trans".
7843  */
net_highlightsubnet(void * infstr,NODEPROTO * topnp,NODEINST * thisni,XARRAY trans,NETWORK * net)7844 void net_highlightsubnet(void *infstr, NODEPROTO *topnp, NODEINST *thisni, XARRAY trans, NETWORK *net)
7845 {
7846 	REGISTER PORTARCINST *pi;
7847 	REGISTER PORTEXPINST *pe;
7848 	REGISTER ARCINST *ai;
7849 	REGISTER NODEINST *ni;
7850 	REGISTER NODEPROTO *np, *subnp;
7851 	REGISTER NETWORK *subnet, **subnets;
7852 	LISTINTBIG *li;
7853 	INTBIG x1, y1, x2, y2, i, count;
7854 	XARRAY rot, tran, temptrans, thistrans;
7855 
7856 	/* make a list of networks inside this cell that connect to the outside */
7857 	li = newintlistobj(net_tool->cluster);
7858 	if (li == 0) return;
7859 	for(pi = thisni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
7860 		if (pi->conarcinst->network == net)
7861 			addtointlistobj(li, (INTBIG)pi->proto->network, TRUE);
7862 	for(pe = thisni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
7863 		if (pe->exportproto->network == net)
7864 			addtointlistobj(li, (INTBIG)pe->proto->network, TRUE);
7865 	subnets = (NETWORK **)getintlistobj(li, &count);
7866 	for(i=0; i<count; i++)
7867 	{
7868 		/* prepare to display the net in the subcell */
7869 		subnet = subnets[i];
7870 		maketrans(thisni, tran);
7871 		makerot(thisni, rot);
7872 		transmult(tran, rot, temptrans);
7873 		transmult(temptrans, trans, thistrans);
7874 		np = thisni->proto;
7875 		for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
7876 		{
7877 			if (ai->network != subnet) continue;
7878 			x1 = ai->end[0].xpos;   y1 = ai->end[0].ypos;
7879 			x2 = ai->end[1].xpos;   y2 = ai->end[1].ypos;
7880 			xform(x1, y1, &x1, &y1, thistrans);
7881 			xform(x2, y2, &x2, &y2, thistrans);
7882 			formatinfstr(infstr, x_("CELL=%s LINE=%ld,%ld,%ld,%ld\n"),
7883 				describenodeproto(topnp), x1, x2, y1, y2);
7884 		}
7885 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
7886 		{
7887 			subnp = ni->proto;
7888 			if (subnp->primindex != 0) continue;
7889 
7890 			/* show network where it travels through a subcell (layout only) */
7891 			if (subnp->cellview == el_iconview) continue;
7892 
7893 			/* see if the network hits the instance */
7894 			net_highlightsubnet(infstr, topnp, ni, thistrans, subnet);
7895 		}
7896 	}
7897 	killintlistobj(li);
7898 }
7899 
7900 /*
7901  * Helper routine to determine whether the string "name" is a number (but it may
7902  * end with network index characters ":", "]", or ",".
7903  */
net_isanumber(CHAR * name)7904 BOOLEAN net_isanumber(CHAR *name)
7905 {
7906 	REGISTER CHAR *pt, save;
7907 	BOOLEAN ret;
7908 
7909 	for(pt = name; *pt != 0; pt++)
7910 		if (*pt == ':' || *pt == ']' || *pt == ',') break;
7911 	if (*pt == 0) return(isanumber(name));
7912 	save = *pt;
7913 	*pt = 0;
7914 	ret = isanumber(name);
7915 	*pt = save;
7916 	return(ret);
7917 }
7918 
7919 /*
7920  * routine to get the network attached to "ni" at its port "pp"
7921  */
getnetonport(NODEINST * ni,PORTPROTO * pp)7922 NETWORK *getnetonport(NODEINST *ni, PORTPROTO *pp)
7923 {
7924 	REGISTER PORTARCINST *pi;
7925 	REGISTER PORTEXPINST *pe;
7926 
7927 	/* see if the port is on an arc */
7928 	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
7929 		if (pi->proto->network == pp->network)
7930 			return(pi->conarcinst->network);
7931 
7932 	/* see if the port is an export */
7933 	for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
7934 		if (pe->proto->network == pp->network)
7935 			return(pe->exportproto->network);
7936 
7937 	/* sorry, this port is not on a network */
7938 	return(NONETWORK);
7939 }
7940 
7941 /*
7942  * routine to add subcell global to cell globals
7943  */
net_addglobalnet(NODEPROTO * subcell,INTBIG subindex,NODEPROTO * cell)7944 static NETWORK *net_addglobalnet(NODEPROTO *subcell, INTBIG subindex, NODEPROTO *cell)
7945 {
7946 	NETWORK *net;
7947 	INTBIG index;
7948 	INTBIG special = -1;
7949 
7950 	if (subindex < 2)
7951 		index = (subindex<cell->globalnetcount && cell->globalnetworks[subindex] != NONETWORK ? subindex : -1);
7952 	else
7953 		index = net_findglobalnet(cell, subcell->globalnetnames[subindex]);
7954 	if (index >= 0)
7955 	{
7956 		net = cell->globalnetworks[index];
7957 		if(cell->globalnetchar[index] != subcell->globalnetchar[subindex])
7958 		{
7959 			ttyputmsg(_("Warning: global network '%s' has different characteristics:"),
7960 				subcell->globalnetnames[subindex]);
7961 			ttyputmsg(_("  In cell %s, it is '%s'"), describenodeproto(cell),
7962 				describeportbits(cell->globalnetchar[index]));
7963 			ttyputmsg(_("  In subcell %s is '%s'"), describenodeproto(subcell),
7964 				describeportbits(subcell->globalnetchar[subindex]));
7965 			if (cell->globalnetchar[index] == 0)
7966 				cell->globalnetchar[index] = subcell->globalnetchar[subindex];
7967 		}
7968 	} else
7969 	{
7970 		net = net_newnetwork(cell);
7971 		net_setglobalnet(&special, (subindex < 2 ? subindex : -1), subcell->globalnetnames[subindex], net,
7972 			subcell->globalnetchar[subindex], cell);
7973 	}
7974 
7975 	net->refcount++;
7976 	return(net);
7977 }
7978 
7979 /*
7980  * routine to find index of global net of cell "np" by "name".
7981  * returns -1 if not found
7982  */
net_findglobalnet(NODEPROTO * np,CHAR * name)7983 INTBIG     net_findglobalnet(NODEPROTO *np, CHAR *name)
7984 {
7985 	INTBIG i;
7986 
7987 	for(i=0; i<np->globalnetcount; i++)
7988 	{
7989 		if(namesame(name, np->globalnetnames[i]) == 0 && np->globalnetworks[i] != NONETWORK)
7990 			return(i);
7991 	}
7992 	return(-1);
7993 }
7994 
net_setglobalnet(INTBIG * special,INTBIG newindex,CHAR * netname,NETWORK * net,INTBIG characteristics,NODEPROTO * np)7995 void net_setglobalnet(INTBIG *special, INTBIG newindex, CHAR *netname, NETWORK *net,
7996 	INTBIG characteristics, NODEPROTO *np)
7997 {
7998 	REGISTER INTBIG i, newsize, *newchar;
7999 	REGISTER NETWORK **newnets;
8000 	REGISTER CHAR **newnetnames;
8001 
8002 	if(net->buswidth != 1)
8003 	{
8004 		ttyputerr(_("Warning (cell %s): signal %s with buswidth %d can't be global"),
8005 			describenodeproto(np), describenetwork(net), net->buswidth);
8006 		return;
8007 	}
8008 
8009 	/* make sure power and ground are in the list */
8010 	if (np->globalnetcount == 0)
8011 	{
8012 		np->globalnetworks = (NETWORK **)emalloc(2 * (sizeof (NETWORK *)), np->lib->cluster);
8013 		if (np->globalnetworks == 0) return;
8014 		np->globalnetchar = (INTBIG *)emalloc(2 * SIZEOFINTBIG, np->lib->cluster);
8015 		if (np->globalnetchar == 0) return;
8016 		np->globalnetnames = (CHAR **)emalloc(2 * (sizeof (CHAR *)), np->lib->cluster);
8017 		if (np->globalnetnames == 0) return;
8018 		np->globalnetworks[GLOBALNETGROUND] = NONETWORK;
8019 		(void)allocstring(&np->globalnetnames[GLOBALNETGROUND], _("Ground"), np->lib->cluster);
8020 		np->globalnetchar[GLOBALNETGROUND] = GNDPORT;
8021 		np->globalnetworks[GLOBALNETPOWER] = NONETWORK;
8022 		(void)allocstring(&np->globalnetnames[GLOBALNETPOWER], _("Power"), np->lib->cluster);
8023 		np->globalnetchar[GLOBALNETPOWER] = PWRPORT;
8024 		np->globalnetcount = 2;
8025 	}
8026 
8027 	if (newindex < 0)
8028 	{
8029 		/* a global net: see if it is in the list */
8030 		for(i=2; i<np->globalnetcount; i++)
8031 		{
8032 			if (*np->globalnetnames[i] == 0)
8033 			{
8034 				newindex = i;
8035 				np->globalnetworks[newindex] = NONETWORK;
8036 				continue;
8037 			}
8038 			if (namesame(netname, np->globalnetnames[i]) == 0)
8039 			{
8040 				newindex = i;
8041 				break;
8042 			}
8043 		}
8044 		if (newindex < 0)
8045 		{
8046 			/* expand the list */
8047 			newsize = np->globalnetcount + 1;
8048 			newnets = (NETWORK **)emalloc(newsize * (sizeof (NETWORK *)), np->lib->cluster);
8049 			if (newnets == 0) return;
8050 			newchar = (INTBIG *)emalloc(newsize * SIZEOFINTBIG, np->lib->cluster);
8051 			if (newchar == 0) return;
8052 			newnetnames = (CHAR **)emalloc(newsize * (sizeof (CHAR *)), np->lib->cluster);
8053 			if (newnetnames == 0) return;
8054 			for(i=0; i<np->globalnetcount; i++)
8055 			{
8056 				newnets[i] = np->globalnetworks[i];
8057 				newchar[i] = np->globalnetchar[i];
8058 				newnetnames[i] = np->globalnetnames[i];
8059 			}
8060 			newindex = np->globalnetcount;
8061 			newnets[newindex] = NONETWORK;
8062 			newchar[newindex] = 0;
8063 			newnetnames[newindex] = 0;
8064 			if (np->globalnetcount > 0)
8065 			{
8066 				efree((CHAR *)np->globalnetworks);
8067 				efree((CHAR *)np->globalnetchar);
8068 				efree((CHAR *)np->globalnetnames);
8069 			}
8070 			np->globalnetworks = newnets;
8071 			np->globalnetchar = newchar;
8072 			np->globalnetnames = newnetnames;
8073 			np->globalnetcount++;
8074 		}
8075 	}
8076 	if (newindex >= 2)
8077 	{
8078 		if (np->globalnetnames[newindex] != 0)
8079 			efree((CHAR *)np->globalnetnames[newindex]);
8080 		(void)allocstring(&np->globalnetnames[newindex], netname, np->lib->cluster);
8081 	}
8082 
8083 	if (*special < 0)
8084 	{
8085 		*special = newindex;
8086 
8087 		/* check if all done */
8088 		if(np->globalnetworks[newindex] == net &&
8089 			np->globalnetchar[newindex] == characteristics &&
8090 			net->globalnet == (INTSML)newindex)
8091 			return;
8092 	} else
8093 	{
8094 		if (*special != newindex)
8095 		{
8096 			if (*special < np->globalnetcount)
8097 			{
8098 				ttyputerr(_("Warning (cell %s): global signals %s and %s are connected"),
8099 					describenodeproto(np), np->globalnetnames[*special], np->globalnetnames[newindex]);
8100 			} else
8101 			{
8102 				ttyputerr(_("Warning (cell %s): global signal %s is connected to another"),
8103 					describenodeproto(np), np->globalnetnames[newindex]);
8104 			}
8105 		}
8106 	}
8107 	if (np->globalnetworks[newindex] != NONETWORK)
8108 	{
8109 		(void)net_mergenet(np->globalnetworks[newindex], net);
8110 	}
8111 	np->globalnetworks[newindex] = net;
8112 	np->globalnetchar[newindex] = characteristics;
8113 	net->globalnet = (INTSML)newindex;
8114 	if (net_debug)
8115 		ttyputmsg(M_("Global network '%s' added to '%s'"), np->globalnetnames[net->globalnet],
8116 			describenodeproto(np));
8117 	/* don't mark above if the entire cell will be renumbered */
8118 	if (!net_globalwork || (np->userbits&REDOCELLNET) == 0)
8119 		net_recursivelymarkabove(np);
8120 }
8121 
8122 /*
8123  * Routine to rip the currently selected bus arc out into individual wires.
8124  */
net_ripbus(void)8125 void net_ripbus(void)
8126 {
8127 	REGISTER ARCINST *ai, *aiw;
8128 	REGISTER NODEINST *niw, *nib, *niblast;
8129 	REGISTER NETWORK *net;
8130 	REGISTER VARIABLE *var, *newvar;
8131 	REGISTER INTBIG i, count, lowend;
8132 	CHAR **strings, **localstrings;
8133 	REGISTER INTBIG lowx, highx, sepx, lowy, highy, sepy, stublen, lowxbus, lowybus, lambda;
8134 	INTBIG sxw, syw, sxb, syb;
8135 
8136 	ai = (ARCINST *)us_getobject(VARCINST, FALSE);
8137 	if (ai == NOARCINST) return;
8138 	if (ai->proto != sch_busarc)
8139 	{
8140 		ttyputerr(_("Must select a bus arc to rip it into individual signals"));
8141 		return;
8142 	}
8143 	net = ai->network;
8144 	if (net == NONETWORK)
8145 	{
8146 		ttyputerr(_("Bus has no network information"));
8147 		return;
8148 	}
8149 	if (net->namecount == 0)
8150 	{
8151 		ttyputerr(_("Bus has no name"));
8152 		return;
8153 	}
8154 	if (net->buswidth <= 1)
8155 	{
8156 		ttyputerr(_("Bus must have multiple signals"));
8157 		return;
8158 	}
8159 
8160 	/* determine which bus name to use */
8161 	var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
8162 	if (var != NOVARIABLE && *((CHAR *)var->addr) != 0)
8163 		count = net_evalbusname(APBUS, (CHAR *)var->addr, &strings, ai, ai->parent, 1); else
8164 			count = net_evalbusname(APBUS, networkname(net, 0), &strings, ai, ai->parent, 1);
8165 	if (count <= 0)
8166 	{
8167 		ttyputerr(_("Bus has zero-width"));
8168 		return;
8169 	}
8170 
8171 	/* determine length of stub wires */
8172 	lambda = lambdaofarc(ai);
8173 	stublen = ai->length / 3;
8174 	stublen = (stublen + lambda/2) / lambda * lambda;
8175 
8176 	/* determine location of individual signals */
8177 	if (ai->end[0].xpos == ai->end[1].xpos)
8178 	{
8179 		lowx = ai->end[0].xpos;
8180 		if (lowx < (ai->parent->lowx + ai->parent->highx) / 2) lowx += stublen; else
8181 			lowx -= stublen;
8182 		sepx = 0;
8183 
8184 		if (ai->end[0].ypos < ai->end[1].ypos) lowend = 0; else lowend = 1;
8185 		lowy = (ai->end[lowend].ypos + lambda - 1) / lambda * lambda;
8186 		highy = ai->end[1-lowend].ypos / lambda * lambda;
8187 		if (highy-lowy >= (net->buswidth-1) * lambda)
8188 		{
8189 			/* signals fit on grid */
8190 			sepy = ((highy-lowy) / ((net->buswidth-1) * lambda)) * lambda;
8191 			lowy = ((highy - lowy) - (sepy * (net->buswidth-1))) / 2 + lowy;
8192 			lowy = (lowy + lambda/2) / lambda * lambda;
8193 		} else
8194 		{
8195 			/* signals don't fit: just make them even */
8196 			lowy = ai->end[lowend].ypos;
8197 			highy = ai->end[1-lowend].ypos;
8198 			sepy = (highy-lowy) / (net->buswidth-1);
8199 		}
8200 		lowxbus = ai->end[0].xpos;   lowybus = lowy;
8201 	} else if (ai->end[0].ypos == ai->end[1].ypos)
8202 	{
8203 		lowy = ai->end[0].ypos;
8204 		if (lowy < (ai->parent->lowy + ai->parent->highy) / 2) lowy += stublen; else
8205 			lowy -= stublen;
8206 		sepy = 0;
8207 
8208 		if (ai->end[0].xpos < ai->end[1].xpos) lowend = 0; else lowend = 1;
8209 		lowx = (ai->end[lowend].xpos + lambda - 1) / lambda * lambda;
8210 		highx = ai->end[1-lowend].xpos / lambda * lambda;
8211 		if (highx-lowx >= (net->buswidth-1) * lambda)
8212 		{
8213 			/* signals fit on grid */
8214 			sepx = ((highx-lowx) / ((net->buswidth-1) * lambda)) * lambda;
8215 			lowx = ((highx - lowx) - (sepx * (net->buswidth-1))) / 2 + lowx;
8216 			lowx = (lowx + lambda/2) / lambda * lambda;
8217 		} else
8218 		{
8219 			/* signals don't fit: just make them even */
8220 			lowx = ai->end[lowend].xpos;
8221 			highx = ai->end[1-lowend].xpos;
8222 			sepx = (highx-lowx) / (net->buswidth-1);
8223 		}
8224 		lowxbus = lowx;   lowybus = ai->end[0].ypos;
8225 	} else
8226 	{
8227 		ttyputerr(_("Bus must be horizontal or vertical to be ripped out"));
8228 		return;
8229 	}
8230 
8231 	/* copy names to a local array */
8232 	localstrings = (CHAR **)emalloc(count * (sizeof (CHAR *)), net_tool->cluster);
8233 	if (localstrings == 0) return;
8234 	for(i=0; i<count; i++)
8235 		(void)allocstring(&localstrings[i], strings[i], net_tool->cluster);
8236 
8237 	/* turn off highlighting */
8238 	us_clearhighlightcount();
8239 
8240 	defaultnodesize(sch_wirepinprim, &sxw, &syw);
8241 	defaultnodesize(sch_buspinprim, &sxb, &syb);
8242 	niblast = NONODEINST;
8243 	for(i=0; i<count; i++)
8244 	{
8245 		/* make the wire pin */
8246 		niw = newnodeinst(sch_wirepinprim, lowx-sxw/2, lowx+sxw/2, lowy-syw/2, lowy+syw/2, 0, 0,
8247 			ai->parent);
8248 		if (niw == NONODEINST) break;
8249 		endobjectchange((INTBIG)niw, VNODEINST);
8250 
8251 		/* make the bus pin */
8252 		nib = newnodeinst(sch_buspinprim, lowxbus-sxb/2, lowxbus+sxb/2, lowybus-syb/2, lowybus+syb/2,
8253 			0, 0, ai->parent);
8254 		if (nib == NONODEINST) break;
8255 		endobjectchange((INTBIG)nib, VNODEINST);
8256 
8257 		/* wire them */
8258 		aiw = newarcinst(sch_wirearc, defaultarcwidth(sch_wirearc), ai->userbits,
8259 			niw, sch_wirepinprim->firstportproto, lowx, lowy, nib,
8260 				sch_buspinprim->firstportproto, lowxbus, lowybus, ai->parent);
8261 		if (aiw == NOARCINST) break;
8262 		newvar = setvalkey((INTBIG)aiw, VARCINST, el_arc_name_key,
8263 			(INTBIG)localstrings[i], VSTRING|VDISPLAY);
8264 		if (newvar != NOVARIABLE)
8265 			defaulttextsize(4, newvar->textdescript);
8266 		endobjectchange((INTBIG)aiw, VARCINST);
8267 
8268 		/* wire to the bus pin */
8269 		if (i == 0)
8270 		{
8271 			aiw = newarcinst(sch_busarc, defaultarcwidth(sch_busarc), ai->userbits,
8272 				ai->end[lowend].nodeinst, ai->end[lowend].portarcinst->proto,
8273 					ai->end[lowend].xpos, ai->end[lowend].ypos,
8274 						nib, sch_buspinprim->firstportproto, lowxbus, lowybus, ai->parent);
8275 		} else
8276 		{
8277 			/* LINTED "niblast" used in proper order */
8278 			aiw = newarcinst(sch_busarc, defaultarcwidth(sch_busarc), ai->userbits, niblast,
8279 				sch_buspinprim->firstportproto, lowxbus-sepx, lowybus-sepy, nib,
8280 					sch_buspinprim->firstportproto, lowxbus, lowybus, ai->parent);
8281 		}
8282 		if (aiw == NOARCINST) break;
8283 		endobjectchange((INTBIG)aiw, VARCINST);
8284 
8285 		/* advance to the next segment */
8286 		niblast = nib;
8287 		lowx += sepx;      lowy += sepy;
8288 		lowxbus += sepx;   lowybus += sepy;
8289 	}
8290 
8291 	/* wire up the last segment */
8292 	aiw = newarcinst(sch_busarc, defaultarcwidth(sch_busarc), ai->userbits,
8293 		ai->end[1-lowend].nodeinst, ai->end[1-lowend].portarcinst->proto,
8294 			ai->end[1-lowend].xpos, ai->end[1-lowend].ypos,
8295 				niblast, sch_buspinprim->firstportproto, lowxbus-sepx, lowybus-sepy, ai->parent);
8296 	if (aiw == NOARCINST) return;
8297 	if (var != NOVARIABLE && *((CHAR *)var->addr) != 0)
8298 	{
8299 		newvar = setvalkey((INTBIG)aiw, VARCINST, el_arc_name_key, var->addr, VSTRING|VDISPLAY);
8300 		if (newvar != NOVARIABLE)
8301 			defaulttextsize(4, newvar->textdescript);
8302 	}
8303 	endobjectchange((INTBIG)aiw, VARCINST);
8304 
8305 	/* remove original arc */
8306 	startobjectchange((INTBIG)ai, VARCINST);
8307 	if (killarcinst(ai))
8308 		ttyputerr(_("Error deleting original arc"));
8309 
8310 	/* free memory */
8311 	for(i=0; i<count; i++)
8312 		efree(localstrings[i]);
8313 	efree((CHAR *)localstrings);
8314 }
8315 
8316 typedef struct
8317 {
8318 	NODEPROTO *np;
8319 	INTBIG     origtemp1;
8320 	INTBIG     nodenumber;
8321 } TEMPSTRUCT;
8322 
8323 /*
8324  * Routine to name all nodes in cell "np" that do not already have node names.
8325  * Returns the number of nodes that were named.
8326  */
net_nameallnodes(NODEPROTO * np,BOOLEAN evenpins)8327 INTBIG net_nameallnodes(NODEPROTO *np, BOOLEAN evenpins)
8328 {
8329 	REGISTER NODEINST *ni;
8330 	REGISTER VARIABLE *var;
8331 	REGISTER CHAR *name, *match, **shortnameoverride;
8332 	REGISTER CHAR *lastname, *thisname, *warnedname;
8333 	CHAR *shortnames[MAXNODEFUNCTION], **namelist;
8334 	INTBIG named, count;
8335 	REGISTER INTBIG i, len, abbrevlen, curindex, total;
8336 	REGISTER TEMPSTRUCT *ts, *nodelist;
8337 	INTBIG cindex, fun, highpseudo[MAXNODEFUNCTION];
8338 	REGISTER void *infstr;
8339 
8340 	/* do not name nodes in "icon" cells */
8341 	if (np->cellview == el_iconview || np->cellview == el_simsnapview) return(0);
8342 
8343 	/* get the length of cell name abbreviations */
8344 	var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_node_abbrevlen_key);
8345 	if (var == NOVARIABLE) abbrevlen = NETDEFAULTABBREVLEN; else
8346 		abbrevlen = var->addr;
8347 
8348 	/* get the node function abbreviations */
8349 	for(i=0; i<MAXNODEFUNCTION; i++)
8350 	{
8351 		highpseudo[i] = 0;
8352 		shortnames[i] = nodefunctionshortname(i);
8353 	}
8354 	var = getvalkey((INTBIG)net_tool, VTOOL, VSTRING|VISARRAY, net_node_abbrev_key);
8355 	if (var != NOVARIABLE)
8356 	{
8357 		shortnameoverride = (CHAR **)var->addr;
8358 		len = getlength(var);
8359 		for(i=0; i<MAXNODEFUNCTION; i++)
8360 		{
8361 			if (i >= len) break;
8362 			if (*shortnameoverride[i] != 0)
8363 				shortnames[i] = shortnameoverride[i];
8364 		}
8365 	}
8366 
8367 	/* get a list of existing names in this cell */
8368 	count = net_gathernodenames(np, &namelist);
8369 
8370 	/* issue warning if there are duplicate names */
8371 	if (count > 1)
8372 	{
8373 		esort(namelist, count, sizeof (CHAR *), sort_stringascending);
8374 		lastname = namelist[0];
8375 		warnedname = 0;
8376 		for(i=1; i<count; i++)
8377 		{
8378 			thisname = (CHAR *)namelist[i];
8379 			if (lastname != 0 && thisname != 0)
8380 			{
8381 				if (namesame(lastname, thisname) == 0)
8382 				{
8383 					if (warnedname == 0 || namesame(warnedname, thisname) != 0)
8384 					{
8385 						ttyputerr(_("***Error: cell %s has multiple nodes with name '%s'"),
8386 							describenodeproto(np), thisname);
8387 					}
8388 					warnedname = thisname;
8389 				}
8390 			}
8391 			lastname = thisname;
8392 		}
8393 	}
8394 
8395 	/* check all nodes to see if they need to be named */
8396 	total = 0;
8397 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
8398 		if (ni->proto->primindex == 0) total++;
8399 	if (total > 0)
8400 	{
8401 		nodelist = (TEMPSTRUCT *)emalloc(total * (sizeof (TEMPSTRUCT)), net_tool->cluster);
8402 		if (nodelist == 0) return(0);
8403 		total = 0;
8404 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
8405 		{
8406 			if (ni->proto->primindex != 0) continue;
8407 			for(i=0; i<total; i++)
8408 				if (nodelist[i].np == ni->proto) break;
8409 			if (i < total) continue;
8410 			nodelist[total].np = ni->proto;
8411 			nodelist[total].origtemp1 = ni->proto->temp1;
8412 			nodelist[total].nodenumber = 0;
8413 			ni->proto->temp1 = (INTBIG)&nodelist[total];
8414 			total++;
8415 		}
8416 		if (total == 0) efree((CHAR *)nodelist);
8417 	}
8418 
8419 	named = 0;
8420 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
8421 	{
8422 		fun = nodefunction(ni);
8423 		if (evenpins == 0 && ni->firstportexpinst == NOPORTEXPINST)
8424 		{
8425 			if (fun == NPPIN || fun == NPART) continue;
8426 		}
8427 
8428 		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
8429 		if (var != NOVARIABLE)
8430 		{
8431 			/* check for existing pseudo-names */
8432 			name = (CHAR *)var->addr;
8433 			while (*name == ' ' || *name == '\t') name++;
8434 			if (*name != 0)
8435 			{
8436 				if (ni->proto->primindex == 0)
8437 				{
8438 					infstr = initinfstr();
8439 					addstringtoinfstr(infstr, ni->proto->protoname);
8440 					match = returninfstr(infstr);
8441 					len = estrlen(match);
8442 					if (len > abbrevlen) match[abbrevlen] = 0;
8443 					len = estrlen(match);
8444 					if (namesamen(name, match, len) == 0)
8445 					{
8446 						cindex = eatoi(&name[len]);
8447 						ts = (TEMPSTRUCT *)ni->proto->temp1;
8448 						if (cindex > ts->nodenumber) ts->nodenumber = cindex;
8449 					}
8450 				} else
8451 				{
8452 					match = shortnames[fun];
8453 					len = estrlen(match);
8454 					if (namesamen(name, match, len) == 0)
8455 					{
8456 						cindex = eatoi(&name[len]);
8457 						if (cindex > highpseudo[fun]) highpseudo[fun] = cindex;
8458 					}
8459 				}
8460 				continue;
8461 			}
8462 		}
8463 		named++;
8464 	}
8465 
8466 	/* see if any naming needs to be done */
8467 	if (named != 0)
8468 	{
8469 		/* make names for nodes without them */
8470 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
8471 		{
8472 			fun = nodefunction(ni);
8473 			if (evenpins == 0 && ni->firstportexpinst == NOPORTEXPINST)
8474 			{
8475 				if (fun == NPPIN || fun == NPART) continue;
8476 			}
8477 
8478 			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
8479 			if (var != NOVARIABLE)
8480 			{
8481 				name = (CHAR *)var->addr;
8482 				while (*name == ' ' || *name == '\t') name++;
8483 				if (*name != 0) continue;
8484 			}
8485 			for(;;)
8486 			{
8487 				if (ni->proto->primindex == 0)
8488 				{
8489 					ts = (TEMPSTRUCT *)ni->proto->temp1;
8490 					curindex = ts->nodenumber;
8491 					curindex++;
8492 					ts->nodenumber = curindex;
8493 					infstr = initinfstr();
8494 					addstringtoinfstr(infstr, ni->proto->protoname);
8495 					match = returninfstr(infstr);
8496 					len = estrlen(match);
8497 					if (len > abbrevlen) match[abbrevlen] = 0;
8498 					infstr = initinfstr();
8499 					formatinfstr(infstr, x_("%s%ld"), match, curindex);
8500 				} else
8501 				{
8502 					highpseudo[fun]++;
8503 					infstr = initinfstr();
8504 					formatinfstr(infstr, x_("%s%ld"), shortnames[fun], highpseudo[fun]);
8505 				}
8506 				name = returninfstr(infstr);
8507 
8508 				/* see if this name is in use */
8509 				for(i=0; i<net_nodenamelistcount; i++)
8510 					if (namesame(name, net_nodenamelist[i]) == 0) break;
8511 				if (i >= net_nodenamelistcount) break;
8512 			}
8513 			var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key, (INTBIG)name, VSTRING);
8514 			if (var != NOVARIABLE)
8515 				if (net_addnodename((CHAR *)var->addr)) break;
8516 		}
8517 	}
8518 
8519 	/* clean up the use of "temp1" */
8520 	for(i=0; i<total; i++)
8521 	{
8522 		ts = &nodelist[i];
8523 		ts->np->temp1 = ts->origtemp1;
8524 	}
8525 	if (total > 0) efree((CHAR *)nodelist);
8526 
8527 	return(named);
8528 }
8529 
8530 /*
8531  * Routine to gather all named nodes in cell "np" and fill the globals
8532  * "net_nodenamelistcount" and "net_nodenamelist" (also sets names "namelist"
8533  * and returns the count).
8534  */
net_gathernodenames(NODEPROTO * np,CHAR *** namelist)8535 INTBIG net_gathernodenames(NODEPROTO *np, CHAR ***namelist)
8536 {
8537 	REGISTER NODEINST *ni;
8538 	REGISTER VARIABLE *var;
8539 	REGISTER CHAR *pt, *name;
8540 	REGISTER INTBIG count, i;
8541 	CHAR **strings;
8542 
8543 	net_nodenamelistcount = 0;
8544 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
8545 	{
8546 		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
8547 		if (var == NOVARIABLE) continue;
8548 		name = (CHAR *)var->addr;
8549 		for(pt = name; *pt != 0; pt++) if (*pt == '[') break;
8550 		if (*pt == 0)
8551 		{
8552 			if (net_addnodename(name)) break;
8553 		} else
8554 		{
8555 			/* array specification: break it up and include each name separately */
8556 			count = net_evalbusname(APBUS, name, &strings, NOARCINST, np, 0);
8557 			for(i=0; i<count; i++)
8558 				if (net_addnodename(strings[i])) break;
8559 		}
8560 	}
8561 	*namelist = net_nodenamelist;
8562 	return(net_nodenamelistcount);
8563 }
8564 
8565 /*
8566  * Routine to add name "name" to the global list "net_nodenamelist" which is
8567  * "net_nodenamelistcount" long.  Returns true on error.
8568  */
net_addnodename(CHAR * name)8569 BOOLEAN net_addnodename(CHAR *name)
8570 {
8571 	REGISTER INTBIG i, newtotal;
8572 	REGISTER CHAR **newlist;
8573 
8574 	if (net_nodenamelistcount >= net_nodenamelisttotal)
8575 	{
8576 		newtotal = net_nodenamelisttotal * 2;
8577 		if (net_nodenamelistcount >= newtotal) newtotal = net_nodenamelistcount + 50;
8578 		newlist = (CHAR **)emalloc(newtotal * (sizeof (CHAR *)), net_tool->cluster);
8579 		if (newlist == 0) return(TRUE);
8580 		for(i=0; i<net_nodenamelistcount; i++)
8581 			newlist[i] = net_nodenamelist[i];
8582 		for(i=net_nodenamelistcount; i<newtotal; i++)
8583 			newlist[i] = 0;
8584 		if (net_nodenamelisttotal > 0) efree((CHAR *)net_nodenamelist);
8585 		net_nodenamelist = newlist;
8586 		net_nodenamelisttotal = newtotal;
8587 	}
8588 	if (net_nodenamelist[net_nodenamelistcount] == 0)
8589 		(void)allocstring(&net_nodenamelist[net_nodenamelistcount], name, net_tool->cluster); else
8590 			(void)reallocstring(&net_nodenamelist[net_nodenamelistcount], name, net_tool->cluster);
8591 	net_nodenamelistcount++;
8592 	return(FALSE);
8593 }
8594 
net_nameallnets(NODEPROTO * np)8595 INTBIG net_nameallnets(NODEPROTO *np)
8596 {
8597 	REGISTER ARCINST *ai;
8598 	REGISTER NETWORK *net;
8599 	REGISTER VARIABLE *var;
8600 	REGISTER CHAR *name;
8601 	CHAR newname[50];
8602 	INTBIG cindex, highpseudo;
8603 	INTBIG named;
8604 
8605 	/* do not name arcs in "icon" cells */
8606 	if (np->cellview == el_iconview || np->cellview == el_simsnapview) return(0);
8607 
8608 	/* find highest numbered net in the cell */
8609 	highpseudo = 0;
8610 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
8611 	{
8612 		var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
8613 		if (var == NOVARIABLE) continue;
8614 
8615 		/* check for existing pseudo-names */
8616 		name = (CHAR *)var->addr;
8617 		if (namesamen(name, x_("net"), 3) != 0) continue;
8618 		cindex = eatoi(&name[3]);
8619 		if (cindex > highpseudo) highpseudo = cindex;
8620 	}
8621 
8622 	/* find nets with no name and name them */
8623 	named = 0;
8624 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
8625 	{
8626 		net = ai->network;
8627 		if (net == NONETWORK || net->namecount > 0) continue;
8628 
8629 		highpseudo++;
8630 		(void)esnprintf(newname, 50, x_("net%ld"), highpseudo);
8631 		var = setvalkey((INTBIG)ai, VARCINST, el_arc_name_key, (INTBIG)newname, VSTRING);
8632 		if (var != NOVARIABLE)
8633 		defaulttextsize(4, var->textdescript);
8634 		named++;
8635 	}
8636 	if (named)
8637 		net_reevaluatecell(np);
8638 	return(named);
8639 }
8640 
8641 /*
8642  * routine to get the two cells to be compared.  These must be the only
8643  * two windows on the display.  Returns true if cells cannot be found.
8644  */
net_getcells(NODEPROTO ** cell1,NODEPROTO ** cell2)8645 BOOLEAN net_getcells(NODEPROTO **cell1, NODEPROTO **cell2)
8646 {
8647 	REGISTER WINDOWPART *w;
8648 
8649 	/* get two windows */
8650 	*cell1 = *cell2 = NONODEPROTO;
8651 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
8652 	{
8653 		if ((w->state&WINDOWTYPE) != DISPWINDOW &&
8654 			(w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
8655 		if (*cell1 == NONODEPROTO) *cell1 = w->curnodeproto; else
8656 		{
8657 			if (*cell2 == NONODEPROTO)
8658 			{
8659 				if (w->curnodeproto != *cell1) *cell2 = w->curnodeproto;
8660 			} else
8661 			{
8662 				if (w->curnodeproto != NONODEPROTO) return(TRUE);
8663 			}
8664 		}
8665 	}
8666 	if (*cell2 == NONODEPROTO) return(TRUE);
8667 	return(FALSE);
8668 }
8669 
8670 
8671 #ifdef NEWRENUM
8672 /*
8673  * Routine to return TRUE if network "net" has the name "netname" on it.
8674  */
net_nethasname(NETWORK * net,NetName * netname)8675 BOOLEAN net_nethasname(NETWORK *net, NetName *netname)
8676 {
8677 	NetName *nn;
8678 
8679 	if (net->namecount == 1)
8680 	{
8681 		nn = (NetName*)net->netnameaddr;
8682 		if (netname == nn) return(TRUE);
8683 	} else if (net->namecount > 1)
8684 	{
8685 		NetName **netnames = (NetName**)net->netnameaddr;
8686 		for(INTBIG k=0; k<net->namecount; k++)
8687 		{
8688 			if (netname ==  netnames[k]) return(TRUE);
8689 		}
8690 	}
8691 	return(FALSE);
8692 }
8693 #else
8694 /*
8695  * Routine to return TRUE if network "net" has the name "name" on it.
8696  */
net_nethasname(NETWORK * net,CHAR * name)8697 BOOLEAN net_nethasname(NETWORK *net, CHAR *name)
8698 {
8699 	NetName *nn;
8700 
8701 	if (net->namecount == 1)
8702 	{
8703 		nn = (NetName*)net->netnameaddr;
8704 		if (namesame(name, nn->name()) == 0) return(TRUE);
8705 	} else if (net->namecount > 1)
8706 	{
8707 		NetName **netnames = (NetName**)net->netnameaddr;
8708 		for(INTBIG k=0; k<net->namecount; k++)
8709 		{
8710 			if (namesame(name, netnames[k]->name()) == 0) return(TRUE);
8711 		}
8712 	}
8713 	return(FALSE);
8714 }
8715 #endif
8716 /*
8717  * Routine to get the network with name "name" in cell "cell".  Accepts networks with
8718  * similar names, as specified by the unification strings.
8719  */
net_getunifiednetwork(CHAR * name,NODEPROTO * cell,NETWORK * notthisnet)8720 NETWORK *net_getunifiednetwork(CHAR *name, NODEPROTO *cell, NETWORK *notthisnet)
8721 {
8722 	REGISTER NETWORK *net;
8723 	REGISTER INTBIG i, j, k, len, unified;
8724 	REGISTER CHAR *pt, *unifystring;
8725 
8726 #ifdef NEWRENUM
8727 	NetName *nn = cell->netd->findNetName(name, TRUE);
8728 	net = nn->firstNet();
8729 	if (net != NONETWORK && net != notthisnet) return(net);
8730 
8731 	/* see if this name is unified */
8732 	unified = -1;
8733 	for(i=0; i<net_unifystringcount; i++)
8734 	{
8735 		unifystring = net_unifystrings[i];
8736 		len = estrlen(unifystring);
8737 		if (namesamen(unifystring, name, len) != 0) continue;
8738 		if (isalnum(name[len])) continue;
8739 		for(k=len; name[k] != 0; k++) if (name[k] == '[') break;
8740 		if (name[k] != 0) continue;
8741 		unified = i;
8742 		break;
8743 	}
8744 #else
8745 	/* see if this name is unified */
8746 	unified = -1;
8747 	for(i=0; i<net_unifystringcount; i++)
8748 	{
8749 		unifystring = net_unifystrings[i];
8750 		len = estrlen(unifystring);
8751 		if (namesamen(unifystring, name, len) != 0) continue;
8752 		if (isalnum(name[len])) continue;
8753 		for(k=len; name[k] != 0; k++) if (name[k] == '[') break;
8754 		if (name[k] != 0) continue;
8755 		unified = i;
8756 		break;
8757 	}
8758 
8759 	NetName *nn = cell->netd->findNetName(name, FALSE);
8760 	if (nn)
8761 	{
8762 		net = nn->firstNet();
8763 		if (net != NONETWORK && net != notthisnet) return(net);
8764 	}
8765 #endif
8766 	if (unified >= 0)
8767 	{
8768 		unifystring = net_unifystrings[unified];
8769 		len = estrlen(unifystring);
8770 		for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
8771 		{
8772 			if (net == notthisnet) continue;
8773 			for(j=0; j<net->namecount; j++)
8774 			{
8775 				pt = networkname(net, j);
8776 				if (namesamen(unifystring, pt, len) != 0) continue;
8777 				if (isalnum(pt[len])) continue;
8778 				for(k=len; pt[k] != 0; k++) if (pt[k] == '[') break;
8779 				if (pt[k] == 0) return(net);
8780 			}
8781 		}
8782 	}
8783 
8784 	/* see if a global name is specified */
8785 	pt = _("Global");
8786 	k = estrlen(pt);
8787 	if (namesamen(name, pt, k) == 0 && name[k] == '-')
8788 	{
8789 		for(i=0; i<cell->globalnetcount; i++)
8790 			if (namesame(&name[k+1], cell->globalnetnames[i]) == 0)
8791 				return(cell->globalnetworks[i]);
8792 	}
8793 	return(NONETWORK);
8794 }
8795 
8796 /*
8797  * Routine to cache the list of network names to unify.
8798  */
net_recacheunifystrings(void)8799 void net_recacheunifystrings(void)
8800 {
8801 	REGISTER INTBIG i;
8802 	REGISTER CHAR *pt, *start, save, **newstrings;
8803 	REGISTER VARIABLE *var;
8804 
8805 	/* remove the former list of unification strings */
8806 	for(i=0; i<net_unifystringcount; i++) efree((CHAR *)net_unifystrings[i]);
8807 	if (net_unifystringcount > 0) efree((CHAR *)net_unifystrings);
8808 	net_unifystringcount = 0;
8809 
8810 	/* get the current list of strings to unify */
8811 	var = getvalkey((INTBIG)net_tool, VTOOL, VSTRING, net_unifystringskey);
8812 	if (var == NOVARIABLE) return;
8813 
8814 	/* parse the list */
8815 	pt = (CHAR *)var->addr;
8816 	for(;;)
8817 	{
8818 		while (*pt == ' ' || *pt == '\t') pt++;
8819 		if (*pt == 0) break;
8820 		start = pt;
8821 		while (*pt != 0 && *pt != ' ' && *pt != '\t') pt++;
8822 		save = *pt;
8823 		*pt = 0;
8824 
8825 		/* make sure there is room */
8826 		newstrings = (CHAR **)emalloc((net_unifystringcount+1) * (sizeof (CHAR *)), net_tool->cluster);
8827 		if (newstrings == 0) return;
8828 		for(i=0; i<net_unifystringcount; i++)
8829 			newstrings[i] = net_unifystrings[i];
8830 		if (net_unifystringcount > 0) efree((CHAR *)net_unifystrings);
8831 		net_unifystrings = newstrings;
8832 		(void)allocstring(&net_unifystrings[net_unifystringcount], start, net_tool->cluster);
8833 		net_unifystringcount++;
8834 
8835 		*pt = save;
8836 	}
8837 }
8838 
8839 /*
8840  * Routine to synchronize the schematic technology with the network tools idea of
8841  * resistor handling.
8842  */
net_tellschematics(void)8843 void net_tellschematics(void)
8844 {
8845 	REGISTER LIBRARY *lib;
8846 	REGISTER NODEPROTO *np;
8847 	REGISTER INTBIG total;
8848 
8849 	/* see how many cells there are */
8850 	total = 0;
8851 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
8852 	{
8853 		if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
8854 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
8855 			total++;
8856 	}
8857 
8858 	if (asktech(sch_tech, x_("ignoring-resistor-topology")) != 0)
8859 	{
8860 		/* currently ignoring resistors */
8861 		if ((net_options&NETIGNORERESISTORS) == 0)
8862 		{
8863 			/* make it start including resistors */
8864 			if (total > 0)
8865 				ttyputmsg(_("Adjusting network topology to include resistors"));
8866 			(void)asktool(us_tool, x_("clear"));
8867 			(void)asktech(sch_tech, x_("include-resistor-topology"));
8868 			net_totalrenumber(NOLIBRARY);
8869 		}
8870 	} else
8871 	{
8872 		/* currently including resistors */
8873 		if ((net_options&NETIGNORERESISTORS) != 0)
8874 		{
8875 			/* make it start ignoring resistors */
8876 			if (total > 0)
8877 				ttyputmsg(_("Adjusting network topology to ignore resistors"));
8878 			(void)asktool(us_tool, x_("clear"));
8879 			(void)asktech(sch_tech, x_("ignore-resistor-topology"));
8880 			net_totalrenumber(NOLIBRARY);
8881 		}
8882 	}
8883 }
8884 
8885 /****************************** NCC CONTROL DIALOG ******************************/
8886 
8887 /* Network: NCC Control */
8888 static DIALOGITEM net_nccoptionsdialogitems[] =
8889 {
8890  /*  1 */ {0, {488,224,512,312}, BUTTON, N_("Do NCC")},
8891  /*  2 */ {0, {488,8,512,72}, BUTTON, N_("Cancel")},
8892  /*  3 */ {0, {364,4,380,200}, CHECK, N_("Recurse through hierarchy")},
8893  /*  4 */ {0, {244,4,260,220}, CHECK, N_("Check export names")},
8894  /*  5 */ {0, {488,96,512,201}, BUTTON, N_("Preanalysis")},
8895  /*  6 */ {0, {432,16,448,208}, BUTTON, N_("NCC Debugging options...")},
8896  /*  7 */ {0, {124,4,140,220}, CHECK, N_("Merge parallel components")},
8897  /*  8 */ {0, {220,4,236,220}, CHECK, N_("Ignore power and ground")},
8898  /*  9 */ {0, {76,4,92,217}, MESSAGE, N_("For all cells:")},
8899  /* 10 */ {0, {191,228,387,400}, SCROLL, x_("")},
8900  /* 11 */ {0, {69,220,480,221}, DIVIDELINE, x_("")},
8901  /* 12 */ {0, {28,312,44,352}, BUTTON, N_("Set")},
8902  /* 13 */ {0, {4,312,20,352}, BUTTON, N_("Set")},
8903  /* 14 */ {0, {28,136,44,305}, EDITTEXT, x_("")},
8904  /* 15 */ {0, {124,232,140,281}, RADIO, N_("Yes")},
8905  /* 16 */ {0, {124,284,140,329}, RADIO, N_("No")},
8906  /* 17 */ {0, {124,332,140,396}, RADIO, N_("Default")},
8907  /* 18 */ {0, {316,20,332,164}, MESSAGE, N_("Size tolerance (amt):")},
8908  /* 19 */ {0, {316,168,332,216}, EDITTEXT, x_("")},
8909  /* 20 */ {0, {68,4,69,401}, DIVIDELINE, x_("")},
8910  /* 21 */ {0, {76,228,92,400}, MESSAGE, N_("Individual cell overrides:")},
8911  /* 22 */ {0, {172,12,188,209}, BUTTON, N_("Clear NCC dates this library")},
8912  /* 23 */ {0, {268,4,284,220}, CHECK, N_("Check component sizes")},
8913  /* 24 */ {0, {4,136,20,305}, EDITTEXT, x_("")},
8914  /* 25 */ {0, {28,4,44,132}, MESSAGE, N_("With cell:")},
8915  /* 26 */ {0, {4,4,20,132}, MESSAGE, N_("Compare cell:")},
8916  /* 27 */ {0, {292,20,308,164}, MESSAGE, N_("Size tolerance (%):")},
8917  /* 28 */ {0, {292,168,308,216}, EDITTEXT, x_("")},
8918  /* 29 */ {0, {488,336,512,400}, BUTTON, N_("Save")},
8919  /* 30 */ {0, {480,4,481,400}, DIVIDELINE, x_("")},
8920  /* 31 */ {0, {412,240,428,388}, BUTTON, N_("Remove all overrides")},
8921  /* 32 */ {0, {148,232,164,281}, RADIO, N_("Yes")},
8922  /* 33 */ {0, {148,284,164,329}, RADIO, N_("No")},
8923  /* 34 */ {0, {148,332,164,396}, RADIO, N_("Default")},
8924  /* 35 */ {0, {148,4,164,220}, CHECK, N_("Merge series transistors")},
8925  /* 36 */ {0, {100,232,116,281}, RADIO, N_("Yes")},
8926  /* 37 */ {0, {100,284,116,329}, RADIO, N_("No")},
8927  /* 38 */ {0, {100,332,116,396}, RADIO, N_("Default")},
8928  /* 39 */ {0, {100,4,116,220}, CHECK, N_("Expand hierarchy")},
8929  /* 40 */ {0, {171,228,187,400}, POPUP, x_("")},
8930  /* 41 */ {0, {392,240,408,388}, BUTTON, N_("List all overrides")},
8931  /* 42 */ {0, {456,4,472,216}, CHECK, N_("Show 'NCCMatch' tags")},
8932  /* 43 */ {0, {4,356,20,400}, BUTTON, N_("Next")},
8933  /* 44 */ {0, {28,356,44,400}, BUTTON, N_("Next")},
8934  /* 45 */ {0, {196,12,212,209}, BUTTON, N_("Clear NCC dates all libraries")},
8935  /* 46 */ {0, {48,4,64,400}, MESSAGE, x_("")},
8936  /* 47 */ {0, {340,4,356,220}, CHECK, N_("Allow no-component nets")},
8937  /* 48 */ {0, {460,232,476,400}, BUTTON, N_("Remove all forced matches")},
8938  /* 49 */ {0, {440,232,456,400}, BUTTON, N_("List all forced matches")},
8939  /* 50 */ {0, {388,4,404,216}, POPUP, x_("")}
8940 };
8941 static DIALOG net_nccoptionsdialog = {{50,75,571,486}, N_("Network Consistency Checker"), 0, 50, net_nccoptionsdialogitems, 0, 0};
8942 
8943 /* special items for the "NCC Control" dialog: */
8944 #define DNCO_DONCCNOW            1		/* Do NCC now (button) */
8945 #define DNCO_RECURSIVENCC        3		/* Do NCC recursively (check) */
8946 #define DNCO_CHECKEXPORTNAME     4		/* Check export names in NCC (check) */
8947 #define DNCO_DOPREANALNOW        5		/* Do NCC Preanalysis now (button) */
8948 #define DNCO_DEBUG               6		/* Debugging settings (button) */
8949 #define DNCO_MERGEPARALLEL       7		/* Merge parallel components in NCC (check) */
8950 #define DNCO_IGNOREPG            8		/* Ignore power/ground in NCC (check) */
8951 #define DNCO_CELLS              10		/* List of cells (scroll) */
8952 #define DNCO_SETSECONDCELL      12		/* Set second cell to compare (button) */
8953 #define DNCO_SETFIRSTCELL       13		/* Set first cell to compare (button) */
8954 #define DNCO_SECONDCELL         14		/* Second cell to compare (edit text) */
8955 #define DNCO_MERGEPARALLELYES   15		/* Yes to Merge parallel components (radio) */
8956 #define DNCO_MERGEPARALLELNO    16		/* No to Merge parallel components (radio) */
8957 #define DNCO_MERGEPARALLELDEF   17		/* Default to Merge parallel components (radio) */
8958 #define DNCO_COMPMATCHTOLAMT    19		/* Component match tolerance (amt) (edit text) */
8959 #define DNCO_CLEARVALIDNCCDATE  22		/* Clear valid NCC dates (button) */
8960 #define DNCO_CHECKCOMPSIZE      23		/* Check comp. size in NCC (check) */
8961 #define DNCO_FIRSTCELL          24		/* First cell to compare (edit text) */
8962 #define DNCO_COMPMATCHTOLPER    28		/* Component match tolerance (%) (edit text) */
8963 #define DNCO_SAVEOPTS           29		/* Save NCC options (button) */
8964 #define DNCO_REMOVEOVERRIDES    31		/* Remove all overrides (button) */
8965 #define DNCO_MERGESERIESYES     32		/* Yes to Merge series transistors (radio) */
8966 #define DNCO_MERGESERIESNO      33		/* No to Merge series transistors (radio) */
8967 #define DNCO_MERGESERIESDEF     34		/* Default to Merge series transistors (radio) */
8968 #define DNCO_MERGESERIES        35		/* Merge series transistors in NCC (check) */
8969 #define DNCO_EXPANDHIERYES      36		/* Yes to expand hierarchy (radio) */
8970 #define DNCO_EXPANDHIERNO       37		/* No to expand hierarchy (radio) */
8971 #define DNCO_EXPANDHIERDEF      38		/* Default to expand hierarchy (radio) */
8972 #define DNCO_EXPANDHIERARCHY    39		/* Expand hierarchy (check) */
8973 #define DNCO_LIBRARYSEL         40		/* Library of cells (popup) */
8974 #define DNCO_LISTOVERRIDES      41		/* List all overrides (button) */
8975 #define DNCO_SHOWMATCHTAGS      42		/* Show 'NCCMatch' tags (check) */
8976 #define DNCO_NEXTFIRSTCELL      43		/* Choose next "first cell" (button) */
8977 #define DNCO_NEXTSECONDCELL     44		/* Choose next "second cell" (button) */
8978 #define DNCO_CLEARALLNCCDATE    45		/* Clear valid NCC dates all libraries (button) */
8979 #define DNCO_OFFSCREENWARN      46		/* Warning if cells are not displayed (message) */
8980 #define DNCO_ALLOWNOCOMPNETS    47		/* Allow no-component networks (check) */
8981 #define DNCO_REMOVEFORCEDMATCH  48		/* Remove all forced-matches (button) */
8982 #define DNCO_LISTFORCEDMATCH    49		/* List all forced-matches (button) */
8983 #define DNCO_AUTORESISTORS      50		/* Automatically check for resistor settings (popup) */
8984 
8985 #define NUMOVERRIDES   3
8986 
8987 static struct
8988 {
8989 	CHAR *description;
8990 	int   yes, no, def;
8991 	int   overridebit, yesbit, nobit;
8992 } net_nccoverridebuttons[NUMOVERRIDES] =
8993 {
8994 	{x_("hierarchy expansion"),
8995 		DNCO_EXPANDHIERYES,        DNCO_EXPANDHIERNO,      DNCO_EXPANDHIERDEF,
8996 		NCCHIERARCHICALOVER,       NCCHIERARCHICAL,        0},
8997 	{x_("parallel component merging"),
8998 		DNCO_MERGEPARALLELYES,     DNCO_MERGEPARALLELNO,   DNCO_MERGEPARALLELDEF,
8999 		NCCNOMERGEPARALLELOVER,    0,                      NCCNOMERGEPARALLEL},
9000 	{x_("series transistor merging"),
9001 		DNCO_MERGESERIESYES,       DNCO_MERGESERIESNO,     DNCO_MERGESERIESDEF,
9002 		NCCMERGESERIESOVER,        NCCMERGESERIES,         0}
9003 };
9004 
9005 static CHAR     **net_librarylist;
9006 static LIBRARY   *net_library;
9007 static NODEPROTO *net_posnodeprotos;
9008 
net_topofcells(CHAR ** c)9009 BOOLEAN net_topofcells(CHAR **c)
9010 {
9011 	Q_UNUSED( c );
9012 	net_posnodeprotos = net_library->firstnodeproto;
9013 	return(TRUE);
9014 }
net_nextcells(void)9015 CHAR *net_nextcells(void)
9016 {
9017 	REGISTER NODEPROTO *np;
9018 
9019 	while (net_posnodeprotos != NONODEPROTO)
9020 	{
9021 		np = net_posnodeprotos;
9022 		net_posnodeprotos = net_posnodeprotos->nextnodeproto;
9023 		if (np->cellview == el_iconview) continue;
9024 		return(nldescribenodeproto(np));
9025 	}
9026 	return(0);
9027 }
net_nextcellswithfunction(void)9028 CHAR *net_nextcellswithfunction(void)
9029 {
9030 	REGISTER NODEPROTO *np;
9031 	REGISTER void *infstr;
9032 
9033 	while (net_posnodeprotos != NONODEPROTO)
9034 	{
9035 		np = net_posnodeprotos;
9036 		net_posnodeprotos = net_posnodeprotos->nextnodeproto;
9037 		if (np->cellview == el_iconview) continue;
9038 		if (np->temp1 == 0) return(nldescribenodeproto(np));
9039 		infstr = initinfstr();
9040 		formatinfstr(infstr, "%s (%s)", nldescribenodeproto(np), (CHAR *)np->temp1);
9041 		return(returninfstr(infstr));
9042 	}
9043 	return(0);
9044 }
9045 
net_nccoptionsdlog(void)9046 void net_nccoptionsdlog(void)
9047 {
9048 	REGISTER VARIABLE *var;
9049 	REGISTER INTBIG itemHit, i, options, oldoptions, clearvalidnccdates, tolerance,
9050 		toleranceamt, libcount, oldcelloptions, clearallnccdates;
9051 	REGISTER UINTBIG wanted;
9052 	REGISTER LIBRARY *lib;
9053 	REGISTER NODEINST *ni;
9054 	REGISTER BOOLEAN checkoffscreen;
9055 	REGISTER ARCINST *ai;
9056 	REGISTER WINDOWPART *win, *winfirst, *winsecond;
9057 	CHAR buf[10], *paramstart[5], *newlang[5];
9058 	REGISTER NODEPROTO *np;
9059 	NODEPROTO *cell1, *cell2;
9060 	static NODEPROTO *firstcell = NONODEPROTO;
9061 	static NODEPROTO *secondcell = NONODEPROTO;
9062 	static LIBRARY *firstlibrary, *secondlibrary;
9063 	REGISTER void *dia;
9064 	static CHAR *resistorOptions[3] = {N_("No resistor adjustments"),
9065 		N_("Include resistors"), N_("Exclude resistors")};
9066 
9067 	dia = DiaInitDialog(&net_nccoptionsdialog);
9068 	if (dia == 0) return;
9069 	DiaUnDimItem(dia, DNCO_CLEARVALIDNCCDATE);
9070 	DiaUnDimItem(dia, DNCO_CLEARALLNCCDATE);
9071 
9072 	if (!net_getcells(&cell1, &cell2))
9073 	{
9074 		firstcell = cell1;   firstlibrary = cell1->lib;
9075 		secondcell = cell2;  secondlibrary = cell2->lib;
9076 	}
9077 	winfirst = winsecond = NOWINDOWPART;
9078 	if (firstcell != NONODEPROTO)
9079 	{
9080 		/* validate this cell */
9081 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9082 			if (lib == firstlibrary) break;
9083 		if (lib == NOLIBRARY) firstcell = NONODEPROTO;
9084 		if (firstcell != NONODEPROTO)
9085 		{
9086 			for(np = firstlibrary->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
9087 				if (np == firstcell) break;
9088 			if (np == NONODEPROTO) firstcell = NONODEPROTO;
9089 		}
9090 		if (firstcell != NONODEPROTO)
9091 		{
9092 			DiaSetText(dia, DNCO_FIRSTCELL, describenodeproto(firstcell));
9093 			for(win = el_topwindowpart; win != NOWINDOWPART; win = win->nextwindowpart)
9094 				if (win->curnodeproto == firstcell) break;
9095 			if (win != NOWINDOWPART) winfirst = win;
9096 		}
9097 	}
9098 	if (secondcell != NONODEPROTO)
9099 	{
9100 		/* validate this cell */
9101 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9102 			if (lib == secondlibrary) break;
9103 		if (lib == NOLIBRARY) secondcell = NONODEPROTO;
9104 		if (secondcell != NONODEPROTO)
9105 		{
9106 			for(np = secondlibrary->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
9107 				if (np == secondcell) break;
9108 			if (np == NONODEPROTO) secondcell = NONODEPROTO;
9109 		}
9110 		if (secondcell != NONODEPROTO)
9111 		{
9112 			DiaSetText(dia, DNCO_SECONDCELL, describenodeproto(secondcell));
9113 			for(win = el_topwindowpart; win != NOWINDOWPART; win = win->nextwindowpart)
9114 				if (win->curnodeproto == secondcell) break;
9115 			if (win != NOWINDOWPART) winsecond = win;
9116 		}
9117 	}
9118 	checkoffscreen = TRUE;
9119 
9120 	/* list the libraries */
9121 	libcount = 0;
9122 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9123 		if ((lib->userbits&HIDDENLIBRARY) == 0) libcount++;
9124 	net_librarylist = (CHAR **)emalloc(libcount * (sizeof (CHAR *)), el_tempcluster);
9125 	libcount = 0;
9126 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9127 		if ((lib->userbits&HIDDENLIBRARY) == 0)
9128 			net_librarylist[libcount++] = lib->libname;
9129 	esort(net_librarylist, libcount, sizeof (CHAR *), sort_stringascending);
9130 	DiaSetPopup(dia, DNCO_LIBRARYSEL, libcount, net_librarylist);
9131 	for(i=0; i<libcount; i++)
9132 		if (namesame(net_librarylist[i], el_curlib->libname) == 0) break;
9133 	if (i < libcount) DiaSetPopupEntry(dia, DNCO_LIBRARYSEL, i);
9134 
9135 	net_library = el_curlib;
9136 	DiaInitTextDialog(dia, DNCO_CELLS, net_topofcells, net_nextcells, DiaNullDlogDone, 0,
9137 		SCSELMOUSE|SCSELKEY|SCREPORT);
9138 	(void)us_setscrolltocurrentcell(DNCO_CELLS, FALSE, TRUE, FALSE, FALSE, dia);
9139 	var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_optionskey);
9140 	if (var == NOVARIABLE) options = 0; else options = var->addr;
9141 	oldoptions = options;
9142 	if ((options&NCCRECURSE) != 0) DiaSetControl(dia, DNCO_RECURSIVENCC, 1);
9143 	if ((options&NCCHIERARCHICAL) != 0) DiaSetControl(dia, DNCO_EXPANDHIERARCHY, 1);
9144 	if ((options&NCCIGNOREPWRGND) != 0) DiaSetControl(dia, DNCO_IGNOREPG, 1);
9145 	if ((options&NCCNOMERGEPARALLEL) == 0) DiaSetControl(dia, DNCO_MERGEPARALLEL, 1);
9146 	if ((options&NCCMERGESERIES) != 0) DiaSetControl(dia, DNCO_MERGESERIES, 1);
9147 	if ((options&NCCCHECKEXPORTNAMES) != 0) DiaSetControl(dia, DNCO_CHECKEXPORTNAME, 1);
9148 	if ((options&NCCCHECKSIZE) != 0) DiaSetControl(dia, DNCO_CHECKCOMPSIZE, 1);
9149 	if ((options&NCCHIDEMATCHTAGS) == 0) DiaSetControl(dia, DNCO_SHOWMATCHTAGS, 1);
9150 	if ((options&NCCINCLUDENOCOMPNETS) != 0) DiaSetControl(dia, DNCO_ALLOWNOCOMPNETS, 1);
9151 
9152 	for(i=0; i<3; i++) newlang[i] = TRANSLATE(resistorOptions[i]);
9153 	DiaSetPopup(dia, DNCO_AUTORESISTORS, 3, newlang);
9154 	switch (options&NCCRESISTINCLUSION)
9155 	{
9156 		case NCCRESISTLEAVE:   DiaSetPopupEntry(dia, DNCO_AUTORESISTORS, 0); break;
9157 		case NCCRESISTINCLUDE: DiaSetPopupEntry(dia, DNCO_AUTORESISTORS, 1); break;
9158 		case NCCRESISTEXCLUDE: DiaSetPopupEntry(dia, DNCO_AUTORESISTORS, 2); break;
9159 	}
9160 
9161 	var = getvalkey((INTBIG)net_tool, VTOOL, -1, net_ncc_comptolerancekey);
9162 	tolerance = 0;
9163 	if (var != NOVARIABLE)
9164 	{
9165 		if ((var->type&VTYPE) == VINTEGER) tolerance = var->addr * WHOLE; else
9166 			if ((var->type&VTYPE) == VFRACT) tolerance = var->addr;
9167 	}
9168 	estrcpy(buf, frtoa(tolerance));
9169 	DiaSetText(dia, DNCO_COMPMATCHTOLPER, buf);
9170 	var = getvalkey((INTBIG)net_tool, VTOOL, VINTEGER, net_ncc_comptoleranceamtkey);
9171 	if (var == NOVARIABLE) toleranceamt = 0; else toleranceamt = var->addr;
9172 	DiaSetText(dia, DNCO_COMPMATCHTOLAMT, frtoa(toleranceamt));
9173 
9174 	/* cache individual cell overrides */
9175 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9176 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
9177 	{
9178 		var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, net_ncc_optionskey);
9179 		if (var == NOVARIABLE) np->temp1 = 0; else np->temp1 = var->addr;
9180 	}
9181 
9182 	net_setnccoverrides(dia);
9183 	clearvalidnccdates = clearallnccdates = 0;
9184 
9185 	/* loop until done */
9186 	for(;;)
9187 	{
9188 		/* check and warn if cells are offscreen */
9189 		if (checkoffscreen)
9190 		{
9191 			if (winfirst == NOWINDOWPART || winsecond == NOWINDOWPART)
9192 			{
9193 				DiaSetText(dia, DNCO_OFFSCREENWARN, x_("!!! WARNING: These cells are not on the screen !!!"));
9194 			} else
9195 			{
9196 				DiaSetText(dia, DNCO_OFFSCREENWARN, x_(""));
9197 			}
9198 			checkoffscreen = FALSE;
9199 		}
9200 
9201 		itemHit = DiaNextHit(dia);
9202 		if (itemHit == DNCO_SAVEOPTS || itemHit == CANCEL) break;
9203 		if (itemHit == DNCO_DONCCNOW || itemHit == DNCO_DOPREANALNOW)
9204 		{
9205 			if (firstcell != NONODEPROTO && secondcell != NONODEPROTO) break;
9206 			DiaMessageInDialog(_("Must first specify two cells to compare"));
9207 			continue;
9208 		}
9209 		if (itemHit == DNCO_MERGEPARALLEL || itemHit == DNCO_IGNOREPG ||
9210 			itemHit == DNCO_CHECKEXPORTNAME || itemHit == DNCO_CHECKCOMPSIZE ||
9211 			itemHit == DNCO_MERGESERIES || itemHit == DNCO_EXPANDHIERARCHY ||
9212 			itemHit == DNCO_ALLOWNOCOMPNETS)
9213 		{
9214 			DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
9215 			clearvalidnccdates = clearallnccdates = 1;
9216 			DiaDimItem(dia, DNCO_CLEARVALIDNCCDATE);
9217 			DiaDimItem(dia, DNCO_CLEARALLNCCDATE);
9218 			continue;
9219 		}
9220 		if (itemHit == DNCO_SHOWMATCHTAGS || itemHit == DNCO_RECURSIVENCC )
9221 		{
9222 			DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
9223 			continue;
9224 		}
9225 		if (itemHit == DNCO_COMPMATCHTOLAMT || itemHit == DNCO_COMPMATCHTOLPER)
9226 		{
9227 			if (itemHit == DNCO_COMPMATCHTOLAMT)
9228 			{
9229 				i = atofr(DiaGetText(dia, DNCO_COMPMATCHTOLAMT));
9230 				if (i == toleranceamt) continue;
9231 			} else
9232 			{
9233 				i = atofr(DiaGetText(dia, DNCO_COMPMATCHTOLPER));
9234 				if (i == tolerance) continue;
9235 			}
9236 			clearvalidnccdates = clearallnccdates = 1;
9237 			DiaDimItem(dia, DNCO_CLEARVALIDNCCDATE);
9238 			DiaDimItem(dia, DNCO_CLEARALLNCCDATE);
9239 			continue;
9240 		}
9241 		if (itemHit == DNCO_SETFIRSTCELL)
9242 		{
9243 			i = us_cellselect(_("First cell to NCC"), paramstart, 0);
9244 			if (i == 0) continue;
9245 			np = getnodeproto(paramstart[0]);
9246 			if (np == NONODEPROTO) continue;
9247 			firstcell = np;
9248 			DiaSetText(dia, DNCO_FIRSTCELL, describenodeproto(np));
9249 			if (firstcell != NONODEPROTO)
9250 			{
9251 				firstlibrary = firstcell->lib;
9252 				for(winfirst = el_topwindowpart; winfirst != NOWINDOWPART; winfirst = winfirst->nextwindowpart)
9253 					if (winfirst->curnodeproto == firstcell) break;
9254 			}
9255 			checkoffscreen = TRUE;
9256 			continue;
9257 		}
9258 		if (itemHit == DNCO_FIRSTCELL)
9259 		{
9260 			firstcell = getnodeproto(DiaGetText(dia, DNCO_FIRSTCELL));
9261 			if (firstcell != NONODEPROTO)
9262 			{
9263 				firstlibrary = firstcell->lib;
9264 				for(winfirst = el_topwindowpart; winfirst != NOWINDOWPART; winfirst = winfirst->nextwindowpart)
9265 					if (winfirst->curnodeproto == firstcell) break;
9266 			}
9267 			checkoffscreen = TRUE;
9268 			continue;
9269 		}
9270 		if (itemHit == DNCO_NEXTFIRSTCELL)
9271 		{
9272 			/* cycle through the open windows, choosing the next "first cell" */
9273 			if (winfirst == NOWINDOWPART) winfirst = el_topwindowpart; else
9274 			{
9275 				winfirst = winfirst->nextwindowpart;
9276 				if (winfirst == NOWINDOWPART) winfirst = el_topwindowpart;
9277 			}
9278 			if (winfirst != NOWINDOWPART && winfirst->curnodeproto != NONODEPROTO)
9279 			{
9280 				firstcell = winfirst->curnodeproto;
9281 				DiaSetText(dia, DNCO_FIRSTCELL, describenodeproto(firstcell));
9282 				if (firstcell != NONODEPROTO) firstlibrary = firstcell->lib;
9283 			}
9284 			checkoffscreen = TRUE;
9285 			continue;
9286 		}
9287 		if (itemHit == DNCO_SETSECONDCELL)
9288 		{
9289 			i = us_cellselect(_("Second cell to NCC"), paramstart, 0);
9290 			if (i == 0) continue;
9291 			np = getnodeproto(paramstart[0]);
9292 			if (np == NONODEPROTO) continue;
9293 			secondcell = np;
9294 			DiaSetText(dia, DNCO_SECONDCELL, describenodeproto(np));
9295 			if (secondcell != NONODEPROTO)
9296 			{
9297 				secondlibrary = secondcell->lib;
9298 				for(winsecond = el_topwindowpart; winsecond != NOWINDOWPART; winsecond = winsecond->nextwindowpart)
9299 					if (winsecond->curnodeproto == secondcell) break;
9300 			}
9301 			checkoffscreen = TRUE;
9302 			continue;
9303 		}
9304 		if (itemHit == DNCO_SECONDCELL)
9305 		{
9306 			secondcell = getnodeproto(DiaGetText(dia, DNCO_SECONDCELL));
9307 			if (secondcell != NONODEPROTO)
9308 			{
9309 				secondlibrary = secondcell->lib;
9310 				for(winsecond = el_topwindowpart; winsecond != NOWINDOWPART; winsecond = winsecond->nextwindowpart)
9311 					if (winsecond->curnodeproto == secondcell) break;
9312 			}
9313 			checkoffscreen = TRUE;
9314 			continue;
9315 		}
9316 		if (itemHit == DNCO_NEXTSECONDCELL)
9317 		{
9318 			/* cycle through the open windows, choosing the next "first cell" */
9319 			if (winsecond == NOWINDOWPART) winsecond = el_topwindowpart; else
9320 			{
9321 				winsecond = winsecond->nextwindowpart;
9322 				if (winsecond == NOWINDOWPART) winsecond = el_topwindowpart;
9323 			}
9324 			if (winsecond != NOWINDOWPART && winsecond->curnodeproto != NONODEPROTO)
9325 			{
9326 				secondcell = winsecond->curnodeproto;
9327 				DiaSetText(dia, DNCO_SECONDCELL, describenodeproto(secondcell));
9328 				if (secondcell != NONODEPROTO) secondlibrary = secondcell->lib;
9329 			}
9330 			checkoffscreen = TRUE;
9331 			continue;
9332 		}
9333 		if (itemHit == DNCO_LISTOVERRIDES)
9334 		{
9335 			net_listnccoverrides(TRUE);
9336 			continue;
9337 		}
9338 		if (itemHit == DNCO_LISTFORCEDMATCH)
9339 		{
9340 			net_listnccforcedmatches();
9341 			continue;
9342 		}
9343 		if (itemHit == DNCO_REMOVEOVERRIDES)
9344 		{
9345 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9346 			{
9347 				if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
9348 				for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
9349 					np->temp1 = 0;
9350 			}
9351 			continue;
9352 		}
9353 		if (itemHit == DNCO_REMOVEFORCEDMATCH)
9354 		{
9355 			net_removenccforcedmatches();
9356 			DiaDimItem(dia, DNCO_REMOVEFORCEDMATCH);
9357 			continue;
9358 		}
9359 		if (itemHit == DNCO_DEBUG)
9360 		{
9361 			options = net_nccdebuggingdlog(options);
9362 			continue;
9363 		}
9364 		for(i=0; i<NUMOVERRIDES; i++)
9365 		{
9366 			if (itemHit == net_nccoverridebuttons[i].yes ||
9367 				itemHit == net_nccoverridebuttons[i].no ||
9368 				itemHit == net_nccoverridebuttons[i].def)
9369 			{
9370 				DiaSetControl(dia, net_nccoverridebuttons[i].yes, 0);
9371 				DiaSetControl(dia, net_nccoverridebuttons[i].no, 0);
9372 				DiaSetControl(dia, net_nccoverridebuttons[i].def, 0);
9373 				DiaSetControl(dia, itemHit, 1);
9374 
9375 				np = net_nccdlgselectedcell(dia, DNCO_LIBRARYSEL, DNCO_CELLS);
9376 				if (np == NONODEPROTO) break;
9377 				np->temp1 &= ~(net_nccoverridebuttons[i].overridebit |
9378 					net_nccoverridebuttons[i].yesbit | net_nccoverridebuttons[i].nobit);
9379 				if (itemHit != net_nccoverridebuttons[i].def)
9380 				{
9381 					np->temp1 |= net_nccoverridebuttons[i].overridebit;
9382 					if (itemHit == net_nccoverridebuttons[i].yes)
9383 					{
9384 						np->temp1 |= net_nccoverridebuttons[i].yesbit;
9385 					} else
9386 					{
9387 						np->temp1 |= net_nccoverridebuttons[i].nobit;
9388 					}
9389 				}
9390 				break;
9391 			}
9392 		}
9393 		if (itemHit == DNCO_CELLS)
9394 		{
9395 			net_setnccoverrides(dia);
9396 			continue;
9397 		}
9398 		if (itemHit == DNCO_CLEARVALIDNCCDATE)
9399 		{
9400 			/* clear valid NCC dates this library */
9401 			clearvalidnccdates = 1;
9402 			DiaDimItem(dia, DNCO_CLEARVALIDNCCDATE);
9403 			continue;
9404 		}
9405 		if (itemHit == DNCO_CLEARALLNCCDATE)
9406 		{
9407 			/* clear all valid NCC dates */
9408 			clearallnccdates = 1;
9409 			DiaDimItem(dia, DNCO_CLEARVALIDNCCDATE);
9410 			DiaDimItem(dia, DNCO_CLEARALLNCCDATE);
9411 			continue;
9412 		}
9413 		if (itemHit == DNCO_LIBRARYSEL)
9414 		{
9415 			i = DiaGetPopupEntry(dia, DNCO_LIBRARYSEL);
9416 			lib = getlibrary(net_librarylist[i]);
9417 			if (lib == NOLIBRARY) continue;
9418 			net_library = lib;
9419 			DiaLoadTextDialog(dia, DNCO_CELLS, net_topofcells, net_nextcells, DiaNullDlogDone, 0);
9420 			net_setnccoverrides(dia);
9421 			continue;
9422 		}
9423 	}
9424 
9425 	if (itemHit != CANCEL)
9426 	{
9427 		options = options & ~(NCCRECURSE | NCCHIERARCHICAL |
9428 			NCCNOMERGEPARALLEL | NCCMERGESERIES |
9429 			NCCIGNOREPWRGND |
9430 			NCCCHECKEXPORTNAMES | NCCCHECKSIZE |
9431 			NCCHIDEMATCHTAGS | NCCINCLUDENOCOMPNETS |
9432 			NCCRESISTINCLUSION);
9433 		if (DiaGetControl(dia, DNCO_RECURSIVENCC) != 0) options |= NCCRECURSE;
9434 		if (DiaGetControl(dia, DNCO_EXPANDHIERARCHY) != 0) options |= NCCHIERARCHICAL;
9435 		if (DiaGetControl(dia, DNCO_MERGEPARALLEL) == 0) options |= NCCNOMERGEPARALLEL;
9436 		if (DiaGetControl(dia, DNCO_MERGESERIES) != 0) options |= NCCMERGESERIES;
9437 		if (DiaGetControl(dia, DNCO_IGNOREPG) != 0) options |= NCCIGNOREPWRGND;
9438 		if (DiaGetControl(dia, DNCO_CHECKEXPORTNAME) != 0) options |= NCCCHECKEXPORTNAMES;
9439 		if (DiaGetControl(dia, DNCO_CHECKCOMPSIZE) != 0) options |= NCCCHECKSIZE;
9440 		if (DiaGetControl(dia, DNCO_SHOWMATCHTAGS) == 0) options |= NCCHIDEMATCHTAGS;
9441 		if (DiaGetControl(dia, DNCO_ALLOWNOCOMPNETS) != 0) options |= NCCINCLUDENOCOMPNETS;
9442 		i = DiaGetPopupEntry(dia, DNCO_AUTORESISTORS);
9443 		switch (i)
9444 		{
9445 			case 0: options |= NCCRESISTLEAVE;     break;
9446 			case 1: options |= NCCRESISTINCLUDE;   break;
9447 			case 2: options |= NCCRESISTEXCLUDE;   break;
9448 		}
9449 		if (options != oldoptions)
9450 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_optionskey, options, VINTEGER);
9451 
9452 		i = atofr(DiaGetText(dia, DNCO_COMPMATCHTOLPER));
9453 		if (i != tolerance)
9454 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_comptolerancekey, i, VFRACT);
9455 		i = atofr(DiaGetText(dia, DNCO_COMPMATCHTOLAMT));
9456 		if (i != toleranceamt)
9457 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_ncc_comptoleranceamtkey, i, VINTEGER);
9458 
9459 		/* make changes to cell overrides */
9460 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9461 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
9462 		{
9463 			var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, net_ncc_optionskey);
9464 			if (var == NOVARIABLE) oldcelloptions = 0; else oldcelloptions = var->addr;
9465 			if (oldcelloptions == np->temp1) continue;
9466 			if (np->temp1 == 0) (void)delvalkey((INTBIG)np, VNODEPROTO, net_ncc_optionskey); else
9467 				setvalkey((INTBIG)np, VNODEPROTO, net_ncc_optionskey, np->temp1, VINTEGER);
9468 		}
9469 
9470 		/* clear valid NCC dates if requested */
9471 		if (clearvalidnccdates != 0 || clearallnccdates != 0)
9472 		{
9473 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9474 			{
9475 				if (clearallnccdates == 0 && lib != el_curlib) continue;
9476 				for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
9477 				{
9478 					net_nccremovematches(np);
9479 					for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
9480 					{
9481 						var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
9482 						if (var != NOVARIABLE)
9483 						{
9484 							if (namesamen((CHAR *)var->addr, x_("NCCmatch"), 8) == 0)
9485 							{
9486 								startobjectchange((INTBIG)ni, VNODEINST);
9487 								(void)delvalkey((INTBIG)ni, VNODEINST, el_node_name_key);
9488 								endobjectchange((INTBIG)ni, VNODEINST);
9489 							}
9490 						}
9491 						var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, net_ncc_matchkey);
9492 						if (var != NOVARIABLE)
9493 						{
9494 							startobjectchange((INTBIG)ni, VNODEINST);
9495 							(void)delvalkey((INTBIG)ni, VNODEINST, net_ncc_matchkey);
9496 							endobjectchange((INTBIG)ni, VNODEINST);
9497 						}
9498 					}
9499 					for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
9500 					{
9501 						var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
9502 						if (var != NOVARIABLE)
9503 						{
9504 							if (namesamen((CHAR *)var->addr, x_("NCCmatch"), 8) == 0)
9505 							{
9506 								startobjectchange((INTBIG)ai, VARCINST);
9507 								(void)delvalkey((INTBIG)ai, VARCINST, el_arc_name_key);
9508 								endobjectchange((INTBIG)ai, VARCINST);
9509 							}
9510 						}
9511 						var = getvalkey((INTBIG)ai, VARCINST, VSTRING, net_ncc_matchkey);
9512 						if (var != NOVARIABLE)
9513 						{
9514 							startobjectchange((INTBIG)ai, VARCINST);
9515 							(void)delvalkey((INTBIG)ai, VARCINST, net_ncc_matchkey);
9516 							endobjectchange((INTBIG)ai, VARCINST);
9517 						}
9518 					}
9519 				}
9520 			}
9521 			net_removeassociations();
9522 		} else if ((options&NCCHIDEMATCHTAGS) != (oldoptions&NCCHIDEMATCHTAGS))
9523 		{
9524 			/* change visibility of "nccmatch" tags */
9525 			if ((options&NCCHIDEMATCHTAGS) == 0) wanted = VDISPLAY; else wanted = 0;
9526 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9527 			{
9528 				for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
9529 				{
9530 					for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
9531 					{
9532 						var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
9533 						if (var != NOVARIABLE)
9534 						{
9535 							if (namesamen((CHAR *)var->addr, x_("NCCmatch"), 8) == 0)
9536 							{
9537 								if ((var->type&VDISPLAY) != wanted)
9538 								{
9539 									startobjectchange((INTBIG)ni, VNODEINST);
9540 									var->type = (var->type & ~VDISPLAY) | wanted;
9541 									endobjectchange((INTBIG)ni, VNODEINST);
9542 								}
9543 							}
9544 						}
9545 						var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, net_ncc_matchkey);
9546 						if (var != NOVARIABLE && (var->type&VDISPLAY) != wanted)
9547 						{
9548 							startobjectchange((INTBIG)ni, VNODEINST);
9549 							var->type = (var->type & ~VDISPLAY) | wanted;
9550 							endobjectchange((INTBIG)ni, VNODEINST);
9551 						}
9552 					}
9553 					for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
9554 					{
9555 						var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
9556 						if (var != NOVARIABLE)
9557 						{
9558 							if (namesamen((CHAR *)var->addr, x_("NCCmatch"), 8) == 0)
9559 							{
9560 								if ((var->type&VDISPLAY) != wanted)
9561 								{
9562 									startobjectchange((INTBIG)ai, VARCINST);
9563 									var->type = (var->type & ~VDISPLAY) | wanted;
9564 									endobjectchange((INTBIG)ai, VARCINST);
9565 								}
9566 							}
9567 						}
9568 						var = getvalkey((INTBIG)ai, VARCINST, VSTRING, net_ncc_matchkey);
9569 						if (var != NOVARIABLE && (var->type&VDISPLAY) != wanted)
9570 						{
9571 							startobjectchange((INTBIG)ai, VARCINST);
9572 							var->type = (var->type & ~VDISPLAY) | wanted;
9573 							endobjectchange((INTBIG)ai, VARCINST);
9574 						}
9575 					}
9576 				}
9577 			}
9578 		}
9579 	}
9580 	DiaDoneDialog(dia);
9581 	efree((CHAR *)net_librarylist);
9582 	if (itemHit == DNCO_DONCCNOW)
9583 	{
9584 		net_compare(FALSE, TRUE, firstcell, secondcell);
9585 	} else if (itemHit == DNCO_DOPREANALNOW)
9586 	{
9587 		net_compare(TRUE, TRUE, firstcell, secondcell);
9588 	}
9589 }
9590 
net_setnccoverrides(void * dia)9591 void net_setnccoverrides(void *dia)
9592 {
9593 	REGISTER INTBIG i, override;
9594 	REGISTER NODEPROTO *np;
9595 
9596 	np = net_nccdlgselectedcell(dia, DNCO_LIBRARYSEL, DNCO_CELLS);
9597 	if (np == NONODEPROTO) return;
9598 
9599 	override = np->temp1;
9600 	for(i=0; i<NUMOVERRIDES; i++)
9601 	{
9602 		DiaSetControl(dia, net_nccoverridebuttons[i].yes, 0);
9603 		DiaSetControl(dia, net_nccoverridebuttons[i].no, 0);
9604 		DiaSetControl(dia, net_nccoverridebuttons[i].def, 0);
9605 		if ((override&net_nccoverridebuttons[i].overridebit) == 0)
9606 		{
9607 			DiaSetControl(dia, net_nccoverridebuttons[i].def, 1);
9608 		} else
9609 		{
9610 			if (net_nccoverridebuttons[i].yesbit != 0)
9611 			{
9612 				if ((override&net_nccoverridebuttons[i].yesbit) != 0)
9613 				{
9614 					DiaSetControl(dia, net_nccoverridebuttons[i].yes, 1);
9615 				} else
9616 				{
9617 					DiaSetControl(dia, net_nccoverridebuttons[i].no, 1);
9618 				}
9619 			}
9620 			if (net_nccoverridebuttons[i].nobit != 0)
9621 			{
9622 				if ((override&net_nccoverridebuttons[i].nobit) != 0)
9623 				{
9624 					DiaSetControl(dia, net_nccoverridebuttons[i].no, 1);
9625 				} else
9626 				{
9627 					DiaSetControl(dia, net_nccoverridebuttons[i].yes, 1);
9628 				}
9629 			}
9630 		}
9631 	}
9632 }
9633 
9634 /*
9635  * Routine to list NCC overrides
9636  */
net_listnccoverrides(BOOLEAN usetemp1)9637 void net_listnccoverrides(BOOLEAN usetemp1)
9638 {
9639 	REGISTER LIBRARY *lib;
9640 	REGISTER NODEPROTO *np;
9641 	REGISTER INTBIG i, overridecount, bits;
9642 	REGISTER CHAR *state;
9643 	REGISTER void *infstr;
9644 	REGISTER VARIABLE *var;
9645 
9646 	overridecount = 0;
9647 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9648 	{
9649 		if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
9650 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
9651 		{
9652 			if (usetemp1) bits = np->temp1; else
9653 			{
9654 				var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, net_ncc_optionskey);
9655 				if (var == NOVARIABLE) bits = 0; else bits = var->addr;
9656 			}
9657 			for(i=0; i<NUMOVERRIDES; i++)
9658 			{
9659 				if ((bits&net_nccoverridebuttons[i].overridebit) == 0)
9660 					continue;
9661 				if (net_nccoverridebuttons[i].yesbit != 0)
9662 				{
9663 					if ((bits&net_nccoverridebuttons[i].yesbit) != 0)
9664 						state = _("on"); else
9665 							state = _("off");
9666 				} else
9667 				{
9668 					if ((bits&net_nccoverridebuttons[i].nobit) != 0)
9669 						state = _("off"); else
9670 							state = _("on");
9671 				}
9672 				if (overridecount == 0)
9673 					ttyputmsg(_("- Current cell overrides:"));
9674 				infstr = initinfstr();
9675 				formatinfstr(infstr, _("    Cell %s forces %s %s"),
9676 					describenodeproto(np), net_nccoverridebuttons[i].description,
9677 						state);
9678 				if ((bits & (NCCHIERARCHICAL|NCCHIERARCHICALOVER)) == NCCHIERARCHICALOVER)
9679 				{
9680 					/* forces hierarchical expansion off: see if there is a function */
9681 					var = getvalkey((INTBIG)np, VNODEPROTO, VSTRING, net_ncc_function_key);
9682 					if (var != NOVARIABLE)
9683 						formatinfstr(infstr, _(" (and has function %s)"), (CHAR *)var->addr);
9684 				}
9685 				ttyputmsg(x_("%s"), returninfstr(infstr));
9686 				overridecount++;
9687 			}
9688 		}
9689 	}
9690 	if (overridecount == 0) ttyputmsg(_("- No cell overrides"));
9691 }
9692 
9693 /*
9694  * Routine to list all forced matches in all libraries.
9695  */
net_listnccforcedmatches(void)9696 void net_listnccforcedmatches(void)
9697 {
9698 	REGISTER LIBRARY *lib;
9699 	REGISTER NODEPROTO *np;
9700 	REGISTER NODEINST *ni;
9701 	REGISTER ARCINST *ai;
9702 	REGISTER VARIABLE *var;
9703 	REGISTER INTBIG count;
9704 
9705 	count = 0;
9706 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9707 	{
9708 		if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
9709 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
9710 		{
9711 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
9712 			{
9713 				var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, net_ncc_forcedassociationkey);
9714 				if (var != NOVARIABLE)
9715 				{
9716 					ttyputmsg(_("Cell %s, node %s has forced match '%s'"),
9717 						describenodeproto(np), describenodeinst(ni), (CHAR *)var->addr);
9718 					count++;
9719 				}
9720 			}
9721 			for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
9722 			{
9723 				var = getvalkey((INTBIG)ai, VARCINST, VSTRING, net_ncc_forcedassociationkey);
9724 				if (var != NOVARIABLE)
9725 				{
9726 					ttyputmsg(_("Cell %s, arc %s has forced match '%s'"),
9727 						describenodeproto(np), describearcinst(ai), (CHAR *)var->addr);
9728 					count++;
9729 				}
9730 			}
9731 		}
9732 	}
9733 	if (count == 0) ttyputmsg(_("There are no forced matches"));
9734 }
9735 
9736 /*
9737  * Routine to remove all forced matches in all libraries.
9738  */
net_removenccforcedmatches(void)9739 void net_removenccforcedmatches(void)
9740 {
9741 	REGISTER LIBRARY *lib;
9742 	REGISTER NODEPROTO *np;
9743 	REGISTER NODEINST *ni;
9744 	REGISTER ARCINST *ai;
9745 	REGISTER VARIABLE *var;
9746 
9747 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9748 	{
9749 		if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
9750 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
9751 		{
9752 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
9753 			{
9754 				var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, net_ncc_forcedassociationkey);
9755 				if (var != NOVARIABLE)
9756 					delvalkey((INTBIG)ni, VNODEINST, net_ncc_forcedassociationkey);
9757 			}
9758 			for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
9759 			{
9760 				var = getvalkey((INTBIG)ai, VARCINST, VSTRING, net_ncc_forcedassociationkey);
9761 				if (var != NOVARIABLE)
9762 					delvalkey((INTBIG)ai, VARCINST, net_ncc_forcedassociationkey);
9763 			}
9764 		}
9765 	}
9766 }
9767 
9768 /*
9769  * Routine to return the cell that is currently selected in a
9770  * dialog.  The item with the popup of libraries is "liblist" and the item
9771  * with the list of cells is "celllist".  Returns NONODEPROTO if none can be determined.
9772  */
net_nccdlgselectedcell(void * dia,INTBIG liblist,INTBIG celllist)9773 NODEPROTO *net_nccdlgselectedcell(void *dia, INTBIG liblist, INTBIG celllist)
9774 {
9775 	REGISTER INTBIG which;
9776 	REGISTER CHAR *pt;
9777 	REGISTER NODEPROTO *np;
9778 	REGISTER LIBRARY *lib;
9779 	REGISTER void *infstr;
9780 
9781 	/* get the library */
9782 	which = DiaGetPopupEntry(dia, liblist);
9783 	if (which < 0) return(NONODEPROTO);
9784 	lib = getlibrary(net_librarylist[which]);
9785 	if (lib == NOLIBRARY) return(NONODEPROTO);
9786 
9787 	which = DiaGetCurLine(dia, celllist);
9788 	if (which < 0) return(NONODEPROTO);
9789 	pt = DiaGetScrollLine(dia, celllist, which);
9790 	if (*pt == 0) return(NONODEPROTO);
9791 	if (lib != el_curlib)
9792 	{
9793 		infstr = initinfstr();
9794 		formatinfstr(infstr, x_("%s:%s"), lib->libname, pt);
9795 		pt = returninfstr(infstr);
9796 	}
9797 	np = getnodeproto(pt);
9798 	return(np);
9799 }
9800 
9801 /****************************** NCC FUNCTION DIALOG ******************************/
9802 
9803 /* NCC Cell Function */
9804 static DIALOGITEM net_nccfundialogitems[] =
9805 {
9806  /*  1 */ {0, {308,184,332,264}, BUTTON, N_("OK")},
9807  /*  2 */ {0, {308,24,332,104}, BUTTON, N_("Cancel")},
9808  /*  3 */ {0, {4,116,20,288}, POPUP, x_("")},
9809  /*  4 */ {0, {4,4,20,112}, MESSAGE, N_("Library:")},
9810  /*  5 */ {0, {24,4,256,288}, SCROLL, x_("")},
9811  /*  6 */ {0, {260,116,276,288}, POPUP, x_("")},
9812  /*  7 */ {0, {260,4,276,112}, MESSAGE, N_("Function:")},
9813  /*  8 */ {0, {280,4,296,288}, CHECK, N_("Override Expansion on Cells with Functions")}
9814 };
9815 static DIALOG net_nccfundialog = {{75,75,416,373}, N_("Assign primitive functions to cells"), 0, 8, net_nccfundialogitems, 0, 0};
9816 
9817 /* special items for the "NCC Debugging" dialog: */
9818 #define DNCF_LIBLIST      3		/* List of libraries (popup) */
9819 #define DNCF_CELLLIST     5		/* List of cells (scroll) */
9820 #define DNCF_FUNCLIST     6		/* List of functions (popup) */
9821 #define DNCF_OVERRIDE     8		/* Override cell expansion (check) */
9822 
net_ncccellfunctiondlog(void)9823 void net_ncccellfunctiondlog(void)
9824 {
9825 	REGISTER void *dia, *infstr;
9826 	REGISTER INTBIG itemHit, libcount, i;
9827 	REGISTER CHAR **functionlist;
9828 	REGISTER BOOLEAN cellselchanged, s, g, d, b;
9829 	REGISTER NODEPROTO *np;
9830 	REGISTER PORTPROTO *pp;
9831 	REGISTER LIBRARY *lib;
9832 	REGISTER VARIABLE *var;
9833 
9834 	dia = DiaInitDialog(&net_nccfundialog);
9835 	if (dia == 0) return;
9836 	DiaSetControl(dia, DNCF_OVERRIDE, 1);
9837 
9838 	/* list the libraries */
9839 	libcount = 0;
9840 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9841 	{
9842 		if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
9843 		libcount++;
9844 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
9845 		{
9846 			var = getvalkey((INTBIG)np, VNODEPROTO, VSTRING, net_ncc_function_key);
9847 			if (var == NOVARIABLE) np->temp1 = 0; else
9848 				np->temp1 = var->addr;
9849 		}
9850 	}
9851 	net_librarylist = (CHAR **)emalloc(libcount * (sizeof (CHAR *)), el_tempcluster);
9852 	libcount = 0;
9853 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
9854 		if ((lib->userbits&HIDDENLIBRARY) == 0)
9855 			net_librarylist[libcount++] = lib->libname;
9856 	esort(net_librarylist, libcount, sizeof (CHAR *), sort_stringascending);
9857 	DiaSetPopup(dia, DNCF_LIBLIST, libcount, net_librarylist);
9858 	for(i=0; i<libcount; i++)
9859 		if (namesame(net_librarylist[i], el_curlib->libname) == 0) break;
9860 	if (i < libcount) DiaSetPopupEntry(dia, DNCF_LIBLIST, i);
9861 	net_library = el_curlib;
9862 	DiaInitTextDialog(dia, DNCF_CELLLIST, net_topofcells, net_nextcellswithfunction, DiaNullDlogDone, 0,
9863 		SCSELMOUSE|SCSELKEY|SCREPORT);
9864 	(void)us_setscrolltocurrentcell(DNCF_CELLLIST, FALSE, TRUE, FALSE, FALSE, dia);
9865 
9866 	/* load the function names */
9867 	functionlist = (CHAR **)emalloc(MAXNODEFUNCTION * (sizeof (CHAR *)), el_tempcluster);
9868 	for(i=0; i<MAXNODEFUNCTION; i++)
9869 		functionlist[i] = nodefunctionname(i, NONODEINST);
9870 	DiaSetPopup(dia, DNCF_FUNCLIST, MAXNODEFUNCTION, functionlist);
9871 	cellselchanged = TRUE;
9872 	for(;;)
9873 	{
9874 		if (cellselchanged)
9875 		{
9876 			cellselchanged = FALSE;
9877 			np = net_nccdlgselectedcell(dia, DNCF_LIBLIST, DNCF_CELLLIST);
9878 			if (np->temp1 == 0) i = 0; else
9879 			{
9880 				for(i=0; i<MAXNODEFUNCTION; i++)
9881 					if (namesame((CHAR *)np->temp1, nodefunctionname(i, NONODEINST)) == 0) break;
9882 			}
9883 			DiaSetPopupEntry(dia, DNCF_FUNCLIST, i);
9884 		}
9885 		itemHit = DiaNextHit(dia);
9886 		if (itemHit == OK || itemHit == CANCEL) break;
9887 		if (itemHit == DNCF_OVERRIDE)
9888 		{
9889 			DiaSetControl(dia, DNCF_OVERRIDE, 1-DiaGetControl(dia, DNCF_OVERRIDE));
9890 			continue;
9891 		}
9892 		if (itemHit == DNCF_CELLLIST)
9893 		{
9894 			cellselchanged = TRUE;
9895 			continue;
9896 		}
9897 		if (itemHit == DNCF_LIBLIST)
9898 		{
9899 			i = DiaGetPopupEntry(dia, DNCF_LIBLIST);
9900 			lib = getlibrary(net_librarylist[i]);
9901 			if (lib == NOLIBRARY) continue;
9902 			net_library = lib;
9903 			DiaLoadTextDialog(dia, DNCF_CELLLIST, net_topofcells, net_nextcellswithfunction, DiaNullDlogDone, 0);
9904 			continue;
9905 		}
9906 		if (itemHit == DNCF_FUNCLIST)
9907 		{
9908 			np = net_nccdlgselectedcell(dia, DNCF_LIBLIST, DNCF_CELLLIST);
9909 			if (np == NONODEPROTO) continue;
9910 			i = DiaGetPopupEntry(dia, DNCF_FUNCLIST);
9911 			if (i == 0)
9912 			{
9913 				np->temp1 = 0;
9914 				i = DiaGetCurLine(dia, DNCF_CELLLIST);
9915 				DiaSetScrollLine(dia, DNCF_CELLLIST, i, nldescribenodeproto(np));
9916 			} else
9917 			{
9918 				np->temp1 = (INTBIG)nodefunctionname(i, NONODEINST);
9919 				infstr = initinfstr();
9920 				formatinfstr(infstr, "%s (%s)", nldescribenodeproto(np), (CHAR *)np->temp1);
9921 				i = DiaGetCurLine(dia, DNCF_CELLLIST);
9922 				DiaSetScrollLine(dia, DNCF_CELLLIST, i, returninfstr(infstr));
9923 
9924 				/* vet the port names */
9925 				switch (i)
9926 				{
9927 					case NPPIN:
9928 					case NPCONTACT:
9929 					case NPNODE:
9930 					case NPCONNECT:
9931 					case NPSUBSTRATE:
9932 					case NPWELL:
9933 					case NPART:
9934 						ttyputmsg(_("This function has no electrical properties, so it makes no sense to assign it to a cell"));
9935 						break;
9936 					case NPTRANMOS:
9937 					case NPTRADMOS:
9938 					case NPTRAPMOS:
9939 					case NPTRANPN:
9940 					case NPTRAPNP:
9941 					case NPTRANJFET:
9942 					case NPTRAPJFET:
9943 					case NPTRADMES:
9944 					case NPTRAEMES:
9945 					case NPTRANSREF:
9946 					case NPTRANS:
9947 						/* must have three ports named "s", "g", and "d" */
9948 						s = g = d = FALSE;
9949 						for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
9950 						{
9951 							if (namesame(pp->protoname, "s") == 0) s = TRUE; else
9952 							if (namesame(pp->protoname, "g") == 0) g = TRUE; else
9953 							if (namesame(pp->protoname, "d") == 0) d = TRUE; else
9954 							{
9955 								s = g = d = FALSE;
9956 								break;
9957 							}
9958 						}
9959 						if (!s || !g || !d)
9960 							ttyputmsg("Transistor cells must have 3 ports named 's', 'g', and 'd'");
9961 						break;
9962 					case NPTRA4NMOS:
9963 					case NPTRA4DMOS:
9964 					case NPTRA4PMOS:
9965 					case NPTRA4NPN:
9966 					case NPTRA4PNP:
9967 					case NPTRA4NJFET:
9968 					case NPTRA4PJFET:
9969 					case NPTRA4DMES:
9970 					case NPTRA4EMES:
9971 					case NPTRANS4:
9972 						/* must have four ports named "s", "g", "d", and "b" */
9973 						s = g = d = b = FALSE;
9974 						for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
9975 						{
9976 							if (namesame(pp->protoname, "s") == 0) s = TRUE; else
9977 							if (namesame(pp->protoname, "g") == 0) g = TRUE; else
9978 							if (namesame(pp->protoname, "d") == 0) d = TRUE; else
9979 							if (namesame(pp->protoname, "b") == 0) b = TRUE; else
9980 							{
9981 								s = g = d = b = FALSE;
9982 								break;
9983 							}
9984 						}
9985 						if (!s || !g || !d || !b)
9986 							ttyputmsg("Transistor cells must have 4 ports named 's', 'g', 'd', and 'b'");
9987 						break;
9988 					case NPRESIST:
9989 					case NPCAPAC:
9990 					case NPECAPAC:
9991 					case NPINDUCT:
9992 						/* must have two ports */
9993 						i = 0;
9994 						for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto) i++;
9995 						if (i != 2)
9996 							ttyputmsg("Cells with this function must have 2 ports");
9997 						break;
9998 					case NPDIODE:
9999 					case NPDIODEZ:
10000 					case NPMETER:
10001 					case NPBASE:
10002 					case NPEMIT:
10003 					case NPCOLLECT:
10004 					case NPBUFFER:
10005 					case NPGATEAND:
10006 					case NPGATEOR:
10007 					case NPGATEXOR:
10008 					case NPFLIPFLOP:
10009 					case NPMUX:
10010 					case NPCONPOWER:
10011 					case NPCONGROUND:
10012 					case NPSOURCE:
10013 					case NPARRAY:
10014 					case NPALIGN:
10015 					case NPCCVS:
10016 					case NPCCCS:
10017 					case NPVCVS:
10018 					case NPVCCS:
10019 					case NPTLINE:
10020 						ttyputmsg(_("This function is not known to NCC, so it is not useful to assign it to a cell"));
10021 						break;
10022 				}
10023 			}
10024 			continue;
10025 		}
10026 	}
10027 	if (itemHit != CANCEL)
10028 	{
10029 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
10030 		{
10031 			if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
10032 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
10033 			{
10034 				var = getvalkey((INTBIG)np, VNODEPROTO, VSTRING, net_ncc_function_key);
10035 				if (var != NOVARIABLE && np->temp1 == 0)
10036 				{
10037 					delvalkey((INTBIG)np, VNODEPROTO, net_ncc_function_key);
10038 					continue;
10039 				}
10040 				if (np->temp1 != 0)
10041 				{
10042 					setvalkey((INTBIG)np, VNODEPROTO, net_ncc_function_key, np->temp1, VSTRING);
10043 					if (DiaGetControl(dia, DNCF_OVERRIDE) != 0)
10044 					{
10045 						var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, net_ncc_optionskey);
10046 						if (var == NOVARIABLE) i = 0; else i = var->addr;
10047 						i |= NCCHIERARCHICALOVER;
10048 						i &= ~NCCHIERARCHICAL;
10049 						setvalkey((INTBIG)np, VNODEPROTO, net_ncc_optionskey, i, VINTEGER);
10050 					}
10051 				}
10052 			}
10053 		}
10054 	}
10055 	DiaDoneDialog(dia);
10056 	efree((CHAR *)net_librarylist);
10057 }
10058 
10059 /****************************** NCC DEBUGGING DIALOG ******************************/
10060 
10061 /* NCC Debugging */
10062 static DIALOGITEM net_nccdebdialogitems[] =
10063 {
10064  /*  1 */ {0, {216,217,240,297}, BUTTON, N_("OK")},
10065  /*  2 */ {0, {216,60,240,140}, BUTTON, N_("Cancel")},
10066  /*  3 */ {0, {4,4,20,332}, CHECK, N_("Enable local processing after match")},
10067  /*  4 */ {0, {28,4,44,332}, CHECK, N_("Enable focus on 'fresh' symmetry groups")},
10068  /*  5 */ {0, {76,4,92,332}, CHECK, N_("Disable unimportant disambiguation messages")},
10069  /*  6 */ {0, {112,4,128,332}, CHECK, N_("Show gemini iterations graphically")},
10070  /*  7 */ {0, {136,4,152,332}, CHECK, N_("Show gemini iterations textually")},
10071  /*  8 */ {0, {160,4,176,332}, CHECK, N_("Show matching progress graphically")},
10072  /*  9 */ {0, {52,4,68,332}, CHECK, N_("Enable focus on 'promising' symmetry groups")},
10073  /* 10 */ {0, {184,4,200,332}, CHECK, N_("Show gemini statistics")}
10074 };
10075 static DIALOG net_nccdebdialog = {{75,75,324,417}, N_("NCC Debugging Settings"), 0, 10, net_nccdebdialogitems, 0, 0};
10076 
10077 /* special items for the "NCC Debugging" dialog: */
10078 #define DNCD_ENALOCAFTERMATCH      3		/* Enable local processing after match (check) */
10079 #define DNCD_ENAFOCSYMGRPFRE       4		/* Enable focus on fresh symmetry groups (check) */
10080 #define DNCD_DISUNDISMSG           5		/* Disable unimportant disambiguation messages (check) */
10081 #define DNCD_SHOWGEMINIGRA         6		/* Show gemini iterations graphically (check) */
10082 #define DNCD_SHOWGEMINITXT         7		/* Show gemini iterations textually (check) */
10083 #define DNCD_SHOWGRAPROG           8		/* Show graphical matching progress (check) */
10084 #define DNCD_ENAFOCSYMGRPPRO       9		/* Enable focus on promising symmetry groups (check) */
10085 #define DNCD_SHOWSTATISTICS       10		/* Show statistics during run (check) */
10086 
net_nccdebuggingdlog(INTBIG options)10087 INTBIG net_nccdebuggingdlog(INTBIG options)
10088 {
10089 	REGISTER void *dia;
10090 	REGISTER INTBIG itemHit, oldoptions;
10091 
10092 	dia = DiaInitDialog(&net_nccdebdialog);
10093 	if (dia == 0) return(options);
10094 
10095 	oldoptions = options;
10096 	if ((options&NCCDISLOCAFTERMATCH) == 0) DiaSetControl(dia, DNCD_ENALOCAFTERMATCH, 1);
10097 	if ((options&NCCENAFOCSYMGRPFRE) != 0) DiaSetControl(dia, DNCD_ENAFOCSYMGRPFRE, 1);
10098 	if ((options&NCCENAFOCSYMGRPPRO) != 0) DiaSetControl(dia, DNCD_ENAFOCSYMGRPPRO, 1);
10099 	if ((options&NCCSUPALLAMBREP) != 0) DiaSetControl(dia, DNCD_DISUNDISMSG, 1);
10100 	if ((options&NCCVERBOSEGRAPHICS) != 0) DiaSetControl(dia, DNCD_SHOWGEMINIGRA, 1);
10101 	if ((options&NCCVERBOSETEXT) != 0) DiaSetControl(dia, DNCD_SHOWGEMINITXT, 1);
10102 	if ((options&NCCGRAPHICPROGRESS) != 0) DiaSetControl(dia, DNCD_SHOWGRAPROG, 1);
10103 	if ((options&NCCENASTATISTICS) != 0) DiaSetControl(dia, DNCD_SHOWSTATISTICS, 1);
10104 	for(;;)
10105 	{
10106 		itemHit = DiaNextHit(dia);
10107 		if (itemHit == OK || itemHit == CANCEL) break;
10108 		if (itemHit == DNCD_ENALOCAFTERMATCH || itemHit == DNCD_ENAFOCSYMGRPFRE ||
10109 			itemHit == DNCD_DISUNDISMSG || itemHit == DNCD_SHOWGEMINIGRA ||
10110 			itemHit == DNCD_SHOWGEMINITXT || itemHit == DNCD_ENAFOCSYMGRPPRO ||
10111 			itemHit == DNCD_SHOWGRAPROG || itemHit == DNCD_SHOWSTATISTICS)
10112 		{
10113 			DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
10114 			continue;
10115 		}
10116 	}
10117 	if (itemHit != CANCEL)
10118 	{
10119 		options = options & ~(NCCDISLOCAFTERMATCH|NCCENAFOCSYMGRPFRE|NCCENAFOCSYMGRPPRO|
10120 			NCCSUPALLAMBREP|NCCVERBOSEGRAPHICS|NCCVERBOSETEXT|NCCGRAPHICPROGRESS|NCCENASTATISTICS);
10121 		if (DiaGetControl(dia, DNCD_ENALOCAFTERMATCH) == 0) options |= NCCDISLOCAFTERMATCH;
10122 		if (DiaGetControl(dia, DNCD_ENAFOCSYMGRPFRE) != 0) options |= NCCENAFOCSYMGRPFRE;
10123 		if (DiaGetControl(dia, DNCD_ENAFOCSYMGRPPRO) != 0) options |= NCCENAFOCSYMGRPPRO;
10124 		if (DiaGetControl(dia, DNCD_DISUNDISMSG) != 0) options |= NCCSUPALLAMBREP;
10125 		if (DiaGetControl(dia, DNCD_SHOWGEMINIGRA) != 0) options |= NCCVERBOSEGRAPHICS;
10126 		if (DiaGetControl(dia, DNCD_SHOWGEMINITXT) != 0) options |= NCCVERBOSETEXT;
10127 		if (DiaGetControl(dia, DNCD_SHOWGRAPROG) != 0) options |= NCCGRAPHICPROGRESS;
10128 		if (DiaGetControl(dia, DNCD_SHOWSTATISTICS) != 0) options |= NCCENASTATISTICS;
10129 	}
10130 	DiaDoneDialog(dia);
10131 	return(options);
10132 }
10133 
10134 /****************************** NETWORK OPTIONS DIALOG ******************************/
10135 
10136 /* Network: Options */
10137 static DIALOGITEM net_optionsdialogitems[] =
10138 {
10139  /*  1 */ {0, {288,148,312,212}, BUTTON, N_("OK")},
10140  /*  2 */ {0, {288,24,312,88}, BUTTON, N_("Cancel")},
10141  /*  3 */ {0, {28,20,44,226}, CHECK, N_("Unify Power and Ground")},
10142  /*  4 */ {0, {52,20,68,226}, CHECK, N_("Unify all like-named nets")},
10143  /*  5 */ {0, {4,4,20,165}, MESSAGE, N_("Network numbering:")},
10144  /*  6 */ {0, {228,36,244,201}, RADIO, N_("Ascending (0:N)")},
10145  /*  7 */ {0, {252,36,268,201}, RADIO, N_("Descending (N:0)")},
10146  /*  8 */ {0, {180,20,196,177}, MESSAGE, N_("Default starting index:")},
10147  /*  9 */ {0, {180,180,196,226}, POPUP, x_("")},
10148  /* 10 */ {0, {148,4,149,246}, DIVIDELINE, x_("")},
10149  /* 11 */ {0, {204,20,220,177}, MESSAGE, N_("Default order:")},
10150  /* 12 */ {0, {156,4,172,177}, MESSAGE, N_("For busses:")},
10151  /* 13 */ {0, {76,20,92,226}, CHECK, N_("Ignore Resistors")},
10152  /* 14 */ {0, {100,20,116,246}, MESSAGE, N_("Unify Networks that start with:")},
10153  /* 15 */ {0, {124,32,140,246}, EDITTEXT, x_("")}
10154 };
10155 static DIALOG net_optionsdialog = {{50,75,371,331}, N_("Network Options"), 0, 15, net_optionsdialogitems, 0, 0};
10156 
10157 /* special items for the "Network Options" dialog: */
10158 #define DNTO_UNIFYPG             3		/* Unify Power and Ground (check) */
10159 #define DNTO_UNIFYLIKENAMEDNETS  4		/* Unify all like-named nets (check) */
10160 #define DNTO_UNNAMEDASCEND       6		/* Number unnamed busses ascending (radio) */
10161 #define DNTO_UNNAMEDDESCEND      7		/* Number unnamed busses descending (radio) */
10162 #define DNTO_UNNAMEDSTARTINDEX   9		/* Starting index of unnamed busses (popup) */
10163 #define DNTO_IGNORERESISTORS    13		/* Ignore resistors (check) */
10164 #define DNTO_UNIFYSTRING        15		/* String for unifying network names (edit text) */
10165 
net_optionsdlog(void)10166 void net_optionsdlog(void)
10167 {
10168 	REGISTER INTBIG itemHit, i;
10169 	CHAR *choices[3], *initunifystrings, *pt;
10170 	REGISTER VARIABLE *var;
10171 	REGISTER BOOLEAN redonets;
10172 	REGISTER void *dia;
10173 
10174 	dia = DiaInitDialog(&net_optionsdialog);
10175 	if (dia == 0) return;
10176 	choices[0] = x_("0");   choices[1] = x_("1");
10177 	DiaSetPopup(dia, DNTO_UNNAMEDSTARTINDEX, 2, choices);
10178 
10179 	/* load general network options */
10180 	if ((net_options&NETCONPWRGND) != 0) DiaSetControl(dia, DNTO_UNIFYPG, 1);
10181 	if ((net_options&NETCONCOMMONNAME) != 0) DiaSetControl(dia, DNTO_UNIFYLIKENAMEDNETS, 1);
10182 	if ((net_options&NETIGNORERESISTORS) != 0) DiaSetControl(dia, DNTO_IGNORERESISTORS, 1);
10183 
10184 	/* load bus naming options */
10185 	if ((net_options&NETDEFBUSBASE1) != 0)
10186 	{
10187 		DiaSetPopupEntry(dia, DNTO_UNNAMEDSTARTINDEX, 1);
10188 		DiaSetText(dia, DNTO_UNNAMEDASCEND, _("Ascending (1:N)"));
10189 		DiaSetText(dia, DNTO_UNNAMEDDESCEND, _("Descending (N:1)"));
10190 	} else
10191 	{
10192 		DiaSetText(dia, DNTO_UNNAMEDASCEND, _("Ascending (0:N)"));
10193 		DiaSetText(dia, DNTO_UNNAMEDDESCEND, _("Descending (N:0)"));
10194 	}
10195 	if ((net_options&NETDEFBUSBASEDESC) != 0) DiaSetControl(dia, DNTO_UNNAMEDDESCEND, 1); else
10196 		DiaSetControl(dia, DNTO_UNNAMEDASCEND, 1);
10197 	var = getvalkey((INTBIG)net_tool, VTOOL, VSTRING, net_unifystringskey);
10198 	if (var == NOVARIABLE) initunifystrings = x_(""); else initunifystrings = (CHAR *)var->addr;
10199 	DiaSetText(dia, DNTO_UNIFYSTRING, initunifystrings);
10200 
10201 	/* loop until done */
10202 	for(;;)
10203 	{
10204 		itemHit = DiaNextHit(dia);
10205 		if (itemHit == OK || itemHit == CANCEL) break;
10206 		if (itemHit == DNTO_UNIFYPG || itemHit == DNTO_UNIFYLIKENAMEDNETS ||
10207 			itemHit == DNTO_IGNORERESISTORS)
10208 		{
10209 			DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
10210 			continue;
10211 		}
10212 		if (itemHit == DNTO_UNNAMEDDESCEND || itemHit == DNTO_UNNAMEDASCEND)
10213 		{
10214 			DiaSetControl(dia, DNTO_UNNAMEDASCEND, 0);
10215 			DiaSetControl(dia, DNTO_UNNAMEDDESCEND, 0);
10216 			DiaSetControl(dia, itemHit, 1);
10217 			continue;
10218 		}
10219 		if (itemHit == DNTO_UNNAMEDSTARTINDEX)
10220 		{
10221 			if (DiaGetPopupEntry(dia, DNTO_UNNAMEDSTARTINDEX) != 0)
10222 			{
10223 				DiaSetText(dia, DNTO_UNNAMEDASCEND, _("Ascending (1:N)"));
10224 				DiaSetText(dia, DNTO_UNNAMEDDESCEND, _("Descending (N:1)"));
10225 			} else
10226 			{
10227 				DiaSetText(dia, DNTO_UNNAMEDASCEND, _("Ascending (0:N)"));
10228 				DiaSetText(dia, DNTO_UNNAMEDDESCEND, _("Descending (N:0)"));
10229 			}
10230 			continue;
10231 		}
10232 	}
10233 
10234 	if (itemHit != CANCEL)
10235 	{
10236 		redonets = FALSE;
10237 		i = net_options & ~(NETCONPWRGND | NETCONCOMMONNAME | NETDEFBUSBASE1 | NETDEFBUSBASEDESC |
10238 			NETIGNORERESISTORS);
10239 		if (DiaGetControl(dia, DNTO_UNIFYPG) != 0) i |= NETCONPWRGND;
10240 		if (DiaGetControl(dia, DNTO_UNIFYLIKENAMEDNETS) != 0) i |= NETCONCOMMONNAME;
10241 		if (DiaGetControl(dia, DNTO_IGNORERESISTORS) != 0) i |= NETIGNORERESISTORS;
10242 		if (DiaGetPopupEntry(dia, DNTO_UNNAMEDSTARTINDEX) != 0) i |= NETDEFBUSBASE1;
10243 		if (DiaGetControl(dia, DNTO_UNNAMEDDESCEND) != 0) i |= NETDEFBUSBASEDESC;
10244 		if (i != net_options)
10245 		{
10246 			redonets = TRUE;
10247 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_optionskey, i, VINTEGER);
10248 			net_tellschematics();
10249 		}
10250 		pt = DiaGetText(dia, DNTO_UNIFYSTRING);
10251 		if (namesame(pt, initunifystrings) != 0)
10252 		{
10253 			redonets = TRUE;
10254 			(void)setvalkey((INTBIG)net_tool, VTOOL, net_unifystringskey, (INTBIG)pt, VSTRING);
10255 		}
10256 		if (redonets)
10257 		{
10258 			net_totalrenumber(NOLIBRARY);
10259 		}
10260 	}
10261 	DiaDoneDialog(dia);
10262 }
10263