1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: simtexsim.c
6  * Simulation tool: TEXSIM output generator
7  * Written by: T.J.Goodman, University of Canterbury, N.Z.
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 "config.h"
33 #if SIMTOOL
34 
35 #include "global.h"
36 #include "efunction.h"
37 #include "sim.h"
38 #include "tecschem.h"
39 
40 #define MAXLENGTH 80
41 #define MAXNAMECHARS 12
42 #define NPGATENOR -NPGATEOR
43 #define NPGATENXOR -NPGATEXOR
44 #define NPGATENAND -NPGATEAND
45 #define NULLSTR x_("")
46 
47 #define RESFILE x_("reservedwords.dat")			/* optional used to check for reserved words */
48 
49 static FILE *sim_texfile, *reservefile;
50 
51 /* prototypes for local routines */
52 static void         sim_writetexcell(NODEPROTO*, INTBIG);
53 static CHAR        *sim_textdlpower(NODEINST*, INTBIG, INTBIG*, INTBIG*, INTBIG*);
54 static INTBIG       sim_texcountwires(NODEINST*);
55 static CHAR        *sim_texsrcname(NODEINST*, PORTARCINST*);
56 static CHAR        *sim_texwritesignals(NODEINST*, INTBIG, INTBIG*);
57 static CHAR        *sim_texwriteffsignals(NODEINST*, INTBIG*);
58 static CHAR        *sim_textracesignal(PORTARCINST*, NODEINST*);
59 static void         sim_texwriteinv(PORTARCINST*, CHAR*, CHAR*);
60 static CHAR        *sim_textdlinst(NODEINST*, INTBIG);
61 static void         sim_texerror(INTBIG, INTBIG*, CHAR*);
62 static void         sim_texstrprint(CHAR*);
63 static CHAR        *sim_texname(CHAR*);
64 static CHAR        *sim_texproto(NODEINST*, INTBIG, INTBIG*);
65 static CHAR        *sim_texffname(NODEINST*, INTBIG*);
66 static CHAR        *sim_texgetdelay(NODEINST*, INTBIG);
67 static BOOLEAN      sim_texnegatedoutput(NODEINST*);
68 static CHAR        *sim_texlibname(NODEPROTO*);
69 static PORTARCINST *sim_oppendpai(PORTARCINST*);
70 static NODEINST    *sim_oppendni(PORTARCINST*);
71 static BOOLEAN      sim_texcheckname(CHAR*);
72 static INTBIG       sim_strcspn(CHAR *str, CHAR *set);
73 
sim_writetexnetlist(NODEPROTO * np)74 void sim_writetexnetlist(NODEPROTO *np)
75 {
76 	NODEPROTO *lnp;
77 	REGISTER LIBRARY *lib;
78 	INTBIG length;
79 	CHAR str1[30], filename[200], *libname, *resfilename, *truename;
80 
81 	/* write the "TDL" file */
82 	(void)estrcpy(filename, np->protoname);
83 	(void)estrcat(filename, x_(".tdl"));
84 	sim_texfile = xcreate(filename, sim_filetypetegas, _("TEGAS File"), &truename);
85 	if (sim_texfile == NULL)
86 	{
87 		if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
88 		return;
89 	}
90 
91 	/* read list of reserved words into an infinite string, each separated by "\n" */
92 	reservefile = xopen(RESFILE, sim_filetypetegastab, x_(""), &resfilename);
93 
94 	sim_texstrprint(x_("/* GENERATED BY THE ELECTRIC VLSI DESIGN SYSTEM */\n\n"));
95 	sim_texstrprint(x_("COMPILE  ;\n\n"));
96 
97 	/* get library name, check validity */
98 	estrcpy(str1, x_("DIRECTORY:  "));
99 	libname = sim_texlibname(np);
100 
101 	length = estrlen(libname);
102 	if (length > 12)
103 	{
104 		ttyputmsg(_("Library name exceeds 12 characters, The name used for the"));
105 		ttyputmsg(_("TDL directory will be truncated to :- %s"), sim_texname(libname));
106 	}
107 
108 	/* check library name */
109 	if (sim_texcheckname(sim_texname(libname)))
110 		estrcat(str1, sim_texname(libname)); else
111 	{
112 		ttyputerr(_("%s IS A RESERVED WORD, RENAME LIBRARY AND RE-RUN"), sim_texname(libname));
113 		return;
114 	}
115 
116 	/* write "directory line" to file */
117 	sim_texstrprint(str1);
118 	xprintf(sim_texfile, x_(" ;\n\n"));
119 
120 	sim_texstrprint(x_("OPTIONS:   REPLACE  ;\n\n"));
121 
122 	/* reset flags for cells that have been written */
123 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
124 		for(lnp = lib->firstnodeproto; lnp != NONODEPROTO; lnp = lnp->nextnodeproto)
125 			lnp->temp1 = lnp->temp2 = 0;
126 
127 	/* write TDL descriptions into file */
128 	sim_writetexcell(np, 1);
129 
130 	sim_texstrprint(x_(" END COMPILE;\n\n "));
131 
132 	/* close files */
133 	if (reservefile != NULL) xclose(reservefile);
134 	xclose(sim_texfile);
135 
136 	ttyputmsg(_("%s written"), truename);
137 }
138 
sim_writetexcell(NODEPROTO * np,INTBIG top)139 void sim_writetexcell(NODEPROTO *np, INTBIG top)
140 {
141 	PORTPROTO *pp, *xpp;
142 	NODEINST *ni, *nextni;
143 	ARCINST *ai;
144 	CHAR str1[MAXLENGTH], *ptr;
145 	INTBIG inputs, nextniinputs, ninegated, nextninegated, f, x, separator,
146 		count, length, tempa, tempb, module_err=0;
147 	INTBIG pwr=0, gnd=0;
148 	REGISTER void *infstr;
149 	Q_UNUSED( top );
150 
151 	/* recurse on sub-cels first */
152 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
153 	{
154 		if (ni->proto->primindex != 0) continue;
155 		if (ni->proto->temp1 != 0) continue;
156 
157 		/* ignore recursive references (showing icon in contents) */
158 		if (isiconof(ni->proto, np)) continue;
159 
160 		sim_writetexcell(ni->proto, 0);
161 	}
162 
163 	/* mark this node written */
164 	np->temp1++;
165 
166 	/* MODULE */
167 	sim_texstrprint(x_("MODULE:  "));
168 	sim_texstrprint(sim_texname(describenodeproto(np)));
169 	sim_texstrprint(x_(";\n\n"));
170 
171 	/* INPUTS */
172 	if (np->firstportproto != NOPORTPROTO)
173 	{
174 		infstr = initinfstr();
175 		addstringtoinfstr(infstr, x_("INPUTS:\n"));
176 
177 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
178 		{
179 			if (!sim_texcheckname(sim_texname(pp->protoname)))
180 				sim_texerror(11, &module_err, sim_texname(pp->protoname));
181 
182 			pp->temp1 = pp->temp2 = 0;
183 			if ((pp->userbits&STATEBITS) == INPORT)
184 			{
185 				addstringtoinfstr(infstr, x_("   "));
186 				addstringtoinfstr(infstr, sim_texname(pp->protoname));
187 				addstringtoinfstr(infstr, x_("\n"));
188 				pp->temp1 = 1;
189 			}
190 		}
191 		addstringtoinfstr(infstr, x_(";\n\n"));
192 		sim_texstrprint(returninfstr(infstr));
193 
194 		/* OUTPUTS */
195 		infstr = initinfstr();
196 		addstringtoinfstr(infstr, x_("OUTPUTS:\n"));
197 
198 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
199 		{
200 			if ((pp->userbits&STATEBITS) == OUTPORT)
201 			{
202 				addstringtoinfstr(infstr, x_("   "));
203 				addstringtoinfstr(infstr, sim_texname(pp->protoname));
204 				addstringtoinfstr(infstr, x_("\n"));
205 				pp->temp1 = 1;
206 			}
207 			if (pp->temp1 == 0) sim_texerror(2, &module_err, pp->protoname);
208 		}
209 		addstringtoinfstr(infstr, x_(";\n\n"));
210 		sim_texstrprint(returninfstr(infstr));
211 	}
212 
213 	/* USE */
214 	infstr = initinfstr();
215 	addstringtoinfstr(infstr, x_("USE:\n\n"));  /* write USE: */
216 
217 	for(ni = np->firstnodeinst, ni->temp2=0; ni != NONODEINST; ni = ni->nextnodeinst)
218 	{
219 		if (ni->temp1 != 0) continue;
220 		ni->temp1++;	     /* mark node seen */
221 		f = nodefunction(ni);
222 
223 		switch(f)
224 		{
225 			case NPGATEAND:
226 			case NPGATEOR:
227 			case NPGATEXOR:
228 				/* Determine whether node should be NAND, NOR or NXOR */
229 				if (sim_texnegatedoutput(ni))
230 				{
231 					x = -f;
232 					ninegated = TRUE;
233 				} else
234 				{
235 					ninegated = FALSE;
236 					x = f;
237 				}
238 
239 				/* Count number of inputs */
240 				if ((inputs = sim_texcountwires(ni)) < 2)
241 					sim_texerror(9, &module_err, sim_texname(describenodeproto(ni->proto)));
242 				for(nextni = ni->nextnodeinst; nextni != NONODEINST; nextni = nextni->nextnodeinst)
243 				{
244 					/* look at similar nodes */
245 					if (nextni->proto != ni->proto) continue;
246 
247 					/* Determine whether next node should be NAND, NOR or NXOR */
248 					if (sim_texnegatedoutput(nextni))
249 						nextninegated = TRUE;    /* negated port/arc ? */
250 							else nextninegated = FALSE;
251 
252 					/* Count number of inputs on next node*/
253 					nextniinputs = sim_texcountwires(nextni);
254 
255 					/* Compare current node and next node, If next node is the same  */
256 					/* mark it seen */
257 					if (nextniinputs == inputs && ninegated == nextninegated)
258 						nextni->temp1++;
259 				}
260 
261 				/* Write USE description for current node */
262 				switch (x)
263 				{
264 					case NPGATEAND:
265 						(void)esnprintf(str1, MAXLENGTH, x_("  %ld-AND = AND(%ld,1),\n"),
266 							inputs, inputs);
267 						break;
268 					case NPGATEOR:
269 						(void)esnprintf(str1, MAXLENGTH, x_("  %ld-OR = OR(%ld,1),\n"),
270 							inputs, inputs);
271 						break;
272 					case NPGATEXOR:
273 						(void)esnprintf(str1, MAXLENGTH, x_("  %ld-XOR = XOR(%ld,1),\n"),
274 							inputs, inputs);
275 						break;
276 					case NPGATENAND:
277 						(void)esnprintf(str1, MAXLENGTH, x_("  %ld-NAND = NAND(%ld,1),\n"),
278 							inputs, inputs);
279 						break;
280 					case NPGATENOR:
281 						(void)esnprintf(str1, MAXLENGTH, x_("  %ld-NOR = NOR(%ld,1),\n"),
282 							inputs, inputs);
283 						break;
284 					case NPGATENXOR:
285 						(void)esnprintf(str1, MAXLENGTH, x_("  %ld-NXOR = NXOR(%ld,1),\n"),
286 							inputs, inputs);
287 						break;
288 				}
289 				addstringtoinfstr(infstr, str1);
290 				break; /* end of switch option */
291 
292 			case NPSOURCE:
293 			case NPRESIST:
294 			case NPCAPAC:
295 			case NPDIODE:
296 			case NPINDUCT:
297 			case NPMETER:
298 				sim_texerror(4, &module_err, sim_texname(describenodeproto(ni->proto)));
299 				break;
300 
301 			/*  This case can either be for an existing  user defined module in this */
302 			/*  directory or for a module from the MASTER directory */
303 			case NPUNKNOWN:
304 				/* ignore recursive references (showing icon in contents) */
305 				if (isiconof(ni->proto, np)) continue;
306 				addstringtoinfstr(infstr, x_("  "));
307 				addstringtoinfstr(infstr, sim_texproto(ni, f, &module_err));
308 				addstringtoinfstr(infstr, x_(" = "));
309 				addstringtoinfstr(infstr, sim_texproto(ni, f, &module_err));
310 				addstringtoinfstr(infstr, x_("///"));
311 				length = estrlen(describenodeproto(ni->proto));
312 
313 				/* if there is a separator, directory name comes after it */
314 				if ((separator = sim_strcspn(describenodeproto(ni->proto), x_("/"))) != length)
315 					addstringtoinfstr(infstr, sim_texname(
316 						describenodeproto(ni->proto) + separator + 1)); else
317 
318 				/* no separator, hence directory name = library name */
319 				addstringtoinfstr(infstr, sim_texlibname(ni->proto));
320 				addstringtoinfstr(infstr, x_(",\n"));
321 
322 				/* if another node is the same as this one mark it seen */
323 				for(nextni = ni->nextnodeinst; nextni != NONODEINST; nextni = nextni->nextnodeinst)
324 					if (nextni->proto == ni->proto) nextni->temp1++;
325 
326 				break; /* from  switch */
327 			default: break;
328 		} /* end of switch */
329 	} /* end of for */
330 
331 	/* get USE string, replace last ',' with a ';' and write to TDL file */
332 	ptr = returninfstr(infstr);
333 	length = estrlen(ptr);
334 	*(ptr+length-2) = ';';
335 	sim_texstrprint(ptr);
336 	sim_texstrprint(x_("\n"));
337 
338 	/* DEFINE */
339 	sim_texstrprint(x_("DEFINE:\n"));
340 
341 	/* count no. of inverters (negated arcs not attached to logic primitives */
342 	count = 1;
343 	for (ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
344 	{
345 		if ((ai->userbits&ISNEGATED) == 0) continue;
346 		if ((ai->end[0].portarcinst->proto->userbits&STATEBITS) == OUTPORT)
347 		{
348 			f = nodefunction(ai->end[0].nodeinst);
349 			if (f == NPGATEAND || f == NPGATEOR || f == NPGATEXOR || f == NPBUFFER)
350 				ai->temp1 = -1; else ai->temp1 = count++;
351 		} else if ((ai->end[1].portarcinst->proto->userbits&STATEBITS) == OUTPORT)
352 		{
353 			f = nodefunction(ai->end[1].nodeinst);
354 			if (f == NPGATEAND || f == NPGATEOR || f == NPGATEXOR || f == NPBUFFER)
355 				ai->temp1 = -1; else ai->temp1 = count++;
356 		} else ai->temp1 = count++;
357 
358 		/* Check to ensure at least one end of negated arc is attached to functional */
359 		/* node */
360 		tempb = ai->end[1].portarcinst->proto->userbits&STATEBITS;
361 		tempa = ai->end[0].portarcinst->proto->userbits&STATEBITS;
362 
363 		if ((tempa&(INPORT|OUTPORT)) == 0 && (tempb&(INPORT|OUTPORT)) == 0)
364 			sim_texerror(3, &module_err, NULLSTR);
365 	}
366 
367 	for (ni = np->firstnodeinst, count=1; ni != NONODEINST; ni = ni->nextnodeinst)
368 	{
369 		ni->temp1 = 0;
370 		f = nodefunction(ni);
371 
372 		/* handle nodeinst descriptions */
373 		switch(f)
374 		{
375 			case NPPIN:
376 			case NPART:
377 				break;
378 
379 			case NPCONPOWER:
380 			case NPCONGROUND:
381 				sim_texstrprint(sim_textdlpower(ni, f, &pwr, &gnd, &module_err));
382 				break;
383 
384 			case NPUNKNOWN:
385 				/* ignore recursive references (showing icon in contents) */
386 				if (isiconof(ni->proto, np)) continue;
387 				/* FALLTHROUGH */
388 			case NPTRANS:
389 			case NPGATEXOR:
390 			case NPGATEAND:
391 			case NPGATEOR:
392 			case NPBUFFER:
393 			case NPFLIPFLOP:
394 				ni->temp2 = count++;
395 				estrcpy(str1, sim_textdlinst(ni, f));
396 				estrcat(str1, x_(" = "));
397 				estrcat(str1, sim_texproto(ni, f, &module_err));
398 				estrcat(str1, sim_texwritesignals(ni, f, &module_err));
399 				estrcat(str1, sim_texgetdelay(ni, f));
400 				sim_texstrprint(str1);
401 				sim_texstrprint(x_(";\n"));
402 				break;
403 
404 			default:
405 				sim_texerror(4, &module_err, describenodeproto(ni->proto));
406 				break;
407 		}
408 	}
409 
410 	/* any ports on the same network in the cell have to be made equivalent points */
411 	/* in the tdl description */
412 	for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
413 	{
414 		if (pp->temp2 != 0) continue;
415 		for(xpp = pp->nextportproto; xpp != NOPORTPROTO; xpp = xpp->nextportproto)
416 		{
417 			if (xpp->network != pp->network) continue;
418 			if (xpp->temp2 != 0) continue;
419 			sim_texstrprint(sim_texname(pp->protoname));
420 			sim_texstrprint(x_(" &= "));
421 			sim_texstrprint(sim_texname(xpp->protoname));
422 			sim_texstrprint(x_(";\n\n"));
423 			xpp->temp2++;
424 		}
425 		pp->temp2++;
426 	}
427 
428 	/* end module */
429 	sim_texstrprint(x_(" END MODULE;\n\n"));
430 
431 	/* if compiled correctly then reset variable */
432 	if (module_err != 0) ttyputerr(_("*** Errors in module %s"),
433 		sim_texname(describenodeproto(np)));
434 }
435 
sim_textdlpower(NODEINST * ni,INTBIG f,INTBIG * pwr,INTBIG * gnd,INTBIG * module_err)436 CHAR *sim_textdlpower(NODEINST *ni, INTBIG f, INTBIG *pwr, INTBIG *gnd, INTBIG *module_err)
437 {
438 	static CHAR str[20];
439 
440 	/* To prevent Un-connected power nodes */
441 	if (ni->firstportarcinst == NOPORTARCINST)
442 	{
443 		sim_texerror(7, module_err, NULLSTR);
444 		return(x_(""));
445 	}
446 
447 	if (f == NPCONGROUND && *gnd != 1)
448 	{
449 		esnprintf(str, 20, x_("NET%ld = GRND;\n"), (INTBIG)ni->firstportarcinst->conarcinst->network);
450 		*gnd = 1;
451 		return(str);
452 	}
453 
454 	if (f == NPCONPOWER && *pwr != 1)
455 	{
456 		esnprintf(str, 20, x_("NET%ld = PWR;\n"), (INTBIG)ni->firstportarcinst->conarcinst->network);
457 		*pwr = 1;
458 		return(str);
459 	}
460 
461 	return(x_(""));
462 }
463 
464 /* routine to count the wires on a primitive with only one inport */
sim_texcountwires(NODEINST * ni)465 INTBIG sim_texcountwires(NODEINST *ni)
466 {
467 	INTBIG inputs;
468 	PORTARCINST *pai;
469 	PORTEXPINST *pei;
470 
471 	for(inputs=0, pai = ni->firstportarcinst; pai != NOPORTARCINST; pai = pai->nextportarcinst)
472 		if (pai->proto == ni->proto->firstportproto) inputs++;
473 
474 	for(pei = ni->firstportexpinst; pei != NOPORTEXPINST; pei = pei->nextportexpinst)
475 		if (pei->proto == ni->proto->firstportproto) inputs++;
476 
477 	return(inputs);
478 }
479 
480 /*
481  * a routine to return the name of the network which may be net<x> or the
482  * name of an export on the net
483  */
sim_texsrcname(NODEINST * ni,PORTARCINST * pai)484 CHAR *sim_texsrcname(NODEINST *ni, PORTARCINST *pai)
485 {
486 	PORTPROTO *pp;
487 	INTBIG exp_found=0;
488 	static CHAR str[MAXNAMECHARS + 1];
489 
490 	for(pp = ni->parent->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
491 	{
492 		if (pp->network == pai->conarcinst->network)
493 		{
494 			esnprintf(str, MAXNAMECHARS+1, x_("%s"), sim_texname(pp->protoname));
495 			exp_found++;
496 			break;
497 		}
498 	}
499 	if (exp_found == 0)
500 		esnprintf(str, MAXNAMECHARS+1, x_("NET%ld"), (INTBIG)pai->conarcinst->network);
501 
502 	return(str);
503 }
504 
505 /* a routine to write the sources of signals on the input ports of a nodeinst */
sim_texwritesignals(NODEINST * ni,INTBIG f,INTBIG * module_err)506 CHAR *sim_texwritesignals(NODEINST *ni, INTBIG f, INTBIG *module_err)
507 {
508 	PORTPROTO *pp;
509 	PORTARCINST *pai;
510 	PORTEXPINST *pei;
511 	INTBIG portwired=0, length;
512 	CHAR *string;
513 	REGISTER void *infstr;
514 
515 	if (f == NPFLIPFLOP)
516 		return(sim_texwriteffsignals(ni, module_err));
517 
518 	if (ni->proto->firstportproto != NOPORTPROTO)
519 	{
520 		infstr = initinfstr();
521 		addstringtoinfstr(infstr, x_("("));
522 	} else return(NULLSTR);
523 
524 	for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
525 	{
526 		if((pp->userbits&STATEBITS) != INPORT) continue;
527 
528 		/* The transistor "s" port is treated as an inport by electric but is used */
529 		/* as an outport by TDL */
530 		if (f == NPTRANS && namesamen(pp->protoname, x_("s"), 1) == 0) continue;
531 
532 		/* Buffer primitive has a "c" port not used by TDL */
533 		if (f == NPBUFFER && *pp->protoname == 'c') continue;
534 
535 		portwired = 0;
536 		for(pai = ni->firstportarcinst; pai != NOPORTARCINST; pai = pai->nextportarcinst)
537 		{
538 			if (pai->proto == pp)
539 			{
540 				addstringtoinfstr(infstr, sim_textracesignal(pai, ni));
541 				addstringtoinfstr(infstr, x_(","));
542 				portwired++;
543 
544 				/* if port is not isolated then write one signal only */
545 				if ((pp->userbits&PORTISOLATED) == 0) break;
546 			}
547 		}
548 		for(pei = ni->firstportexpinst; pei != NOPORTEXPINST; pei = pei->nextportexpinst)
549 		{
550 			if (pei->proto == pp)
551 			{
552 				addstringtoinfstr(infstr, sim_texname(pei->exportproto->protoname));
553 				addstringtoinfstr(infstr, x_(","));
554 				portwired++;
555 			}
556 		}
557 		if (portwired == 0)
558 		{
559 			sim_texerror(8, module_err, pp->protoname);
560 			addstringtoinfstr(infstr, x_("NC,"));
561 		}
562 	}
563 	string = returninfstr(infstr);
564 	if (portwired == 0) return(NULLSTR);
565 
566 	/* replace last ',' with a ')' */
567 	length = estrlen(string);
568 	*(string + length - 1) = ')';
569 	*(string+length) = '\0';
570 	return(string);
571 }
572 
573 /*
574  * routine to write the signals in the correct pin order for TDL for flip
575  * flops n.b this is essentially the same as sim_texwritesignals
576  */
sim_texwriteffsignals(NODEINST * ni,INTBIG * module_err)577 CHAR *sim_texwriteffsignals(NODEINST *ni, INTBIG *module_err)
578 {
579 	PORTPROTO *pp;
580 	PORTARCINST *pai;
581 	PORTEXPINST *pei;
582 	CHAR signals[5][MAXNAMECHARS + 1], *string;
583 	CHAR *ptr;
584 	INTBIG x, length;
585 	REGISTER void *infstr;
586 	Q_UNUSED( module_err );
587 
588 	for(pp = ni->proto->firstportproto, x=0; pp != NOPORTPROTO; pp = pp->nextportproto)
589 	{
590 		if((pp->userbits&STATEBITS) == OUTPORT) continue;
591 		ptr = &signals[x++][0];
592 		estrcpy(ptr, x_("NC,"));   /* if no-connection write NC */
593 
594 		for(pai = ni->firstportarcinst; pai != NOPORTARCINST; pai = pai->nextportarcinst)
595 		{
596 			if (pai->proto == pp)
597 			{
598 				estrcpy(ptr,sim_textracesignal(pai, ni));
599 				estrcat(ptr, x_(","));
600 				break;
601 			}
602 		}
603 		for(pei = ni->firstportexpinst; pei != NOPORTEXPINST; pei = pei->nextportexpinst)
604 		{
605 			if (pei->proto == pp)
606 			{
607 				estrcpy(ptr, sim_texname(pei->exportproto->protoname));
608 				estrcat(ptr, x_(","));
609 				break;
610 			}
611 		}
612 	}
613 
614 	/* We now have the signals in 5 arrays ready to be output in the correct */
615 	/* order which is 2,0,1,3,4.If the flip flop is a D or T type don't put */
616 	/* out array[1][]. */
617 	infstr = initinfstr();
618 	addstringtoinfstr(infstr, x_("("));
619 	addstringtoinfstr(infstr, signals[2]);
620 	addstringtoinfstr(infstr, signals[0]);
621 
622 	/* JK and SR have one input more than D or T flip flops */
623 	if ((ni->userbits&FFTYPE) == FFTYPERS || (ni->userbits&FFTYPE) == FFTYPEJK)
624 		addstringtoinfstr(infstr, signals[1]);
625 
626 	addstringtoinfstr(infstr, signals[3]);
627 	addstringtoinfstr(infstr, signals[4]);
628 
629 	string = returninfstr(infstr);
630 	length = estrlen(string);
631 	*(string+length-1) = ')';
632 	return(string);
633 }
634 
635 /*
636  * routine to trace back to the output source supplying a signal to the
637  * portarcinst of a nodeinst
638  */
sim_textracesignal(PORTARCINST * pai,NODEINST * ni)639 CHAR *sim_textracesignal(PORTARCINST *pai, NODEINST *ni)
640 {
641 	static CHAR str[MAXNAMECHARS];
642 
643 	if ((pai->conarcinst->userbits&ISNEGATED) == 0) return(sim_texsrcname(ni, pai));
644 
645 	/* insert an inverter description if a negated arc attached to primitive */
646 	/* other than AND,OR,XOR */
647 	if (pai->conarcinst->temp1 != -1)
648 	{
649 		esnprintf(str, MAXNAMECHARS, x_("I%ld.O"), pai->conarcinst->temp1);
650 		sim_texwriteinv(pai, str, sim_texsrcname(ni, pai));
651 		return(str);
652 	}
653 	return(sim_texsrcname(ni, pai));
654 }
655 
656 /* write out an inverter description for a negated arc */
sim_texwriteinv(PORTARCINST * pai,CHAR * str1,CHAR * str2)657 void sim_texwriteinv(PORTARCINST *pai, CHAR *str1, CHAR *str2)
658 {
659 	static CHAR invstring[MAXNAMECHARS * 4];
660 	CHAR tempstr[MAXNAMECHARS];
661 
662 	if (pai->conarcinst->temp1 == -1) return;
663 
664 	estrcpy(tempstr, sim_texname(str1));
665 	esnprintf(invstring, MAXNAMECHARS*4, x_("I%ld(%s) = NOT(%s);\n"), pai->conarcinst->temp1, tempstr, sim_texname(str2));
666 	sim_texstrprint(invstring);
667 	pai->conarcinst->temp1 = -1; /* write once only */
668 }
669 
670 /*
671  * routine to return a string with the TDL names of the output sources from
672  * this nodeinst. if neccessary arcs that are negated will have inverter
673  * descriptions written.
674  */
sim_textdlinst(NODEINST * ni,INTBIG f)675 CHAR *sim_textdlinst(NODEINST *ni, INTBIG f)
676 {
677 	NODEINST *xni;
678 	PORTARCINST  *xpai, *ppai, *pai;
679 	PORTPROTO   *pp;
680 	PORTEXPINST *pei;
681 	CHAR str1[10], str2[MAXNAMECHARS + 10], *netstr;
682 	INTBIG length, portcount=0, instcount=0;
683 	REGISTER void *infstr;
684 
685 	esnprintf(str1, 10, x_("U%ld"), ni->temp2);
686 	infstr = initinfstr();
687 	addstringtoinfstr(infstr, str1);
688 	addstringtoinfstr(infstr, x_("("));
689 
690 	for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
691 	{
692 		if (((pp->userbits&STATEBITS) == INPORT) && f != NPTRANS) continue;
693 		if (f == NPTRANS && namesamen(pp->protoname, x_("g"), 1) == 0) continue;
694 
695 		portcount++;
696 		for(pai = ni->firstportarcinst; pai != NOPORTARCINST; pai = pai->nextportarcinst)
697 		{
698 			if (pai->proto != pp) continue;
699 			if (portcount == instcount) continue;
700 			instcount++;
701 
702 			/* if arc on port not negated or a description for an inverter for a negated */
703 			/* arc already exists simply write the source name of this port/arc inst.*/
704 
705 			if ((pai->conarcinst->userbits&ISNEGATED) == 0 || pai->conarcinst->temp1 == -1)
706 			{
707 				addstringtoinfstr(infstr, sim_texsrcname(ni, pai));
708 				addstringtoinfstr(infstr, x_(","));
709 				break;
710 			} else
711 
712 			/* if the negation is at this end (ie nearest this node) write an inverter */
713 			/* with the port name of the output as inverter input and the net name of the */
714 			/* arc as inverter output. The source name is the net name of the arc */
715 			if ((pai->conarcinst->userbits&REVERSEEND) == 0)
716 			{
717 				esnprintf(str2, MAXNAMECHARS + 10, x_("U%ld.%s"), ni->temp2, sim_texname(pai->proto->protoname));
718 				addstringtoinfstr(infstr, str2);
719 				addstringtoinfstr(infstr, x_(","));
720 				sim_texwriteinv(pai, sim_texsrcname(ni, pai), str2);
721 			} else
722 
723 			/* if the negated arc is reversed get the name of the port/arc instance at the*/
724 			/* opposite end. */
725 			if ((pai->conarcinst->userbits&REVERSEEND) != 0)
726 			{
727 				xpai = sim_oppendpai(pai);
728 				xni = sim_oppendni(pai);
729 
730 				/* if the port at the opposite end is an input port use the net name. The */
731 				/* handling of the negated arc will be done by sim_textracesignal() */
732 				if ((xpai->proto->userbits&STATEBITS) ==INPORT)
733 				{
734 					addstringtoinfstr(infstr, sim_texsrcname(ni, pai));
735 					addstringtoinfstr(infstr, x_(","));
736 				} else
737 				{
738 					/* if the port at the opposite end is not an inport, look at all other    */
739 					/* port/arc instances. If one of these is on a new net, insert an    */
740 					/* inverter description with the input to the inverter the current net name */
741 					/* and the output the new net name. The source name will be the new net name */
742 					for(ppai = xni->firstportarcinst; ppai != NOPORTARCINST; ppai = ppai->nextportarcinst)
743 					{
744 						if (ppai == xpai) continue;
745 						if (ppai->conarcinst->network != pai->conarcinst->network)
746 						{
747 							netstr = sim_texsrcname(xni, ppai);
748 							break;
749 						}
750 					}
751 					addstringtoinfstr(infstr, netstr);
752 					addstringtoinfstr(infstr, x_(","));
753 					sim_texwriteinv(pai, netstr, sim_texsrcname(ni, pai));
754 				} /* end of else*/
755 			}/* end of else*/
756 		} /* end of for */
757 
758 		for(pei = ni->firstportexpinst; pei != NOPORTEXPINST; pei = pei->nextportexpinst)
759 		{
760 			if (pei->proto != pp) continue;
761 			if (portcount == instcount) continue;
762 			instcount++;
763 			addstringtoinfstr(infstr, sim_texname(pei->exportproto->protoname));
764 			addstringtoinfstr(infstr, x_(","));
765 			break;
766 		}
767 		if (instcount < portcount) addstringtoinfstr(infstr, x_("NC,"));
768 	}
769 	netstr = returninfstr(infstr);
770 	if (portcount == 0) return(NULLSTR);
771 	length = estrlen(netstr);
772 	*(netstr+length-1) = ')';
773 	return(netstr);
774 }
775 
776 /* To handle all error conditions */
sim_texerror(INTBIG error,INTBIG * lasterror,CHAR * str)777 void sim_texerror(INTBIG error, INTBIG *lasterror, CHAR *str)
778 {
779 	CHAR *msg;
780 	REGISTER void *infstr;
781 
782 	infstr = initinfstr();
783 	switch (error)
784 	{
785 		case 1:
786 			addstringtoinfstr(infstr, _("UNABLE TO OPEN TDL FILE"));
787 			break;
788 		case 2:
789 			formatinfstr(infstr, _("EXPORT %s MUST BE EITHER INPUT OR OUTPUT"), str);
790 			break;
791 		case 3:
792 			addstringtoinfstr(infstr, _("NEGATED ARC MUST BE CONNECTED TO INPUT OR OUTPUT OF NODEINST"));
793 			break;
794 		case 4:
795 			formatinfstr(infstr, _("NODETYPE %s NOT SUPPORTED"), str);
796 			break;
797 		case 5:
798 			addstringtoinfstr(infstr, _("UNABLE TO OPEN TDL LISTFILE"));
799 			break;
800 		case 6:
801 			addstringtoinfstr(infstr, _("ERROR IN TDL LISTFILE"));
802 			break;
803 		case 7:
804 			addstringtoinfstr(infstr, _("PWR / GND NODE UNCONNECTED"));
805 			break;
806 		case 8:
807 			formatinfstr(infstr, _("UNWIRED PORT %s"), str);
808 			break;
809 		case 9:
810 			formatinfstr(infstr, _("ONLY ONE INPUT ON %s"), str);
811 			break;
812 		case 10:
813 			addstringtoinfstr(infstr, _("T TYPE FLIP-FLOP MUST BE MS"));
814 			break;
815 		case 11:
816 			formatinfstr(infstr, _("%s IS A RESERVED WORD"), str);
817 			break;
818 	}
819 
820 	msg = returninfstr(infstr);
821 	sim_texstrprint(_("\n/************* ERROR **************/\n/*** "));
822 	sim_texstrprint(msg);
823 	sim_texstrprint(x_(" ***\n\n"));
824 	ttyputerr(x_("%s"), msg);
825 	*lasterror = error;
826 }
827 
828 /*
829  * this routine outputs TDL to the .TDL file. the maximum line length in a
830  * TDL file is 80 chars. this routine ensures that no lines exceed this
831  * it searches for the last space character and inserts a new line character
832  * at that point
833  */
sim_texstrprint(CHAR * str)834 void sim_texstrprint(CHAR *str)
835 {
836 	INTBIG length, charcount;
837 	CHAR *start_ptr, *max_line_ptr, newline[2];
838 	CHAR outstring[MAXLENGTH+3];
839 
840 	start_ptr = str;
841 	estrcpy(newline, x_("\n"));
842 	length = estrlen(start_ptr);
843 
844 	while (*start_ptr != '\0')
845 	{
846 		/* no new line chars and length > MAX */
847 		if (length > MAXLENGTH && (!estrchr(start_ptr, '\n')))
848 		{
849 			max_line_ptr = start_ptr + MAXLENGTH;
850 			charcount = MAXLENGTH;
851 
852 			/* find a suitable place to break string */
853 			while (!(*max_line_ptr == ',' || *max_line_ptr == ' '))
854 			{
855 				charcount -=1; max_line_ptr -=1;
856 				if (max_line_ptr == start_ptr)   /* no suitable break point */
857 				{
858 					max_line_ptr = start_ptr + MAXLENGTH;
859 					charcount = MAXLENGTH;
860 					break;
861 				}
862 			}
863 
864 			/* copy string from start up to break point (max_line_ptr) */
865 			estrncpy(outstring, start_ptr, charcount + 1);
866 			estrcat(outstring, newline);
867 			xprintf(sim_texfile, x_("%s"), outstring);
868 			start_ptr = max_line_ptr + 1;
869 			length = estrlen(start_ptr);
870 		} else
871 		{
872 			xprintf(sim_texfile, x_("%s"), start_ptr);
873 			break;
874 		}
875 	}
876 }
877 
878 /* returns a string of max 12 chars and in upper case for TDL */
sim_texname(CHAR * str)879 CHAR *sim_texname(CHAR *str)
880 {
881 	static CHAR buffer[MAXNAMECHARS +1], letter;
882 	CHAR tempbuffer[MAXNAMECHARS +1];
883 	INTBIG i, length;
884 
885 	if ((length=estrlen(str)) > MAXNAMECHARS) length = MAXNAMECHARS;
886 	estrncpy(tempbuffer, str, length);
887 	for(i=0; i != length; i++)
888 	{
889 		letter = tempbuffer[i];
890 		buffer[i] = toupper(letter);
891 	}
892 	buffer[length] = '\0';
893 	return(buffer);
894 }
895 
896 /*
897  * routine to return the TDL name of a nodeinst
898  * this routine will strip out a TDL directory name if present
899  */
sim_texproto(NODEINST * ni,INTBIG f,INTBIG * module_err)900 CHAR *sim_texproto(NODEINST *ni, INTBIG f, INTBIG *module_err)
901 {
902 	INTBIG x, length, span;
903 	static CHAR buffer[MAXNAMECHARS];
904 
905 	if (f == NPGATEAND || f == NPGATEOR || f == NPGATEXOR)
906 	{
907 		if((x=sim_texcountwires(ni)) > 1) esnprintf(buffer, MAXNAMECHARS, x_("%ld-"), x); else
908 		{
909 			sim_texerror(9, module_err, describenodeproto(ni->proto));
910 			esnprintf(buffer, MAXNAMECHARS, x_("2-"));
911 		}
912 
913 		if (sim_texnegatedoutput(ni)) estrcat(buffer, x_("N"));
914 	} else estrcpy(buffer, x_(""));
915 
916 	switch(f)
917 	{
918 		case NPGATEAND:
919 			estrcat(buffer, x_("AND"));
920 			return(buffer);
921 		case NPGATEOR:
922 			estrcat(buffer, x_("OR"));
923 			return(buffer);
924 		case NPGATEXOR:
925 			estrcat(buffer, x_("XOR"));
926 			return(buffer);
927 		case NPBUFFER:
928 			if (sim_texnegatedoutput(ni)) estrcat(buffer, x_("NOT"));
929 				else estrcat(buffer, x_("DELAY"));
930 			return(buffer);
931 		case NPFLIPFLOP:
932 			return(sim_texffname(ni, module_err));
933 		case NPTRANS:
934 			estrcat(buffer, x_("BDSWITCH"));
935 			return(buffer);
936 		case NPUNKNOWN:
937 			length = estrlen(describenodeproto(ni->proto));
938 			if ((span = sim_strcspn(describenodeproto(ni->proto), x_("/"))) != length)
939 			{
940 				if (span > MAXNAMECHARS) span = MAXNAMECHARS;
941 				estrncpy(buffer, describenodeproto(ni->proto), span);
942 				return(sim_texname(buffer));
943 			}
944 			return(sim_texname(describenodeproto(ni->proto)));
945 		default:
946 			 return(buffer); /* for now */
947 	}
948 }
949 
950 /* routine to return the TDL primitive name of a flip-flop in electric */
sim_texffname(NODEINST * ni,INTBIG * module_err)951 CHAR *sim_texffname(NODEINST *ni, INTBIG *module_err)
952 {
953 	static CHAR name[5];
954 
955 	name[0] = 0;
956 	switch (ni->userbits&FFTYPE)
957 	{
958 		case FFTYPERS: estrcpy(name, x_("SR"));   break;
959 		case FFTYPEJK: estrcpy(name, x_("JK"));   break;
960 		case FFTYPED:  estrcpy(name, x_("D"));    break;
961 		case FFTYPET:
962 			if ((ni->userbits&FFCLOCK) != FFCLOCKMS)
963 				sim_texerror(10, module_err, NULLSTR);
964 			estrcpy(name, x_("TMNE"));
965 			break;
966 	}
967 	switch (ni->userbits&FFCLOCK)
968 	{
969 		case FFCLOCKMS: estrcat(name, x_("MNE"));   break;
970 		case FFCLOCKP:  estrcat(name, x_("EPE"));   break;
971 		case FFCLOCKN:  estrcat(name, x_("ENE"));   break;
972 	}
973 	return(name);
974 }
975 
976 /*
977  * this routine returns a string containing the TDL delay. if no delay variable
978  * present the default "/1,1/" is returned
979  */
sim_texgetdelay(NODEINST * ni,INTBIG f)980 CHAR *sim_texgetdelay(NODEINST *ni, INTBIG f)
981 {
982 	VARIABLE *var;
983 	static CHAR str1[30], str2[30];
984 	static INTBIG SIM_rise_delay_key = 0, SIM_fall_delay_key = 0;
985 
986 	/* user defined modules are not allowed delays */
987 	if (f == NPUNKNOWN) return(x_(""));
988 
989 	/* initialise variable for signal source names to be held on portarcinsts */
990 	/* and TEX rise and fall time delays */
991 	if (SIM_rise_delay_key == 0) SIM_rise_delay_key = makekey(x_("SIM_rise_delay"));
992 	if (SIM_fall_delay_key == 0) SIM_fall_delay_key = makekey(x_("SIM_fall_delay"));
993 
994 	var = getvalkey((INTBIG)ni, VNODEINST, -1, SIM_rise_delay_key);
995 	if (var == NOVARIABLE) esnprintf(str1, 30, x_("/1,")); else
996 	{
997 		if ((var->type&VTYPE) == VINTEGER) esnprintf(str1, 30, x_("/%1ld,"), var->addr);
998 		if ((var->type&VTYPE) == VSTRING) esnprintf(str1, 30, x_("/%s,"), (CHAR *)var->addr);
999 	}
1000 
1001 	var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, SIM_fall_delay_key);
1002 	if (var == NOVARIABLE) esnprintf(str2, 30, x_("1/")); else
1003 	{
1004 		if ((var->type&VTYPE) == VINTEGER) esnprintf(str2, 30, x_("%1ld/"), var->addr);
1005 		if ((var->type&VTYPE) == VSTRING) esnprintf(str2, 30, x_("%s/"), (CHAR *)var->addr);
1006 	}
1007 
1008 	estrcat(str1, str2);
1009 	return(str1);
1010 }
1011 
1012 /* determines whether a nodeinst has an output arc that is negated */
sim_texnegatedoutput(NODEINST * ni)1013 BOOLEAN sim_texnegatedoutput(NODEINST *ni)
1014 {
1015 	PORTARCINST *pai;
1016 
1017 	for(pai = ni->firstportarcinst; pai != NOPORTARCINST; pai = pai->nextportarcinst)
1018 	{
1019 		if ((pai->conarcinst->userbits&ISNEGATED) == 0) continue;
1020 		if ((pai->proto->userbits&STATEBITS) == OUTPORT) return(TRUE);
1021 	}
1022 	return(FALSE);
1023 }
1024 
1025 /* routine to remove the path specification from the electric library name */
sim_texlibname(NODEPROTO * np)1026 CHAR *sim_texlibname(NODEPROTO *np)
1027 {
1028 	INTBIG separator;
1029 
1030 	if (np->primindex != 0) return(x_("MASTER"));
1031 
1032 	separator = sim_strcspn(np->lib->libname, x_(":]")) + 1;
1033 	if (separator == (INTBIG)(estrlen(np->lib->libname)+1)) separator = 0;
1034 	return(sim_texname((np->lib->libname + separator)));
1035 }
1036 
1037 /*
1038  * routine to return the portarcinst at the opposite end of the arc which
1039  * connects tO pai
1040  */
sim_oppendpai(PORTARCINST * pai)1041 PORTARCINST *sim_oppendpai(PORTARCINST *pai)
1042 {
1043 	if (pai->conarcinst->end[0].portarcinst == pai)
1044 		return(pai->conarcinst->end[1].portarcinst);
1045 	return(pai->conarcinst->end[0].portarcinst);
1046 }
1047 
1048 /*
1049  * routine to return the nodeinst at the opposite end of the arc which
1050  * connects to pai
1051  */
sim_oppendni(PORTARCINST * pai)1052 NODEINST *sim_oppendni(PORTARCINST *pai)
1053 {
1054 	if (pai->conarcinst->end[0].portarcinst == pai)
1055 		return(pai->conarcinst->end[1].nodeinst);
1056 	return(pai->conarcinst->end[0].nodeinst);
1057 }
1058 
1059 /*
1060  * routine that takes a string of max. length 12 and checks to see if it is a
1061  * reserved word
1062  */
sim_texcheckname(CHAR * str)1063 BOOLEAN sim_texcheckname(CHAR *str)
1064 {
1065 	CHAR name[MAXNAMECHARS], *p, fileline[MAXLENGTH];
1066 	INTBIG i=0, x=0;
1067 
1068 	if (reservefile != NULL)
1069 	{
1070 		xseek(reservefile, 0, 0);
1071 		p = fileline;
1072 		while (!xfgets(fileline, MAXLENGTH, reservefile))
1073 		{
1074 			for(i=0; i != MAXNAMECHARS-1; i++) name[i]= 0;
1075 			i = 0;
1076 			while (!(*p == '\n' || *p =='\0')) name[i++] = *p++;
1077 
1078 			p = fileline;
1079 			if ((x = estrlen(str)) < 2) x = 2;  /* minimum abbrev. is 2 chars */
1080 			if (namesamen(name, str, x) == 0) return(FALSE);
1081 		}
1082 		return(TRUE);
1083 	}
1084 	return(TRUE);
1085 }
1086 
1087 /* private version of library function (may not be on all systems) */
sim_strcspn(CHAR * str,CHAR * set)1088 INTBIG sim_strcspn(CHAR *str, CHAR *set)
1089 {
1090 	INTBIG pos;
1091 	CHAR *pt;
1092 
1093 	for(pos=0; str[pos] != 0; pos++)
1094 	{
1095 		for(pt = set; *pt != 0; pt++)
1096 			if (str[pos] == *pt) break;
1097 		if (*pt != 0) break;
1098 	}
1099 	return(pos);
1100 }
1101 
1102 #endif /* SIMTOOL - at top */
1103