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