1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: simsilos.c
6  * Generator for SILOS simulator, Version 2
7  * Written by: Sid Penstone, Queen's University
8  * Modified by: Steven M. Rubin, Static Free Software
9  *
10  * Copyright (c) 2000 Static Free Software.
11  *
12  * Electric(tm) is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * Electric(tm) is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with Electric(tm); see the file COPYING.  If not, write to
24  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
25  * Boston, Mass 02111-1307, USA.
26  *
27  * Static Free Software
28  * 4119 Alpine Road
29  * Portola Valley, California 94028
30  * info@staticfreesoft.com
31  */
32 
33 #include "config.h"
34 #if SIMTOOL
35 
36 #include "global.h"
37 #include "efunction.h"
38 #include "sim.h"
39 #include "usr.h"
40 #include "tecschem.h"
41 
42 #define MAXSTR  79		/* split lines into 80 characters */
43 #define MAXNAME 12		/* Maximum macro name length */
44 
45 /* Types returned by sim_silostype() */
46 
47 #define SILOSCELL		-1		/* Complex node */
48 #define SILOSUNKNOWN	 0		/* All connected together */
49 #define SILOSNMOS		 1		/* Transistor */
50 #define SILOSPMOS		 2		/* P-transistor */
51 #define SILOSAND		 3		/* AND gate */
52 #define SILOSOR			 4		/* OR gate */
53 #define SILOSXOR		 5		/* XOR */
54 #define SILOSINV		 6		/* Inverter */
55 #define SILOSBUF		 7		/* Buffer */
56 #define SILOSSOURCE		 8		/* Source, not .CLK */
57 #define SILOSRES		 9		/* Resistor in SILOS */
58 #define SILOSCAP		10		/* Capacitor */
59 #define SILOSDFF		11		/* D flip flop */
60 #define SILOSJKFF		12		/* JK flip flop */
61 #define SILOSSRFF		13		/* RS flip flop */
62 #define SILOSTFF		14		/* Toggle flip flop */
63 #define SILOSCLK		15		/* .CLK (may not be used yet */
64 #define SILOSOUT		16		/* Output point */
65 #define SILOSCLOCK		17		/* Clocks, etc. declared as globals */
66 
67 /********************** global variables *********************/
68 
69 static FILE  *sim_silfile;
70 static INTBIG sim_pseudonet;		/* for internal networks */
71 static INTBIG sim_silos_global_name_key = 0;
72 static INTBIG sim_silos_model_key = 0;		/* for model on cell */
73 
74 /* ************************************************************* */
75 
76 /* prototypes for local routines */
77 static INTBIG  sim_writesilcell(NODEPROTO*, BOOLEAN);
78 static void    sim_writesilinstances(NODEPROTO*, BOOLEAN);
79 static CHAR   *sim_silportname(BOOLEAN, NODEINST*, PORTPROTO*, NODEPROTO*);
80 static CHAR   *sim_silname(NODEINST*);
81 static CHAR   *sim_silproto(NODEINST*, BOOLEAN);
82 static CHAR   *sim_siltext(CHAR*);
83 static void    sim_sendtosil(CHAR*);
84 static CHAR   *sim_silarcname(ARCINST*);
85 static BOOLEAN sim_silnegated(PORTARCINST*);
86 static CHAR   *sim_silspecials(CHAR*);
87 static INTBIG  sim_silostype(NODEINST*);
88 static CHAR   *sim_silrisetime(NODEINST*);
89 static CHAR   *sim_silfalltime(NODEINST*);
90 static INTBIG  sim_silgetcapacitance(NODEINST*);
91 static void    sim_silwriteflipflop(BOOLEAN, NODEINST*, NODEPROTO*, INTBIG);
92 static CHAR   *sim_sil_isaport(NODEPROTO*, CHAR*);
93 static CHAR   *sim_convertsub(CHAR*);
94 
95 /*
96  * routine to write a ".sil" file from the cell "np"
97  */
sim_writesilnetlist(NODEPROTO * np)98 void sim_writesilnetlist(NODEPROTO *np)
99 {
100 	CHAR name[100], numberstring[100], *truename;
101 	REGISTER NODEPROTO *lnp;
102 	REGISTER LIBRARY *lib;
103 
104 	/* make sure network tool is on */
105 	if ((net_tool->toolstate&TOOLON) == 0)
106 	{
107 		ttyputerr(_("Network tool must be running...turning it on"));
108 		toolturnon(net_tool);
109 		ttyputerr(_("...now reissue the simulation command"));
110 		return;
111 	}
112 
113 	/* first write the "sil" file */
114 	(void)estrcpy(name, np->protoname);
115 	(void)estrcat(name, x_(".sil"));
116 	sim_silfile = xcreate(name, sim_filetypesilos, _("SILOS File"), &truename);
117 	if (sim_silfile == NULL)
118 	{
119 		if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
120 		return;
121 	}
122 	sim_sendtosil(x_("\n"));
123 	sim_sendtosil(x_("$ CELL "));
124 	sim_sendtosil(describenodeproto(np));
125 	sim_sendtosil(x_(" FROM LIBRARY:"));
126 	sim_sendtosil(np->lib->libname);
127 	sim_sendtosil(x_("\n"));
128 	if ((us_useroptions&NODATEORVERSION) == 0)
129 	{
130 		if (np->creationdate)
131 		{
132 			(void)esnprintf(numberstring, 100, x_("$ CELL CREATED ON %s"),
133 				timetostring((time_t)np->creationdate));
134 			sim_sendtosil(numberstring);
135 			sim_sendtosil(x_("\n"));
136 		}
137 		if (np->version)
138 		{
139 			(void)esnprintf(numberstring, 100, x_("$ VERSION %ld"), np->version);
140 			sim_sendtosil(numberstring);
141 			sim_sendtosil(x_("\n"));
142 		}
143 		if (np->revisiondate)
144 		{
145 			(void)esnprintf(numberstring, 100, x_("$ LAST REVISED %s"),
146 				timetostring((time_t)np->revisiondate));
147 			sim_sendtosil(numberstring);
148 			sim_sendtosil(x_("\n"));
149 		}
150 		(void)esnprintf(numberstring, 100,
151 			x_("$ SILOS netlist written by Electric Design System; Version %s"), el_version);
152 		sim_sendtosil(numberstring);
153 		sim_sendtosil(x_("\n"));
154 
155 		(void)esnprintf(numberstring, 100, x_("%s"), timetostring(getcurrenttime()));
156 		sim_sendtosil(x_("$ WRITTEN ON "));
157 		sim_sendtosil(numberstring);
158 		sim_sendtosil(x_("\n"));
159 	} else
160 	{
161 		sim_sendtosil(x_("$ SILOS netlist written by Electric Design System\n"));
162 	}
163 
164 	if (sim_silos_global_name_key == 0)
165 		sim_silos_global_name_key = makekey(x_("SIM_silos_global_name"));
166 	if (sim_silos_model_key == 0)
167 		sim_silos_model_key = makekey(x_("SC_silos"));
168 
169 	/* reset flags for cells that have been written */
170 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
171 		for(lnp = lib->firstnodeproto; lnp != NONODEPROTO; lnp = lnp->nextnodeproto)
172 			lnp->temp1 = 0;
173 	if (sim_writesilcell(np, TRUE) != 0)
174 		ttyputmsg(_("Back-annotation information has been added (library must be saved)"));
175 	sim_sendtosil(x_("\n"));
176 
177 	/* clean up */
178 	xclose(sim_silfile);
179 	ttyputmsg(_("%s written"), truename);
180 
181 }
182 
183 /*
184  * recursively called routine to print the SILOS description of cell "np".
185  * The description is treated as the top-level cell if "top" is true
186  * np is the current nodeproto
187  */
sim_writesilcell(NODEPROTO * np,BOOLEAN top)188 INTBIG sim_writesilcell(NODEPROTO *np, BOOLEAN top)
189 {
190 	UCHAR1 buf[256];
191 	REGISTER INTBIG i, j, nodetype, clktype, count, backannotate;
192 	REGISTER NODEINST *ni;
193 	REGISTER PORTPROTO *pp;
194 	REGISTER NODEPROTO *onp;
195 	REGISTER NETWORK *net;
196 	REGISTER VARIABLE *var;
197 	REGISTER FILE *f;
198 	CHAR line[100], *filename, *extra;
199 	CHAR **model, *name;
200 
201 	/* stop if requested */
202 	if (el_pleasestop != 0)
203 	{
204 		(void)stopping(STOPREASONDECK);
205 		return(0);
206 	}
207 	backannotate = 0;
208 
209 	/* First look for any global sources */
210 	if (top)
211 	{
212 		for (ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
213 		{
214 			if (ni->proto->primindex == 0) continue;	/* only real sources */
215 
216 			nodetype = nodefunction(ni);
217 			if (nodetype != NPSOURCE) continue;
218 
219 			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sim_silos_global_name_key);
220 			if (var != NOVARIABLE)	/* is this a global source ? */
221 			{
222 				name = (CHAR *)var->addr;
223 				(void)esnprintf(line, 100, x_(".GLOBAL %s"), sim_silspecials(name));
224 				sim_sendtosil(line);
225 				sim_sendtosil(x_("\n"));
226 			}
227 
228 			/* Get the source type */
229 			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_spicemodelkey);
230 			if (var == NOVARIABLE)
231 			{
232 				ttyputerr(_("Unspecified source:"));
233 				esnprintf(line, 100, x_("$$$$$ Unspecified source: \n"));
234 			} else	/* There is more */
235 			{
236 				clktype = 0;	/* Extra data required if variable there */
237 				for(extra = (CHAR *)var->addr; *extra != 0 && *extra != '/'; extra++)
238 				{
239 					switch (*extra)
240 					{
241 						case 'g':	/* a global clock (THIS IS WRONG!!!) */
242 							(void)esnprintf(line, 100, x_("%s .CLK "), name);
243 							clktype = 1;
244 							break;
245 						case 'h':	/* a fixed high source (THIS IS WRONG!!!) */
246 							(void)esnprintf(line, 100, x_("%s .CLK 0 S1 $ HIGH LEVEL"), name);
247 							break;
248 						case 'l':	/* a fixed low source (THIS IS WRONG!!!) */
249 							(void)esnprintf(line, 100, x_("%s .CLK 0 S0 $ LOW LEVEL"), name);
250 							break;
251 					}
252 				}
253 				if (*extra == '/') extra++;
254 				if (clktype == 1) estrcat(line, extra);
255 			}
256 			sim_sendtosil(line);
257 			sim_sendtosil(x_("\n"));
258 		}
259 	}
260 
261 	/* Read a behavior file if it is available */
262 	FOR_CELLGROUP(onp, np)
263 	{
264 		var = getval((INTBIG)onp, VNODEPROTO, VSTRING, x_("SIM_silos_behavior_file"));
265 		if (var != NOVARIABLE)
266 		{
267 			f = xopen(truepath((CHAR *)var->addr), sim_filetypesilos, x_(""), &filename);
268 			if (f == NULL)
269 				ttyputerr(_("Cannot find SILOS behavior file %s on cell %s"),
270 					(CHAR *)var->addr, describenodeproto(onp)); else
271 			{
272 				/* copy the file */
273 				for(;;)
274 				{
275 					count = xfread(buf, 1, 256, f);
276 					if (count <= 0) break;
277 					if (xfwrite(buf, 1, count, sim_silfile) != count)
278 						ttyputerr(_("Error copying file"));
279 				}
280 				xclose(f);
281 				sim_sendtosil(x_("\n"));
282 
283 				/* mark this cell as written */
284 				np->temp1++;
285 				return(backannotate);
286 			}
287 		}
288 	}
289 
290 	/*
291 	 * There was no behavior file...
292 	 * Get the SILOS model from the library if it exists
293 	 */
294 	FOR_CELLGROUP(onp, np)
295 	{
296 		var = getvalkey((INTBIG)onp, VNODEPROTO, VSTRING|VISARRAY, sim_silos_model_key);
297 		if (var != NOVARIABLE)
298 		{
299 			model = (CHAR **)var->addr;
300 			j = getlength(var);
301 			for(i = 0; i < j; i++)
302 				xprintf(sim_silfile, x_("%s\n"), model[i]);
303 			sim_sendtosil(x_("\n"));
304 
305 			/* mark this cell as written */
306 			np->temp1++;
307 			return(backannotate);
308 		}
309 	}
310 
311 	/*
312 	 * No database model either...
313 	 * must write netlist for this cell
314 	 * ...recurse on sub-cells first
315 	 */
316 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
317 	{
318 		if (ni->proto->primindex != 0) continue;
319 
320 		/* ignore recursive references (showing icon in contents) */
321 		if (isiconof(ni->proto, np)) continue;
322 
323 		/* get actual subcell (including contents/body distinction) */
324 		/* NOTE: this gets the schematic before the layout */
325 		onp = contentsview(ni->proto);
326 		if (onp == NONODEPROTO) onp = ni->proto;
327 
328 		/* write the subcell */
329 		if (onp->temp1 == 0)
330 		{
331 			if (sim_writesilcell(onp, FALSE) != 0) backannotate = 1;
332 		}
333 	}
334 
335 	/* make sure that all nodes have names on them */
336 	if (asktool(net_tool, x_("name-nodes"), (INTBIG)np) != 0) backannotate++;
337 
338 	/* mark this cell as written */
339 	np->temp1++;
340 
341 	/* write the header if this not the top level */
342 	if (!top)
343 	{
344 		sim_sendtosil(x_("\n"));
345 		sim_sendtosil(x_(".MACRO"));
346 		(void)estrcpy(line, np->protoname);
347 		for (i=0; line[i] && line[i] != '{'; i++)
348 			;
349 		line[i] = 0;			/* explicit termination of line */
350 		if(estrlen(line) > MAXNAME)
351 		{
352 			ttyputerr(_(".MACRO name %s is too long;"), line);
353 			line[MAXNAME] = 0;
354 			ttyputerr(_("truncated to %s"), line);
355 		}
356 		sim_sendtosil(x_(" "));
357 		sim_sendtosil(sim_siltext(line));
358 
359 		/*
360 		 * This is different from sim_silportname() because it finds ports on
361 		 * the np, not the ni - No shortcuts here!
362 		 */
363 		if (np->firstportproto != NOPORTPROTO)
364 		{
365 			for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
366 			{
367 				if (portispower(pp) || portisground(pp)) continue;
368 				(void)estrcpy(line, sim_convertsub(pp->protoname));
369 				sim_sendtosil(x_(" "));
370 				sim_sendtosil(sim_siltext(line));
371 			}
372 		}
373 		sim_sendtosil(x_("\n"));
374 	}
375 
376 	/* initialize ports that get used */
377 	for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
378 		net->temp1 = 0;
379 	if (np->firstnodeinst != NONODEINST)	/* any valid nodes ? */
380 		sim_writesilinstances(np, top);
381 	if (top == 0) sim_sendtosil(x_(".EOM\n"));
382 	sim_sendtosil(x_("\n"));
383 	return(backannotate);
384 }						/* end sim_writesilcell() */
385 
386 
387 /* Function to write the instances contained in 'np'
388  * This was part of sim_writesilcell before...
389  */
sim_writesilinstances(NODEPROTO * np,BOOLEAN top)390 void sim_writesilinstances(NODEPROTO *np, BOOLEAN top)
391 {
392 	REGISTER INTBIG j, schem_ref;
393 	REGISTER INTBIG nodetype;
394 	REGISTER NODEINST *ni;
395 	REGISTER NODEPROTO *cnp;
396 	REGISTER PORTPROTO *pp, *lastpp, *outpp, *ipp;
397 	REGISTER PORTARCINST *pi;
398 	CHAR line[100];
399 
400 	sim_pseudonet = 1;
401 	schem_ref = 1;
402 
403 	/* look at every node in this cell */
404 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
405 	{
406 		ni->temp1 = 0;
407 
408 		/* not interested in passive nodes (ports electrically shorted) */
409 		j = 0;
410 		lastpp = ni->proto->firstportproto;
411 		if (lastpp == NOPORTPROTO) continue;
412 		for(pp = lastpp->nextportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
413 			if (pp->network != lastpp->network) j++;
414 		if (j == 0) continue;
415 
416 		/* all remaining nodes have at least two distinct ports */
417 		ni->temp1 = schem_ref++;
418 
419 		/* reset flag for output port */
420 		outpp = NOPORTPROTO;
421 
422 		nodetype = sim_silostype(ni);
423 		switch (nodetype)
424 		{
425 			case SILOSCELL:		/* Complex cell uses instance name */
426 				sim_sendtosil(x_("("));
427 				sim_sendtosil(sim_silname(ni));
428 				sim_sendtosil(x_(" "));
429 				sim_sendtosil(sim_silproto(ni, FALSE));	/* write the type */
430 
431 				/* write the rest of the port(s), connected or not */
432 				cnp = contentsview(ni->proto);
433 				if (cnp == NONODEPROTO) cnp = ni->proto;
434 				for(pp = cnp->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
435 				{
436 					ipp = equivalentport(cnp, pp, ni->proto);
437 					if (ipp == NOPORTPROTO) continue;
438 					sim_sendtosil(sim_silportname(top, ni, ipp, np));
439 				}
440 				break;
441 
442 			case SILOSNMOS:
443 			case SILOSPMOS:
444 			case SILOSTFF:
445 			case SILOSDFF:
446 			case SILOSJKFF:
447 			case SILOSSRFF:
448 				/* Transistors and flip-flops need a part number */
449 				sim_sendtosil(sim_silname(ni));
450 				sim_sendtosil(x_(" "));
451 				sim_sendtosil(sim_silproto(ni, FALSE));
452 
453 				/* write the names of the port(s) */
454 				if (nodetype == SILOSTFF || nodetype == SILOSDFF ||
455 					nodetype == SILOSJKFF || nodetype == SILOSSRFF)
456 				{
457 					(void)sim_silwriteflipflop(top, ni, np, nodetype);
458 				} else
459 				{
460 					for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
461 						sim_sendtosil(sim_silportname(top, ni, pp, np));
462 				}
463 				break;
464 
465 			case SILOSCLOCK:
466 			case SILOSSOURCE:
467 				if (!top) ttyputerr(_("WARNING: Global Clock in a sub-cell"));
468 				break;
469 
470 			case SILOSAND:	/* only need positive logic here */
471 			case SILOSOR:
472 			case SILOSXOR:
473 			case SILOSBUF:
474 				/* Gates use their output port as a name */
475 				for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
476 				{
477 					/* write the output signal as the name */
478 					if ((pp->userbits&STATEBITS) == OUTPORT)
479 					{
480 						/* Find the name of the output port */
481 						sim_sendtosil(sim_silportname(top, ni, pp, np));
482 
483 						/* Record that we used it */
484 						outpp = pp;
485 						sim_sendtosil(x_(" "));
486 
487 						/*
488 						 * determine if this proto is negated...
489 						 * find a pi that is connected to this pp
490 						 */
491 						for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
492 							if (pi->proto == pp) break;
493 
494 						/* sim_silnegated handles NOPORTARCINST */
495 						sim_sendtosil(sim_silproto(ni, sim_silnegated(pi)));
496 					}
497 					if (outpp != NOPORTPROTO)	/* found the output name */
498 						break;
499 				}
500 				if (pp == NOPORTPROTO)
501 					ttyputerr(_("Could not find an output connection on %s"), ni->proto->protoname);
502 
503 				/* get the fall and rise times */
504 				sim_sendtosil(sim_silrisetime(ni));
505 				sim_sendtosil(sim_silfalltime(ni));
506 
507 				/* write the rest of the port(s) iff they're connected */
508 				for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
509 				{
510 					if (pp == outpp) continue;	/* already used this port */
511 
512 					/* search for a connection */
513 					for (pi = ni->firstportarcinst; pi != NOPORTARCINST && pi->proto != pp;
514 						pi = pi->nextportarcinst)
515 							;
516 
517 					if (pi != NOPORTARCINST)	/* ... port is connected */
518 						sim_sendtosil(sim_silportname(top, ni, pp, np));
519 				}
520 				break;
521 
522 			case SILOSCAP:
523 				/* find a connected port for the node name */
524 				for (pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
525 				{
526 					/* search for a connection */
527 					for (pi = ni->firstportarcinst; pi != NOPORTARCINST && pi->proto != pp;
528 						pi = pi->nextportarcinst)
529 							;
530 
531 					if (pi != NOPORTARCINST)	/* ...port is connected */
532 						break;			/* out of "for (pp" */
533 				}
534 
535 				if (pp != NOPORTPROTO)	/* ...there is a connection */
536 				{
537 					/* write port name as output */
538 					sim_sendtosil(sim_silportname(top, ni, pp, np));
539 
540 					sim_sendtosil(x_(" "));
541 					sim_sendtosil(sim_silproto(ni, FALSE));
542 
543 					j = sim_silgetcapacitance(ni);
544 					if (j >= 0)
545 					{
546 						(void)esnprintf(line, 100, x_(" %ld"), j);
547 						sim_sendtosil(line);
548 					} else
549 						ttyputerr(_("Warning: capacitor with no value"));
550 				}
551 				break;
552 
553 			case SILOSRES:	/* sorry! can't handle the resistive gate yet */
554 			default:	/* some compilers may not like this empty default */
555 				break;
556 		}
557 		sim_sendtosil(x_("\n"));
558 	}
559 }
560 
561 /*
562  * Find a name to write for the port prototype, pp, on the node instance, ni
563  * The node instance is located within the prototype, np
564  * If there is an arc connected to the port, use the net name, or NETn.
565  * If there are more than one arc (that are not electrically connected)
566  * on the port, concatenate the names (with spaces between them).
567  * If there is no arc, but the port is an export, use the exported name.
568  * If the port is a power or ground port, ignore it
569  * If this is not the top level cell (ie. a .macro) remove [] notation.
570  */
sim_silportname(BOOLEAN top,NODEINST * ni,PORTPROTO * pp,NODEPROTO * np)571 CHAR *sim_silportname(BOOLEAN top, NODEINST *ni, PORTPROTO *pp, NODEPROTO *np)
572 {
573 	REGISTER PORTPROTO *epp;
574 	REGISTER PORTARCINST *pi;
575 	REGISTER PORTEXPINST *pe;
576 	REGISTER ARCINST *ai = NOARCINST;
577 	CHAR *portname;
578 	BOOLEAN noarcs;
579 	REGISTER void *infstr;
580 
581 	if (portispower(pp) || portisground(pp)) return(x_(""));
582 
583 	infstr = initinfstr();
584 
585 	noarcs = TRUE;
586 
587 	/* find all portarcinsts that are connected to this pp */
588 	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
589 	{
590 		if (pi->proto == pp)	/* if this pi is connected */
591 		{
592 			/* found an arc */
593 			noarcs = FALSE;
594 
595 			/* if an input connection has a bubble, negate the signal */
596 			if (sim_silnegated(pi) && ((pp->userbits&STATEBITS) == INPORT))
597 				addstringtoinfstr(infstr, x_(" -")); else
598 					addtoinfstr(infstr, ' ');
599 
600 			/* find the arc connected to this pi */
601 			ai = pi->conarcinst;
602 			if (ai != NOARCINST)
603 			{
604 				/*
605 				 * get the name...
606 				 * this is either the network name, or of the form NETn
607 				 */
608 				if (top)
609 					addstringtoinfstr(infstr, sim_silspecials(sim_silarcname(ai))); else
610 						addstringtoinfstr(infstr, sim_sil_isaport(np, sim_silspecials(sim_silarcname(ai))));
611 			} else /* this is a database error, and won't ever occur */
612 			{
613 				ttyputerr(_("Error: there is a PORTARCINST without a CONARCINST"));
614 				return(x_(""));
615 			}
616 
617 			/* if PORTISOLATED, then there may be more unconnected arcs */
618 			/* otherwise, break out of for loop */
619 			if (pp->userbits&PORTISOLATED) continue;
620 			break;		/* out of "for (pi..." */
621 		}
622 	}
623 
624 	/* if this is the top cell and we didn't find an arc */
625 	if (top && noarcs)
626 	{
627 		/* search for an export */
628 		for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
629 		{
630 			if (pe->proto == pp)	/* this port is an export */
631 			{
632 				addtoinfstr(infstr, ' ');
633 
634 				/* write the export name */
635 				epp = pe->exportproto;
636 				if (epp->network->namecount > 0)
637 				{
638 					if (top) addstringtoinfstr(infstr, sim_silspecials(networkname(epp->network, 0))); else
639 						addstringtoinfstr(infstr, sim_sil_isaport(np, sim_silspecials(networkname(epp->network, 0))));
640 				} else	/* this would be a database error - won't happen */
641 				{
642 					ttyputerr(_("Error: there is a net on an export, but no net name"));
643 					return(x_(""));
644 				}
645 				break;	/* out of "for (pe..." */
646 			}
647 		}
648 	}
649 
650 	/* get the name that we've just built */
651 	portname = returninfstr(infstr);
652 
653 	/* nothing connected to this port...leave a position */
654 	if (portname[0] == '\0') return(x_(" .SKIP"));
655 	return(portname);
656 }
657 
658 /*
659  * routine to return a string describing the SILOS part name of nodeinst
660  * "ni"
661  */
sim_silname(NODEINST * ni)662 CHAR *sim_silname(NODEINST *ni)
663 {
664 	static CHAR name[100];
665 	REGISTER VARIABLE *var;
666 	static INTBIG SIM_silos_node_name_key = 0;
667 
668 	if (SIM_silos_node_name_key == 0)
669 		SIM_silos_node_name_key = makekey(x_("SIM_silos_node_name"));
670 	var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, SIM_silos_node_name_key);
671 	if (var != NOVARIABLE) return((CHAR *)var->addr);
672 	var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
673 	if (var != NOVARIABLE)
674 	{
675 		estrcpy(name, (CHAR *)var->addr);
676 		if (isalpha(name[0])) return(name);
677 		if (name[0] == '[') return(sim_convertsub(name));
678 	}
679 	(void)esnprintf(name, 100, x_("U%ld"), ni->temp1);
680 	return(name);
681 }
682 
683 /*
684  * routine to return a string describing the SILOS type of nodeinst "ni"
685  * if 'neg' is true, then the negated version is needed
686  */
sim_silproto(NODEINST * ni,BOOLEAN neg)687 CHAR *sim_silproto(NODEINST *ni, BOOLEAN neg)
688 {
689 	REGISTER INTBIG f;
690 	static CHAR name[100];
691 
692 	/* cells use their real name */
693 	if (ni->proto->primindex == 0)
694 	{
695 		esnprintf(name, 100, x_("%s"), sim_siltext(ni->proto->protoname));
696 		if (estrlen(name) > MAXNAME) name[MAXNAME] = 0;
697 		return(name);
698 	}
699 
700 	f = sim_silostype(ni);
701 	switch (f)
702 	{
703 		case SILOSNMOS:
704 			return(x_(".NMOS"));
705 		case SILOSPMOS:
706 			return(x_(".PMOS"));
707 		case SILOSBUF:
708 		case SILOSINV:
709 			if (neg) return(x_(".INV"));
710 			return(x_(".BUF"));
711 		case SILOSXOR:
712 			if (neg) return(x_(".XNOR"));
713 			return(x_(".XOR"));
714 		case SILOSAND:
715 			if (neg) return(x_(".NAND"));
716 			return(x_(".AND"));
717 		case SILOSOR:
718 			if (neg) return(x_(".NOR"));
719 			return(x_(".OR"));
720 		case SILOSRES:
721 			return(x_(".RES"));
722 		case SILOSCAP:
723 			return(x_(".CAP"));
724 		case SILOSJKFF:
725 			if ((ni->userbits&FFCLOCK) == FFCLOCKN) return(x_(".JKNEFF"));
726 			return(x_(".JKPEFF"));
727 		case SILOSDFF:
728 			if ((ni->userbits&FFCLOCK) == FFCLOCKN) return(x_(".DNEFF"));
729 			return(x_(".DPEFF"));
730 		case SILOSSRFF:
731 			if ((ni->userbits&FFCLOCK) == FFCLOCKN) return(x_(".SRNEFF"));
732 			return(x_(".SRPEFF"));
733 		case SILOSTFF:
734 			if ((ni->userbits&FFCLOCK) == FFCLOCKN) return(x_(".TNEFF"));
735 			return(x_(".TPEFF"));
736 	}
737 	return(sim_siltext(ni->proto->protoname));
738 }
739 
740 /*
741  * routine to replace all non-printing characters
742  * in the string "p" with the letter "X" and return the string
743  * We will not permit a digit in the first location; replace it
744  * with '_'
745  */
sim_siltext(CHAR * p)746 CHAR *sim_siltext(CHAR *p)
747 {
748 	REGISTER CHAR *t;
749 	REGISTER void *infstr;
750 
751 	for(t = p; *t != 0; t++) if (!isprint(*t)) break;
752 	if (*t == 0 && (!isdigit(*p))) return(p);
753 
754 	infstr = initinfstr();
755 	if (isdigit(*p)) addtoinfstr(infstr, '_');
756 	for(t = p; *t != 0; t++)
757 		if (isprint(*t)) addtoinfstr(infstr, *t); else
758 			addtoinfstr(infstr, '_');
759 	return(returninfstr(infstr));
760 }
761 
762 /* Write to the .sil file, but break into printable lines */
763 
sim_sendtosil(CHAR * str)764 void sim_sendtosil(CHAR *str)
765 {
766 	static INTBIG count = 0;
767 	INTBIG i;
768 
769 	if (*str == '\n') count = 0;
770 	if ((count + (i = estrlen(str))) > MAXSTR)
771 	{
772 		if (*str == '$')
773 		{
774 			xprintf(sim_silfile, x_("\n"));
775 			count = 0;
776 		} else
777 		{
778 			xprintf(sim_silfile, x_("\n+"));
779 			count = 1;
780 		}
781 	}
782 	xprintf(sim_silfile, x_("%s"), str);
783 	count += i;
784 	return;
785 }
786 
787 /*
788  * routine to return the name of arc "ai" (either its network name or
789  * a generated name
790  */
sim_silarcname(ARCINST * ai)791 CHAR *sim_silarcname(ARCINST *ai)
792 {
793 	static CHAR line[50];
794 
795 	if (ai->network->namecount > 0) return(networkname(ai->network, 0));
796 	if (ai->network->temp1 == 0) ai->network->temp1 = sim_pseudonet++;
797 	(void)esnprintf(line, 50, x_("NET%ld"), ai->network->temp1);
798 	return(line);
799 }
800 
801 /* Function to determine if this end of the connecting arc is negated */
sim_silnegated(PORTARCINST * pi)802 BOOLEAN sim_silnegated(PORTARCINST *pi)
803 {
804 	REGISTER ARCINST *ai;
805 	INTBIG thisend;
806 
807 	if (pi == NOPORTARCINST) return(FALSE);
808 
809 	ai = pi->conarcinst;
810 	if (ai == NOARCINST) return(FALSE);
811 	if ((ai->userbits&ISNEGATED) == 0) return(FALSE);
812 
813 	if (ai->end[0].portarcinst == pi) thisend = 0; else
814 		thisend = 1;
815 	if ((thisend == 0 && (ai->userbits&REVERSEEND) == 0) ||
816 		(thisend == 1 && (ai->userbits&REVERSEEND) != 0)) return(TRUE);
817 	return(FALSE);
818 }
819 
820 /*
821  * function to convert special names to SILOS format
822  */
823 
sim_silspecials(CHAR * str)824 CHAR *sim_silspecials(CHAR *str)
825 {
826 	if (namesamen(str, x_("vdd"), 3) == 0) return(x_(".VDD"));
827 	if (namesamen(str, x_("vss"), 3) == 0) return(x_(".VSS"));
828 	if (namesamen(str, x_("vcc"), 3) == 0) return(x_(".VCC"));
829 	if (namesamen(str, x_("gnd"), 3) == 0) return(x_(".GND"));
830 	if (namesamen(str, x_("low"), 3) == 0) return(x_(".GND"));
831 	if (namesamen(str, x_("hig"), 3) == 0) return(x_(".VDD"));
832 	return(str);
833 }
834 
835 /*
836  * Function to return the SILOS type of a node
837  * Read the contents of the added string, make it available to
838  * the caller
839  */
sim_silostype(NODEINST * ni)840 INTBIG sim_silostype(NODEINST *ni)
841 {
842 	INTBIG func;
843 
844 	if (ni->proto->primindex == 0) return(SILOSCELL);
845 
846 	func = nodefunction(ni);
847 	switch(func)
848 	{
849 		case NPTRAPMOS:
850 		case NPTRA4PMOS:
851 			return(SILOSPMOS);
852 		case NPTRANMOS:
853 		case NPTRA4NMOS:
854 			return(SILOSNMOS);
855 		case NPGATEAND:
856 			return(SILOSAND);
857 		case NPGATEOR:
858 			return(SILOSOR);
859 		case NPGATEXOR:
860 			return(SILOSXOR);
861 		case NPBUFFER:
862 			return(SILOSBUF);
863 		case NPRESIST:
864 			return(SILOSRES);
865 		case NPCAPAC:
866 			return(SILOSCAP);
867 		case NPFLIPFLOP:	/* We will decode further here */
868 			switch (ni->userbits&FFTYPE)
869 			{
870 				case FFTYPERS: return(SILOSSRFF);
871 				case FFTYPEJK: return(SILOSJKFF);
872 				case FFTYPED:  return(SILOSDFF);
873 				case FFTYPET:  return(SILOSTFF);
874 			}
875 			return(SILOSDFF);
876 		case NPSOURCE:
877 			return(SILOSCLOCK);
878 		case NPMETER:
879 			return(SILOSOUT);
880 		default:
881 			return(SILOSUNKNOWN);
882 		}
883 }
884 
885 /*
886  * This function returns a string containing the rise time, as stored in
887  * the variable SIM_rise_delay on node instance ni.
888  * SIM_rise_delay can be multiple numbers (e.g. "rise_time,fanout")
889  * This function returns a string.
890  * A space is inserted as the first character in the string.
891  * Returns an empty string if no variable found.
892  */
sim_silrisetime(NODEINST * ni)893 CHAR *sim_silrisetime(NODEINST *ni)
894 {
895 	REGISTER VARIABLE *var;
896 	static INTBIG SIM_sil_risetime_key = 0;
897 	static CHAR s[80];
898 
899 	if (SIM_sil_risetime_key == 0)
900 		SIM_sil_risetime_key = makekey(x_("SIM_rise_delay"));
901 	var = getvalkey((INTBIG)ni, VNODEINST, -1, SIM_sil_risetime_key);
902 	if (var != NOVARIABLE)
903 	{
904 		if ((var->type&VTYPE) == VINTEGER)
905 		{
906 			(void)esnprintf(s, 80, x_(" %ld"), var->addr);
907 			return(s);
908 		}
909 		if ((var->type&VTYPE) == VSTRING)
910 		{
911 			(void)esnprintf(s, 80, x_(" %s"), (CHAR *)var->addr);
912 			return(s);
913 		}
914 	}
915 	return(x_(""));
916 }
917 
918 /*
919  * This function returns a string containing the fall time, as stored in
920  * the variable SIM_fall_delay on node instance ni.
921  * SIM_fall_delay can be either an integer or a string
922  * (e.g. "fall_time,fanout")
923  * This function returns a string.
924  * A space is inserted as the first character in the string.
925  * Returns an empty string if no variable found.
926  */
sim_silfalltime(NODEINST * ni)927 CHAR *sim_silfalltime(NODEINST *ni)
928 {
929 	REGISTER VARIABLE *var;
930 	static INTBIG SIM_sil_falltime_key = 0;
931 	static CHAR s[80];
932 
933 	if (SIM_sil_falltime_key == 0)
934 		SIM_sil_falltime_key = makekey(x_("SIM_fall_delay"));
935 	var = getvalkey((INTBIG)ni, VNODEINST, -1, SIM_sil_falltime_key);
936 	if (var != NOVARIABLE)
937 	{
938 		if ((var->type&VTYPE) == VINTEGER)
939 		{
940 			(void)esnprintf(s, 80, x_(" %ld"), var->addr);
941 			return(s);
942 		}
943 		if ((var->type&VTYPE) == VSTRING)
944 		{
945 			(void)esnprintf(s, 80, x_(" %s"), (CHAR *)var->addr);
946 			return(s);
947 		}
948 	}
949 	return(x_(""));
950 }
951 
952 /*
953  * Function to return an integer as the capacitance defined
954  * by "SCHEM_capacitance" variable on an instance of a capacitor.
955  * The returned units are in microfarads (is this right?).
956  * Return -1 if nothing found.
957  */
sim_silgetcapacitance(NODEINST * ni)958 INTBIG sim_silgetcapacitance(NODEINST *ni)
959 {
960 	REGISTER VARIABLE *var;
961 	float farads;
962 	INTBIG microfarads;
963 
964 	var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_capacitancekey);
965 	if (var != NOVARIABLE)
966 	{
967 		farads = (float)eatof(describesimplevariable(var));
968 		microfarads = eatoi(displayedunits(farads, VTUNITSCAP, INTCAPUNITUFARAD));
969 		return(microfarads);
970 	}
971 	return(-1);
972 }
973 
974 /*
975  * Function to write the ports of a flip-flop;
976  * get them in the Electric order, then rewrite them
977  * 'ni' is the current NODEINST, found in 'np' cell
978  */
979 #define JORD 0
980 #define K	 1
981 #define Q	 2
982 #define QB   3
983 #define CK	 4
984 #define PRE  5
985 #define CLR  6
sim_silwriteflipflop(BOOLEAN top,NODEINST * ni,NODEPROTO * np,INTBIG type)986 void sim_silwriteflipflop(BOOLEAN top, NODEINST *ni, NODEPROTO *np, INTBIG type)
987 {
988 	REGISTER PORTPROTO *pp;
989 	CHAR line[8][50], out[100];
990 	INTBIG i;
991 
992 	for(pp = ni->proto->firstportproto, i=0; pp != NOPORTPROTO && i < 7; pp = pp->nextportproto, i++)
993 	{
994 		/* find arcs on this port */
995 		(void)esnprintf(line[i], 50, x_(" %s"), sim_silportname(top, ni, pp, np));
996 	}
997 	if (namesamen(line[PRE], x_(" .SKIP"), 4) == 0 && namesamen(line[CLR], x_(" .SKIP"), 4) == 0)
998 	{
999 		*line[CLR] = 0;		/* If neither on, don't print */
1000 		*line[PRE] = 0;
1001 	}
1002 	if (type == SILOSDFF) (void)esnprintf(out, 100, x_("%s%s%s%s /%s%s"),
1003 		line[CK], line[JORD], line[PRE], line[CLR], line[Q], line[QB]); else
1004 			(void)esnprintf(out, 100, x_("%s%s%s%s%s /%s%s"), line[CK], line[JORD],
1005 				line[K], line[PRE], line[CLR], line[Q], line[QB]);
1006 	sim_sendtosil(out);
1007 }
1008 
1009 /* Function to check if a port of an instance is connected to one of
1010 the ports of the containing instance. If so, get rid of the '[]' format;
1011 replace '[' with '__', ignore ']'.
1012 */
sim_sil_isaport(NODEPROTO * np,CHAR * portname)1013 CHAR *sim_sil_isaport(NODEPROTO *np, CHAR *portname)
1014 {
1015 	REGISTER PORTPROTO *pp;
1016 
1017 	if (estrchr(portname, '[') == NULL) return(portname);		/* no references anyhow */
1018 	pp = getportproto(np, portname);
1019 	if (pp != NOPORTPROTO) return(sim_convertsub(portname));
1020 	return(portname);
1021 }
1022 
1023 /* replace subscripted name with __ format */
sim_convertsub(CHAR * string)1024 static CHAR *sim_convertsub(CHAR *string)
1025 {
1026 	CHAR *ptr;
1027 	static CHAR newname[100];
1028 
1029 	for (ptr = newname; *string; string++)
1030 	{
1031 		if (*string == '[')
1032 		{
1033 			estrcpy(ptr, x_("__"));
1034 			ptr+=2;
1035 		} else if (*string == ']')
1036 		{
1037 			continue;
1038 		} else
1039 		{
1040 			*ptr = *string;
1041 			ptr++;
1042 		}
1043 	}
1044 	*ptr = 0;
1045 	return(newname);
1046 }
1047 
1048 #endif	/* SIMTOOL - at top */
1049