1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: simverilog.c
6 * Generator for Verilog simulator
7 * Written by: Steven M. Rubin
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 "network.h"
39 #include "usr.h"
40 #include "tecgen.h"
41 #include "tecschem.h"
42 #include "edialogs.h"
43
44 #define IMPLICITINVERTERNODENAME x_("Imp") /* name of inverters generated from negated wires */
45 #define IMPLICITINVERTERSIGNAME x_("ImpInv") /* name of signals generated from negated wires */
46 #define MAXDECLARATIONWIDTH 80 /* maximum size of output line */
47
48 INTBIG sim_verilog_statekey; /* key for "SIM_verilog_state" */
49 static INTBIG sim_verstate;
50 static FILE *sim_verfile;
51 static INTBIG sim_verilogcodekey = 0;
52 static INTBIG sim_verilogdeclarationkey = 0;
53 static INTBIG sim_verilogwiretypekey = 0;
54 static INTBIG sim_verilogtemplatekey = 0; /* key for "ATTR_verilog_template" */
55 static CHAR sim_verdeclarationline[MAXDECLARATIONWIDTH];
56 static INTBIG sim_verdeclarationprefix;
57 static CHAR **sim_verilognamelist;
58 static INTBIG sim_verilognamelisttotal = 0;
59 static INTBIG *sim_verilognamelistlow;
60 static INTBIG *sim_verilognamelisthigh;
61 static INTBIG *sim_verilognamelisttempval;
62 static INTBIG sim_verilogglobalnetcount; /* number of global nets */
63 static INTBIG sim_verilogglobalnettotal = 0; /* size of global net array */
64 static CHAR **sim_verilogglobalnets; /* global net names */
65 static UINTBIG *sim_verilogglobalchars; /* global net characteristics */
66
67 typedef struct
68 {
69 NETWORK *net;
70 PORTPROTO *pp;
71 } WIRELIST;
72
73 static WIRELIST *sim_verilogwirelist;
74 static INTBIG sim_verilogwirelisttotal = 0;
75
76 /* verilog signal plotting */
77 #define VERSIGNALSHOWN 1
78 #define DEFIRSIMTIMERANGE 10.0E-9f /* initial size of simulation window: 10ns */
79
80 #define NOVERSIGNAL ((VERSIGNAL *)-1)
81
82 typedef struct Iversignal
83 {
84 CHAR *symbol;
85 CHAR *signalname;
86 CHAR *signalcontext;
87 INTBIG signal; /* waveform window trace pointer */
88 INTBIG flags;
89 INTBIG level;
90 INTBIG width; /* bus width */
91 struct Iversignal **signals; /* signals in the bus */
92 INTBIG count; /* number of stimuli on this signal */
93 INTBIG total; /* size of allocated array of stimuli on this signal */
94 double *stimtime; /* array of time values for stimuli on this signal */
95 INTSML *stimstate; /* state of signal for each stimuli */
96 struct Iversignal *realversignal; /* repeat signals point to the main entry */
97 struct Iversignal *nextversignal;
98 } VERSIGNAL;
99
100 static VERSIGNAL *sim_verfirstsignal = NOVERSIGNAL;
101 static INTBIG sim_verlineno;
102 static CHAR sim_verline[300];
103 static CHAR sim_vercurscope[1000];
104 static FILE *sim_verfd;
105 static INTBIG sim_vercurlevel;
106 static INTBIG sim_verfilesize;
107 static void *sim_verprogressdialog; /* for showing input progress */
108 static INTBIG sim_numcharsused; /* number of characters used in signal symbols */
109 static INTBIG sim_charused[256]; /* which characters are used in signal symbols */
110 static double sim_timescale; /* scale of Verilog time to real time (in secs) */
111 static INTBIG sim_verignoresigname; /* number of levels of verilog name to ignore */
112 static VERSIGNAL *sim_verwindow_iter;
113 static VERSIGNAL *sim_verwindow_lastiter;
114
115
116 /* prototypes for local routines */
117 static BOOLEAN sim_verwritecell(NODEPROTO*, CHAR*);
118 static CHAR *sim_verconvertname(CHAR *p);
119 static BOOLEAN sim_verincludetypedcode(NODEPROTO*, INTBIG, CHAR*);
120 static void sim_verinitdeclaration(CHAR *header);
121 static void sim_veradddeclaration(CHAR *signame);
122 static void sim_vertermdeclaration(void);
123 static INTBIG sim_vergetnetworks(NODEPROTO *cell, CHAR ***namelist, INTBIG **lowindex,
124 INTBIG **highindex, INTBIG **tempval, WIRELIST **wirelist, INTBIG *netcount,
125 NETWORK **pwrnet, NETWORK **gndnet, INTBIG quiet);
126 static void sim_verwritelongline(CHAR *s);
127 static int sim_versortwirelistsbyname(const void *e1, const void *e2);
128 static CHAR *sim_vernamenoindices(CHAR *p);
129 static CHAR *sim_verstartofindex(CHAR *name);
130 static void sim_vergatherglobals(NODEPROTO *np);
131 static NETWORK *sim_vergetnetonport(NODEINST *ni, PORTPROTO *pp);
132 static void sim_verwritebus(NETWORK **outernetlist, INTBIG lowindex, INTBIG highindex, INTBIG tempval,
133 INTBIG *unconnectednet, CHAR *name, NETWORK *pwrnet, NETWORK *gndnet, void *infstr);
134 static CHAR *sim_vercellname(NODEPROTO *np);
135 static BOOLEAN sim_vercharhandlerwave(WINDOWPART *w, INTSML chr, INTBIG special);
136 static BOOLEAN sim_vertopofsignals(CHAR **c);
137 static CHAR *sim_vernextsignals(void);
138 static void sim_verhelpwindow(void);
139 static void sim_verparsetoend(CHAR **pt);
140 static void sim_vershowcurrentlevel(NODEPROTO *cell);
141 static int sim_versortsignalnames(const void *e1, const void *e2);
142 static INTBIG sim_vergetsignalhash(CHAR *name);
143 static void sim_verfreesimdata(void);
144 static void sim_versetvalue(VERSIGNAL *vs, double curtime, INTSML state);
145 static void sim_veraddsignals(void);
146
147 /*
148 * Routine to free all memory associated with this module.
149 */
sim_freeverilogmemory(void)150 void sim_freeverilogmemory(void)
151 {
152 REGISTER INTBIG i;
153
154 if (sim_verilognamelisttotal > 0)
155 {
156 for(i=0; i<sim_verilognamelisttotal; i++)
157 efree(sim_verilognamelist[i]);
158 efree((CHAR *)sim_verilognamelist);
159 efree((CHAR *)sim_verilognamelistlow);
160 efree((CHAR *)sim_verilognamelisthigh);
161 efree((CHAR *)sim_verilognamelisttempval);
162 }
163 if (sim_verilogwirelisttotal > 0)
164 efree((CHAR *)sim_verilogwirelist);
165
166 for(i=0; i<sim_verilogglobalnettotal; i++)
167 if (sim_verilogglobalnets[i] != 0)
168 efree((CHAR *)sim_verilogglobalnets[i]);
169 if (sim_verilogglobalnettotal > 0)
170 {
171 efree((CHAR *)sim_verilogglobalnets);
172 efree((CHAR *)sim_verilogglobalchars);
173 }
174 sim_verfreesimdata();
175 }
176
177 /*
178 * routine to write a ".v" file from the cell "np"
179 */
sim_writevernetlist(NODEPROTO * np)180 void sim_writevernetlist(NODEPROTO *np)
181 {
182 CHAR name[100], numberstring[100], *truename, *respar[2];
183 REGISTER NODEPROTO *lnp, *onp, *tnp;
184 REGISTER LIBRARY *lib, *olib;
185 REGISTER INTBIG i;
186 REGISTER VARIABLE *var;
187
188 /* make sure network tool is on */
189 if ((net_tool->toolstate&TOOLON) == 0)
190 {
191 ttyputerr(_("Network tool must be running...turning it on"));
192 toolturnon(net_tool);
193 ttyputerr(_("...now reissue the simulation command"));
194 return;
195 }
196 if (sim_verilogcodekey == 0)
197 sim_verilogcodekey = makekey(x_("VERILOG_code"));
198 if (sim_verilogdeclarationkey == 0)
199 sim_verilogdeclarationkey = makekey(x_("VERILOG_declaration"));
200 if (sim_verilogwiretypekey == 0)
201 sim_verilogwiretypekey = makekey(x_("SIM_verilog_wire_type"));
202 if (sim_verilogtemplatekey == 0)
203 sim_verilogtemplatekey = makekey(x_("ATTR_verilog_template"));
204
205 var = getvalkey((INTBIG)sim_tool, VTOOL, VINTEGER, sim_verilog_statekey);
206 if (var == NOVARIABLE) sim_verstate = 0; else
207 sim_verstate = var->addr;
208
209 /* first write the "ver" file */
210 (void)estrcpy(name, np->protoname);
211 (void)estrcat(name, x_(".v"));
212 sim_verfile = xcreate(name, sim_filetypeverilog, _("VERILOG File"), &truename);
213 if (sim_verfile == NULL)
214 {
215 if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
216 return;
217 }
218
219 /* see if there are any resistors in this circuit */
220 if (hasresistors(np))
221 {
222 /* has resistors: make sure they are being ignored */
223 if (asktech(sch_tech, x_("ignoring-resistor-topology")) == 0)
224 {
225 /* must redo network topology to ignore resistors */
226 respar[0] = x_("resistors");
227 respar[1] = x_("ignore");
228 (void)telltool(net_tool, 2, respar);
229 }
230 }
231
232 /* write header information */
233 xprintf(sim_verfile, x_("/* Verilog for cell %s from Library %s */\n"),
234 describenodeproto(np), np->lib->libname);
235 us_emitcopyright(sim_verfile, x_("/* "), x_(" */"));
236 if ((us_useroptions&NODATEORVERSION) == 0)
237 {
238 if (np->creationdate)
239 xprintf(sim_verfile, x_("/* Created on %s */\n"),
240 timetostring((time_t)np->creationdate));
241 if (np->revisiondate)
242 xprintf(sim_verfile, x_("/* Last revised on %s */\n"),
243 timetostring((time_t)np->revisiondate));
244 (void)esnprintf(numberstring, 100, x_("%s"), timetostring(getcurrenttime()));
245 xprintf(sim_verfile, x_("/* Written on %s by Electric VLSI Design System, version %s */\n"),
246 numberstring, el_version);
247 } else
248 {
249 xprintf(sim_verfile, x_("/* Written by Electric VLSI Design System */\n"));
250 }
251
252 /*
253 * determine whether any cells have name clashes in other libraries
254 */
255 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
256 for(tnp = lib->firstnodeproto; tnp != NONODEPROTO; tnp = tnp->nextnodeproto)
257 tnp->temp2 = 0;
258 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
259 {
260 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
261 for(tnp = lib->firstnodeproto; tnp != NONODEPROTO; tnp = tnp->nextnodeproto)
262 {
263 for(olib = lib->nextlibrary; olib != NOLIBRARY; olib = olib->nextlibrary)
264 {
265 if ((olib->userbits&HIDDENLIBRARY) != 0) continue;
266 for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
267 if (namesame(tnp->protoname, onp->protoname) == 0) break;
268 if (onp != NONODEPROTO) {
269 tnp->temp2 = onp->temp2 = 1;
270 }
271 }
272 }
273 }
274
275 /* gather all global signal names */
276 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
277 for(onp = lib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
278 onp->temp1 = 0;
279 sim_verilogglobalnetcount = 0;
280 sim_vergatherglobals(np);
281 if (sim_verilogglobalnetcount > 0)
282 {
283 xprintf(sim_verfile, x_("\nmodule glbl();\n"));
284 for(i=0; i<sim_verilogglobalnetcount; i++)
285 {
286 if (sim_verilogglobalchars[i] == PWRPORT)
287 {
288 xprintf(sim_verfile, x_(" supply1 %s;\n"),
289 sim_verilogglobalnets[i]);
290 } else if (sim_verilogglobalchars[i] == GNDPORT)
291 {
292 xprintf(sim_verfile, x_(" supply0 %s;\n"),
293 sim_verilogglobalnets[i]);
294 } else if ((sim_verstate&VERILOGUSETRIREG) != 0)
295 {
296 xprintf(sim_verfile, x_(" trireg %s;\n"),
297 sim_verilogglobalnets[i]);
298 } else
299 {
300 xprintf(sim_verfile, x_(" wire %s;\n"),
301 sim_verilogglobalnets[i]);
302 }
303 }
304 xprintf(sim_verfile, x_("endmodule\n"));
305 }
306
307 /* reset flags for cells that have been written */
308 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
309 for(lnp = lib->firstnodeproto; lnp != NONODEPROTO; lnp = lnp->nextnodeproto)
310 lnp->temp1 = 0;
311 begintraversehierarchy();
312 initparameterizedcells();
313 if (sim_verwritecell(np, 0))
314 ttyputmsg(_("Back-annotation information has been added (library must be saved)"));
315 endtraversehierarchy();
316
317 /* clean up */
318 xclose(sim_verfile);
319 ttyputmsg(_("%s written"), truename);
320 }
321
322 /*
323 * recursively called routine to print the Verilog description of cell "np".
324 */
sim_verwritecell(NODEPROTO * np,CHAR * paramname)325 BOOLEAN sim_verwritecell(NODEPROTO *np, CHAR *paramname)
326 {
327 REGISTER INTBIG i, j, k, l, nodetype, implicitports, total, localwires, nindex, wt,
328 impinv, nodewidth, isnegated, namecount, sigcount, wholenegated, dropbias,
329 low, high, addednames;
330 REGISTER BOOLEAN backannotate, first, dumpcell;
331 REGISTER NODEINST *ni;
332 REGISTER ARCINST *ai;
333 REGISTER PORTPROTO *pp, *lastpp, *opp, *cpp;
334 REGISTER NODEPROTO *onp, *cnp, *nip, *nipc;
335 REGISTER PORTARCINST *pi;
336 REGISTER PORTEXPINST *pe;
337 REGISTER NETWORK *net, *onet, *gnet, **outernetlist;
338 NETWORK *pwrnet, *gndnet, *pwrnetdummy, *gndnetdummy;
339 WIRELIST *wirelist;
340 INTBIG *lowindex, *highindex, *tempval, netcount, unconnectednet;
341 REGISTER VARIABLE *var, *vartemplate;
342 CHAR **namelist, *porttype, *thisline, *signame, impsigname[100], *startpt, line[200],
343 invsigname[100], *op, *pt, *opt, **ptr, *wiretype, save, osave, *pname, *modulename,
344 **strings, **nodenames, *nodename, *gn, *dir, *cellname, *behavefile;
345 REGISTER void *infstr;
346
347 /* stop if requested */
348 if (el_pleasestop != 0)
349 {
350 (void)stopping(STOPREASONDECK);
351 return(FALSE);
352 }
353 backannotate = FALSE;
354
355 /* use attached file if specified */
356 var = getval((INTBIG)np, VNODEPROTO, VSTRING, x_("SIM_verilog_behave_file"));
357 if (var != NOVARIABLE)
358 {
359 behavefile = (CHAR *)var->addr;
360 if (*behavefile != 0)
361 {
362 xprintf(sim_verfile, x_("`include \"%s\"\n"), behavefile);
363
364 /* mark this cell as written */
365 np->temp1++;
366 return(backannotate);
367 }
368 }
369
370 /* use library behavior if it is available */
371 onp = anyview(np, el_verilogview);
372 if (onp != NONODEPROTO)
373 {
374 var = getvalkey((INTBIG)onp, VNODEPROTO, VSTRING|VISARRAY, el_cell_message_key);
375 if (var != NOVARIABLE)
376 {
377 l = getlength(var);
378 for(i=0; i<l; i++)
379 {
380 thisline = ((CHAR **)var->addr)[i];
381 xprintf(sim_verfile, x_("%s\n"), thisline);
382 }
383 }
384
385 /* mark this cell as written */
386 np->temp1++;
387 return(backannotate);
388 }
389
390 /* make sure that all nodes and networks have names on them */
391 addednames = 0;
392 if (asktool(net_tool, x_("name-nodes"), (INTBIG)np) != 0) addednames++;
393 if (asktool(net_tool, x_("name-nets"), (INTBIG)np) != 0) addednames++;
394 if (addednames != 0)
395 {
396 backannotate = TRUE;
397 net_endbatch();
398 }
399
400 /* write netlist for this cell, first recurse on sub-cells */
401 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
402 {
403 if (ni->proto->primindex != 0) continue;
404
405 /* ignore recursive references (showing icon in contents) */
406 if (isiconof(ni->proto, np)) continue;
407
408 /* see if this cell has a template */
409 var = getvalkey((INTBIG)ni->proto, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
410 if (var != NOVARIABLE) continue;
411
412 /* get actual subcell (including contents/body distinction) */
413 /* NOTE: this gets the schematic before the layout */
414 onp = contentsview(ni->proto);
415 if (onp == NONODEPROTO) onp = ni->proto; else
416 {
417 /* see if this contents cell has a template */
418 var = getvalkey((INTBIG)onp, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
419 if (var != NOVARIABLE) continue;
420 }
421 dumpcell = TRUE;
422 if (onp->temp1 != 0) dumpcell = FALSE;
423 cellname = sim_vercellname(ni->proto);
424 pname = parameterizedname(ni, cellname);
425 if (pname != 0)
426 {
427 /* do not force multiple writes if there is a behavioral file */
428 var = getval((INTBIG)onp, VNODEPROTO, VSTRING, x_("SIM_verilog_behave_file"));
429 if (var == NOVARIABLE)
430 {
431 if (inparameterizedcells(onp, pname) == 0)
432 {
433 dumpcell = TRUE;
434 addtoparameterizedcells(onp, pname, 0);
435 }
436 }
437 }
438
439 /* write the subcell */
440 if (dumpcell)
441 {
442 downhierarchy(ni, onp, 0);
443 if (sim_verwritecell(onp, pname)) backannotate = TRUE;
444 uphierarchy();
445 }
446 }
447
448 /* mark this cell as written */
449 np->temp1++;
450
451 /* prepare arcs to store implicit inverters */
452 impinv = 1;
453 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
454 ai->temp1 = 0;
455 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
456 {
457 if ((ai->userbits&ISNEGATED) == 0) continue;
458 if ((ai->userbits&REVERSEEND) == 0)
459 {
460 ni = ai->end[0].nodeinst;
461 pi = ai->end[0].portarcinst;
462 } else
463 {
464 ni = ai->end[1].nodeinst;
465 pi = ai->end[1].portarcinst;
466 }
467 if (ni->proto == sch_bufprim || ni->proto == sch_andprim ||
468 ni->proto == sch_orprim || ni->proto == sch_xorprim)
469 {
470 if ((sim_verstate&VERILOGUSEASSIGN) != 0) continue;
471 if (estrcmp(pi->proto->protoname, x_("y")) == 0) continue;
472 }
473
474 /* must create implicit inverter here */
475 ai->temp1 = impinv;
476 if (ai->proto != sch_busarc) impinv++; else
477 {
478 net = ai->network;
479 if (net == NONETWORK) impinv++; else
480 impinv += net->buswidth;
481 }
482 }
483
484 /* gather networks in the cell */
485 namecount = sim_vergetnetworks(np, &namelist, &lowindex, &highindex,
486 &tempval, &wirelist, &netcount, &pwrnet, &gndnet, 0);
487
488 /* write the module header */
489 xprintf(sim_verfile, x_("\n"));
490 infstr = initinfstr();
491 if (paramname == 0) modulename = sim_vercellname(np); else
492 modulename = sim_verconvertname(paramname);
493 formatinfstr(infstr, x_("module %s("), modulename);
494 first = TRUE;
495 for(i=0; i<namecount; i++)
496 {
497 if (tempval[i] <= 1 || tempval[i] >= 6) continue;
498 if (!first) addstringtoinfstr(infstr, x_(", "));
499 addstringtoinfstr(infstr, namelist[i]);
500 first = FALSE;
501 }
502 addstringtoinfstr(infstr, x_(");"));
503 sim_verwritelongline(returninfstr(infstr));
504
505 /* look for "wire/trireg" overrides */
506 for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
507 net->temp2 = 0;
508 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
509 {
510 var = getvalkey((INTBIG)ai, VARCINST, VSTRING, sim_verilogwiretypekey);
511 if (var == NOVARIABLE) continue;
512 if (namesame((CHAR *)var->addr, x_("wire")) == 0) ai->network->temp2 = 1; else
513 if (namesame((CHAR *)var->addr, x_("trireg")) == 0) ai->network->temp2 = 2;
514 }
515
516 /* write description of formal parameters to module */
517 first = TRUE;
518 j = 0;
519 for(i=0; i<namecount; i++)
520 {
521 if (tempval[i] > 1 && tempval[i] < 6)
522 {
523 switch (tempval[i])
524 {
525 case 2: case 3: porttype = x_("input"); break;
526 case 4: case 5: porttype = x_("output"); break;
527 }
528 xprintf(sim_verfile, x_(" %s"), porttype);
529 if (lowindex[i] > highindex[i])
530 {
531 xprintf(sim_verfile, x_(" %s;"), namelist[i]);
532 if (wirelist[j].net->temp2 != 0)
533 {
534 if (wirelist[j].net->temp2 == 1) xprintf(sim_verfile, x_(" wire")); else
535 xprintf(sim_verfile, x_(" trireg"));
536 xprintf(sim_verfile, x_(" %s;"), namelist[i]);
537 }
538 } else
539 {
540 if ((tempval[i]&1) != 0)
541 {
542 low = highindex[i]; high = lowindex[i];
543 } else
544 {
545 low = lowindex[i]; high = highindex[i];
546 }
547 xprintf(sim_verfile, x_(" [%ld:%ld] %s;"), low, high, namelist[i]);
548 if (wirelist[j].net->temp2 != 0)
549 {
550 if (wirelist[j].net->temp2 == 1) xprintf(sim_verfile, x_(" wire")); else
551 xprintf(sim_verfile, x_(" trireg"));
552 xprintf(sim_verfile, x_(" [%ld:%ld] %s;"), low, high, namelist[i]);
553 }
554 }
555 xprintf(sim_verfile, x_("\n"));
556 first = FALSE;
557 }
558
559 /* advance pointer to network information */
560 if (lowindex[i] <= highindex[i]) j += highindex[i] - lowindex[i];
561 j++;
562 }
563 if (!first) xprintf(sim_verfile, x_("\n"));
564
565 /* describe power and ground nets */
566 if (pwrnet != NONETWORK) xprintf(sim_verfile, x_(" supply1 vdd;\n"));
567 if (gndnet != NONETWORK) xprintf(sim_verfile, x_(" supply0 gnd;\n"));
568
569 /* determine whether to use "wire" or "trireg" for networks */
570 if ((sim_verstate&VERILOGUSETRIREG) != 0) wiretype = x_("trireg"); else
571 wiretype = x_("wire");
572
573 /* write "wire/trireg" declarations for internal single-wide signals */
574 localwires = 0;
575 for(wt=0; wt<2; wt++)
576 {
577 first = TRUE;
578 j = 0;
579 for(i=0; i<namecount; i++)
580 {
581 if (tempval[i] <= 1 && lowindex[i] > highindex[i])
582 {
583 if (wirelist[j].net->temp2 == 0) estrcpy(impsigname, wiretype); else
584 {
585 if (wirelist[j].net->temp2 == 1) estrcpy(impsigname, x_("wire")); else
586 estrcpy(impsigname, x_("trireg"));
587 }
588 if ((wt == 0) ^ (namesame(wiretype, impsigname) == 0))
589 {
590 if (first)
591 {
592 esnprintf(invsigname, 100, x_(" %s"), impsigname);
593 sim_verinitdeclaration(invsigname);
594 }
595 sim_veradddeclaration(namelist[i]);
596 localwires++;
597 first = FALSE;
598 }
599 }
600
601 /* advance pointer to network information */
602 if (lowindex[i] <= highindex[i]) j += highindex[i] - lowindex[i];
603 j++;
604 }
605 if (!first) sim_vertermdeclaration();
606 }
607
608 /* write "wire/trireg" declarations for internal busses */
609 for(i=0; i<namecount; i++)
610 {
611 if (tempval[i] > 1) continue;
612 if (lowindex[i] > highindex[i]) continue;
613
614 if ((tempval[i]&1) != 0)
615 {
616 xprintf(sim_verfile, x_(" %s [%ld:%ld] %s;\n"), wiretype,
617 highindex[i], lowindex[i], namelist[i]);
618 } else
619 {
620 xprintf(sim_verfile, x_(" %s [%ld:%ld] %s;\n"), wiretype,
621 lowindex[i], highindex[i], namelist[i]);
622 }
623 localwires++;
624 }
625 if (localwires != 0) xprintf(sim_verfile, x_("\n"));
626
627 /* add "wire" declarations for implicit inverters */
628 if (impinv > 1)
629 {
630 esnprintf(invsigname, 100, x_(" %s"), wiretype);
631 sim_verinitdeclaration(invsigname);
632 for(i=1; i<impinv; i++)
633 {
634 esnprintf(impsigname, 100, x_("%s%ld"), IMPLICITINVERTERSIGNAME, i);
635 sim_veradddeclaration(impsigname);
636 }
637 sim_vertermdeclaration();
638 }
639
640 /* add in any user-specified declarations and code */
641 first = sim_verincludetypedcode(np, sim_verilogdeclarationkey, x_("declarations"));
642 first |= sim_verincludetypedcode(np, sim_verilogcodekey, x_("code"));
643 if (!first)
644 xprintf(sim_verfile, x_(" /* automatically generated Verilog */\n"));
645
646 /* load Verilog names onto the networks */
647 for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
648 net->temp2 = 0;
649 j = 0;
650 for(i=0; i<namecount; i++)
651 {
652 if (lowindex[i] > highindex[i])
653 {
654 net = wirelist[j++].net;
655 ptr = (CHAR **)(&net->temp2);
656 if (net->globalnet > 1 && net->globalnet < np->globalnetcount)
657 {
658 gn = sim_verconvertname(np->globalnetnames[net->globalnet]);
659 *ptr = (CHAR *)emalloc((estrlen(gn)+7) * SIZEOFCHAR, sim_tool->cluster);
660 estrcpy(*ptr, x_(" glbl."));
661 estrcat(*ptr, gn);
662 } else
663 {
664 *ptr = (CHAR *)emalloc((estrlen(namelist[i])+2) * SIZEOFCHAR, sim_tool->cluster);
665 estrcpy(*ptr, x_(" "));
666 estrcat(*ptr, namelist[i]);
667 }
668 } else
669 {
670 if ((tempval[i]&1) != 0) dir = x_("D"); else dir = x_("U");
671 for(k=lowindex[i]; k<=highindex[i]; k++)
672 {
673 net = wirelist[j++].net;
674 infstr = initinfstr();
675 formatinfstr(infstr, x_("%s%s[%ld]"), dir, namelist[i], k);
676 ptr = (CHAR **)(&net->temp2);
677 (void)allocstring(ptr, returninfstr(infstr), sim_tool->cluster);
678 }
679 }
680 }
681
682 /* look at every node in this cell */
683 unconnectednet = 1;
684 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
685 {
686 /* not interested in passive nodes (ports electrically connected) */
687 if (ni->proto->primindex != 0)
688 {
689 j = 0;
690 lastpp = ni->proto->firstportproto;
691 if (lastpp == NOPORTPROTO) continue;
692 for(pp = lastpp->nextportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
693 if (pp->network != lastpp->network) j++;
694 if (j == 0) continue;
695 }
696
697 nodewidth = ni->arraysize;
698 if (nodewidth < 1) nodewidth = 1;
699
700 nodetype = nodefunction(ni);
701
702 /* special case: verilog should ignore R L C etc. */
703 if (nodetype == NPRESIST || nodetype == NPCAPAC || nodetype == NPECAPAC ||
704 nodetype == NPINDUCT || nodetype == NPDIODE || nodetype == NPDIODEZ) continue;
705
706 /* use "assign" statement if possible */
707 if ((sim_verstate&VERILOGUSEASSIGN) != 0)
708 {
709 if (nodetype == NPGATEAND || nodetype == NPGATEOR ||
710 nodetype == NPGATEXOR || nodetype == NPBUFFER)
711 {
712 /* assign possible: determine operator */
713 switch (nodetype)
714 {
715 case NPGATEAND: op = x_(" & "); break;
716 case NPGATEOR: op = x_(" | "); break;
717 case NPGATEXOR: op = x_(" ^ "); break;
718 case NPBUFFER: op = x_(""); break;
719 }
720 for(nindex=0; nindex<nodewidth; nindex++)
721 {
722 /* write a line describing this signal */
723 infstr = initinfstr();
724 wholenegated = 0;
725 first = TRUE;
726 for(i=0; i<2; i++)
727 {
728 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
729 {
730 if (i == 0)
731 {
732 if (estrcmp(pi->proto->protoname, x_("y")) != 0) continue;
733 } else
734 {
735 if (estrcmp(pi->proto->protoname, x_("a")) != 0) continue;
736 }
737
738 /* determine the network name at this port */
739 net = pi->conarcinst->network;
740 if (nodewidth > 1)
741 {
742 (void)net_evalbusname(
743 (pi->conarcinst->proto->userbits&AFUNCTION)>>AFUNCTIONSH,
744 networkname(net, 0), &strings, pi->conarcinst, np, 1);
745 estrcpy(impsigname, strings[nindex]);
746 signame = impsigname;
747 } else
748 {
749 if (net != NONETWORK && net->namecount > 0)
750 signame = networkname(net, 0); else
751 signame = describenetwork(net);
752 if (net == pwrnet) signame = x_("vdd"); else
753 if (net == gndnet) signame = x_("gnd");
754 }
755
756 /* see if this end is negated */
757 isnegated = 0;
758 ai = pi->conarcinst;
759 if ((ai->userbits&ISNEGATED) != 0)
760 {
761 if ((ai->end[0].nodeinst == ni && (ai->userbits&REVERSEEND) == 0) ||
762 (ai->end[1].nodeinst == ni && (ai->userbits&REVERSEEND) != 0))
763 {
764 isnegated = 1;
765 }
766 }
767
768 /* write the port name */
769 if (i == 0)
770 {
771 /* got the output port: do the left-side of the "assign" */
772 addstringtoinfstr(infstr, x_("assign "));
773 addstringtoinfstr(infstr, signame);
774 addstringtoinfstr(infstr, x_(" = "));
775 if (isnegated != 0)
776 {
777 addstringtoinfstr(infstr, x_("~("));
778 wholenegated = 1;
779 }
780 break;
781 } else
782 {
783 if (!first)
784 addstringtoinfstr(infstr, op);
785 first = FALSE;
786 if (isnegated != 0) addstringtoinfstr(infstr, x_("~"));
787 addstringtoinfstr(infstr, signame);
788 }
789 }
790 }
791 if (wholenegated != 0)
792 addstringtoinfstr(infstr, x_(")"));
793 addstringtoinfstr(infstr, x_(";"));
794 sim_verwritelongline(returninfstr(infstr));
795 }
796 continue;
797 }
798 }
799
800 /* get the name of the node */
801 implicitports = 0;
802 dropbias = 0;
803 if (ni->proto->primindex == 0)
804 {
805 /* ignore recursive references (showing icon in contents) */
806 if (isiconof(ni->proto, np)) continue;
807 cellname = sim_vercellname(ni->proto);
808 pname = parameterizedname(ni, cellname);
809 if (pname == 0) pname = cellname; else
810 pname = sim_verconvertname(pname);
811 (void)allocstring(&nodename, pname, sim_tool->cluster);
812 } else
813 {
814 pt = ni->proto->protoname;
815
816 /* convert 4-port transistors to 3-port */
817 switch (nodetype)
818 {
819 case NPTRA4NMOS: nodetype = NPTRANMOS; dropbias = 1; break;
820 case NPTRA4PMOS: nodetype = NPTRAPMOS; dropbias = 1; break;
821 }
822 switch (nodetype)
823 {
824 case NPTRANMOS:
825 implicitports = 2;
826 pt = x_("tranif1");
827 var = getvalkey((INTBIG)ni, VNODEINST, -1, sim_weaknodekey);
828 if (var != NOVARIABLE) pt = x_("rtranif1");
829 break;
830 case NPTRAPMOS:
831 implicitports = 2;
832 pt = x_("tranif0");
833 var = getvalkey((INTBIG)ni, VNODEINST, -1, sim_weaknodekey);
834 if (var != NOVARIABLE) pt = x_("rtranif0");
835 break;
836 case NPGATEAND:
837 implicitports = 1;
838 pt = x_("and");
839 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
840 if (estrcmp(pi->proto->protoname, x_("y")) == 0) break;
841 if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
842 pt = x_("nand");
843 break;
844 case NPGATEOR:
845 implicitports = 1;
846 pt = x_("or");
847 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
848 if (estrcmp(pi->proto->protoname, x_("y")) == 0) break;
849 if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
850 pt = x_("nor");
851 break;
852 case NPGATEXOR:
853 implicitports = 1;
854 pt = x_("xor");
855 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
856 if (estrcmp(pi->proto->protoname, x_("y")) == 0) break;
857 if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
858 pt = x_("xnor");
859 break;
860 case NPBUFFER:
861 implicitports = 1;
862 pt = x_("buf");
863 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
864 if (estrcmp(pi->proto->protoname, x_("y")) == 0) break;
865 if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
866 pt = x_("not");
867 break;
868 }
869 (void)allocstring(&nodename, pt, sim_tool->cluster);
870 }
871
872 if (nodewidth > 1)
873 {
874 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
875 if (var == NOVARIABLE) nodewidth = 1; else
876 {
877 sigcount = net_evalbusname(APBUS, (CHAR *)var->addr, &nodenames,
878 NOARCINST, NONODEPROTO, 0);
879 if (sigcount != nodewidth) nodewidth = 1;
880 }
881 }
882
883 /* write the node (may be arrayed) */
884 for(nindex=0; nindex<nodewidth; nindex++)
885 {
886 /* look for a Verilog template on the prototype */
887 vartemplate = getvalkey((INTBIG)ni->proto, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
888 if (vartemplate == NOVARIABLE)
889 {
890 cnp = contentsview(ni->proto);
891 if (cnp != NONODEPROTO)
892 vartemplate = getvalkey((INTBIG)cnp, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
893 }
894
895 if (vartemplate == NOVARIABLE)
896 {
897 /* write the type of the node */
898 infstr = initinfstr();
899 addstringtoinfstr(infstr, x_(" "));
900 addstringtoinfstr(infstr, nodename);
901
902 /* write the name of the node */
903 if (nodewidth > 1)
904 {
905 addstringtoinfstr(infstr, x_(" "));
906 addstringtoinfstr(infstr, sim_vernamenoindices(nodenames[nindex]));
907 } else
908 {
909 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
910 if (var != NOVARIABLE)
911 {
912 addstringtoinfstr(infstr, x_(" "));
913 addstringtoinfstr(infstr, sim_vernamenoindices((CHAR *)var->addr));
914 }
915 }
916 addstringtoinfstr(infstr, x_("("));
917 }
918
919 /* write the rest of the ports */
920 first = TRUE;
921 switch (implicitports)
922 {
923 case 0: /* explicit ports */
924 cnp = contentsview(ni->proto);
925 if (cnp == NONODEPROTO) cnp = ni->proto;
926 for(net = cnp->firstnetwork; net != NONETWORK; net = net->nextnetwork)
927 net->temp2 = (INTBIG)NONETWORK;
928 cpp = NOPORTPROTO;
929 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
930 {
931 cpp = equivalentport(ni->proto, pp, cnp);
932 if (cpp == NOPORTPROTO) continue;
933 net = sim_vergetnetonport(ni, pp);
934 if (net != NONETWORK && net->buswidth > 1)
935 {
936 sigcount = net->buswidth;
937 if (nodewidth > 1 && cpp->network->buswidth * nodewidth == net->buswidth)
938 {
939 /* map wide bus to a particular instantiation of an arrayed node */
940 if (cpp->network->buswidth == 1)
941 {
942 onet = (NETWORK *)cpp->network->temp2;
943 if (onet == NONETWORK)
944 cpp->network->temp2 = (INTBIG)net->networklist[nindex];
945 } else
946 {
947 for(i=0; i<cpp->network->buswidth; i++)
948 {
949 onet = (NETWORK *)cpp->network->networklist[i]->temp2;
950 if (onet == NONETWORK)
951 cpp->network->networklist[i]->temp2 =
952 (INTBIG)net->networklist[i + nindex*cpp->network->buswidth];
953 }
954 }
955 } else
956 {
957 if (cpp->network->buswidth != net->buswidth)
958 {
959 ttyputerr(_("***ERROR: port %s on node %s in cell %s is %d wide, but is connected/exported with width %d"),
960 pp->protoname, describenodeinst(ni), describenodeproto(np),
961 cpp->network->buswidth, net->buswidth);
962 sigcount = mini(sigcount, cpp->network->buswidth);
963 if (sigcount == 1) sigcount = 0;
964 }
965 onet = (NETWORK *)cpp->network->temp2;
966 if (onet == NONETWORK) cpp->network->temp2 = (INTBIG)net;
967 for(i=0; i<sigcount; i++)
968 {
969 onet = (NETWORK *)cpp->network->networklist[i]->temp2;
970 if (onet == NONETWORK)
971 cpp->network->networklist[i]->temp2 = (INTBIG)net->networklist[i];
972 }
973 }
974 } else
975 {
976 onet = (NETWORK *)cpp->network->temp2;
977 if (onet == NONETWORK) cpp->network->temp2 = (INTBIG)net;
978 }
979 }
980
981 /* special case for Verilog templates */
982 if (vartemplate != NOVARIABLE)
983 {
984 infstr = initinfstr();
985 addstringtoinfstr(infstr, x_(" "));
986 for(pt = (CHAR *)vartemplate->addr; *pt != 0; pt++)
987 {
988 if (pt[0] != '$' || pt[1] != '(')
989 {
990 addtoinfstr(infstr, *pt);
991 continue;
992 }
993 startpt = pt + 2;
994 for(pt = startpt; *pt != 0; pt++)
995 if (*pt == ')') break;
996 save = *pt;
997 *pt = 0;
998 pp = getportproto(ni->proto, startpt);
999 if (pp != NOPORTPROTO)
1000 {
1001 /* port name found: use its verilog node */
1002 net = sim_vergetnetonport(ni, pp);
1003 if (net == NONETWORK)
1004 {
1005 formatinfstr(infstr, x_("UNCONNECTED%ld"), unconnectednet++);
1006 } else
1007 {
1008 if (net->buswidth > 1)
1009 {
1010 sigcount = net->buswidth;
1011 if (nodewidth > 1 && pp->network->buswidth * nodewidth == net->buswidth)
1012 {
1013 /* map wide bus to a particular instantiation of an arrayed node */
1014 if (pp->network->buswidth == 1)
1015 {
1016 onet = net->networklist[nindex];
1017 if (onet == pwrnet) addstringtoinfstr(infstr, x_("vdd")); else
1018 if (onet == gndnet) addstringtoinfstr(infstr, x_("gnd")); else
1019 addstringtoinfstr(infstr, &((CHAR *)onet->temp2)[1]);
1020 } else
1021 {
1022 outernetlist = (NETWORK **)emalloc(pp->network->buswidth * (sizeof (NETWORK *)),
1023 sim_tool->cluster);
1024 for(j=0; j<pp->network->buswidth; j++)
1025 outernetlist[j] = net->networklist[i + nindex*pp->network->buswidth];
1026 for(opt = pp->protoname; *opt != 0; opt++)
1027 if (*opt == '[') break;
1028 osave = *opt;
1029 *opt = 0;
1030 sim_verwritebus(outernetlist, 0, net->buswidth-1, 0,
1031 &unconnectednet, 0, pwrnet, gndnet, infstr);
1032 *opt = osave;
1033 efree((CHAR *)outernetlist);
1034 }
1035 } else
1036 {
1037 if (pp->network->buswidth != net->buswidth)
1038 {
1039 ttyputerr(_("***ERROR: port %s on node %s in cell %s is %d wide, but is connected/exported with width %d"),
1040 pp->protoname, describenodeinst(ni), describenodeproto(np),
1041 cpp->network->buswidth, net->buswidth);
1042 sigcount = mini(sigcount, cpp->network->buswidth);
1043 if (sigcount == 1) sigcount = 0;
1044 }
1045 outernetlist = (NETWORK **)emalloc(net->buswidth * (sizeof (NETWORK *)),
1046 sim_tool->cluster);
1047 for(j=0; j<net->buswidth; j++)
1048 outernetlist[j] = net->networklist[j];
1049 for(opt = pp->protoname; *opt != 0; opt++)
1050 if (*opt == '[') break;
1051 osave = *opt;
1052 *opt = 0;
1053 sim_verwritebus(outernetlist, 0, net->buswidth-1, 0,
1054 &unconnectednet, 0, pwrnet, gndnet, infstr);
1055 *opt = osave;
1056 efree((CHAR *)outernetlist);
1057 }
1058 } else
1059 {
1060 if (net == pwrnet) addstringtoinfstr(infstr, x_("vdd")); else
1061 if (net == gndnet) addstringtoinfstr(infstr, x_("gnd")); else
1062 addstringtoinfstr(infstr, &((CHAR *)net->temp2)[1]);
1063 }
1064 }
1065 } else if (namesame(startpt, x_("node_name")) == 0)
1066 {
1067 if (nodewidth > 1) opt = nodenames[nindex]; else
1068 {
1069 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
1070 if (var == NOVARIABLE) opt = x_(""); else
1071 opt = (CHAR *)var->addr;
1072 }
1073 addstringtoinfstr(infstr, sim_vernamenoindices(opt));
1074 } else
1075 {
1076 /* no port name found, look for variable name */
1077 esnprintf(line, 200, x_("ATTR_%s"), startpt);
1078 var = getval((INTBIG)ni, VNODEINST, -1, line);
1079 if (var == NOVARIABLE)
1080 var = getval((INTBIG)ni, VNODEINST, -1, startpt);
1081 if (var == NOVARIABLE)
1082 {
1083 /* value not found: see if this is a parameter and use default */
1084 nip = ni->proto;
1085 nipc = contentsview(nip);
1086 if (nipc != NONODEPROTO) nip = nipc;
1087 var = getval((INTBIG)nip, VNODEPROTO, -1, line);
1088 }
1089 if (var == NOVARIABLE)
1090 addstringtoinfstr(infstr, x_("??")); else
1091 {
1092 addstringtoinfstr(infstr, describesimplevariable(var));
1093 }
1094 }
1095 *pt = save;
1096 if (save == 0) break;
1097 }
1098 break;
1099 }
1100
1101 /* generate the line the normal way */
1102 namecount = sim_vergetnetworks(cnp, &namelist, &lowindex, &highindex,
1103 &tempval, &wirelist, &netcount, &pwrnetdummy, &gndnetdummy, 1);
1104 l = 0;
1105 for(i=0; i<namecount; i++)
1106 {
1107 /* ignore networks that aren't exported */
1108 if (tempval[i] <= 1 || tempval[i] >= 6)
1109 {
1110 l++;
1111 if (lowindex[i] <= highindex[i])
1112 l += highindex[i] - lowindex[i];
1113 continue;
1114 }
1115 if (first) first = FALSE; else
1116 addstringtoinfstr(infstr, x_(", "));
1117 if (lowindex[i] > highindex[i])
1118 {
1119 /* single signal */
1120 addstringtoinfstr(infstr, x_("."));
1121 addstringtoinfstr(infstr, namelist[i]);
1122 addstringtoinfstr(infstr, x_("("));
1123 net = (NETWORK *)wirelist[l++].net->temp2;
1124 if (net == NONETWORK || net->temp2 == 0)
1125 {
1126 formatinfstr(infstr, x_("UNCONNECTED%ld"), unconnectednet++);
1127 } else
1128 {
1129 if (net == pwrnet) addstringtoinfstr(infstr, x_("vdd")); else
1130 if (net == gndnet) addstringtoinfstr(infstr, x_("gnd")); else
1131 addstringtoinfstr(infstr, &((CHAR *)net->temp2)[1]);
1132 }
1133 addstringtoinfstr(infstr, x_(")"));
1134 } else
1135 {
1136 total = highindex[i]-lowindex[i]+1;
1137 outernetlist = (NETWORK **)emalloc(total * (sizeof (NETWORK *)),
1138 sim_tool->cluster);
1139 for(j=lowindex[i]; j<=highindex[i]; j++)
1140 outernetlist[j-lowindex[i]] = (NETWORK *)wirelist[j-lowindex[i]+l].net->temp2;
1141
1142 sim_verwritebus(outernetlist, lowindex[i], highindex[i], tempval[i],
1143 &unconnectednet, namelist[i], pwrnet, gndnet, infstr);
1144 l += highindex[i] - lowindex[i] + 1;
1145 efree((CHAR *)outernetlist);
1146 }
1147 }
1148 addstringtoinfstr(infstr, x_(");"));
1149 break;
1150
1151 case 1: /* and/or gate: write ports in the proper order */
1152 for(i=0; i<2; i++)
1153 {
1154 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1155 {
1156 if (i == 0)
1157 {
1158 if (estrcmp(pi->proto->protoname, x_("y")) != 0) continue;
1159 } else
1160 {
1161 if (estrcmp(pi->proto->protoname, x_("a")) != 0) continue;
1162 }
1163 if (first) first = FALSE; else
1164 addstringtoinfstr(infstr, x_(", "));
1165 net = pi->conarcinst->network;
1166 if (nodewidth > 1)
1167 {
1168 if (net->buswidth == nodewidth) net = net->networklist[nindex];
1169 } else
1170 {
1171 if (net->buswidth > 1)
1172 {
1173 ttyputerr(_("***ERROR: cell %s, node %s is not arrayed but is connected to a bus"),
1174 describenodeproto(np), describenodeinst(ni));
1175 net = net->networklist[0];
1176 }
1177 }
1178 signame = &((CHAR *)net->temp2)[1];
1179 if (net == pwrnet) signame = x_("vdd"); else
1180 if (net == gndnet) signame = x_("gnd");
1181 if (i != 0 && pi->conarcinst->temp1 != 0)
1182 {
1183 /* this input is negated: write the implicit inverter */
1184 esnprintf(invsigname, 100, x_("%s%ld"), IMPLICITINVERTERSIGNAME,
1185 pi->conarcinst->temp1+nindex);
1186 xprintf(sim_verfile, x_(" inv %s%ld (%s, %s);\n"),
1187 IMPLICITINVERTERNODENAME, pi->conarcinst->temp1+nindex,
1188 invsigname, signame);
1189 signame = invsigname;
1190 }
1191 addstringtoinfstr(infstr, signame);
1192 }
1193 }
1194 addstringtoinfstr(infstr, x_(");"));
1195 break;
1196
1197 case 2: /* transistors: write ports in the proper order */
1198 /* schem: g/s/d mos: g/s/g/d */
1199 gnet = ni->proto->firstportproto->network;
1200 for(i=0; i<2; i++)
1201 {
1202 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1203 {
1204 for(opp = ni->proto->firstportproto; opp != pp; opp = opp->nextportproto)
1205 if (opp->network == pp->network) break;
1206 if (opp != pp) continue;
1207 if (dropbias != 0 && namesame(pp->protoname, x_("b")) == 0) continue;
1208 if (i == 0)
1209 {
1210 if (pp->network == gnet) continue;
1211 } else
1212 {
1213 if (pp->network != gnet) continue;
1214 }
1215 net = NONETWORK;
1216 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1217 if (pi->proto->network == pp->network) break;
1218 if (pi != NOPORTARCINST) net = pi->conarcinst->network; else
1219 {
1220 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1221 if (pe->proto == pp) break;
1222 if (pe != NOPORTEXPINST) net = pe->exportproto->network;
1223 }
1224 if (first) first = FALSE; else
1225 addstringtoinfstr(infstr, x_(", "));
1226 if (net == NONETWORK)
1227 {
1228 ttyputmsg(_("***Warning: cell %s, node %s is not fully connected"),
1229 describenodeproto(np), describenodeinst(ni));
1230 esnprintf(impsigname, 100, x_("UNCONNECTED%ld"), unconnectednet++);
1231 signame = impsigname;
1232 } else
1233 {
1234 if (nodewidth > 1)
1235 {
1236 (void)net_evalbusname(APBUS, networkname(net, 0), &strings, pi->conarcinst, np, 1);
1237 estrcpy(impsigname, strings[nindex]);
1238 signame = impsigname;
1239 } else
1240 {
1241 signame = &((CHAR *)net->temp2)[1];
1242 if (net == pwrnet) signame = x_("vdd"); else
1243 if (net == gndnet) signame = x_("gnd");
1244 }
1245 if (i != 0 && pi != NOPORTARCINST && pi->conarcinst->temp1 != 0)
1246 {
1247 /* this input is negated: write the implicit inverter */
1248 esnprintf(invsigname, 100, x_("%s%ld"), IMPLICITINVERTERSIGNAME,
1249 pi->conarcinst->temp1+nindex);
1250 xprintf(sim_verfile, x_(" inv %s%ld (%s, %s);\n"),
1251 IMPLICITINVERTERNODENAME, pi->conarcinst->temp1+nindex,
1252 invsigname, signame);
1253 signame = invsigname;
1254 }
1255 }
1256 addstringtoinfstr(infstr, signame);
1257 }
1258 }
1259 addstringtoinfstr(infstr, x_(");"));
1260 break;
1261 }
1262 sim_verwritelongline(returninfstr(infstr));
1263 }
1264 efree((CHAR *)nodename);
1265 }
1266 if (paramname == 0) modulename = sim_vercellname(np); else
1267 modulename = sim_verconvertname(paramname);
1268 xprintf(sim_verfile, x_("endmodule /* %s */\n"), modulename);
1269
1270 /* free net names */
1271 for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1272 if (net->temp2 != 0) efree((CHAR *)net->temp2);
1273
1274 return(backannotate);
1275 }
1276
1277 /*
1278 * Routine to add a bus of signals named "name" to the infinite string "infstr". If "name" is zero,
1279 * do not include the ".NAME()" wrapper. The signals are in "outernetlist" and range in index from
1280 * "lowindex" to "highindex". They are described by a bus with characteristic "tempval"
1281 * (low bit is on if the bus descends). Any unconnected networks can be numbered starting at
1282 * "*unconnectednet". The power and grounds nets are "pwrnet" and "gndnet".
1283 */
sim_verwritebus(NETWORK ** outernetlist,INTBIG lowindex,INTBIG highindex,INTBIG tempval,INTBIG * unconnectednet,CHAR * name,NETWORK * pwrnet,NETWORK * gndnet,void * infstr)1284 void sim_verwritebus(NETWORK **outernetlist, INTBIG lowindex, INTBIG highindex, INTBIG tempval,
1285 INTBIG *unconnectednet, CHAR *name, NETWORK *pwrnet, NETWORK *gndnet, void *infstr)
1286 {
1287 REGISTER INTBIG breakbus, numexported, numinternal, j, k, start, end, order, li;
1288 REGISTER NETWORK *net, *onet, *lastnet;
1289 REGISTER CHAR *thisnetname, *lastnetname, *pt, *lastpt;
1290
1291 /* array signal: see if it gets split out */
1292 breakbus = 0;
1293
1294 /* bus cannot have pwr/gnd, must be connected */
1295 numexported = numinternal = 0;
1296 for(j=lowindex; j<=highindex; j++)
1297 {
1298 net = outernetlist[j-lowindex];
1299 if (net == NONETWORK || net->temp1 == 6) break;
1300 if (net->temp1 > 1) numexported++; else
1301 numinternal++;
1302 }
1303 if (j <= highindex) breakbus = 1;
1304
1305 /* must be all exported or all internal, not a mix */
1306 if (numexported > 0 && numinternal > 0) breakbus = 1;
1307
1308 if (breakbus == 0)
1309 {
1310 /* see if all of the nets on this bus are distinct */
1311 for(j=lowindex+1; j<=highindex; j++)
1312 {
1313 net = outernetlist[j-lowindex];
1314 for(k=lowindex; k<j; k++)
1315 {
1316 onet = outernetlist[k-lowindex];
1317 if (net == onet) break;
1318 }
1319 if (k < j) break;
1320 }
1321 if (j <= highindex) breakbus = 1; else
1322 {
1323 /* bus entries must have the same root name and go in order */
1324 lastnet = NONETWORK;
1325 for(j=lowindex; j<=highindex; j++)
1326 {
1327 net = outernetlist[j-lowindex];
1328 thisnetname = (CHAR *)net->temp2;
1329 if (*thisnetname == 'D')
1330 {
1331 if ((tempval&1) == 0) break;
1332 } else if (*thisnetname == 'U')
1333 {
1334 if ((tempval&1) != 0) break;
1335 }
1336 thisnetname++;
1337
1338 for(pt = thisnetname; *pt != 0; pt++)
1339 if (*pt == '[') break;
1340 if (*pt == 0) break;
1341 if (j > lowindex)
1342 {
1343 lastnetname = &((CHAR *)lastnet->temp2)[1];
1344 for(li = 0; lastnetname[li] != 0; li++)
1345 {
1346 if (thisnetname[li] != lastnetname[li]) break;
1347 if (lastnetname[li] == '[') break;
1348 }
1349 if (lastnetname[li] != '[' || thisnetname[li] != '[') break;
1350 if (myatoi(pt+1) != myatoi(&lastnetname[li+1])+1) break;
1351 }
1352 lastnet = net;
1353 }
1354 if (j <= highindex) breakbus = 1;
1355 }
1356 }
1357
1358 if (name != 0) formatinfstr(infstr, x_(".%s("), name);
1359 if (breakbus != 0)
1360 {
1361 addstringtoinfstr(infstr, x_("{"));
1362 if ((tempval&1) != 0)
1363 {
1364 start = highindex;
1365 end = lowindex;
1366 order = -1;
1367 } else
1368 {
1369 start = lowindex;
1370 end = highindex;
1371 order = 1;
1372 }
1373 for(j=start; ; j += order)
1374 {
1375 if (j != start)
1376 addstringtoinfstr(infstr, x_(", "));
1377 net = outernetlist[j-lowindex];
1378 if (net == NONETWORK)
1379 {
1380 formatinfstr(infstr, x_("UNCONNECTED%ld"), *unconnectednet);
1381 (*unconnectednet)++;
1382 } else
1383 {
1384 if (net == pwrnet) addstringtoinfstr(infstr, x_("vdd")); else
1385 if (net == gndnet) addstringtoinfstr(infstr, x_("gnd")); else
1386 addstringtoinfstr(infstr, &((CHAR *)net->temp2)[1]);
1387 }
1388 if (j == end) break;
1389 }
1390 addstringtoinfstr(infstr, x_("}"));
1391 } else
1392 {
1393 lastnet = outernetlist[0];
1394 for(lastpt = &((CHAR *)lastnet->temp2)[1]; *lastpt != 0; lastpt++)
1395 if (*lastpt == '[') break;
1396 net = outernetlist[highindex-lowindex];
1397 for(pt = &((CHAR *)net->temp2)[1]; *pt != 0; pt++)
1398 {
1399 if (*pt == '[') break;
1400 addtoinfstr(infstr, *pt);
1401 }
1402 if ((tempval&1) != 0)
1403 {
1404 formatinfstr(infstr, x_("[%ld:%ld]"), myatoi(pt+1), myatoi(lastpt+1));
1405 } else
1406 {
1407 formatinfstr(infstr, x_("[%ld:%ld]"), myatoi(lastpt+1), myatoi(pt+1));
1408 }
1409 }
1410 if (name != 0) addstringtoinfstr(infstr, x_(")"));
1411 }
1412
1413 /*
1414 * Routine to add text from all nodes in cell "np"
1415 * (which have "verilogkey" text on them)
1416 * to that text to the output file. Returns true if anything
1417 * was found.
1418 */
sim_verincludetypedcode(NODEPROTO * np,INTBIG verilogkey,CHAR * descript)1419 BOOLEAN sim_verincludetypedcode(NODEPROTO *np, INTBIG verilogkey, CHAR *descript)
1420 {
1421 BOOLEAN first;
1422 REGISTER INTBIG len, i;
1423 REGISTER NODEINST *ni;
1424 REGISTER VARIABLE *var;
1425
1426 /* write out any directly-typed Verilog code */
1427 first = TRUE;
1428 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1429 {
1430 if (ni->proto != gen_invispinprim) continue;
1431 var = getvalkey((INTBIG)ni, VNODEINST, -1, verilogkey);
1432 if (var == NOVARIABLE) continue;
1433 if ((var->type&VTYPE) != VSTRING) continue;
1434 if ((var->type&VDISPLAY) == 0) continue;
1435 if (first)
1436 {
1437 first = FALSE;
1438 xprintf(sim_verfile, x_(" /* user-specified Verilog %s */\n"),
1439 descript);
1440 }
1441 if ((var->type&VISARRAY) == 0)
1442 {
1443 xprintf(sim_verfile, x_(" %s\n"), (CHAR *)var->addr);
1444 } else
1445 {
1446 len = getlength(var);
1447 for(i=0; i<len; i++)
1448 xprintf(sim_verfile, x_(" %s\n"), ((CHAR **)var->addr)[i]);
1449 }
1450 }
1451 if (!first) xprintf(sim_verfile, x_("\n"));
1452 return(first);
1453 }
1454
1455 /*
1456 * Routine to write a long line to the Verilog file, breaking it where sensible.
1457 */
sim_verwritelongline(CHAR * s)1458 void sim_verwritelongline(CHAR *s)
1459 {
1460 CHAR *pt, save;
1461 INTBIG i;
1462 CHAR *lastspace;
1463
1464 lastspace = NULL;
1465 i = 0;
1466 for (pt = s; *pt; pt++)
1467 {
1468 if (*pt == ' ' || *pt == ',') lastspace = pt;
1469 ++i;
1470 if (i >= MAXDECLARATIONWIDTH)
1471 {
1472 if (lastspace != NULL)
1473 {
1474 if (*lastspace != ' ') lastspace++;
1475 save = *lastspace; *lastspace = 0;
1476 xputs(s, sim_verfile);
1477 *lastspace = save;
1478 xputs(x_("\n "), sim_verfile);
1479 s = lastspace;
1480 if (*s == ' ') s++;
1481 i = 6 + pt-s+1;
1482 lastspace = NULL;
1483 } else
1484 {
1485 xputs(x_("\n "), sim_verfile);
1486 i = 6 + 1;
1487 }
1488 }
1489 }
1490 xputs(s, sim_verfile);
1491 xputs(x_("\n"), sim_verfile);
1492 }
1493
1494 /*
1495 * Routine to initialize the collection of signal names in a declaration.
1496 * The declaration starts with the string "header".
1497 */
sim_verinitdeclaration(CHAR * header)1498 void sim_verinitdeclaration(CHAR *header)
1499 {
1500 estrcpy(sim_verdeclarationline, header);
1501 sim_verdeclarationprefix = estrlen(sim_verdeclarationline);
1502 }
1503
1504 /*
1505 * Routine to add "signame" to the collection of signal names in a declaration.
1506 */
sim_veradddeclaration(CHAR * signame)1507 void sim_veradddeclaration(CHAR *signame)
1508 {
1509 if (estrlen(sim_verdeclarationline) + estrlen(signame) + 3 > MAXDECLARATIONWIDTH)
1510 {
1511 xprintf(sim_verfile, x_("%s;\n"), sim_verdeclarationline);
1512 sim_verdeclarationline[sim_verdeclarationprefix] = 0;
1513 }
1514 if ((INTBIG)estrlen(sim_verdeclarationline) != sim_verdeclarationprefix)
1515 estrcat(sim_verdeclarationline, x_(","));
1516 estrcat(sim_verdeclarationline, x_(" "));
1517 estrcat(sim_verdeclarationline, signame);
1518 }
1519
1520 /*
1521 * Routine to terminate the collection of signal names in a declaration
1522 * and write the declaration to the Verilog file.
1523 */
sim_vertermdeclaration(void)1524 void sim_vertermdeclaration(void)
1525 {
1526 xprintf(sim_verfile, x_("%s;\n"), sim_verdeclarationline);
1527 }
1528
1529 /*
1530 * Routine to return the name of cell "c", given that it may be ambiguously used in multiple
1531 * libraries.
1532 */
sim_vercellname(NODEPROTO * np)1533 CHAR *sim_vercellname(NODEPROTO *np)
1534 {
1535 REGISTER void *infstr;
1536
1537
1538 /* Some other function is messing with temp2 during verilog netlisting
1539 so this function is broken. For now, every instance will be prepended
1540 with it's library name
1541 if (np->temp2 == 0)
1542 return(sim_verconvertname(np->protoname));
1543 */
1544
1545 infstr = initinfstr();
1546 formatinfstr(infstr, x_("%s__%s"), np->lib->libname, sim_vernamenoindices(np->protoname));
1547 return(returninfstr(infstr));
1548 }
1549
1550 /*
1551 * routine to adjust name "p" and return the string.
1552 * Verilog does permit a digit in the first location; prepend a "_" if found.
1553 * Verilog only permits the "_" and "$" characters: all others are converted to "_".
1554 * Verilog does not permit nonnumeric indices, so "P[A]" is converted to "P_A_"
1555 * Verilog does not permit multidimensional arrays, so "P[1][2]" is converted to "P_1_[2]"
1556 * and "P[1][T]" is converted to "P_1_T_"
1557 */
sim_verconvertname(CHAR * p)1558 CHAR *sim_verconvertname(CHAR *p)
1559 {
1560 REGISTER CHAR *t, *end;
1561 REGISTER void *infstr;
1562
1563 /* simple names are trivially accepted as is */
1564 for(t = p; *t != 0; t++) if (!isalnum(*t)) break;
1565 if (*t == 0 && !isdigit(*p)) return(p);
1566
1567 infstr = initinfstr();
1568 end = sim_verstartofindex(p);
1569 for(t = p; t < end; t++)
1570 {
1571 if (*t == '[' || *t == ']')
1572 {
1573 addtoinfstr(infstr, '_');
1574 if (*t == ']' && t[1] == '[') t++;
1575 } else
1576 {
1577 if (isalnum(*t) || *t == '_' || *t == '$')
1578 addtoinfstr(infstr, *t); else
1579 addtoinfstr(infstr, '_');
1580 }
1581 }
1582 addstringtoinfstr(infstr, end);
1583 if (*end != 0) addstringtoinfstr(infstr, x_("_"));
1584 return(returninfstr(infstr));
1585 }
1586
1587 /*
1588 * routine to adjust name "p" and return the string.
1589 * This code removes all index indicators and other special characters, turning
1590 * them into "_".
1591 */
sim_vernamenoindices(CHAR * p)1592 CHAR *sim_vernamenoindices(CHAR *p)
1593 {
1594 REGISTER CHAR *t;
1595 REGISTER void *infstr;
1596
1597 infstr = initinfstr();
1598 if (isdigit(*p)) addtoinfstr(infstr, '_');
1599 for(t = p; *t != 0 ; t++)
1600 {
1601 if (isalnum(*t) || *t == '_' || *t == '$')
1602 addtoinfstr(infstr, *t); else
1603 addtoinfstr(infstr, '_');
1604 }
1605 return(returninfstr(infstr));
1606 }
1607
1608 /*
1609 * Routine to return the character position in network name "name" that is the start of indexing.
1610 * If there is no indexing ("clock"), this will point to the end of the string.
1611 * If there is simple indexing ("dog[12]"), this will point to the "[".
1612 * If the index is nonnumeric ("dog[cat]"), this will point to the end of the string.
1613 *
1614 * If there are multiple indices, ("dog[12][45]") this will point to the last "[" (unless it is nonnumeric).
1615 * NO, if there are multiple indices, ("dog[12][45]") this will point to the end of the string.
1616 */
sim_verstartofindex(CHAR * name)1617 CHAR *sim_verstartofindex(CHAR *name)
1618 {
1619 REGISTER INTBIG len, i;
1620
1621 len = estrlen(name);
1622 if (name[len-1] != ']') return(name+len);
1623 for(i = len-2; i > 0; i--)
1624 {
1625 if (name[i] == '[') break;
1626 /* if (name[i] == ':' || name[i] == ',') continue; */
1627 if (name[i] == ':' || name[i] == ',') break;
1628 if (!isdigit(name[i])) break;
1629 }
1630 if (name[i] != '[') return(name+len);
1631 if (i > 0 && name[i-1] == ']') return(name+len);
1632 return(name+i);
1633 }
1634
1635 /*
1636 * Routine to scan networks in cell "cell". The "temp1" field is filled in with
1637 * 0: internal network (ascending order when in a bus)
1638 * 1: internal network (descending order when in a bus)
1639 * 2: exported input network (ascending order when in a bus)
1640 * 3: exported input network (descending order when in a bus)
1641 * 4: exported output network (ascending order when in a bus)
1642 * 5: exported output network (descending order when in a bus)
1643 * 6: power or ground network
1644 * All networks are sorted by name within "temp1" and the common array entries are
1645 * reduced to a list of names (in "namelist") and their low/high range of indices
1646 * (in "lowindex" and "highindex", with high < low if no indices apply). The value
1647 * of "temp1" is returned in the array "tempval". The list of "netcount" networks
1648 * found (uncombined by index) is returned in "wirelist". The power and ground nets
1649 * are stored in "pwrnet" and "gndnet". The total number of names is returned.
1650 */
sim_vergetnetworks(NODEPROTO * cell,CHAR *** namelist,INTBIG ** lowindex,INTBIG ** highindex,INTBIG ** tempval,WIRELIST ** wirelist,INTBIG * netcount,NETWORK ** pwrnet,NETWORK ** gndnet,INTBIG quiet)1651 INTBIG sim_vergetnetworks(NODEPROTO *cell, CHAR ***namelist,
1652 INTBIG **lowindex, INTBIG **highindex, INTBIG **tempval,
1653 WIRELIST **wirelist, INTBIG *netcount, NETWORK **pwrnet, NETWORK **gndnet, INTBIG quiet)
1654 {
1655 REGISTER NETWORK *net, *endnet, *subnet;
1656 REGISTER PORTPROTO *pp, *widestpp;
1657 REGISTER BOOLEAN updir, downdir, randomdir, multipwr, multignd, found;
1658 REGISTER NODEINST *ni;
1659 REGISTER ARCINST *ai;
1660 REGISTER PORTARCINST *pi;
1661 REGISTER INTBIG wirecount, i, j, k, namelistcount, index, newtotal, dirbit,
1662 *newtemp, *newlow, *newhigh, comp, fun, last, widestfound;
1663 REGISTER UINTBIG characteristics;
1664 REGISTER CHAR **newnamelist, save, *pt, *ept, *name, *endname;
1665 REGISTER void *infstr;
1666
1667 /* initialize to describe all nets */
1668 namelistcount = 0;
1669 wirecount = 0;
1670 for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1671 {
1672 net->temp1 = 0;
1673 if (net->buswidth > 1) continue;
1674 wirecount++;
1675 }
1676
1677 /* determine default direction of busses */
1678 if ((net_options&NETDEFBUSBASEDESC) != 0) dirbit = 1; else
1679 dirbit = 0;
1680
1681 /* mark exported networks */
1682 for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1683 {
1684 switch (pp->userbits&STATEBITS)
1685 {
1686 case OUTPORT: j = 4+dirbit; break;
1687 default: j = 2+dirbit; break;
1688 }
1689 if (pp->network->buswidth > 1)
1690 {
1691 /* bus export: mark individual network entries */
1692 for(i=0; i<pp->network->buswidth; i++)
1693 {
1694 net = pp->network->networklist[i];
1695 net->temp1 = j;
1696 }
1697 } else
1698 {
1699 /* single wire export: mark the network */
1700 net = pp->network;
1701 net->temp1 = j;
1702 }
1703 }
1704
1705 /* postprocess to ensure the directionality is correct */
1706 for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1707 {
1708 if (net->temp1 == 0) continue;
1709 if (net->namecount <= 0) continue;
1710 name = networkname(net, 0);
1711 for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1712 {
1713 if (pp->network->buswidth > 1) continue;
1714 if (namesame(pp->protoname, name) != 0) continue;
1715 switch (pp->userbits&STATEBITS)
1716 {
1717 case OUTPORT: j = 4+dirbit; break;
1718 default: j = 2+dirbit; break;
1719 }
1720 net->temp1 = j;
1721 }
1722 }
1723
1724 /* make sure all busses go in the same direction */
1725 for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1726 {
1727 if (net->buswidth <= 1) continue;
1728 j = 0;
1729 for(i=0; i<net->buswidth; i++)
1730 {
1731 subnet = net->networklist[i];
1732 if (subnet->temp1 == 0) continue;
1733 if (j == 0) j = subnet->temp1;
1734 if (subnet->temp1 != j) break;
1735 }
1736 if (i >= net->buswidth) continue;
1737
1738 /* mixed directionality: make it all nonoutput */
1739 for(i=0; i<net->buswidth; i++)
1740 {
1741 subnet = net->networklist[i];
1742 subnet->temp1 = 2+dirbit;
1743 }
1744 }
1745
1746 /* scan all networks for those that go in descending order */
1747 for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1748 {
1749 if (net->buswidth <= 1) continue;
1750 updir = downdir = randomdir = FALSE;
1751 last = 0;
1752 for(i=0; i<net->buswidth; i++)
1753 {
1754 subnet = net->networklist[i];
1755 if (subnet->namecount == 0) break;
1756 for(pt = networkname(subnet, 0); *pt != 0; pt++)
1757 if (*pt == '[') break;
1758 if (*pt == 0) break;
1759 if (isdigit(pt[1]) == 0) break;
1760 index = myatoi(pt+1);
1761 if (i != 0)
1762 {
1763 if (index == last-1) downdir = TRUE; else
1764 if (index == last+1) updir = TRUE; else
1765 randomdir = TRUE;
1766 }
1767 last = index;
1768 }
1769 if (randomdir) continue;
1770 if (updir && downdir) continue;
1771 if (!updir && !downdir) continue;
1772 if (downdir) dirbit = 1; else
1773 dirbit = 0;
1774 for(i=0; i<net->buswidth; i++)
1775 {
1776 subnet = net->networklist[i];
1777 subnet->temp1 = (subnet->temp1 & ~1) | dirbit;
1778 }
1779 }
1780
1781 /* find power and ground */
1782 *pwrnet = *gndnet = NONETWORK;
1783 multipwr = multignd = FALSE;
1784 for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1785 {
1786 if (portispower(pp))
1787 {
1788 if (*pwrnet != NONETWORK && *pwrnet != pp->network && !multipwr)
1789 {
1790 if (quiet == 0)
1791 ttyputmsg(_("Warning: multiple power networks in cell %s"),
1792 describenodeproto(cell));
1793 multipwr = TRUE;
1794 }
1795 *pwrnet = pp->network;
1796 }
1797 if (portisground(pp))
1798 {
1799 if (*gndnet != NONETWORK && *gndnet != pp->network && !multignd)
1800 {
1801 if (quiet == 0)
1802 ttyputmsg(_("Warning: multiple ground networks in cell %s"),
1803 describenodeproto(cell));
1804 multignd = TRUE;
1805 }
1806 *gndnet = pp->network;
1807 }
1808 }
1809 for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1810 {
1811 if (net->globalnet >= 0 && net->globalnet < cell->globalnetcount)
1812 {
1813 characteristics = cell->globalnetchar[net->globalnet];
1814 if (characteristics == PWRPORT)
1815 {
1816 if (*pwrnet != NONETWORK && *pwrnet != net && !multipwr)
1817 {
1818 if (quiet == 0)
1819 ttyputmsg(_("Warning: multiple power networks in cell %s"),
1820 describenodeproto(cell));
1821 multipwr = TRUE;
1822 }
1823 *pwrnet = net;
1824 } else if (characteristics == GNDPORT)
1825 {
1826 if (*gndnet != NONETWORK && *gndnet != net && !multignd)
1827 {
1828 if (quiet == 0)
1829 ttyputmsg(_("Warning: multiple ground networks in cell %s"),
1830 describenodeproto(cell));
1831 multignd = TRUE;
1832 }
1833 *gndnet = net;
1834 }
1835 }
1836 }
1837 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1838 {
1839 fun = nodefunction(ni);
1840 if (fun == NPCONPOWER || fun == NPCONGROUND)
1841 {
1842 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1843 {
1844 ai = pi->conarcinst;
1845 if (fun == NPCONPOWER)
1846 {
1847 if (*pwrnet != NONETWORK && *pwrnet != ai->network && !multipwr)
1848 {
1849 if (quiet == 0)
1850 ttyputmsg(_("Warning: multiple power networks in cell %s"),
1851 describenodeproto(cell));
1852 multipwr = TRUE;
1853 }
1854 *pwrnet = ai->network;
1855 } else
1856 {
1857 if (*gndnet != NONETWORK && *gndnet != ai->network && !multignd)
1858 {
1859 if (quiet == 0)
1860 ttyputmsg(_("Warning: multiple ground networks in cell %s"),
1861 describenodeproto(cell));
1862 multignd = TRUE;
1863 }
1864 *gndnet = ai->network;
1865 }
1866 }
1867 }
1868 }
1869 if (*pwrnet != NONETWORK) (*pwrnet)->temp1 = 6;
1870 if (*gndnet != NONETWORK) (*gndnet)->temp1 = 6;
1871
1872 /* make sure there is room in the array of networks */
1873 if (wirecount > sim_verilogwirelisttotal)
1874 {
1875 if (sim_verilogwirelisttotal > 0)
1876 efree((CHAR *)sim_verilogwirelist);
1877 sim_verilogwirelisttotal = 0;
1878 sim_verilogwirelist = (WIRELIST *)emalloc(wirecount * (sizeof (WIRELIST)),
1879 sim_tool->cluster);
1880 if (sim_verilogwirelist == 0) return(0);
1881 sim_verilogwirelisttotal = wirecount;
1882 }
1883
1884 /* load the array */
1885 if (wirecount > 0)
1886 {
1887 i = 0;
1888 for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1889 {
1890 if (net->buswidth > 1) continue;
1891 sim_verilogwirelist[i].net = net;
1892 sim_verilogwirelist[i].pp = NOPORTPROTO;
1893
1894 /* find the widest export that touches this network */
1895 widestfound = -1;
1896 widestpp = NOPORTPROTO;
1897 for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1898 {
1899 found = FALSE;
1900 if (pp->network == net) found = TRUE; else
1901 {
1902 if (pp->network->buswidth > 1)
1903 {
1904 for(j=0; j<pp->network->buswidth; j++)
1905 if (pp->network->networklist[j] == net) break;
1906 if (j < pp->network->buswidth) found = TRUE;
1907 }
1908 }
1909 if (found)
1910 {
1911 if (pp->network->buswidth > widestfound)
1912 {
1913 widestfound = pp->network->buswidth;
1914 widestpp = pp;
1915 }
1916 }
1917 }
1918 if (widestpp != NOPORTPROTO) sim_verilogwirelist[i].pp = widestpp;
1919 i++;
1920 }
1921
1922 /* sort the networks by name */
1923 esort(sim_verilogwirelist, wirecount, sizeof (WIRELIST), sim_versortwirelistsbyname);
1924
1925 /* organize by name and index order */
1926 for(i=0; i<wirecount; i++)
1927 {
1928 net = sim_verilogwirelist[i].net;
1929
1930 /* make sure there is room in the list */
1931 if (namelistcount >= sim_verilognamelisttotal)
1932 {
1933 newtotal = sim_verilognamelisttotal * 2;
1934 if (newtotal <= namelistcount) newtotal = namelistcount + 5;
1935 newnamelist = (CHAR **)emalloc(newtotal * (sizeof (CHAR *)),
1936 sim_tool->cluster);
1937 if (newnamelist == 0) return(0);
1938 newlow = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
1939 if (newlow == 0) return(0);
1940 newhigh = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
1941 if (newhigh == 0) return(0);
1942 newtemp = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
1943 if (newtemp == 0) return(0);
1944 for(j=0; j<newtotal; j++) newnamelist[j] = 0;
1945 for(j=0; j<namelistcount; j++)
1946 {
1947 newnamelist[j] = sim_verilognamelist[j];
1948 newlow[j] = sim_verilognamelistlow[j];
1949 newhigh[j] = sim_verilognamelisthigh[j];
1950 newtemp[j] = sim_verilognamelisttempval[j];
1951 }
1952 if (sim_verilognamelisttotal > 0)
1953 {
1954 efree((CHAR *)sim_verilognamelist);
1955 efree((CHAR *)sim_verilognamelistlow);
1956 efree((CHAR *)sim_verilognamelisthigh);
1957 efree((CHAR *)sim_verilognamelisttempval);
1958 }
1959 sim_verilognamelist = newnamelist;
1960 sim_verilognamelistlow = newlow;
1961 sim_verilognamelisthigh = newhigh;
1962 sim_verilognamelisttempval = newtemp;
1963 sim_verilognamelisttotal = newtotal;
1964 }
1965
1966 /* add this name to the list */
1967 if (net->globalnet > 1 && net->globalnet < net->parent->globalnetcount)
1968 {
1969 name = net->parent->globalnetnames[net->globalnet];
1970 } else
1971 {
1972 if (net->namecount == 0) name = describenetwork(net); else
1973 name = networkname(net, 0);
1974
1975 /* if exported, be sure to get the export name */
1976 if (net->temp1 > 1 && net->temp1 < 6)
1977 {
1978 for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1979 if (pp->network == net) break;
1980 if (pp != NOPORTPROTO) name = pp->protoname;
1981 }
1982 }
1983
1984 pt = sim_verstartofindex(name);
1985 save = *pt;
1986 *pt = 0;
1987 if (sim_verilognamelist[namelistcount] != 0)
1988 efree(sim_verilognamelist[namelistcount]);
1989 (void)allocstring(&sim_verilognamelist[namelistcount],
1990 sim_verconvertname(name), sim_tool->cluster);
1991 sim_verilognamelisttempval[namelistcount] = net->temp1;
1992 if (save == 0)
1993 {
1994 /* single wire: set range to show that */
1995 sim_verilognamelistlow[namelistcount] = 1;
1996 sim_verilognamelisthigh[namelistcount] = 0;
1997 } else
1998 {
1999 sim_verilognamelistlow[namelistcount] =
2000 sim_verilognamelisthigh[namelistcount] = myatoi(pt+1);
2001 for(j=i+1; j<wirecount; j++)
2002 {
2003 endnet = sim_verilogwirelist[j].net;
2004 if (endnet == NONETWORK) break;
2005 if (endnet->temp1 != net->temp1) break;
2006 if (sim_verilogwirelist[j].pp != sim_verilogwirelist[i].pp) break;
2007 if (endnet->globalnet != net->globalnet) break;
2008 if (endnet->namecount == 0) break;
2009 endname = networkname(endnet, 0);
2010 ept = sim_verstartofindex(endname);
2011 if (*ept != '[') break;
2012 *ept = 0;
2013 comp = namesame(name, endname);
2014 *ept = '[';
2015 if (comp != 0) break;
2016 index = myatoi(ept+1);
2017
2018 /* make sure export indices go in order */
2019 if (index != sim_verilognamelisthigh[namelistcount]+1)
2020 break;
2021 if (index > sim_verilognamelisthigh[namelistcount])
2022 sim_verilognamelisthigh[namelistcount] = index;
2023 i = j;
2024 }
2025 }
2026 *pt = save;
2027 namelistcount++;
2028 }
2029 }
2030
2031 /* make sure all names are unique */
2032 for(i=1; i<namelistcount; i++)
2033 {
2034 /* single signal: give it that name */
2035 if (sim_verilognamelistlow[i] == sim_verilognamelisthigh[i])
2036 {
2037 infstr = initinfstr();
2038 formatinfstr(infstr, x_("%s_%ld_"), sim_verilognamelist[i], sim_verilognamelistlow[i]);
2039 (void)reallocstring(&sim_verilognamelist[i], returninfstr(infstr), sim_tool->cluster);
2040 }
2041
2042 /* see if it clashes */
2043 for(j=0; j<i; j++)
2044 if (namesame(sim_verilognamelist[i], sim_verilognamelist[j]) == 0) break;
2045 if (j < i)
2046 {
2047 /* name the same: rename */
2048 pt = 0;
2049 for(k=1; k<1000; k++)
2050 {
2051 infstr = initinfstr();
2052 formatinfstr(infstr, x_("%s_%ld"), sim_verilognamelist[i], k);
2053 pt = returninfstr(infstr);
2054 for(j=0; j<namelistcount; j++)
2055 if (namesame(pt, sim_verilognamelist[j]) == 0) break;
2056 if (j >= namelistcount) break;
2057 }
2058 (void)reallocstring(&sim_verilognamelist[i], pt, sim_tool->cluster);
2059 }
2060 }
2061
2062 *namelist = sim_verilognamelist;
2063 *lowindex = sim_verilognamelistlow;
2064 *highindex = sim_verilognamelisthigh;
2065 *tempval = sim_verilognamelisttempval;
2066 *wirelist = sim_verilogwirelist;
2067 *netcount = wirecount;
2068 return(namelistcount);
2069 }
2070
2071 /*
2072 * Helper routine for "esort" that makes networks with names go in ascending name order.
2073 */
sim_versortwirelistsbyname(const void * e1,const void * e2)2074 int sim_versortwirelistsbyname(const void *e1, const void *e2)
2075 {
2076 REGISTER WIRELIST *w1, *w2;
2077 REGISTER NETWORK *net1, *net2;
2078 REGISTER CHAR *pt1, *pt2;
2079 CHAR empty[1];
2080
2081 w1 = (WIRELIST *)e1;
2082 w2 = (WIRELIST *)e2;
2083 net1 = w1->net;
2084 net2 = w2->net;
2085 if (net1->temp1 != net2->temp1) return(net1->temp1 - net2->temp1);
2086 empty[0] = 0;
2087 if (net1->globalnet > 1 && net1->globalnet < net1->parent->globalnetcount)
2088 {
2089 pt1 = net1->parent->globalnetnames[net1->globalnet];
2090 } else
2091 {
2092 if (net1->namecount == 0) pt1 = empty; else pt1 = networkname(net1, 0);
2093 }
2094 if (net2->globalnet > 1 && net2->globalnet < net2->parent->globalnetcount)
2095 {
2096 pt2 = net2->parent->globalnetnames[net2->globalnet];
2097 } else
2098 {
2099 if (net2->namecount == 0) pt2 = empty; else pt2 = networkname(net2, 0);
2100 }
2101 return(namesamenumeric(pt1, pt2));
2102 }
2103
2104 /*
2105 * Routine to return the network connected to node "ni", port "pp".
2106 */
sim_vergetnetonport(NODEINST * ni,PORTPROTO * pp)2107 NETWORK *sim_vergetnetonport(NODEINST *ni, PORTPROTO *pp)
2108 {
2109 REGISTER PORTARCINST *pi;
2110 REGISTER PORTEXPINST *pe;
2111
2112 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2113 if (pi->proto == pp) return(pi->conarcinst->network);
2114 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
2115 if (pe->proto == pp) return(pe->exportproto->network);
2116 return(NONETWORK);
2117 }
2118
2119 /*
2120 * Routine to recursively examine cells and gather global network names.
2121 */
sim_vergatherglobals(NODEPROTO * np)2122 void sim_vergatherglobals(NODEPROTO *np)
2123 {
2124 REGISTER INTBIG i, newtotal, globalnet;
2125 REGISTER UINTBIG *newchars;
2126 NETWORK *net;
2127 REGISTER CHAR *gname, **newlist;
2128 REGISTER NODEPROTO *onp, *cnp;
2129 REGISTER NODEINST *ni;
2130 REGISTER PORTARCINST *pi;
2131
2132 if (np->temp1 != 0) return;
2133 np->temp1 = 1;
2134
2135 /* mark all exported nets */
2136 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2137 {
2138 if (ni->proto != sch_globalprim) continue;
2139 pi = ni->firstportarcinst;
2140 if (pi == NOPORTARCINST) continue;
2141 net = pi->conarcinst->network;
2142 if (net == NONETWORK) continue;
2143 globalnet = net->globalnet;
2144 if (globalnet < 2) continue;
2145
2146 /* global net found: see if it is already in the list */
2147 gname = sim_verconvertname(np->globalnetnames[globalnet]);
2148 for(i=0; i<sim_verilogglobalnetcount; i++)
2149 if (namesame(gname, sim_verilogglobalnets[i]) == 0) break;
2150 if (i < sim_verilogglobalnetcount) continue;
2151
2152 /* add the global net name */
2153 if (sim_verilogglobalnetcount >= sim_verilogglobalnettotal)
2154 {
2155 newtotal = sim_verilogglobalnettotal * 2;
2156 if (sim_verilogglobalnetcount >= newtotal)
2157 newtotal = sim_verilogglobalnetcount + 5;
2158 newlist = (CHAR **)emalloc(newtotal * (sizeof (CHAR *)), sim_tool->cluster);
2159 if (newlist == 0) return;
2160 newchars = (UINTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
2161 if (newchars == 0) return;
2162 for(i=0; i<sim_verilogglobalnettotal; i++)
2163 {
2164 newlist[i] = sim_verilogglobalnets[i];
2165 newchars[i] = sim_verilogglobalchars[i];
2166 }
2167 for(i=sim_verilogglobalnettotal; i<newtotal; i++)
2168 newlist[i] = 0;
2169 if (sim_verilogglobalnettotal > 0)
2170 {
2171 efree((CHAR *)sim_verilogglobalnets);
2172 efree((CHAR *)sim_verilogglobalchars);
2173 }
2174 sim_verilogglobalnets = newlist;
2175 sim_verilogglobalchars = newchars;
2176 sim_verilogglobalnettotal = newtotal;
2177 }
2178 if (sim_verilogglobalnets[sim_verilogglobalnetcount] != 0)
2179 efree((CHAR *)sim_verilogglobalnets[sim_verilogglobalnetcount]);
2180 (void)allocstring(&sim_verilogglobalnets[sim_verilogglobalnetcount], gname,
2181 sim_tool->cluster);
2182
2183 /* should figure out the characteristics of this global!!! */
2184 sim_verilogglobalchars[sim_verilogglobalnetcount] =
2185 ((ni->userbits&NTECHBITS) >> NTECHBITSSH) << STATEBITSSH;
2186 sim_verilogglobalnetcount++;
2187 }
2188
2189 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2190 {
2191 onp = ni->proto;
2192 if (onp->primindex != 0) continue;
2193
2194 /* ignore recursive references (showing icon in contents) */
2195 if (isiconof(onp, np)) continue;
2196
2197 if (onp->cellview == el_iconview)
2198 {
2199 cnp = contentsview(onp);
2200 if (cnp != NONODEPROTO) onp = cnp;
2201 }
2202
2203 sim_vergatherglobals(onp);
2204 }
2205 }
2206
2207 /*************************************** READING VCD DUMPS INTO WAVEFORM ***************************************/
2208
sim_verfreesimdata(void)2209 void sim_verfreesimdata(void)
2210 {
2211 REGISTER VERSIGNAL *vs;
2212
2213 while (sim_verfirstsignal != NOVERSIGNAL)
2214 {
2215 vs = sim_verfirstsignal;
2216 sim_verfirstsignal = vs->nextversignal;
2217 if (vs->total > 0)
2218 {
2219 efree((CHAR *)vs->stimtime);
2220 efree((CHAR *)vs->stimstate);
2221 }
2222 if (vs->width > 1) efree((CHAR *)vs->signals);
2223 efree((CHAR *)vs);
2224 }
2225 }
2226
sim_verparsefile(CHAR * file,NODEPROTO * cell)2227 void sim_verparsefile(CHAR *file, NODEPROTO *cell)
2228 {
2229 REGISTER INTBIG i, len, numsignals, curposition, hashtablesize, hashcode, units, width,
2230 namelen, symbollen, contextlen, structlen, structsize;
2231 REGISTER INTSML state=0;
2232 REGISTER double curtime;
2233 REGISTER NODEINST *ni;
2234 REGISTER BOOLEAN foundlevel, foundend;
2235 REGISTER VARIABLE *var;
2236 REGISTER CHAR *keyword, *symname, *nodename, *symbol, *name, *context;
2237 REGISTER VERSIGNAL *vs, *vslast, **verhash, **vslist, *subvs;
2238 NODEPROTO *np;
2239 REGISTER STRINGOBJ *sosymbol, *soname, *socontext;
2240 REGISTER void *infstr;
2241 double min, max;
2242 REGISTER UCHAR1 *onestruct;
2243 CHAR *filename, *pt, *pars[10];
2244 extern COMCOMP us_showdp;
2245
2246 sim_verfd = xopen(file, el_filetypetext, 0, &filename);
2247 if (sim_verfd == 0) return;
2248
2249 /* show the progress dialog */
2250 sim_verfilesize = filesize(sim_verfd);
2251 if (sim_verfilesize > 0)
2252 {
2253 sim_verprogressdialog = DiaInitProgress(x_(""), _("Reading dump file..."));
2254 if (sim_verprogressdialog == 0)
2255 {
2256 xclose(sim_verfd);
2257 return;
2258 }
2259 }
2260 DiaSetProgress(sim_verprogressdialog, 0, sim_verfilesize);
2261
2262 sim_timescale = 1.0;
2263 sim_vercurscope[0] = 0;
2264 sim_verlineno = 0;
2265 sim_vercurlevel = 0;
2266 numsignals = 0;
2267 verhash = 0;
2268 hashtablesize = 1;
2269 vslast = NOVERSIGNAL;
2270 sim_verfreesimdata();
2271 sosymbol = newstringobj(sim_tool->cluster);
2272 soname = newstringobj(sim_tool->cluster);
2273 socontext = newstringobj(sim_tool->cluster);
2274 for(;;)
2275 {
2276 if (xfgets(sim_verline, 300, sim_verfd)) break;
2277 sim_verlineno++;
2278 if ((sim_verlineno%100) == 0)
2279 {
2280 if (stopping(STOPREASONSIMULATE)) break;
2281 curposition = xtell(sim_verfd);
2282 DiaSetProgress(sim_verprogressdialog, curposition, sim_verfilesize);
2283 }
2284
2285 /* accumulate the scope name */
2286 pt = sim_verline;
2287 keyword = getkeyword(&pt, x_(" "));
2288 if (keyword == NOSTRING) continue;
2289
2290 /* ignore "$date", "$version" or "$timescale" */
2291 if (namesame(keyword, x_("$date")) == 0 ||
2292 namesame(keyword, x_("$version")) == 0)
2293 {
2294 sim_verparsetoend(&pt);
2295 continue;
2296 }
2297 if (namesame(keyword, x_("$timescale")) == 0)
2298 {
2299 if (xfgets(sim_verline, 300, sim_verfd)) break;
2300 sim_verlineno++;
2301 units = -1;
2302 pt = sim_verline;
2303 keyword = getkeyword(&pt, x_(" "));
2304 for(pt = keyword; *pt != 0; pt++)
2305 if (!isdigit(*pt)) break;
2306 if (*pt == 0)
2307 {
2308 ttyputerr(_("No time units on line %ld"), pt, sim_verlineno);
2309 } else
2310 {
2311 if (namesame(pt, "ps") == 0) units = INTTIMEUNITPSEC; else
2312 if (namesame(pt, "s") == 0) units = INTTIMEUNITSEC; else
2313 ttyputerr(_("Unknown time units: '%s' on line %ld"), pt, sim_verlineno);
2314 }
2315 if (units >= 0)
2316 {
2317 *pt = 0;
2318 sim_timescale = figureunits(keyword, VTUNITSTIME, units);
2319 }
2320 sim_verparsetoend(&pt);
2321 continue;
2322 }
2323 if (namesame(keyword, x_("$scope")) == 0)
2324 {
2325 keyword = getkeyword(&pt, x_(" "));
2326 if (keyword != NOSTRING)
2327 {
2328 if (namesame(keyword, x_("module")) == 0 || namesame(keyword, x_("task")) == 0 ||
2329 namesame(keyword, x_("function")) == 0)
2330 {
2331 keyword = getkeyword(&pt, x_(" "));
2332 if (keyword != NOSTRING)
2333 {
2334 if (sim_vercurscope[0] != 0) strcat(sim_vercurscope, x_("."));
2335 strcat(sim_vercurscope, keyword);
2336 sim_vercurlevel++;
2337 }
2338 }
2339 sim_verparsetoend(&pt);
2340 }
2341 continue;
2342 }
2343
2344 if (namesame(keyword, x_("$upscope")) == 0)
2345 {
2346 if (sim_vercurlevel <= 0 || sim_vercurscope[0] == 0)
2347 {
2348 ttyputerr(_("Unbalanced $upscope on line %ld"), sim_verlineno);
2349 continue;
2350 } else
2351 {
2352 len = strlen(sim_vercurscope);
2353 for(i=len-1; i>0; i--) if (sim_vercurscope[i] == '.') break;
2354 if (sim_vercurscope[i] == '.') sim_vercurscope[i] = 0;
2355 sim_vercurlevel--;
2356 }
2357 sim_verparsetoend(&pt);
2358 continue;
2359 }
2360
2361 if (namesame(keyword, x_("$var")) == 0)
2362 {
2363 keyword = getkeyword(&pt, x_(" "));
2364 if (keyword != NOSTRING)
2365 {
2366 if (namesame(keyword, x_("wire")) == 0 ||
2367 namesame(keyword, x_("supply0")) == 0 ||
2368 namesame(keyword, x_("supply1")) == 0 ||
2369 namesame(keyword, x_("reg")) == 0 ||
2370 namesame(keyword, x_("parameter")) == 0 ||
2371 namesame(keyword, x_("trireg")) == 0)
2372 {
2373 /* get the bus width */
2374 keyword = getkeyword(&pt, x_(" "));
2375 if (keyword == NOSTRING) continue;
2376 width = myatoi(keyword);
2377
2378 /* get the symbol name for this signal */
2379 keyword = getkeyword(&pt, x_(" "));
2380 if (keyword == NOSTRING) continue;
2381 clearstringobj(sosymbol);
2382 addstringtostringobj(keyword, sosymbol);
2383
2384 /* get the signal name */
2385 keyword = getkeyword(&pt, x_(" "));
2386 if (keyword == NOSTRING) continue;
2387 clearstringobj(soname);
2388 addstringtostringobj(keyword, soname);
2389
2390 /* see if there is an index */
2391 keyword = getkeyword(&pt, x_(" "));
2392 if (keyword == NOSTRING) continue;
2393 foundend = FALSE;
2394 if (namesame(keyword, x_("$end")) == 0) foundend = TRUE; else
2395 addstringtostringobj(keyword, soname);
2396
2397 /* set the context */
2398 clearstringobj(socontext);
2399 addstringtostringobj(sim_vercurscope, socontext);
2400
2401 /* allocate one big object with structure and names */
2402 structlen = sizeof (VERSIGNAL);
2403 symbol = getstringobj(sosymbol); symbollen = (estrlen(symbol)+1) * SIZEOFCHAR;
2404 name = getstringobj(soname); namelen = (estrlen(name)+1) * SIZEOFCHAR;
2405 context = getstringobj(socontext); contextlen = (estrlen(context)+1) * SIZEOFCHAR;
2406 structsize = structlen + symbollen + namelen + contextlen;
2407 onestruct = (UCHAR1 *)emalloc(structsize, sim_tool->cluster);
2408 if (onestruct == 0) continue;
2409 vs = (VERSIGNAL *)onestruct;
2410 vs->symbol = (CHAR *)&onestruct[structlen];
2411 vs->signalname = (CHAR *)&onestruct[structlen+symbollen];
2412 vs->signalcontext = (CHAR *)&onestruct[structlen+symbollen+namelen];
2413 strcpy(vs->symbol, symbol);
2414 strcpy(vs->signalname, name);
2415 strcpy(vs->signalcontext, context);
2416 vs->nextversignal = NOVERSIGNAL;
2417 if (vslast == NOVERSIGNAL) sim_verfirstsignal = vs; else
2418 vslast->nextversignal = vs;
2419 vslast = vs;
2420 vs->level = sim_vercurlevel;
2421 vs->flags = 0;
2422 vs->signal = 0;
2423 vs->total = 0;
2424 vs->count = 0;
2425 vs->width = width;
2426 vs->realversignal = NOVERSIGNAL;
2427 numsignals++;
2428
2429 if (width > 1)
2430 {
2431 /* create fake signals for the individual entries */
2432 vslist = (VERSIGNAL **)emalloc(width * (sizeof (VERSIGNAL *)), sim_tool->cluster);
2433 if (vslist == 0) continue;
2434 vs->signals = vslist;
2435 for(i=0; i<width; i++)
2436 {
2437 structlen = sizeof (VERSIGNAL);
2438 infstr = initinfstr();
2439 formatinfstr(infstr, x_("%s[%ld]"), vs->signalname, i);
2440 name = returninfstr(infstr); namelen = (estrlen(name)+1) * SIZEOFCHAR;
2441 context = sim_vercurscope; contextlen = (estrlen(context)+1) * SIZEOFCHAR;
2442 structsize = structlen + namelen + contextlen;
2443 onestruct = (UCHAR1 *)emalloc(structsize, sim_tool->cluster);
2444 if (onestruct == 0) break;
2445 subvs = (VERSIGNAL *)onestruct;
2446 subvs->symbol = 0;
2447 subvs->signalname = (CHAR *)&onestruct[structlen];
2448 subvs->signalcontext = (CHAR *)&onestruct[structlen+namelen];
2449 strcpy(subvs->signalname, name);
2450 strcpy(subvs->signalcontext, context);
2451 subvs->nextversignal = NOVERSIGNAL;
2452 if (vslast == NOVERSIGNAL) sim_verfirstsignal = subvs; else
2453 vslast->nextversignal = subvs;
2454 vslast = subvs;
2455 subvs->level = sim_vercurlevel;
2456 subvs->flags = 0;
2457 subvs->signal = 0;
2458 subvs->total = 0;
2459 subvs->count = 0;
2460 subvs->width = 1;
2461 subvs->realversignal = NOVERSIGNAL;
2462 vslist[i] = subvs;
2463 numsignals++;
2464 }
2465 }
2466 if (foundend) continue;
2467 } else
2468 {
2469 ttyputerr(_("Invalid $var on line %ld: %s"), sim_verlineno, sim_verline);
2470 continue;
2471 }
2472 }
2473 sim_verparsetoend(&pt);
2474 continue;
2475 }
2476
2477 if (namesame(keyword, x_("$enddefinitions")) == 0)
2478 {
2479 sim_verparsetoend(&pt);
2480 infstr = initinfstr();
2481 formatinfstr(infstr, _("Found %ld signal names"), numsignals);
2482 DiaSetTextProgress(sim_verprogressdialog, _("Building signal table..."));
2483 DiaSetCaptionProgress(sim_verprogressdialog, returninfstr(infstr));
2484
2485 /* build a table for finding signal names */
2486 for(i=0; i<256; i++) sim_charused[i] = -1;
2487 sim_numcharsused = 0;
2488 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2489 {
2490 if (vs->symbol == 0) continue;
2491 for(pt = vs->symbol; *pt != 0; pt++)
2492 {
2493 i = *pt & 0xFF;
2494 if (sim_charused[i] < 0)
2495 sim_charused[i] = ++sim_numcharsused;
2496 }
2497 }
2498
2499 hashtablesize = pickprime(numsignals*2);
2500 verhash = (VERSIGNAL **)emalloc(hashtablesize * (sizeof (VERSIGNAL *)), sim_tool->cluster);
2501 if (verhash == 0) return;
2502 for(i=0; i<hashtablesize; i++) verhash[i] = NOVERSIGNAL;
2503
2504 /* insert the signals */
2505 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2506 {
2507 if (vs->symbol == 0) continue;
2508 hashcode = sim_vergetsignalhash(vs->symbol) % hashtablesize;
2509 for(i=0; i<hashtablesize; i++)
2510 {
2511 if (verhash[hashcode] == NOVERSIGNAL)
2512 {
2513 verhash[hashcode] = vs;
2514 break;
2515 }
2516 if (strcmp(vs->symbol, verhash[hashcode]->symbol) == 0)
2517 {
2518 /* same symbol name: merge the signals */
2519 vs->realversignal = verhash[hashcode];
2520 break;
2521 }
2522 hashcode++;
2523 if (hashcode >= hashtablesize) hashcode = 0;
2524 }
2525 }
2526 DiaSetTextProgress(sim_verprogressdialog, _("Reading stimulus..."));
2527 continue;
2528 }
2529 if (namesame(keyword, x_("$dumpvars")) == 0)
2530 {
2531 curtime = 0.0;
2532 for(;;)
2533 {
2534 if (xfgets(sim_verline, 300, sim_verfd)) break;
2535 sim_verlineno++;
2536 if ((sim_verlineno%1000) == 0)
2537 {
2538 if (stopping(STOPREASONSIMULATE)) break;
2539 curposition = xtell(sim_verfd);
2540 DiaSetProgress(sim_verprogressdialog, curposition, sim_verfilesize);
2541 }
2542 if (sim_verline[0] == '0' || sim_verline[0] == '1' ||
2543 sim_verline[0] == 'x' || sim_verline[0] == 'z')
2544 {
2545 symname = &sim_verline[1];
2546 hashcode = sim_vergetsignalhash(symname) % hashtablesize;
2547 vs = NOVERSIGNAL;
2548 for(i=0; i<hashtablesize; i++)
2549 {
2550 vs = verhash[hashcode];
2551 if (vs == NOVERSIGNAL) break;
2552 if (strcmp(symname, vs->symbol) == 0) break;
2553 hashcode++;
2554 if (hashcode >= hashtablesize) hashcode = 0;
2555 }
2556 if (vs == NOVERSIGNAL)
2557 {
2558 ttyputmsg(_("Unknown symbol '%s' on line %ld"), symname, sim_verlineno);
2559 continue;
2560 }
2561
2562 /* insert the stimuli */
2563 switch (sim_verline[0])
2564 {
2565 case '0': state = (LOGIC_LOW << 8) | GATE_STRENGTH; break;
2566 case '1': state = (LOGIC_HIGH << 8) | GATE_STRENGTH; break;
2567 case 'x': state = (LOGIC_X << 8) | GATE_STRENGTH; break;
2568 case 'z': state = (LOGIC_Z << 8) | GATE_STRENGTH; break;
2569 }
2570 sim_versetvalue(vs, curtime, state);
2571 continue;
2572 }
2573 if (sim_verline[0] == '$')
2574 {
2575 if (namesame(&sim_verline[0], x_("$end")) == 0) continue;
2576 ttyputmsg(_("Unknown directive on line %ld: %s"), sim_verlineno, sim_verline);
2577 continue;
2578 }
2579 if (sim_verline[0] == '#')
2580 {
2581 curtime = myatoi(&sim_verline[1]) * sim_timescale;
2582 continue;
2583 }
2584 if (sim_verline[0] == 'b')
2585 {
2586 for(pt = &sim_verline[1]; *pt != 0; pt++)
2587 if (*pt == ' ') break;
2588 if (*pt == 0)
2589 {
2590 ttyputmsg(_("Bus has missing signal name on line %ld: %s"), sim_verlineno, sim_verline);
2591 continue;
2592 }
2593 symname = &pt[1];
2594 hashcode = sim_vergetsignalhash(symname) % hashtablesize;
2595 vs = NOVERSIGNAL;
2596 for(i=0; i<hashtablesize; i++)
2597 {
2598 vs = verhash[hashcode];
2599 if (vs == NOVERSIGNAL) break;
2600 if (strcmp(symname, vs->symbol) == 0) break;
2601 hashcode++;
2602 if (hashcode >= hashtablesize) hashcode = 0;
2603 }
2604 if (vs == NOVERSIGNAL)
2605 {
2606 ttyputmsg(_("Unknown symbol '%s' on line %ld"), symname, sim_verlineno);
2607 continue;
2608 }
2609 for(i=0; i<vs->width; i++)
2610 {
2611 switch (sim_verline[i+1])
2612 {
2613 case '0': state = (LOGIC_LOW << 8) | GATE_STRENGTH; break;
2614 case '1': state = (LOGIC_HIGH << 8) | GATE_STRENGTH; break;
2615 case 'x': state = (LOGIC_X << 8) | GATE_STRENGTH; break;
2616 case 'z': state = (LOGIC_Z << 8) | GATE_STRENGTH; break;
2617 }
2618 sim_versetvalue(vs->signals[i], curtime, state);
2619 }
2620 continue;
2621 }
2622 ttyputmsg(_("Unknown stimulus on line %ld: %s"), sim_verlineno, sim_verline);
2623 }
2624 }
2625 }
2626 DiaDoneProgress(sim_verprogressdialog);
2627 xclose(sim_verfd);
2628 if (verhash != 0) efree((CHAR *)verhash);
2629 killstringobj(sosymbol);
2630 killstringobj(soname);
2631 killstringobj(socontext);
2632
2633 /* pick an associated cell */
2634 if (cell == NONODEPROTO)
2635 {
2636 i = ttygetparam(_("Please select a cell to associate with this dump file: "),
2637 &us_showdp, 3, pars);
2638 if (i > 0) cell = getnodeproto(pars[0]);
2639 if (cell == NONODEPROTO) return;
2640 }
2641
2642 /* remember signal list stored on this cell */
2643 sim_window_grabcachedsignalsoncell(cell);
2644
2645 /* display the waveform window */
2646 i = sim_window_isactive(&np);
2647 if ((i&SIMWINDOWWAVEFORM) == 0)
2648 {
2649 if (i != 0 && np != cell)
2650 {
2651 /* stop simulation of cell "np" */
2652 sim_window_stopsimulation();
2653 }
2654 if (sim_window_create(0, cell,
2655 ((sim_window_state&SHOWWAVEFORM) != 0 ? sim_vercharhandlerwave : 0),
2656 us_charhandler, IRSIM)) return;
2657 sim_window_state = (sim_window_state & ~SIMENGINECUR) | SIMENGINECURVERILOG;
2658 sim_window_settimerange(0, 0.0, DEFIRSIMTIMERANGE);
2659 sim_window_setmaincursor(DEFIRSIMTIMERANGE/5.0*2.0);
2660 sim_window_setextensioncursor(DEFIRSIMTIMERANGE/5.0*3.0);
2661 }
2662
2663 /* find a subcell and set the initial simulation level from it */
2664 sim_vercurlevel = -1;
2665 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2666 {
2667 if (ni->proto->primindex != 0) continue;
2668 if (isiconof(ni->proto, cell)) continue;
2669 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
2670 if (var != NOVARIABLE)
2671 {
2672 nodename = (CHAR *)var->addr;
2673 for(sim_vercurlevel=2; sim_vercurlevel<4; sim_vercurlevel++)
2674 {
2675 foundlevel = FALSE;
2676 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2677 {
2678 if (vs->level != sim_vercurlevel) continue;
2679 foundlevel = TRUE;
2680 estrcpy(sim_vercurscope, vs->signalcontext);
2681 len = estrlen(sim_vercurscope);
2682 for(i=len-1; i>0; i--) if (sim_vercurscope[i] == '.') break;
2683 if (i < 0) continue;
2684 if (namesame(&sim_vercurscope[i+1], nodename) == 0) break;
2685 }
2686 if (!foundlevel)
2687 {
2688 sim_vercurlevel = -1;
2689 break;
2690 }
2691 if (vs != NOVERSIGNAL)
2692 {
2693 sim_vercurlevel--;
2694 sim_vercurscope[i] = 0;
2695 break;
2696 }
2697 }
2698 if (sim_vercurlevel >= 0 && sim_vercurlevel < 4) break;
2699 }
2700 }
2701 if (sim_vercurlevel < 0)
2702 {
2703 /* no subcell found: just start at the top level */
2704 sim_vercurlevel = 1;
2705 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2706 {
2707 if (vs->level != sim_vercurlevel) continue;
2708 estrcpy(sim_vercurscope, vs->signalcontext);
2709 break;
2710 }
2711 }
2712 sim_verignoresigname = sim_vercurlevel - 1;
2713
2714 /* show current level */
2715 sim_vershowcurrentlevel(cell);
2716 sim_window_gettimeextents(&min, &max);
2717 sim_window_settimerange(0, min, max);
2718 sim_window_redraw();
2719 }
2720
sim_versetvalue(VERSIGNAL * vs,double curtime,INTSML state)2721 void sim_versetvalue(VERSIGNAL *vs, double curtime, INTSML state)
2722 {
2723 REGISTER INTBIG newtotal, i;
2724 REGISTER INTSML *newstate;
2725 REGISTER double *newtime;
2726
2727 if (vs->count >= vs->total)
2728 {
2729 newtotal = vs->total * 2;
2730 if (vs->count >= newtotal) newtotal = vs->count + 50;
2731 newtime = (double *)emalloc(newtotal * (sizeof (double)), sim_tool->cluster);
2732 newstate = (INTSML *)emalloc(newtotal * SIZEOFINTSML, sim_tool->cluster);
2733 if (newtime == 0 || newstate == 0) return;
2734 for(i=0; i<vs->count; i++)
2735 {
2736 newtime[i] = vs->stimtime[i];
2737 newstate[i] = vs->stimstate[i];
2738 }
2739 if (vs->total > 0)
2740 {
2741 efree((CHAR *)vs->stimtime);
2742 efree((CHAR *)vs->stimstate);
2743 }
2744 vs->total = newtotal;
2745 vs->stimtime = newtime;
2746 vs->stimstate = newstate;
2747 }
2748 vs->stimtime[vs->count] = curtime;
2749 vs->stimstate[vs->count] = state;
2750 vs->count++;
2751 }
2752
sim_vergetsignalhash(CHAR * name)2753 INTBIG sim_vergetsignalhash(CHAR *name)
2754 {
2755 REGISTER INTBIG value, index, i, len;
2756
2757 value = 0;
2758 len = estrlen(name);
2759 for(i=len-1; i>=0; i--)
2760 {
2761 index = sim_charused[name[i] & 0xFF];
2762 value = (value * sim_numcharsused) + index;
2763 }
2764 return(value);
2765 }
2766
sim_vershowcurrentlevel(NODEPROTO * cell)2767 void sim_vershowcurrentlevel(NODEPROTO *cell)
2768 {
2769 REGISTER INTBIG tot, i, j, buscount, plainnet, numnets, namednet, shownsignals,
2770 busprefixlen, oldsigcount;
2771 REGISTER CHAR *pt, *opt, *start, save, *name, *busprefix;
2772 CHAR **oldsignames;
2773 REGISTER void *infstr;
2774 REGISTER VERSIGNAL *vs, **netlist, *realvs, *subvs;
2775 INTBIG *bussignals;
2776 Q_UNUSED( cell );
2777
2778 /* show the waveform window */
2779 sim_window_cleartracehighlight();
2780 sim_window_killalltraces(FALSE);
2781 infstr = initinfstr();
2782 formatinfstr(infstr, _("level=%s"), sim_vercurscope);
2783 pt = returninfstr(infstr);
2784 for(j=0; j<sim_verignoresigname; j++)
2785 {
2786 while (*pt != 0 && *pt != '.') pt++;
2787 if (*pt == '.') pt++;
2788 }
2789 sim_window_titleinfo(pt);
2790 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2791 {
2792 vs->flags &= ~VERSIGNALSHOWN;
2793 vs->signal = 0;
2794 }
2795 /* first show the signals saved from last time */
2796 oldsigcount = sim_window_getcachedsignals(&oldsignames);
2797 shownsignals = 0;
2798 for(j=0; j<oldsigcount; j++)
2799 {
2800 /* see if the name is a bus */
2801 for(pt = oldsignames[j]; *pt != 0; pt++) if (*pt == '\t') break;
2802 if (*pt == '\t')
2803 {
2804 /* a bus */
2805 pt++;
2806 sim_initbussignals();
2807 for(;;)
2808 {
2809 for(start = pt; *pt != 0; pt++) if (*pt == '\t') break;
2810 save = *pt;
2811 *pt = 0;
2812 opt = start;
2813 if (*opt == '-') opt++;
2814 for( ; *opt != 0; opt++)
2815 if (!isdigit(*opt) || *opt == ':') break;
2816 if (*opt == ':') start = opt+1;
2817 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2818 {
2819 name = vs->signalname;
2820 if (namesame(name, start) != 0) continue;
2821 realvs = vs;
2822 if (vs->realversignal != NOVERSIGNAL) realvs = vs->realversignal;
2823 if ((realvs->flags&VERSIGNALSHOWN) != 0) continue;
2824
2825 realvs->signal = sim_window_newtrace(-1, name, (INTBIG)realvs);
2826 sim_window_loaddigtrace(realvs->signal, realvs->count, realvs->stimtime, realvs->stimstate);
2827 realvs->flags |= VERSIGNALSHOWN;
2828 sim_addbussignal(realvs->signal);
2829 shownsignals++;
2830 break;
2831 }
2832 *pt++ = save;
2833 if (save == 0) break;
2834 }
2835
2836 /* create the bus */
2837 infstr = initinfstr();
2838 for(pt = oldsignames[j]; *pt != 0; pt++)
2839 {
2840 if (*pt == '\t') break;
2841 addtoinfstr(infstr, *pt);
2842 }
2843 pt = returninfstr(infstr);
2844 buscount = sim_getbussignals(&bussignals);
2845 (void)sim_window_makebus(buscount, bussignals, pt);
2846 } else
2847 {
2848 /* a single signal */
2849 pt = oldsignames[j];
2850 if (*pt == '-') pt++;
2851 for( ; *pt != 0; pt++)
2852 if (!isdigit(*pt) || *pt == ':') break;
2853 if (*pt == ':') pt++; else pt = oldsignames[j];
2854 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2855 {
2856 name = vs->signalname;
2857 if (namesame(name, pt) != 0) continue;
2858 realvs = vs;
2859 if (vs->realversignal != NOVERSIGNAL) realvs = vs->realversignal;
2860 if ((realvs->flags&VERSIGNALSHOWN) != 0) continue;
2861
2862 realvs->signal = sim_window_newtrace(-1, name, (INTBIG)realvs);
2863 sim_window_loaddigtrace(realvs->signal, realvs->count, realvs->stimtime, realvs->stimstate);
2864 realvs->flags |= VERSIGNALSHOWN;
2865 shownsignals++;
2866 break;
2867 }
2868 }
2869 }
2870
2871 /* show default signals if none are cached */
2872 if (oldsigcount == 0)
2873 {
2874 /* see how many signals of each type are left */
2875 plainnet = namednet = 0;
2876 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2877 {
2878 if (vs->symbol == 0) continue;
2879 if (vs->level != sim_vercurlevel) continue;
2880 if (estrcmp(sim_vercurscope, vs->signalcontext) != 0) continue;
2881 realvs = vs;
2882 if (vs->realversignal != NOVERSIGNAL) realvs = vs->realversignal;
2883 if ((realvs->flags&VERSIGNALSHOWN) != 0) continue;
2884 if (namesamen(vs->signalname, x_("net"), 3) == 0) plainnet++; else
2885 namednet++;
2886 }
2887 numnets = namednet;
2888 if (numnets == 0 && shownsignals == 0)
2889 numnets = plainnet;
2890 if (numnets > 0)
2891 {
2892 netlist = (VERSIGNAL **)emalloc(numnets * (sizeof (VERSIGNAL *)), sim_tool->cluster);
2893 if (netlist == 0) return;
2894 tot = 0;
2895 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2896 {
2897 if (vs->symbol == 0) continue;
2898 if (vs->level != sim_vercurlevel) continue;
2899 if (estrcmp(sim_vercurscope, vs->signalcontext) != 0) continue;
2900 realvs = vs;
2901 if (vs->realversignal != NOVERSIGNAL) realvs = vs->realversignal;
2902 if ((realvs->flags&VERSIGNALSHOWN) != 0) continue;
2903 if (namednet > 0)
2904 {
2905 if (namesamen(vs->signalname, x_("net"), 3) == 0) continue;
2906 }
2907 netlist[tot++] = vs;
2908 }
2909 esort(netlist, tot, sizeof (VERSIGNAL *), sim_versortsignalnames);
2910 busprefixlen = 0;
2911 busprefix = 0;
2912 sim_initbussignals();
2913 for(j=0; j<tot; j++)
2914 {
2915 vs = netlist[j];
2916 realvs = vs;
2917 if (vs->realversignal != NOVERSIGNAL) realvs = vs->realversignal;
2918
2919 /* if in a bus, see if it is done */
2920 if (busprefixlen > 0 && (namesamen(vs->signalname, busprefix, busprefixlen) != 0 ||
2921 vs->signalname[busprefixlen] != '[' || realvs->width > 1))
2922 {
2923 buscount = sim_getbussignals(&bussignals);
2924 save = busprefix[busprefixlen];
2925 busprefix[busprefixlen] = 0;
2926 (void)sim_window_makebus(buscount, bussignals, busprefix);
2927 busprefix[busprefixlen] = save;
2928 busprefixlen = 0;
2929 sim_initbussignals();
2930 }
2931 if (realvs->width > 1)
2932 {
2933 /* show a bus */
2934 sim_initbussignals();
2935 for(i=0; i<realvs->width; i++)
2936 {
2937 subvs = realvs->signals[i];
2938 subvs->signal = sim_window_newtrace(-1, subvs->signalname, (INTBIG)subvs);
2939 sim_window_loaddigtrace(subvs->signal, subvs->count, subvs->stimtime, subvs->stimstate);
2940 subvs->flags |= VERSIGNALSHOWN;
2941 sim_addbussignal(subvs->signal);
2942 }
2943 buscount = sim_getbussignals(&bussignals);
2944 (void)sim_window_makebus(buscount, bussignals, vs->signalname);
2945 sim_initbussignals();
2946 } else
2947 {
2948 realvs->signal = sim_window_newtrace(-1, vs->signalname, (INTBIG)realvs);
2949 sim_window_loaddigtrace(realvs->signal, realvs->count, realvs->stimtime, realvs->stimstate);
2950 realvs->flags |= VERSIGNALSHOWN;
2951 if (busprefixlen == 0)
2952 {
2953 for(i=0; vs->signalname[i] != 0; i++)
2954 if (vs->signalname[i] == '[') break;
2955 if (vs->signalname[i] == '[')
2956 {
2957 busprefix = vs->signalname;
2958 busprefixlen = i;
2959 sim_addbussignal(realvs->signal);
2960 }
2961 } else sim_addbussignal(realvs->signal);
2962 }
2963 }
2964 if (busprefixlen > 0)
2965 {
2966 buscount = sim_getbussignals(&bussignals);
2967 save = busprefix[busprefixlen];
2968 busprefix[busprefixlen] = 0;
2969 (void)sim_window_makebus(buscount, bussignals, busprefix);
2970 busprefix[busprefixlen] = save;
2971 }
2972 efree((CHAR *)netlist);
2973 }
2974 }
2975
2976 sim_window_redraw();
2977 }
2978
sim_versortsignalnames(const void * e1,const void * e2)2979 int sim_versortsignalnames(const void *e1, const void *e2)
2980 {
2981 VERSIGNAL *vs1, *vs2;
2982
2983 vs1 = *((VERSIGNAL **)e1);
2984 vs2 = *((VERSIGNAL **)e2);
2985 return(namesamenumeric(vs1->signalname, vs2->signalname));
2986 }
2987
sim_verparsetoend(CHAR ** pt)2988 void sim_verparsetoend(CHAR **pt)
2989 {
2990 REGISTER CHAR *keyword;
2991
2992 for(;;)
2993 {
2994 keyword = getkeyword(pt, x_(" "));
2995 if (keyword == NOSTRING) return;
2996 if (*keyword == 0)
2997 {
2998 if (stopping(STOPREASONSIMULATE)) break;
2999 if (xfgets(sim_verline, 300, sim_verfd)) break;
3000 sim_verlineno++;
3001 *pt = sim_verline;
3002 continue;
3003 }
3004 if (namesame(keyword, x_("$end")) == 0) return;
3005 }
3006 }
3007
3008 /*
3009 * The character handler for the waveform window of ALS simulation
3010 */
sim_vercharhandlerwave(WINDOWPART * w,INTSML chr,INTBIG special)3011 BOOLEAN sim_vercharhandlerwave(WINDOWPART *w, INTSML chr, INTBIG special)
3012 {
3013 NODEPROTO *np;
3014 REGISTER INTBIG *highsigs, highsig, i, j, thispos, *bussigs,
3015 trl, nexttr, prevtr, pos, buscount;
3016 REGISTER VERSIGNAL *vs;
3017
3018 ttynewcommand();
3019
3020 /* special characters are not handled here */
3021 if (special != 0)
3022 return(us_charhandler(w, chr, special));
3023
3024 /* can always preserve snapshot */
3025 if (chr == 'p')
3026 {
3027 sim_window_savegraph();
3028 return(FALSE);
3029 }
3030
3031 /* can always do help */
3032 if (chr == '?')
3033 {
3034 sim_verhelpwindow();
3035 return(FALSE);
3036 }
3037
3038 /* if not simulating, don't handle any simulation commands */
3039 if (sim_window_isactive(&np) == 0)
3040 return(us_charhandler(w, chr, special));
3041 switch (chr)
3042 {
3043 /* convert busses */
3044 case 'b':
3045 if (sim_window_buscommand()) return(FALSE);
3046 highsigs = sim_window_gethighlighttraces();
3047 return(FALSE);
3048
3049 /* add trace */
3050 case 'a':
3051 sim_veraddsignals();
3052 return(FALSE);
3053
3054 case 'i':
3055 case 'r':
3056 case DELETEKEY:
3057 break;
3058 default:
3059 return(FALSE);
3060 }
3061
3062 /* the following commands demand a current trace...get it */
3063 highsigs = sim_window_gethighlighttraces();
3064 if (highsigs[0] == 0)
3065 {
3066 ttyputerr(_("Select a signal name first"));
3067 return(FALSE);
3068 }
3069 if (chr == 'i')
3070 {
3071 for(j=0; highsigs[j] != 0; j++)
3072 {
3073 highsig = highsigs[j];
3074 vs = (VERSIGNAL *)sim_window_gettracedata(highsig);
3075 ttyputmsg("Signal %s has %d stimuli on it:", vs->signalname, vs->count);
3076 for(i=0; i<vs->count; i++)
3077 {
3078 ttyputmsg(" %d at time %s (%g)", vs->stimstate[i],
3079 sim_windowconvertengineeringnotation(vs->stimtime[i]), vs->stimtime[i]);
3080 }
3081 }
3082 return(FALSE);
3083 }
3084 if (chr == 'r' || chr == DELETEKEY) /* remove trace(s) */
3085 {
3086 sim_window_cleartracehighlight();
3087
3088 /* delete them */
3089 nexttr = prevtr = 0;
3090 for(j=0; highsigs[j] != 0; j++)
3091 {
3092 highsig = highsigs[j];
3093 thispos = sim_window_gettraceframe(highsig);
3094 bussigs = sim_window_getbustraces(highsig);
3095 for(buscount=0; bussigs[buscount] != 0; buscount++) ;
3096 sim_window_inittraceloop();
3097 nexttr = prevtr = 0;
3098 for(;;)
3099 {
3100 trl = sim_window_nexttraceloop();
3101 if (trl == 0) break;
3102 pos = sim_window_gettraceframe(trl);
3103 if (pos > thispos)
3104 {
3105 if (pos-1 == thispos) nexttr = trl;
3106 pos = pos - 1 + buscount;
3107 sim_window_settraceframe(trl, pos);
3108 } else if (pos == thispos-1) prevtr = trl;
3109 }
3110 if (buscount > 0)
3111 {
3112 for(i=0; i<buscount; i++)
3113 sim_window_settraceframe(bussigs[i], thispos+i);
3114 }
3115
3116 /* remove from the simulator's list */
3117 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3118 {
3119 if (vs->signal == highsig)
3120 {
3121 vs->signal = 0;
3122 break;
3123 }
3124 }
3125
3126 /* kill trace */
3127 sim_window_killtrace(highsig);
3128 }
3129
3130 /* redraw */
3131 if (nexttr != 0)
3132 {
3133 sim_window_addhighlighttrace(nexttr);
3134 } else if (prevtr != 0)
3135 {
3136 sim_window_addhighlighttrace(prevtr);
3137 }
3138 sim_window_redraw();
3139 return(FALSE);
3140 }
3141
3142 return(FALSE);
3143 }
3144
3145 /* Simulation Signal Selection */
3146 static DIALOGITEM sim_sigselectdialogitems[] =
3147 {
3148 /* 1 */ {0, {344,276,368,356}, BUTTON, N_("OK")},
3149 /* 2 */ {0, {344,184,368,264}, BUTTON, N_("Cancel")},
3150 /* 3 */ {0, {4,4,336,356}, SCROLLMULTI, x_("")},
3151 /* 4 */ {0, {348,4,364,176}, CHECK, N_("Show lower levels")}
3152 };
3153 static DIALOG sim_sigselectdialog = {{75,75,452,441}, N_("Select Signal for Simulation"), 0, 4, sim_sigselectdialogitems, 0, 0};
3154
3155 /* special items for the "Simulation Signal Selection" dialog: */
3156 #define DSSS_LIST 3 /* list of signals (scroll) */
3157 #define DSSS_SHOWLOWER 4 /* show lower levels (check) */
3158
3159 BOOLEAN sim_signalshowlower = FALSE;
3160
3161 /*
3162 * Routine to prompt the user for signal names and add them to the waveform window.
3163 */
sim_veraddsignals(void)3164 void sim_veraddsignals(void)
3165 {
3166 REGISTER void *infstr, *dia;
3167 CHAR *pt;
3168 REGISTER INTBIG i, traces, itemHit, *list;
3169 REGISTER VERSIGNAL *vs;
3170
3171 dia = DiaInitDialog(&sim_sigselectdialog);
3172 if (dia == 0) return;
3173 DiaInitTextDialog(dia, DSSS_LIST, sim_vertopofsignals, sim_vernextsignals, DiaNullDlogDone, 0,
3174 SCSELMOUSE|SCSELKEY|SCHORIZBAR);
3175 if (sim_signalshowlower) DiaSetControl(dia, DSSS_SHOWLOWER, 1);
3176 infstr = initinfstr();
3177 formatinfstr(infstr, "Signal in %s", sim_vercurscope);
3178 ttyputmsg("%s", returninfstr(infstr));
3179 for(;;)
3180 {
3181 itemHit = DiaNextHit(dia);
3182 if (itemHit == OK || itemHit == CANCEL) break;
3183 if (itemHit == DSSS_SHOWLOWER)
3184 {
3185 sim_signalshowlower = !sim_signalshowlower;
3186 if (sim_signalshowlower) DiaSetControl(dia, DSSS_SHOWLOWER, 1); else
3187 DiaSetControl(dia, DSSS_SHOWLOWER, 0);
3188 DiaLoadTextDialog(dia, DSSS_LIST, sim_vertopofsignals, sim_vernextsignals, DiaNullDlogDone, 0);
3189 continue;
3190 }
3191 }
3192
3193 if (itemHit == OK)
3194 {
3195 list = DiaGetCurLines(dia, DSSS_LIST);
3196 for(i=0; list[i] >= 0; i++)
3197 {
3198 pt = DiaGetScrollLine(dia, DSSS_LIST, list[i]);
3199
3200 /* find the signal */
3201 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3202 {
3203 if (vs->signal != 0) continue;
3204 if (namesame(vs->signalcontext, sim_vercurscope) != 0) continue;
3205 if (namesame(vs->signalname, pt) == 0) break;
3206 }
3207 if (vs == NOVERSIGNAL)
3208 {
3209 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3210 {
3211 if (vs->signal != 0) continue;
3212 infstr = initinfstr();
3213 formatinfstr(infstr, x_("%s.%s"), vs->signalcontext, vs->signalname);
3214 if (namesame(pt, returninfstr(infstr)) == 0) break;
3215 }
3216 }
3217 if (vs == NOVERSIGNAL) continue;
3218
3219 /* ready to add: remove highlighting */
3220 sim_window_cleartracehighlight();
3221
3222 /* count the number of traces */
3223 sim_window_inittraceloop();
3224 for(traces=0; ; traces++) if (sim_window_nexttraceloop() == 0) break;
3225
3226 /* create a new trace in the last slot */
3227 vs->signal = sim_window_newtrace(-1, vs->signalname, (INTBIG)vs);
3228 sim_window_addhighlighttrace(vs->signal);
3229 sim_window_setnumframes(sim_window_getnumframes()+1);
3230 sim_window_loaddigtrace(vs->signal, vs->count, vs->stimtime, vs->stimstate);
3231 }
3232 }
3233 sim_window_redraw();
3234 DiaDoneDialog(dia);
3235 }
3236
sim_vertopofsignals(CHAR ** c)3237 BOOLEAN sim_vertopofsignals(CHAR **c)
3238 {
3239 Q_UNUSED( c );
3240 sim_verwindow_iter = sim_verfirstsignal;
3241 return(TRUE);
3242 }
3243
sim_vernextsignals(void)3244 CHAR *sim_vernextsignals(void)
3245 {
3246 VERSIGNAL *vs;
3247 REGISTER void *infstr;
3248
3249 for(;;)
3250 {
3251 vs = sim_verwindow_iter;
3252 if (vs == NOVERSIGNAL) break;
3253 sim_verwindow_iter = vs->nextversignal;
3254 if (vs->signal != 0) continue;
3255 if (vs->count <= 0) continue;
3256 if (sim_signalshowlower)
3257 {
3258 if (vs->level < sim_vercurlevel) continue;
3259 if (vs->level == sim_vercurlevel)
3260 {
3261 if (estrcmp(vs->signalcontext, sim_vercurscope) != 0) continue;
3262 return(vs->signalname);
3263 }
3264 infstr = initinfstr();
3265 formatinfstr(infstr, x_("%s.%s"), vs->signalcontext, vs->signalname);
3266 return(returninfstr(infstr));
3267 }
3268 if (vs->level != sim_vercurlevel) continue;
3269 if (estrcmp(vs->signalcontext, sim_vercurscope) != 0) continue;
3270 return(vs->signalname);
3271 }
3272 return(0);
3273 }
3274
sim_vertopofinstances(CHAR ** c)3275 BOOLEAN sim_vertopofinstances(CHAR **c)
3276 {
3277 Q_UNUSED( c );
3278 sim_verwindow_iter = sim_verfirstsignal;
3279 sim_verwindow_lastiter = NOVERSIGNAL;
3280 return(TRUE);
3281 }
3282
sim_vernextinstance(void)3283 CHAR *sim_vernextinstance(void)
3284 {
3285 VERSIGNAL *vs;
3286 REGISTER INTBIG len, curlen, i;
3287
3288 curlen = estrlen(sim_vercurscope);
3289 for(;;)
3290 {
3291 vs = sim_verwindow_iter;
3292 if (vs == NOVERSIGNAL) break;
3293 sim_verwindow_iter = vs->nextversignal;
3294 if (vs->level != sim_vercurlevel+1) continue;
3295 if (estrncmp(vs->signalcontext, sim_vercurscope, curlen) != 0) continue;
3296 if (vs->signalcontext[curlen] != '.') continue;
3297 if (sim_verwindow_lastiter != NOVERSIGNAL &&
3298 strcmp(vs->signalcontext, sim_verwindow_lastiter->signalcontext) == 0) continue;
3299 sim_verwindow_lastiter = vs;
3300 len = estrlen(vs->signalcontext);
3301 for(i=len-1; i>0; i--)
3302 if (vs->signalcontext[i] == '.') break;
3303 if (i > 0) i++;
3304 return(&vs->signalcontext[i]);
3305 }
3306 return(0);
3307 }
3308
sim_verhelpwindow(void)3309 void sim_verhelpwindow(void)
3310 {
3311 NODEPROTO *np;
3312 INTBIG active;
3313
3314 active = sim_window_isactive(&np);
3315 if (active == 0)
3316 {
3317 ttyputmsg(_("There is no current simulation"));
3318 return;
3319 }
3320
3321 ttyputmsg(_("These keys may be typed in the Verilog Waveform window:"));
3322 ttyputinstruction(x_(" a"), 5, _("Add signal to simulation window"));
3323 ttyputinstruction(x_(" r"), 5, _("Remove signal from the window"));
3324 ttyputinstruction(x_(" b"), 5, _("Combine selected signals into a bus"));
3325 ttyputinstruction(x_(" p"), 5, _("Preserve snapshot of simulation window in database"));
3326 }
3327
3328 /*
3329 * Routine to move down the hierarchy into instance "level" and show
3330 * signals at that level.
3331 */
sim_verlevel_set(CHAR * level,NODEPROTO * cell)3332 void sim_verlevel_set(CHAR *level, NODEPROTO *cell)
3333 {
3334 REGISTER VERSIGNAL *vs;
3335 REGISTER INTBIG len;
3336 REGISTER BOOLEAN foundlowerlevel;
3337 REGISTER CHAR *lowerlevel;
3338
3339 /* see if this name is in the data */
3340 if (level != 0)
3341 {
3342 foundlowerlevel = FALSE;
3343 lowerlevel = 0;
3344 len = estrlen(sim_vercurscope);
3345 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3346 {
3347 if (vs->level != sim_vercurlevel+1) continue;
3348 if (namesamen(vs->signalcontext, sim_vercurscope, len) != 0) continue;
3349 if (vs->signalcontext[len] != '.') continue;
3350
3351 /* check the lower level */
3352 if (namesame(&vs->signalcontext[len+1], level) == 0) break;
3353 if (foundlowerlevel)
3354 {
3355 if (lowerlevel != 0)
3356 {
3357 if (namesame(lowerlevel, &vs->signalcontext[len+1]) != 0)
3358 lowerlevel = 0;
3359 }
3360 } else
3361 {
3362 lowerlevel = &vs->signalcontext[len+1];
3363 foundlowerlevel = TRUE;
3364 }
3365 }
3366
3367 if (vs == NOVERSIGNAL)
3368 {
3369 /* did not find the lower level */
3370 if (lowerlevel != 0)
3371 {
3372 estrcat(sim_vercurscope, x_("."));
3373 estrcat(sim_vercurscope, lowerlevel);
3374 sim_vercurlevel++;
3375 }
3376 }
3377
3378 estrcat(sim_vercurscope, x_("."));
3379 estrcat(sim_vercurscope, level);
3380 sim_vercurlevel++;
3381 }
3382
3383 sim_window_grabcachedsignalsoncell(cell);
3384 sim_vershowcurrentlevel(cell);
3385 }
3386
3387 /*
3388 * Routine to move up one level of hierarchy in the display of signal names.
3389 */
sim_verlevel_up(NODEPROTO * cell)3390 void sim_verlevel_up(NODEPROTO *cell)
3391 {
3392 REGISTER INTBIG i;
3393
3394 if (sim_vercurlevel <= 0)
3395 {
3396 ttyputerr(_("At the top level of the hierarchy"));
3397 return;
3398 }
3399 sim_vercurlevel--;
3400 for(i=estrlen(sim_vercurscope)-1; i>0; i--)
3401 if (sim_vercurscope[i] == '.') break;
3402 sim_vercurscope[i] = 0;
3403 sim_window_grabcachedsignalsoncell(cell);
3404 sim_vershowcurrentlevel(cell);
3405 }
3406
sim_verlevel_cur(void)3407 CHAR *sim_verlevel_cur(void)
3408 {
3409 return(sim_vercurscope);
3410 }
3411
3412 /*
3413 * Routine to add the signal called "signame" to the waveform window.
3414 */
sim_veraddhighlightednet(CHAR * signame)3415 void sim_veraddhighlightednet(CHAR *signame)
3416 {
3417 REGISTER VERSIGNAL *vs;
3418 REGISTER INTBIG traces;
3419 REGISTER void *infstr;
3420
3421 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3422 {
3423 if (vs->signal != 0) continue;
3424 infstr = initinfstr();
3425 formatinfstr(infstr, x_("%s.%s"), vs->signalcontext, vs->signalname);
3426 if (namesame(signame, returninfstr(infstr)) == 0) break;
3427 }
3428 if (vs == NOVERSIGNAL) return;
3429
3430 /* ready to add: remove highlighting */
3431 sim_window_cleartracehighlight();
3432
3433 /* count the number of traces */
3434 sim_window_inittraceloop();
3435 for(traces=0; ; traces++) if (sim_window_nexttraceloop() == 0) break;
3436
3437 /* create a new trace in the last slot */
3438 vs->signal = sim_window_newtrace(-1, vs->signalname, (INTBIG)vs);
3439 sim_window_addhighlighttrace(vs->signal);
3440 sim_window_setnumframes(sim_window_getnumframes()+1);
3441 sim_window_loaddigtrace(vs->signal, vs->count, vs->stimtime, vs->stimstate);
3442 }
3443
3444 /*
3445 * Routine that feeds the current signals into the explorer window.
3446 */
sim_verreportsignals(WINDOWPART * simwin,void * (* addbranch)(CHAR *,void *),void * (* findbranch)(CHAR *,void *),void * (* addleaf)(CHAR *,void *),CHAR * (* nodename)(void *))3447 void sim_verreportsignals(WINDOWPART *simwin, void *(*addbranch)(CHAR*, void*),
3448 void *(*findbranch)(CHAR*, void*), void *(*addleaf)(CHAR*, void*), CHAR *(*nodename)(void*))
3449 {
3450 REGISTER INTBIG j, k, len;
3451 REGISTER CHAR *pt, save;
3452 REGISTER void *curlevel, *nextlevel;
3453 REGISTER VERSIGNAL *vs;
3454 CHAR signame[500];
3455
3456 for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3457 {
3458 if (vs->level < 1) continue;
3459 esnprintf(signame, 500, x_("%s.%s"), vs->signalcontext, vs->signalname);
3460 len = strlen(signame);
3461 for(j=len-2; j>0; j--)
3462 if (signame[j] == '.') break;
3463 if (j <= 0)
3464 {
3465 /* no "." qualifiers */
3466 (*addleaf)(signame, 0);
3467 } else
3468 {
3469 /* is down the hierarchy */
3470 signame[j] = 0;
3471
3472 /* now find the location for this branch */
3473 curlevel = 0;
3474 pt = signame;
3475 for(;;)
3476 {
3477 for(k=0; pt[k] != 0; k++) if (pt[k] == '.') break;
3478 save = pt[k];
3479 pt[k] = 0;
3480 nextlevel = (*findbranch)(pt, curlevel);
3481 if (nextlevel == 0)
3482 nextlevel = (*addbranch)(pt, curlevel);
3483 curlevel = nextlevel;
3484 if (save == 0) break;
3485 pt[k] = save;
3486 pt = &pt[k+1];
3487 }
3488 (*addleaf)(&signame[j+1], curlevel);
3489 signame[j] = '.';
3490 }
3491 }
3492 }
3493
3494 #endif /* SIMTOOL - at top */
3495