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