1 /****************************************************************************
2     Copyright (C) 1987-2015 by Jeffery P. Hansen
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18     Last edit by hansen on Fri Feb 13 20:25:04 2009
19 ****************************************************************************/
20 #include "thyme.h"
21 
22 int errCount = 0;
23 int warnCount = 0;
24 extern Place curPlace;			/* The current place */
25 
26 VGSim vgsim;
27 
28 /*
29  * These undoable object functions are only used in the main tkgate code, but
30  * since they are used in the common hash table code we provide stubs here for
31  * the hash table code to use.
32  */
ob_malloc(int s,char * x)33 void *ob_malloc(int s,char *x) { return malloc(s); }
ob_calloc(int n,int s,char * x)34 void *ob_calloc(int n,int s,char *x) { return calloc(n,s); }
ob_free(void * p)35 void ob_free(void *p) { free(p); }
ob_strdup(char const * s)36 char *ob_strdup(char const *s) { return strdup(s); }
ob_set_type(void * o,char * n)37 void ob_set_type(void *o,char *n) {}
ob_touch(void * o)38 void ob_touch(void *o) {}
39 
40 /*****************************************************************************
41  *
42  * Initialize the security flags
43  *
44  * Parameters:
45  *     vgs		VGSecurity object to be initialized.
46  *     trusted		Non-zero to indicate full trust of input file.
47  *
48  *****************************************************************************/
VGSecurity_init(VGSecurity * vgs,int trusted)49 void VGSecurity_init(VGSecurity *vgs,int trusted)
50 {
51   vgs->vgs_send = trusted;
52   vgs->vgs_fopen = trusted;
53   vgs->vgs_writemem = trusted;
54   vgs->vgs_queue = trusted;
55   vgs->vgs_exec = trusted ? 2 : 0;
56   vgs->vgs_handling = 0;
57 }
58 
59 /*****************************************************************************
60  *
61  * Handle a security exception
62  *
63  * Parameters:
64  *     vgs		VGSecurity object to be initialized.
65  *
66  *****************************************************************************/
VGSecurity_handleException(VGSecurity * vgs,VGThread * t,const char * name)67 void VGSecurity_handleException(VGSecurity *vgs,VGThread *t,const char *name)
68 {
69   EvQueue *Q = Circuit_getQueue(t->t_modCtx->mc_circuit);
70 
71   switch (vgs->vgs_handling) {
72   case 0 :		/* ignore */
73     return;
74   case 1 :		/* warning */
75     vgio_printf("error run Execution of protected system task '%s' blocked.\n",name);
76     return;
77   case 2 :		/* stop */
78     EvQueue_stopAfter(Q,0);
79     VGThread_suspend(t);
80     EvQueue_enqueueAfter(Q,new_EvThread(t), 0);
81     vgio_printf("error run Simulation stopped on attempted execution of protected system task '%s'.\n",name);
82     return;
83   }
84 }
85 
86 /*****************************************************************************
87  *
88  * Initialize the VGSim object
89  *
90  * Parameters:
91  *     vg		VGSim object to be initialized.
92  *
93  *****************************************************************************/
VGSim_init(VGSim * vg)94 void VGSim_init(VGSim *vg)
95 {
96   vg->vg_baseDirectory = 0;
97   vg->vg_topModuleName = 0;
98   vg->vg_defaultTopModuleName = 0;
99   SHash_init(&vg->vg_modules);
100   Circuit_init(&vg->vg_circuit);
101   vg->vg_interactive = 0;
102   VGSecurity_init(&vg->vg_sec,0);
103   vg->vg_timescale.ts_units = 0;
104   vg->vg_timescale.ts_precision = 0;
105   vg->vg_haveTScount = 0;
106   vg->vg_noTimeViolations = 0;
107   vg->vg_initTime = 0;
108   vg->vg_delayType = DT_TYP;
109   vg->vg_std = VSTD_1995;
110 }
111 
usage()112 static void usage()
113 {
114   errorCmd(ERR_USAGE);
115   if (errCount) {
116     waitForExit();
117   }
118 }
119 
120 /*****************************************************************************
121  *
122  * Open an file in the current path context
123  *
124  * Parameters:
125  *     name		Name of file to open.
126  *
127  * Open a file in the context of the current circuit.
128  * If the first character of 'name' is '/', then the
129  * file is opened "as is".  Otherwise the following
130  * path is searched:
131  *
132  *    The base_directory spoecified by -B option
133  *    current directory
134  *    user's home directory (value of HOME)
135  *****************************************************************************/
openInPath(const char * name)136 FILE *openInPath(const char *name)
137 {
138   char buf[STRMAX];
139   FILE *f;
140   char *r;
141 
142   /*
143    * If full path, just open the file.
144    */
145   if (*name == '/') return fopen(name,"r");
146 
147   /*
148    * If a base directory is specified, look in that directory.
149    */
150   if ((r = vgsim.vg_baseDirectory)) {
151     strcpy(buf,r);
152     if ((r = strrchr(buf,'/'))) {
153       if (r != buf) {
154 	strcpy(r+1,name);
155 	if ((f = fopen(buf,"r"))) return f;
156       }
157     }
158   }
159 
160   /*
161    * Look in the current directory.
162    */
163   if ((f = fopen(name,"r")))
164     return f;
165 
166   /*
167    * Look in the user's home directory.
168    */
169   if ((r = getenv("HOME"))) {
170     strcpy(buf,r);
171     strcat(buf,"/");
172     strcat(buf,name);
173     if ((f = fopen(buf,"r"))) return f;
174   }
175 
176   return 0;
177 }
178 
179 /*****************************************************************************
180  *
181  * Add a module declaration to the module table.
182  *
183  * Parameters:
184  *     vg		The vgsim object
185  *     m		Module declatation object
186  *
187  *****************************************************************************/
VGSim_addModule(VGSim * vg,ModuleDecl * m)188 void VGSim_addModule(VGSim *vg, ModuleDecl *m)
189 {
190   if (!vg->vg_defaultTopModuleName && List_numElems(&m->m_ports) == 0)
191     vg->vg_defaultTopModuleName = m->m_name;
192 
193   SHash_insert(&vg->vg_modules, m->m_name, m);
194 
195   /* Do post-definition processing of module */
196   if (m->m_specify && Specify_numStats(m->m_specify) > 0) {
197     ModuleDecl_makeFaninTree(m);
198   }
199 
200   /* Update global timescale */
201   if (m->m_timescale.ts_units != 0) {
202     if (vg->vg_timescale.ts_units == 0 || m->m_timescale.ts_units < vg->vg_timescale.ts_units)
203       vg->vg_timescale.ts_units = m->m_timescale.ts_units;
204 
205     vg->vg_haveTScount++;
206   }
207   if (m->m_timescale.ts_precision != 0) {
208     if (vg->vg_timescale.ts_precision == 0 || m->m_timescale.ts_precision < vg->vg_timescale.ts_precision)
209       vg->vg_timescale.ts_precision = m->m_timescale.ts_precision;
210   }
211 }
212 
213 /*****************************************************************************
214  *
215  * Lookup a module declaration in the module table.
216  *
217  * Parameters:
218  *     vg		The vgsim object
219  *     name		Name of the module to find
220  *
221  * Returns:		Module declaration object or null if not found.
222  *
223  *****************************************************************************/
VGSim_findModule(VGSim * vg,const char * name)224 ModuleDecl *VGSim_findModule(VGSim *vg, const char *name)
225 {
226   return (ModuleDecl*) SHash_find(&vg->vg_modules, name);
227 }
228 
229 /*****************************************************************************
230  *
231  * Load a list of files
232  *
233  * Parameters:
234  *     vg		The vgsim object
235  *     load_files	List of files to be loaded.
236  *
237  *****************************************************************************/
VGSim_loadFiles(VGSim * vg,List * load_files)238 void VGSim_loadFiles(VGSim *vg, List *load_files)
239 {
240   ListElem *E;
241 
242   for (E = List_first(load_files);E;E = List_next(load_files,E)) {
243     const char *fileName = (const char*)ListElem_obj(E);
244 
245     if (VerilogLoad(fileName) < 0) {
246       errorCmd(ERR_NOREAD,fileName);
247     }
248   }
249 }
250 
251 /*****************************************************************************
252  *
253  * Print specified modules for debugging purposes
254  *
255  * Parameters:
256  *     vg		The vgsim object
257  *     show_modules	List of modules to be printed
258  *
259  *****************************************************************************/
VGSim_printModules(VGSim * vg,List * show_modules)260 void VGSim_printModules(VGSim *vg,List *show_modules)
261 {
262   ListElem *E;
263 
264   for (E = List_first(show_modules);E;E = List_next(show_modules,E)) {
265     const char *modName = (const char*)ListElem_obj(E);
266 
267     if (strcmp(modName,"-") == 0) {
268       HashElem *HE;
269       for (HE = Hash_first(&vg->vg_modules);HE;HE = Hash_next(&vg->vg_modules,HE)) {
270 	ModuleDecl *m = (ModuleDecl *) HashElem_obj(HE);
271 	printf("\n");
272 	ModuleDecl_print(m, stdout);
273       }
274     } else {
275       ModuleDecl *m = VGSim_findModule(vg, modName);
276       if (m) {
277 	printf("\n");
278 	ModuleDecl_print(m, stdout);
279       }
280     }
281   }
282 }
283 
284 /*****************************************************************************
285  *
286  * Show useful information about defined modules.
287  *
288  * Parameters:
289  *     vg		The vgsim object
290  *
291  * This function is invoked with the '-s' switch and is used by tkgate to
292  * check the integrety of text modules.
293  *
294  *****************************************************************************/
VGSim_displayModuleData(VGSim * vg)295 void VGSim_displayModuleData(VGSim *vg)
296 {
297   HashElem *he;
298 
299   for (he = Hash_first(&vg->vg_modules);he;he = Hash_next(&vg->vg_modules,he)) {
300     ModuleDecl *m = (ModuleDecl *) HashElem_obj(he);
301 
302     ModuleDecl_printData(m);
303   }
304 }
305 
306 /*****************************************************************************
307  *
308  * Set the default timescale for all modules to 1ns / 1ns.
309  *
310  * Parameters:
311  *     vg		The vgsim object
312  *
313  *****************************************************************************/
VGSim_useDefaultTimescale(VGSim * vg)314 void VGSim_useDefaultTimescale(VGSim *vg)
315 {
316   HashElem *he;
317   Timescale ts;
318 
319   ts.ts_units = ts.ts_precision = Directive_parseTimescale(1,"ns");
320 
321   vg->vg_timescale = ts;
322 
323   for (he = Hash_first(&vg->vg_modules);he;he = Hash_next(&vg->vg_modules,he)) {
324     ModuleDecl *m = (ModuleDecl *) HashElem_obj(he);
325     m->m_timescale = ts;
326   }
327 }
328 
exitIfError()329 void exitIfError()
330 {
331   if (vgsim.vg_interactive) {
332     if (errCount > 0) {
333       waitForExit();
334       exit(0);
335     }
336   }
337 }
338 
startSimulation(const char * topName,int warning_mode,List * load_scripts,const char * initTimeSpec)339 int startSimulation(const char *topName,int warning_mode,List *load_scripts,const char *initTimeSpec)
340 {
341   ModuleDecl *m = VGSim_findModule(&vgsim, topName);
342   ListElem *le;
343 
344   /*
345    * We have a top module name, but if we can't find it we are toast.
346    */
347   if (!m) {
348     errorFile(&curPlace,ERR_NOTOP, topName);
349     exitIfError();
350     return 1;
351   }
352 
353   /*
354    * Build the circuit and sort threads for proper initialization.
355    */
356   Circuit_build(&vgsim.vg_circuit,m);
357   Circuit_sortThreads(&vgsim.vg_circuit);
358   Circuit_check(&vgsim.vg_circuit);
359 
360   if (vgsim.vg_interactive) {
361     exitIfError();
362 
363     /*
364      * warning_mode codes:
365      *    1 - ignore warnings
366      *    2 - report warnings only if there were errors
367      *    3 - always report warnings
368      *    4 - always report warnings and stop simulator even if only warnings
369      */
370     switch (warning_mode) {
371     case 3 :
372     case 2 :
373     case 1 :
374       break;
375     case 4 :
376     default :
377       if (warnCount > 0) {
378 	waitForExit();
379 	exit(0);
380       }
381     }
382 
383     /*
384       Why was this here?
385       Circuit_update(&vgsim.vg_circuit);
386     */
387 
388 
389     /*
390      * Report that we are ready to simulate and tell TkGate what time
391      * units and precision we are currently using.
392      */
393     {
394       int n1,n2;
395       char u1[STRMAX],u2[STRMAX];
396 
397       Timescale_decode(vgsim.vg_timescale.ts_units, &n1, u1);
398       Timescale_decode(vgsim.vg_timescale.ts_precision, &n2, u2);
399 
400       vgio_printf("ok %d %s / %d %s\n",n1,u1,n2,u2);
401     }
402   } else {
403     if (errCount > 0) {
404       vgio_printf("Total of %d errors in input file(s).\n",errCount);
405       exit(0);
406     }
407   }
408 
409 
410   /*
411    * Check to see if there is an initialization time specification.  If so,
412    * use this to supress timing violations at the beginning of the simulation.
413    */
414   if (initTimeSpec) {
415     double n;
416     char units[STRMAX];
417     if (sscanf(initTimeSpec,"%lf%s",&n,units) == 2 && n >= 0) {
418       vgsim.vg_initTime = Timescale_toSimtime(&vgsim.vg_timescale,n,units);
419     } else if (strcmp(initTimeSpec,"none") == 0)
420       vgsim.vg_noTimeViolations = 1;
421   }
422 
423 
424   /*
425    * If there were any simulation scripte specified on the command line,
426    * load them now.
427    */
428   for (le = List_first(load_scripts);le;le = List_next(load_scripts,le)) {
429     char *fileName = (char*)ListElem_obj(le);
430     int argc = 3;
431     char *argv[3];
432     argv[1] = "1";
433     argv[2] = fileName;
434     Circuit_execScript(&vgsim.vg_circuit,argc,argv);
435   }
436 
437 
438   /*
439    * Start the actual simulation.
440    */
441   Circuit_run(&vgsim.vg_circuit);
442 
443   return 0;
444 }
445 
446 /*****************************************************************************
447  *
448  * Display the license for Verga.
449  *
450  *****************************************************************************/
showLicense()451 void showLicense()
452 {
453   printf("%s %s - Verilog Simulator for TkGate\n",VGSIM_NAME,VGSIM_VERSION);
454   printf("%s\n",VGSIM_COPYRIGHT);
455   printf("\n");
456   printf("    This program is free software; you can redistribute it and/or modify\n");
457   printf("    it under the terms of the GNU General Public License as published by\n");
458   printf("    the Free Software Foundation; either version 2 of the License, or\n");
459   printf("    (at your option) any later version.\n");
460   printf("\n");
461   printf("    This program is distributed in the hope that it will be useful,\n");
462   printf("    but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
463   printf("    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
464   printf("    GNU General Public License for more details.\n");
465   printf("\n");
466   printf("    You should have received a copy of the GNU General Public License along\n");
467   printf("    with this program; if not, write to the Free Software Foundation, Inc.,\n");
468   printf("    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n");
469   printf("\n");
470   exit(0);
471 }
472 
473 /*****************************************************************************
474  *
475  * main program
476  *
477  *****************************************************************************/
main(int argc,char * argv[])478 int main(int argc,char *argv[])
479 {
480   //extern char *optarg;
481   //extern int optind;
482   extern int yy_is_editor;
483   extern int warning_mode;
484   List load_files;
485   List load_scripts;
486   List show_modules;
487   int scan_mode = 0;
488   int c;
489   int quiet = 0;
490   int delete_on_load = 0;
491   unsigned delete_hash_code = 0;
492   ListElem *le;
493   const char *initTimeSpec = 0;
494 
495   initErrorMessages();
496   List_init(&load_files);
497   List_init(&load_scripts);
498   List_init(&show_modules);
499   VGSim_init(&vgsim);
500 
501   yy_is_editor = 0;
502 
503   /*
504    * Parse the command-line options.
505    */
506   while (argc > 0) {
507     while ((c = getopt(argc,argv,"eslqid:S:P:t:B:D:W:I:V:")) != EOF) {
508       switch (c) {
509       case 'e' :
510 	dumpErrorMessages();
511 	exit(0);
512 	break;
513       case 'l' :
514 	showLicense();
515 	break;
516       case 'S' :
517 	List_addToTail(&load_scripts,optarg);
518 	break;
519       case 'D' :
520 	if (sscanf(optarg,"%u",&delete_hash_code) == 1)
521 	  delete_on_load = 1;
522 	break;
523       case 'V' :
524       	if (strncmp(optarg, "v1995", strlen("v1995")) == 0)
525 		vgsim.vg_std = VSTD_1995;
526 	else if (strncmp(optarg, "v2001", strlen("v2001")) == 0)
527 		vgsim.vg_std = VSTD_2001;
528 	break;
529       case 'W' :
530 	sscanf(optarg,"%d",&warning_mode);
531 	break;
532       case 'q' :
533 	quiet = 1;
534 	break;
535       case 's' :
536 	scan_mode = 1;
537 	Place_setMode((placemode_t)(PM_MODULE|PM_MODLINE));
538 	break;
539       case 'i' :
540 	vgsim.vg_interactive = 1;
541 	Place_setMode((placemode_t)(PM_FILE|PM_LINE|PM_MODULE|PM_MODLINE));
542 	break;
543       case 'P' :
544 	List_addToTail(&show_modules,optarg);
545 	break;
546       case 'B' :
547 	vgsim.vg_baseDirectory = optarg;
548 	break;
549       case 't' :
550 	vgsim.vg_topModuleName = optarg;
551 	break;
552       case 'd' :
553 	if (strcasecmp(optarg,"min") == 0)
554 	  vgsim.vg_delayType = DT_MIN;
555 	else if (strcasecmp(optarg,"max") == 0)
556 	  vgsim.vg_delayType = DT_MAX;
557 	else if (strcasecmp(optarg,"typical") == 0)
558 	  vgsim.vg_delayType = DT_TYP;
559 	break;
560       case 'I' :
561 	initTimeSpec = optarg;
562 	break;
563       default :
564 	usage();
565 	break;
566       }
567     }
568     argc -= optind;
569     argv += optind;
570 #if OPTRESET
571     optreset = 1;
572 #endif
573     optind = 0;
574     if (argc > 0) {
575       List_addToTail(&load_files,argv[0]);
576       argc--;
577       argv++;
578     }
579   }
580 
581   /*
582    * Disable security guards if not running in interactive mode.
583    */
584   if (!vgsim.vg_interactive)
585     VGSecurity_init(&vgsim.vg_sec,1);
586 
587   if (!quiet) {
588     vgio_comment("%s %s - Verilog Simulator for TkGate\n",VGSIM_NAME,VGSIM_VERSION);
589     vgio_comment("%s\n",VGSIM_COPYRIGHT);
590     vgio_comment("  %s comes with ABSOLUTELY NO WARRANTY;  run with -l switch\n",VGSIM_NAME);
591     vgio_comment("  for license and warranty details.  Report problems to starling13@gmail.com\n");
592     vgio_comment("  [compiled on %s %s]\n",__DATE__,__TIME__);
593   }
594 
595   /*
596    * Load design files specified on the command line.
597    */
598   VGSim_loadFiles(&vgsim,&load_files);
599 
600   /*
601    * If no timescale specified, assume a default.
602    */
603   if (vgsim.vg_timescale.ts_units == 0) {
604     VGSim_useDefaultTimescale(&vgsim);
605   }
606 
607 
608   /*
609    * When thyme is executed by tkgate, the circuit files are passed indirectly as
610    * temporary files and after loading the files, it is ok to delete them.  The '-D n'
611    * switch can be used to delete the files after reading, but in order to prevent
612    * accidental deletion of user files, we require that a hash code computed from
613    * the file name matches the value given to the -D switch.  This value can be computed
614    * within tkgate, but it is unlikely that a correct value can be given accidentally.
615    */
616   if (delete_on_load) {
617     for (le = List_first(&load_files);le;le = List_next(&load_files,le)) {
618       char *fileName = (char*)ListElem_obj(le);
619       unsigned fileHash = computestrhash(fileName);
620       if (fileHash == delete_hash_code)
621 	unlink(fileName);
622     }
623   }
624 
625   /*
626    * If the -s switch was used, we are just doing a scan, so just do the scan
627    * and exit.
628    */
629   if (scan_mode) {
630     VGSim_displayModuleData(&vgsim);
631     exit(0);
632   }
633 
634   /*
635    * If there are modules to display, display them and exit.
636    */
637   if (List_numElems(&show_modules) > 0) {
638     VGSim_printModules(&vgsim,&show_modules);
639     exit(0);
640   }
641 
642   /*
643    * No explicit top-module was given, try the default top module.
644    */
645   if (!vgsim.vg_topModuleName)
646     vgsim.vg_topModuleName = vgsim.vg_defaultTopModuleName;
647 
648   /*
649    * Either all modules must have a `timescale or none of them should have
650    * a `timescale.  Do this check here.
651    */
652   if (vgsim.vg_haveTScount != 0
653       && vgsim.vg_haveTScount != Hash_numElems(&vgsim.vg_modules)) {
654     errorFile(&curPlace,ERR_TIMESCALEAN);
655     exitIfError();
656     return 1;
657   }
658 
659   /*
660    * If we do not have a top module name, we must exit.
661    */
662   if (!vgsim.vg_topModuleName) {
663     errorFile(&curPlace,ERR_NOTOP, "<none>");
664     exitIfError();
665     return 1;
666   }
667 
668   startSimulation(vgsim.vg_topModuleName,warning_mode,&load_scripts,initTimeSpec);
669 
670   return 0;
671 }
672 
673