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