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