1 #if HAVE_ALLOCA_H
2 #include <alloca.h>
3 #endif
4 #if HAVE_MALLOC_H
5 #include <malloc.h>
6 #endif
7 #include <string.h>
8 #include <fstream>
9 #include <sstream>
10 #include <map>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <sys/types.h>
14 #if HAVE_SOCKET
15 #include <sys/socket.h>
16 #endif
17
18 extern "C" {
19 #include <regex.h>
20 }
21
22 #define KERNEL
23 #include <freehdl/kernel-acl.hh>
24 #include <freehdl/kernel-flags.hh>
25 #include <freehdl/kernel-kernel-class.hh>
26 #include <freehdl/kernel-name-stack.hh>
27 #include <freehdl/kernel-map-list.hh>
28 #include <freehdl/kernel-sig-info.hh>
29 #include <freehdl/kernel-register.hh>
30 #include <freehdl/kernel-persistent-dump.hh>
31 #include <freehdl/kernel-persistent-cdfg-dump.hh>
32 #include <freehdl/kernel-dump.hh>
33 #include <freehdl/kernel-db.hh>
34 #include <freehdl/kernel-error.hh>
35 #include <freehdl/kernel-fhdl-stream.hh>
36
37 #ifdef PERFMON_STATISTICS
38 #include "pcounter.hh"
39 #endif
40
41
42 // The kernel. Note, there is only a single instantiation of
43 // the kernel_class
44 kernel_class kernel;
45
46 //global variables:
47 #define BUFSIZE (sizeof(long)*8 + 1)
48 #define LIMIT_SIZE 200000
49 #define STOCK_TIME_BUFFER_SIZE 29
50 char stock_time[STOCK_TIME_BUFFER_SIZE];
51 fstream file;
52 string timescale_unit = "ns";
53 int timescale = 1;
54 int coef_str_length = 7;
55 bool quiet = false;
56
57 buffer_stream dump_buffer;
58 buffer_stream file_buffer;
59 FILE* info_file = NULL;
60 FILE* index_file = NULL;
61 FILE* string_file = NULL;
62 extern void write_info_file(list<Xinfo_data_descriptor*> &xinfo_desc, FILE* info_file,
63 FILE* index_file, FILE* string_file);
64
65
66 // Time calculation
print_sim_time(fhdl_ostream_t & outp)67 void print_sim_time(fhdl_ostream_t &outp)
68 {
69 outp << "Simulation time = " << time_to_string (kernel.get_sim_time ())
70 << " + " << kernel.get_delta () << "d\n";
71 }
72
73
74 // writes the content of file_buffer in the VCD file
75 // then cleans it.
write_in_file(buffer_stream & file_buffer)76 void write_in_file(buffer_stream &file_buffer)
77 {
78 file << file_buffer.str();
79 file_buffer.clean();
80 }
81
82
83 // vcd_mapping_table: opens file and reads user_defined translation table
84 Tmap
get_map_list(char * fileTranslation)85 get_map_list( char* fileTranslation)
86 {
87 char ch;
88 int j = 0;
89 int i = 0;
90 char buf[80];
91 string value;
92 string instance_name;
93 ifstream g(fileTranslation);
94 Tmap table;
95 while( !(g.eof()))
96 {
97 g.get(ch);
98 if (ch == '#') {
99 while (ch != '\n') g.get(ch);
100 j = 0;
101 i = 0;
102 } else if (ch == '(' ){
103 do {
104 g.get(ch);
105 if (ch != '\'' && ch != ' ' && ch != ',') buf[j++] = ch;
106 }
107 while( ch != ')');
108 buf[j-1] = '\0';
109 value = buf;
110 table[instance_name] = strdup(value.c_str());
111 } else if (ch == ')'){
112 } else if (ch == '\n'){
113 } else {
114 do {
115 buf[i++] = ch;
116 g.get(ch);
117 }
118 while(ch != ' ');
119 buf[i] = '\0';
120 instance_name = buf;
121 }
122 }
123 g.close();
124
125 return table;
126 }
127
128
129 // This function verfies the alpha-numeric of file names. Returns false
130 // if d is not a valid file name
131 bool
char_verifier(const char * d)132 char_verifier(const char* d)
133 {
134 const static char* test_table = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.";
135
136 if (d == NULL) return false;
137
138 while (*d != '\0') {
139 const char *test_char = test_table;
140 while (*test_char != '\0')
141 if (*test_char == *d)
142 break;
143 else
144 test_char++;
145 if (*test_char == '\0')
146 return false;
147 d++;
148 }
149
150 return true;
151 }
152
153
154 // creates the dumped signal lists
155
156 void
create_dumper_processes(sig_info_base * sinfo,type_info_interface * info,name_stack & nstack,acl * a)157 create_dumper_processes(sig_info_base *sinfo, type_info_interface *info,
158 name_stack &nstack, acl *a)
159 {
160 switch (info->id) {
161 case ARRAY:
162 {
163 array_info &ainfo = *(array_info*)info;
164
165 if (ainfo.element_type->id == ENUM)
166 break;
167
168 const int lb = ainfo.left_bound;
169 const int rb = ainfo.right_bound;
170
171 // Create a new acl with size 1 greater than acl a and copy
172 // content of a to new acl
173 const int new_acl_size = (a == NULL? 0 : a->get_size()) + 1;
174 acl *new_acl = new(new_acl_size) acl;
175 if (a != NULL)
176 *new_acl = *a;
177 // Add a dummy element so that the current size of new_acl is set
178 // appropriately
179 *new_acl << -1;
180
181 // For each element of the array call create_dumper_process
182 // recursively
183 if (lb <= rb)
184 {
185 for (int i = lb; i <= rb; i++)
186 {
187 new_acl->set(new_acl_size - 1, i);
188 create_dumper_processes(sinfo, ainfo.element_type, nstack, new_acl);
189 }
190 } else {
191 for (int i = lb; i >= rb; i--)
192 {
193 new_acl->set(new_acl_size - 1, i);
194 create_dumper_processes(sinfo, ainfo.element_type, nstack, new_acl);
195 }
196 }
197
198 delete new_acl;
199 return; // We're done, so return
200 break;
201 }
202
203 case RECORD:
204 {
205 record_info &rinfo = *(record_info*)info;
206 const int length = rinfo.record_size;
207 // Create a new acl with size 1 greater than acl a and copy
208 // content of a to new acl
209 const int new_acl_size = (a == NULL? 0 : a->get_size()) + 1;
210 acl *new_acl = new(new_acl_size) acl;
211 if (a != NULL)
212 *new_acl = *a;
213 // Add a dummy element so that the current size of new_acl is set
214 // appropriately
215 *new_acl << -1;
216
217 // For each element of the array call create_dumper_process
218 // recursively
219 for (int i = 0; i < length; i++)
220 {
221 new_acl->set(new_acl_size - 1, i);
222 create_dumper_processes(sinfo, rinfo.element_types [i], nstack, new_acl);
223 }
224
225 delete new_acl;
226 return; // We're done, so return
227 break;
228 }
229
230 default:
231 break;
232 }
233
234 // Create a dumper process for the entire instance
235 nstack.push(signal_dump_process_list.size() + 1);
236 signal_dump* dumper_proc = new signal_dump(nstack, sinfo, a);
237 signal_dump_process_list.push_back(dumper_proc);
238 //and finally pops the name stack and deletes the acces code list
239 nstack.pop();
240 }
241
242
243 const char* command_table[]={
244 "q", "quit", "n", "next", "c", "cycle", "r", "run", "dump", "d",
245 "don", "doff", "dc", "ds", "ds_view", "nds", "s", "show", "dv", "wdd",
246 "wddl", "h", "help", "db_view", NULL
247 };
248
249 // This function validates the input command
250 bool
nu_clear(string & d)251 nu_clear(string &d)
252 {
253 int i = 0;
254 const char* regex_n = d.c_str();
255 while (true)
256 {
257 const char* regex_i = command_table[i++];
258 if (regex_i == NULL)
259 return false;
260 if (strcmp(regex_i, regex_n) == 0)
261 return true;
262 }
263
264 return false;
265 }
266
267
268 // time conversion function
269 char*
time_conversion(const lint & tval,const int & coef_str_length)270 time_conversion(const lint &tval, const int &coef_str_length )
271 {
272 // store the time value in fs the tmp_time_buffer
273 char *cursor = stock_time + STOCK_TIME_BUFFER_SIZE - 1;
274 char *pos_end_cursor = stock_time + STOCK_TIME_BUFFER_SIZE - 1;
275 lint l = tval;
276 *(cursor--) = '\0';
277 while (l > 0) {
278 lint new_l = l / 10;
279 int diff = l - (new_l << 3) - (new_l << 1);
280 *(cursor--) = (char)diff + '0';
281 l = new_l;
282 }
283 const int str_len = (int)(pos_end_cursor-cursor);
284 // calculates the difference between the string lengths
285 const int diff = str_len - coef_str_length;
286 // if this difference is positiv(i.e: time value is greater
287 // than coefficient time, which actually presents timescale
288 if (diff > 0) {
289 strcpy(stock_time,(cursor+1));
290 stock_time[diff] = '\0';
291 } else if(diff == 0) {
292 // the case occurs when the time grid (timescale + timeunit) is too
293 // small to represent the change of the signal
294 stock_time[0] = '0';
295 stock_time[1] = '\0';
296 } else if(diff < 0) {
297 stock_time[0] = '0';
298 stock_time[1] = '\0';
299 }
300 return stock_time;
301 }
302
303 // time unit conversion function: converts the time unit to the given unit
304
time_unit_conversion(string & tsu)305 int time_unit_conversion(string &tsu)
306 {
307 lint coef_conversion = 1000000;
308 dump_buffer.clean();
309
310 if (tsu == "s")
311 coef_conversion = 1000000000000000LL;
312 else if (tsu == "ms")
313 coef_conversion = 100000000000LL;
314 else if (tsu == "us")
315 coef_conversion = 1000000000LL;
316 else if (tsu == "ns")
317 coef_conversion = 1000000LL;
318 else if (tsu == "ps")
319 coef_conversion = 1000LL;
320 else if (tsu == "fs")
321 coef_conversion = 1LL;
322
323 coef_conversion = coef_conversion * timescale;
324 dump_buffer << coef_conversion ;
325 coef_str_length = dump_buffer.str_len();
326
327 return coef_str_length;
328 }
329
330
331 //f_log2 function used to determine the size of each signal type
f_log2(lint x)332 int f_log2(lint x)
333 {
334 int log = 0;
335 do
336 {
337 x = x/2;
338 log++;
339 }
340 while(x != 0);
341 return log;
342 }
343
344
345 // vcd_file function
346
vcd_file(char * fileName,string & cmd)347 void vcd_file (char* fileName, string &cmd)
348 {
349
350 // store the time in the vcd_file
351 lint tval = kernel.get_sim_time();
352 //if tval >= 0 call time_conversion function to convert time
353 // then write it in the file
354 if (tval >= 0 )
355 file_buffer << '#' << time_conversion(tval, coef_str_length) << '\n';
356 // switch the dump cases and store the informtion in vcd_file
357 // dump and dump on case
358 if (cmd == "d" || cmd == "dump" || cmd == "don" )
359 {
360 if (cmd == "d" || cmd == "dump") {file_buffer << "$dumpvars" << '\n';}
361 else {file_buffer << "$dumpon" <<'\n';}
362 int count = 0;
363 list<signal_dump*>::iterator ig = signal_dump_process_list.begin();
364 for (list<signal_dump*>::iterator it = signal_dump_process_list.begin();
365 it != signal_dump_process_list.end(); it++)
366 {
367 if ((*it)->sname != (*ig)->sname)
368 //delete dump_buffer to alow a new storage
369 dump_buffer.clean();
370 // call the vcd_print function into calling write_value function
371 (*it)->write_value();
372 ig = it;
373 }
374 }
375 // dump off case
376 else if (cmd == "doff")
377 {
378 file_buffer << "$dumpoff" << '\n';
379 const char* dump_pointer = dump_buffer.str();
380 for (list<signal_dump*>::iterator it = signal_dump_process_list.begin();
381 it != signal_dump_process_list.end(); it++)
382 {
383 // call the vcd_print function
384 (*it)->type->vcd_print(dump_buffer, (*it)->reader_pointer,(*it)->translation_table, false);
385 // all signals are assigned to 'x' or 'bx' then written in the file
386 if (dump_pointer[0] == 'b')
387 file_buffer <<"bx" << ' ' << (*it)->vcd_signal_identifier << '\n';
388 else
389 file_buffer <<'x'<< ' ' << (*it)->vcd_signal_identifier << '\n';
390 }
391 }
392 file_buffer << "$end" <<'\n' ;
393 }
394
395 //chooses the right vcd_signal_identifier
choose_identifier(char * tab)396 char* choose_identifier(char *tab)
397 {
398 int index = 0;
399 while(1)
400 {
401 if (tab[index] == 0)
402 tab[index] = 33;
403 else
404 tab[index]++;
405 if(tab[index] > 126)
406 {
407 tab[index] = 33;
408 index++;
409 }
410 else break;
411 }
412
413 return tab;
414 }
415
416
417
418 //file get_size_range: writes size of signal and range of array in file
419 int
get_size_range(fhdl_ostream_t & outp,list<signal_dump * >::iterator it,ostringstream & range,int & size)420 get_size_range(fhdl_ostream_t &outp, list<signal_dump*>::iterator it, ostringstream &range, int &size)
421 {
422 array_info *ainfo = ((array_info*)(*it)->type);
423 array_info *element_ainfo = (array_info*)(ainfo->element_type);
424
425 // *****************************************************************
426 // first, tests the element type( case array)
427 // *****************************************************************
428 if (ainfo->id == ARRAY) {
429
430 //****************************************************************
431 // test of the direction (case to):
432 //****************************************************************
433 if (ainfo->index_direction == to) {
434 // tests the subelement type. If it is an array or integer:
435 if (ainfo->element_type->id == ARRAY ||ainfo->element_type->id == INTEGER)
436 {
437 //*****************************
438 // if it's an array:
439 //****************************
440 if (ainfo->element_type->id == ARRAY){
441
442 //**********************************************
443 // tests the subelement direction( to or downto)
444 //**********************************************
445 if (element_ainfo->index_direction == downto)
446 // if downto then defines the range from left to right:
447 range << "[" << element_ainfo->left_bound << ":"
448 << element_ainfo->right_bound << "]";
449 else
450 // else(if to) then defines the range from right to left:
451 range <<"["<< element_ainfo->right_bound <<":"
452 << element_ainfo->left_bound << "]";
453 //then determes the size of this array:
454 size = element_ainfo->length;
455 //else: i.e if the subelement is integer type
456 } else {
457 //then calculates the difference between its right and left bounds
458 lint x = (lint)element_ainfo->right_bound - (lint)element_ainfo->left_bound ;
459 x = x < 0? -x : x;
460 // then uses the function f_log2 to determine the binary size of this element:
461 size = f_log2(x);
462 range << "";
463 }
464 // else if the subelement is neither an array nor an integer(i.e: enum or real)
465 } else {
466 // then the range is determined from right to left of the array element
467 range << "[" << ainfo->right_bound << ":" <<ainfo->left_bound << "]";
468 // and the size is the length of this array
469 size = ainfo->length;
470 }
471
472 //diplays a warning on the screen indicating the inversion range of this array.
473 //This will be done if quiet si true:
474 if (!quiet)
475 outp <<"warning: Direction of signal " << (*it)->instance_name.c_str()
476 <<"["<<ainfo->left_bound<< " to " << ainfo->right_bound <<"]"
477 << " will be converted to "<<"["<<ainfo->right_bound
478 <<" downto "<<ainfo->left_bound<<"]"<<" in VCD file\n";
479
480 // *****************************************************************
481 // case downto of direction test:
482 // *****************************************************************
483 }else if (ainfo->index_direction == downto) {
484
485 //*******************************************************
486 // tests the subelement type when it is array or integer:
487 //*******************************************************
488 if (ainfo->element_type->id == ARRAY || ainfo->element_type->id == INTEGER)
489 {
490
491 //*********************
492 // if it's an array:
493 //********************
494 if (ainfo->element_type->id == ARRAY){
495
496 //**********************************************
497 // tests subelements direction (may be "to" or "downto")
498 //**********************************************
499 if (element_ainfo->index_direction == downto)
500 // if downto then defines the range from left to right:
501 range << "["<< element_ainfo->left_bound
502 <<":"<<element_ainfo->right_bound <<"]";
503 else
504 // else(if to) then defines the range from right to left:
505 range <<"[" << element_ainfo->right_bound
506 <<":"<<element_ainfo->left_bound << "]";
507 //then calculates the difference between its right and left bounds
508 size = element_ainfo->length;
509 //else: i.e if the subelement is integer type
510 } else {
511 //then calculates the difference between its right and left bounds
512 lint x = (lint)element_ainfo->right_bound - (lint)element_ainfo->left_bound ;
513 // then uses the function f_log2 to determine the binary size of this element:
514 size = f_log2(x < 0? -x : x);
515 range << "";
516 }
517 // else if the subelement is neither array nor integer(i.e: enum or real)
518 }else {
519 // then the range is determined from right to left of the array element
520 range << "[" <<ainfo->left_bound << ":" <<ainfo->right_bound << "]";
521 // and the size is the length of this array
522 size = ((array_info*)(*it)->type)->length;
523 }
524 }
525
526 // *****************************************************************
527 // now test the element type (integer case)
528 // *****************************************************************
529 } else if ((*it)->type->id == INTEGER) {
530 integer_info_base *iinfo = ((integer_info_base*)(*it)->type);
531 // then calculate the difference between its right and left bounds to determine the range
532 lint x = (lint)(iinfo->left_bound) - (lint)(iinfo->right_bound);
533 // and use f_log2 function to determine the binary size of this element
534 size = f_log2(x < 0? -x : x);
535 range <<"";
536 // if the element is neither integer nor array:
537 } else {
538 // then the element size is determined...
539 size = (*it)->type->size;
540 range <<"";
541 }
542
543 return size;
544 }
545
546
547
548 // decides the case of up and/or down scope and writes module name.
hierarchy(int & n_count,int & o_count,char * stock_var,string & old_value)549 void hierarchy (int &n_count, int &o_count, char* stock_var, string &old_value)
550 {
551 /***********************************************************/
552 /* This rountine copies the module names in array stock_mod*/
553 /***********************************************************/
554 const int len = strlen(stock_var);
555 #ifdef HAVE_ALLOCA
556 char *stock_var_cpy = (char*)alloca((len+1) * sizeof(char));
557 char **stock_mod = (char**)alloca(n_count * sizeof(char*));
558 #else
559 char *stock_var_cpy = (char*)malloc((len+1) * sizeof(char));
560 char **stock_mod = (char**)malloc(n_count * sizeof(char*));
561 #endif
562 strcpy(stock_var_cpy,stock_var);
563 int i = 1;
564 for (int h = len; h >= 0; h--) {
565 // every module is referenced with ':' in the instance name
566 if (stock_var_cpy[h] == ':') {
567 stock_mod[n_count-(i++)] = &stock_var_cpy[h+1];
568 stock_var_cpy[h] = '\0';
569 }
570 }
571
572 // i should NEVER be greater than (n_count+1)!
573 v_assert(i > (n_count + 1), "i > n_count");
574
575 regex_t preg;// used in regular expression function
576 const char *regex_i = old_value.c_str();// used in
577 // regular expression function
578 const char *regex_n = stock_mod[0];// used in regular
579 // expression function.
580 //Calculates the difference between the new count and the last count
581 const int diff = n_count - o_count;
582 // if this difference is positiv(i.e: that we go down in the module
583 // hierarchies)
584 if ( diff > 0){
585 // write in the file the new modules names until the last one
586 for(int i = o_count; i < n_count; i++)
587 file << "$scope module "<< stock_mod[i]<<" $end" <<endl;
588 // if not(i.e: that we go up in the module hierarchies)
589 } else if(diff < 0) {
590 int j = 0;
591 for (int i = 0; i < n_count; i++){
592 // and the regex_n to new module name in the stock module name
593 regex_n = stock_mod[i];
594 // then we find the existence of this module using regular
595 // expression function
596 regcomp(&preg, regex_n, REG_NOSUB);
597 int h = regexec(&preg, regex_i, 0, NULL, REG_NOTEOL);
598 // if the new name dont exist, the boucle will be breaked
599 if (h != 0)
600 break;
601 // else we go down in the stocked module names
602 else
603 j++;
604 }
605 //then writes the new module names in the file
606 for (int i = j; i <= (j - diff); i++)
607 file <<"$upscope " <<" " << "$end" << endl;
608 for (int i = j; i < n_count; i++)
609 file <<"$scope module " <<stock_mod[i] <<" " << "$end" << endl;
610
611 // if the differnce is equal to zero(i.e: we are in the same
612 // hierarchy)
613 }else if (diff == 0){
614 int j = 0;
615 for (int i = 0; i < n_count; i++){
616 // and the regex_n to new module name in the stock module name
617 regex_n = stock_mod[i];
618 // then we find the existence of this module using regular
619 // expression function
620 regcomp(&preg, regex_n, REG_NOSUB);
621 int h = regexec(&preg, regex_i, 0, NULL, REG_NOTEOL);
622 // if the new name dont exist, the boucle will be breaked
623 if (h != 0)
624 break;
625 // else we go down in the stocked module names
626 else
627 j++;
628 }
629 //then writes the new module names in the file
630 for ( int i = j;i < n_count; i++)
631 file <<"$upscope " <<" " << "$end" << endl;
632 for ( int i = j;i < n_count; i++)
633 file <<"$scope module " <<stock_mod[i] <<" " << "$end" << endl;
634
635 }
636 #ifndef HAVE_ALLOCA
637 free (stock_var_cpy);
638 free (stock_mod);
639 #endif
640 }
641
642
643 // Separates instance strings like ":addcomp:test:a" into sections (":" are removed)
644 inline vector<string>
split(const string & path)645 split (const string &path)
646 {
647 vector<string> result;
648 for (unsigned int i = 0; i < path.size (); i++)
649 if (path [i] == ':')
650 result.push_back ("");
651 else
652 result.back () += path [i];
653
654 return result;
655 }
656
657
658 // Searches for the first element (strating from the beginning) that
659 // are not equal. Returns the number of element that is not equal.
660 inline int
find_different_element(const vector<string> & str1,const vector<string> & str2)661 find_different_element (const vector<string> &str1, const vector<string> &str2)
662 {
663 for (unsigned int i = 0; i < min (str1.size (), str2.size ()); i++)
664 if (str1 [i] != str2 [i])
665 return i;
666
667 return min (str1.size (), str2.size ());
668 }
669
670
671 //Initial_values function:
672
write_header(fhdl_ostream_t & outp,char * fileName)673 void write_header(fhdl_ostream_t &outp, char* fileName)
674 {
675 // { ???, INTEGER, ENUM, FLOAT, PHYSICAL, RECORD, ARRAY, ACCESS, VHDLFILE};
676 static const char *id_str_table[] = { "???", "integer", "trireg",
677 "real", "time", "???", "reg", "???", "???" };
678 char tab[5] = "\0\0\0\0";// used to calculate signal identifiers
679 // (each character is in range 33 to 126)
680 int size = 0;// size of signal(for array its length)
681 string old_value; //used to store
682 //the last instance name, which is executed
683 int o_count = 0;// used to count how many ':' in old_value
684
685 //write in file, date, version and timescale
686 file << "$date" << endl;
687 file << " " << __DATE__<<" "<<__TIME__<<endl;
688 file << "$end" << endl;
689 file << "$version" << endl;
690 file << " " << "FREEHDL " PACKAGE_VERSION << endl;
691 file << "$end" << endl;
692 file << "$timescale" << endl;
693 file << " " << timescale<<" "<<timescale_unit<< endl;
694 file <<"$end" << endl;
695
696 vector<string> current_path;
697
698 // presents the dumped signal lists to define the modules and variables and write them in the file
699 for (list<signal_dump*>::iterator it = signal_dump_process_list.begin();
700 it != signal_dump_process_list.end(); it++)
701 {
702 ostringstream range;
703 //call get_size_range function
704 get_size_range(outp, it, range, size);
705
706 // get path name vector for current signal
707 vector<string> path_vec = split ((*it)->instance_name);
708 path_vec.pop_back ();
709
710 // get first element that is not equal
711 const unsigned int diff = find_different_element (path_vec, current_path);
712
713 while (diff < current_path.size ())
714 {
715 file <<"$upscope $end" << endl;
716 current_path.pop_back ();
717 }
718
719 for (unsigned int i = diff; i < path_vec.size (); i++)
720 {
721 file << "$scope module " << path_vec [i] << " $end" << endl;
722 current_path.push_back (path_vec [i]);
723 }
724
725 // Check whether a space must be inserted between the value and
726 // the signal identifier and print indentifier. No space is
727 // inserted for bit enumeration types (bit, boolean, std_logic,
728 // std_ulogic).
729 if ((*it)->translation_table != NULL &&
730 (*it)->type->id == ENUM)
731 strcpy((*it)->vcd_signal_identifier, choose_identifier(tab));
732 else {
733 strcpy((*it)->vcd_signal_identifier + 1, choose_identifier(tab));
734 (*it)->vcd_signal_identifier[0] = ' ';
735 }
736 // and finally writes in file signal value, name and identifier
737 file << "$var " << " " << id_str_table[int((*it)->type->id)] << " "
738 << size << " " << tab << " " << (*it)->name.c_str()+1 << range.str()
739 << " " << "$end" << endl;
740 }
741
742 while (current_path.size () > 0)
743 {
744 file << "$upscope $end" << endl;
745 current_path.pop_back ();
746 }
747 file <<"$enddefinitions"<<" "<<"$end" << endl;
748 }
749
750
751 // Print-help
752
print_help(fhdl_ostream_t & outp)753 void print_help(fhdl_ostream_t &outp)
754 {
755 outp << "Available commands:\n";
756 outp << " h : prints list of available commands\n";
757 outp << " c <number> : execute cycles = execute <number> simulation cycles\n";
758 outp << " n : next = execute next simulation cycle\n";
759 outp << " q : quit = quit simulation\n";
760 outp << " r <time> : run = execute simulation for <time>\n";
761 outp << " d : dump = dump signals\n";
762 outp << " doff : dump off = stop dumping signals\n";
763 outp << " don : dump on = continue dumping signals\n";
764 outp << " s : show = show signal values\n";
765 outp << " dv : dump var = dump a signal from the signal lists\n";
766 outp << " ds : dump show = shows the list of dumped signals\n";
767 outp << " nds : number show = shows the number of dumped signals\n";
768 outp << " wdd : write binary design info\n";
769 outp << " wddl : write design info using a CDFG style syntax\n";
770 outp << " db_view : print kernel database\n";
771 outp << " dc [-f <filename>] [-t <timescale> <time unit>] [-cfg <translation file>] [-q] :"
772 "control waveform dumping\n";
773 #ifdef EVENT_PROFILE
774 outp << " p <file> : event profile information write to <file>\n";
775 #endif
776 }
777
778 // scc function: presents the kernel function
779
scc(fhdl_istream_t & inp,fhdl_ostream_t & outp)780 void scc(fhdl_istream_t &inp, fhdl_ostream_t &outp) {
781
782 //Declaration of needed parameters
783 bool header_written = true;
784 bool dump_done = false;
785 bool open_file = true;
786 char fileName[80] = "wave.dmp";
787 string cmd;
788
789 //file_buffer initialisation
790 file_buffer.clean();
791 // print help on the screen
792 if (!quiet) print_help(outp);
793
794 // Print the current simulation time
795 if (!quiet) print_sim_time(outp);
796
797
798 while (true) {
799
800 if (!inp.eof()) {
801 // Output prompt
802 if (!quiet) outp << "> "; outp.flush();
803 // Read next command to excute
804 inp >> cmd;
805
806 } else
807 cmd = "q";
808
809 // Quit simulation
810 if (cmd == "q" || cmd == "quit"){
811
812 //Writing the file buffer in the waveform file
813 write_in_file(file_buffer);
814 return;
815
816 // Print help screen
817 } else if (cmd == "h" || cmd == "help") {
818 print_help(outp);
819
820 // Simulate the next cycle
821 } else if (cmd == "n" || cmd == "next") {
822
823 //call initial_values function
824 if (header_written && dump_done){
825 file.open(fileName, ios::out);
826 write_header(outp, fileName);
827 header_written = false;
828 }
829 // Execute next simulation cycle
830 kernel.next_cycle();
831 // Print simulation time
832 if (!quiet) print_sim_time(outp);
833
834 // Cycle
835 } else if (cmd == "c" || cmd == "cycle") {
836 STATISTICS(int counter_start = kernel.executed_processes_counter;);
837 STATISTICS(int transactions_counter = kernel.created_transactions_counter;);
838 //call write_header function
839 if ( header_written && dump_done){
840 file.open(fileName, ios::out);
841 write_header(outp, fileName);
842 header_written = false;
843 }
844 if (!quiet) outp << "Number of cycles to execute? "; outp.flush();
845 int cycles;
846 inp >> cycles;
847 if (!quiet) outp << "Executing " << cycles << " simulation cycles.\n";
848 while (cycles--) {
849 // Execute next simulation cycle
850 kernel.next_cycle();
851 }
852 // Print simulation time
853 if (!quiet) {
854 print_sim_time(outp);
855 outp << "\n";
856 STATISTICS(outp << kernel.executed_processes_counter - counter_start
857 << " processes were executed.\n";);
858 STATISTICS(outp << kernel.created_transactions_counter - transactions_counter
859 << " transaction were created.\n";);
860 }
861
862 // Run
863 } else if (cmd == "r" || cmd == "run") {
864 if (!quiet)
865 outp << "Run simulation for which time span? "; outp.flush();
866 int val, i;
867 inp >> val;
868 string time_unit;
869 inp >> time_unit;
870 if (!quiet)
871 outp << "\n";
872
873 for (i=0; i < L3std_Q8standard_I4time::unit_count; i++)
874 if (!strcmp(time_unit.c_str(), L3std_Q8standard_I4time::units[i])) break;
875 if (i == L3std_Q8standard_I4time::unit_count) {
876 kernel_error_stream << "Unknown time unit " << time_unit << "\n";
877 continue;
878 }
879 //call initial_values function
880 if ( header_written && dump_done){
881 file.open(fileName, ios::out);
882 write_header(outp, fileName);
883 header_written = false;
884 }
885 STATISTICS(int counter_start = kernel.executed_processes_counter;);
886 STATISTICS(int transactions_counter = kernel.created_transactions_counter;);
887
888 lint time_value = kernel.get_sim_time();
889 time_value = time_value + L3std_Q8standard_I4time::scale[i] * (lint)val;
890 if (!quiet) {
891 outp << "Simulating model to time " << val << " " << time_unit << "\n";
892 }
893
894 #ifdef PERFMON_STATISTICS
895 start_pcounter(main_argc, main_argv);
896 #endif
897
898 // Perform simulation
899 kernel.do_sim(time_value);
900
901 #ifdef PERFMON_STATISTICS
902 end_pcounter();
903 #endif
904
905 // Print simulation time
906 if (!quiet) {
907 print_sim_time(outp);
908 outp << "\n";
909 STATISTICS(outp << kernel.executed_processes_counter - counter_start <<
910 " processes were executed.\n";);
911 STATISTICS(outp << kernel.created_transactions_counter - transactions_counter
912 << " transaction were created.\n";);
913 }
914
915 // Print all signals
916 } else if (cmd == "s" || cmd == "show") {
917 // Setup connection to the kernel data base
918 db_explorer<db_key_type::sig_info_base_p, db_entry_type::sig_info_extension> sig_info_ext (kernel_db);
919
920 for (signal_map_t::iterator iter = signal_name_table.begin (); iter != signal_name_table.end (); iter++)
921 {
922 sig_info_base *sig = iter->second;
923
924 buffer_stream s;
925 s.clean();
926 outp << sig_info_ext.get (sig).instance_name << " = ";
927 sig->type->print(s, (sig)->reader_pointer, VHDL_PRINT_MODE);
928 outp << s.str() << "\n";
929 }
930
931 // dump a set of signal
932 } else if (cmd == "dv"){
933 // Setup connection to the kernel data base and get entry
934 // associated with the current sig info pointer.
935 db_explorer<db_key_type::sig_info_base_p, db_entry_type::sig_info_extension> sig_info_ext (kernel_db);
936
937 // read signal name
938 inp >> cmd;
939 name_stack nstack;
940 nstack.push("Dumper");
941 regex_t preg;
942 regcomp(&preg, cmd.c_str(), REG_EXTENDED | REG_NOSUB | REG_ICASE | REG_NEWLINE);
943
944 for (signal_map_t::iterator iter = signal_name_table.begin (); iter != signal_name_table.end (); iter++)
945 {
946 sig_info_base *sig = iter->second;
947
948 int h = regexec(&preg, sig_info_ext.get (sig).instance_name.c_str(), 0, NULL, 0);
949 if (h == 0 &&
950 !(sig_info_ext.get (sig).kernel_flags & IS_DUMPED)) {
951 // call signal_dump creation function
952 create_dumper_processes(sig, sig->type, nstack, NULL);
953 sig_info_ext.get (sig).kernel_flags |= IS_DUMPED;
954 }
955 }
956 dump_done = true;
957
958 // Optimize wait_elements in order to save memory and runtime
959 kernel.compact_wait_elements();
960
961 // dump all signals
962 } else if (cmd == "d" || cmd == "dump") {
963 // Setup connection to the kernel data base
964 db_explorer<db_key_type::sig_info_base_p, db_entry_type::sig_info_extension> sig_info_ext (kernel_db);
965
966 name_stack nstack;
967 nstack.push("dumper");
968
969 for (signal_map_t::iterator iter = signal_name_table.begin (); iter != signal_name_table.end (); iter++)
970 {
971 sig_info_base *sig = iter->second;
972
973 // call signal_dump list creation function
974 if (!(sig_info_ext.get (sig).kernel_flags & IS_DUMPED)) {
975 create_dumper_processes(sig, sig->type, nstack, NULL);
976 sig_info_ext.get (sig).kernel_flags |= IS_DUMPED;
977 }
978 }
979
980 nstack.pop();
981 dump_done = true;
982
983 // Optimize wait_elements in order to save memory and runtime
984 kernel.compact_wait_elements();
985
986 //call initial_values function
987 if (header_written && dump_done){
988 file.open(fileName, ios::out);
989 write_header(outp, fileName);
990 header_written = false;
991 }
992 //calling the vcd_file function
993 vcd_file(fileName, cmd);
994
995 // Continue dumping signals
996 } else if (cmd == "don") {
997 for (list<signal_dump*>::iterator it = signal_dump_process_list.begin();
998 it != signal_dump_process_list.end(); it++)
999 (*it)->dump_on();
1000 vcd_file(fileName, cmd);
1001
1002 // Stop dumping signals
1003 } else if (cmd == "doff") {
1004 for (list<signal_dump*>::iterator it = signal_dump_process_list.begin();
1005 it != signal_dump_process_list.end(); it++)
1006 (*it)->dump_off();
1007 vcd_file(fileName, cmd);
1008
1009 // Print dumped signal lists
1010 } else if (cmd == "ds" || cmd == "ds_view") {
1011 outp <<"Dumped signal lists is: " << "\n";
1012 for (list<signal_dump*>::iterator it = signal_dump_process_list.begin();
1013 it != signal_dump_process_list.end(); it++)
1014 {
1015 dump_buffer.clean();
1016 outp << (*it)->instance_name << " = ";
1017 (*it)->type->vcd_print(dump_buffer, (*it)->reader_pointer,(*it)->translation_table, false);
1018 outp << dump_buffer.str() << "\n";
1019 }
1020
1021 // Print number of dumped signals:
1022 } else if (cmd == "nds" ) {
1023 int j = 0;
1024
1025 for (list<signal_dump*>::iterator it = signal_dump_process_list.begin();
1026 it != signal_dump_process_list.end(); it++) j++;
1027 outp <<"The number of dumped signals is: "<< j << "\n";
1028
1029 //Dump process configuration
1030 } else if (cmd == "dc" ) {
1031
1032 char buffer[1000];
1033 inp.get(buffer, 1000, '\n');
1034 stringstream sub_cmd;
1035 sub_cmd << buffer;
1036
1037 while (!sub_cmd.eof()) {
1038 // Read command parameter
1039 sub_cmd >> cmd;
1040 if (cmd =="-f"){
1041 char test_fileName[1000];
1042 sub_cmd >> test_fileName;
1043 // valid file name?
1044 if (!char_verifier(test_fileName))
1045 kernel_error_stream << "'" << test_fileName << "' is not a valid file name! Output file name is set to 'wave.dmp'!\n";
1046 else
1047 strcpy(fileName, test_fileName);
1048
1049 } else if (cmd =="-t"){
1050 sub_cmd >> timescale;
1051 sub_cmd >> timescale_unit;
1052 // call the time_unit_conversion function to convert time
1053 time_unit_conversion(timescale_unit);
1054 } else if (cmd == "-q"){
1055 // assign quiet to false dont allow a display on screen of comments
1056 quiet = true;
1057 } else if (cmd == "-cfg") {
1058 // name of the file containing translation table
1059 char fileTranslation[1000];
1060 // read file contenent translation table of each user_defined type
1061 sub_cmd >> fileTranslation;
1062 // valid file name?
1063 if (!char_verifier(fileTranslation))
1064 kernel_error_stream << "'" << fileTranslation << "' is not a valid file name!\n";
1065 else
1066 // call the reading file to get user defined translation table
1067 mapping_translation_table = get_map_list( fileTranslation);
1068 } else
1069 break;
1070 }
1071
1072 // Writes design database in binary mode
1073 } else if (cmd == "wdd" ) {
1074 //Opening the corresponding files to write in
1075 buffer_stream file_name;
1076 file_name.clean();
1077 file_name << kernel.executable_name << ".data";
1078 info_file = fopen(file_name.str(),"wb");// data file
1079 file_name.clean();
1080 file_name << kernel.executable_name << ".index";
1081 index_file = fopen(file_name.str(),"wb");// Index file
1082 file_name.clean();
1083 file_name << kernel.executable_name <<".string";
1084 string_file = fopen(file_name.str(),"wb"); // string file
1085 //call the funtion to write in files
1086 write_info_file(Xinfo_descriptors, info_file, index_file, string_file);
1087 //Close files
1088 fclose(info_file);
1089 fclose(index_file);
1090 fclose(string_file);
1091
1092 // Write design database in cdfg style
1093 } else if (cmd == "wddl" ) {
1094 string ddbl_file_name = string(kernel.executable_name) + ".ddb.lsp";
1095 ofstream ddbl_stream(ddbl_file_name.c_str());
1096 //call the funtion to write design database
1097 write_cdfg_info_file(Xinfo_descriptors, ddbl_stream);
1098 //Close files
1099 ddbl_stream.close();
1100
1101 // Print content of kernel database
1102 } else if (cmd == "db_view") {
1103
1104 for (db::key_iterator iter = kernel_db.begin (); iter != kernel_db.end (); iter++)
1105 {
1106 db_base::db_key_entry_pair &entry = kernel_db.find (*iter);
1107 outp << entry.first->get_name () << "(" << (int)((long)(*iter).value) << ") :";
1108 for (unsigned int i = 0; i < entry.second.size (); i++)
1109 if (entry.second [i] != NULL)
1110 outp << " " << entry.second [i]->get_name ();
1111
1112 outp << "\n";
1113 }
1114 }
1115
1116 #ifdef EVENT_PROFILE
1117 else if (cmd == "p" || cmd == "profile") {
1118 if (!quiet) outp << "Print into file: "; outp.flush();
1119 char filename[80];
1120 inp >> filename;
1121 if (!quiet) outp << "\n";
1122 kernel.event_report(filename);
1123 }
1124 #endif
1125 else {
1126 // Check for valid command
1127 kernel_error_stream << "Unknown command '" << cmd << "'. Type h for help.\n";
1128 kernel_error_stream.flush();
1129 }
1130 }
1131 }
1132
1133 // main program
1134 int
kernel_main(int argc,char * argv[],handle_info * hinfo)1135 kernel_main (int argc, char *argv[], handle_info *hinfo) {
1136
1137 // Savely initialize the 'free_acl' memory
1138 memset (free_acl, 0, sizeof(acl*)*(MAX_ACL_DEPTH+1));
1139
1140 // Store command line arguments
1141 main_argc = argc;
1142 main_argv = argv;
1143 // Set executable name
1144 kernel.executable_name = argv[0];
1145
1146 // First, associate in/out streams with default streams
1147 kernel_error_stream.bind_to_stream(cerr);
1148 kernel_output_stream.bind_to_stream(cout);
1149 model_output_stream.bind_to_stream(cout);
1150 input_stream.bind_to_stream(cin);
1151
1152 // Assue that the commands are read from stdin
1153 bool cmd_param = false;
1154 // Command buffer for command passed over as a command line
1155 // parameter
1156 stringstream cmd_stream;
1157 // Analyze command line parameters
1158 int i = 0;
1159 while (++i < argc) {
1160 if (!strcmp(argv[i], "-cmd")) {
1161 // Commands to execute are specified as a string. Each command
1162 // is separated by ';'
1163 cmd_param = true; // Store that commands are read from parameter
1164 // string. Split up the commands given in the command line string.
1165 i++;
1166 string cmds = string (i < argc? argv[i] : "");
1167 string cmd;
1168 for (unsigned int s = 0; s < cmds.size (); s++)
1169 {
1170 // Search for ';' or end of string
1171 if (cmds [s] == ';')
1172 {
1173 if (cmd != "")
1174 {
1175 cmd_stream << cmd << endl;
1176 cmd = "";
1177 }
1178 }
1179 else
1180 cmd += cmds [s];
1181 }
1182 if (cmd != "")
1183 cmd_stream << cmd << endl;
1184
1185 } else if (!strcmp(argv[i], "-FHDLgui")) {
1186 #ifdef HAVE_SOCKET
1187 // The simulator communicates with its environment via 4 socket
1188 // connections. The socket file base name is defined by the
1189 // command line parameter. The actual socket file names are
1190 // derived by appending 0, 1, 2 or 3 to the base name. 0 is
1191 // associated with a kernel error socket (to print messages
1192 // generated by the kernel (e.g., caused by an illegal simulator
1193 // command)), 1 represents the normal kernel output channel
1194 // (e.g., to list signal values), 2 is the model output channel
1195 // (e.g., to print assert messages) and 3 is the input channel.
1196 string FHDLgui_socket_base = argv[++i];
1197
1198 int sockfd;
1199
1200 // **********************************************
1201 // First, bind kernel error socket
1202 // **********************************************
1203 bzero((char *) &serv_addr_kernel_error, sizeof(serv_addr_kernel_error));
1204 serv_addr_kernel_error.sun_family = AF_UNIX;
1205 strcpy(serv_addr_kernel_error.sun_path, FHDLgui_socket_base.c_str());
1206 strcat(serv_addr_kernel_error.sun_path, "0");
1207 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1208 sockfd = 0; // if sockets are not supported, then
1209 if (connect(sockfd, (struct sockaddr *) &serv_addr_kernel_error,
1210 strlen(serv_addr_kernel_error.sun_path) + sizeof(serv_addr_kernel_error.sun_family)))
1211 kernel_error_stream << "could not open socket '" << serv_addr_kernel_error.sun_path << "\n";
1212 else
1213 kernel_error_stream.bind_to_socket(sockfd);
1214
1215 // **********************************************
1216 // Bind kernel output socket
1217 // **********************************************
1218 bzero((char *) &serv_addr_kernel_output, sizeof(serv_addr_kernel_output));
1219 serv_addr_kernel_output.sun_family = AF_UNIX;
1220 strcpy(serv_addr_kernel_output.sun_path, FHDLgui_socket_base.c_str());
1221 strcat(serv_addr_kernel_output.sun_path, "1");
1222 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1223 if (connect(sockfd, (struct sockaddr *) &serv_addr_kernel_output,
1224 strlen(serv_addr_kernel_output.sun_path) + sizeof(serv_addr_kernel_output.sun_family)))
1225 kernel_error_stream << "could not open socket '" << serv_addr_kernel_output.sun_path << "\n";
1226 else
1227 kernel_output_stream.bind_to_socket(sockfd);
1228
1229 // **********************************************
1230 // Bind model output socket
1231 // **********************************************
1232 bzero((char *) &serv_addr_model_output, sizeof(serv_addr_model_output));
1233 serv_addr_model_output.sun_family = AF_UNIX;
1234 strcpy(serv_addr_model_output.sun_path, FHDLgui_socket_base.c_str());
1235 strcat(serv_addr_model_output.sun_path, "2");
1236 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1237 if (connect(sockfd, (struct sockaddr *) &serv_addr_model_output,
1238 strlen(serv_addr_model_output.sun_path) + sizeof(serv_addr_model_output.sun_family)))
1239 kernel_error_stream << "could not open socket '" << serv_addr_model_output.sun_path << "\n";
1240 else
1241 model_output_stream.bind_to_socket(sockfd);
1242
1243
1244 // **********************************************
1245 // Bind input socket
1246 // **********************************************
1247 bzero((char *) &serv_addr_input, sizeof(serv_addr_input));
1248 serv_addr_input.sun_family = AF_UNIX;
1249 strcpy(serv_addr_input.sun_path, FHDLgui_socket_base.c_str());
1250 strcat(serv_addr_input.sun_path, "3");
1251 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1252 if (connect(sockfd, (struct sockaddr *) &serv_addr_input,
1253 strlen(serv_addr_input.sun_path) + sizeof(serv_addr_input.sun_family)))
1254 kernel_error_stream << "could not open socket '" << serv_addr_input.sun_path << "\n";
1255 else
1256 input_stream.bind_to_socket(sockfd);
1257
1258 #else
1259 kernel_error_stream << "error: system does not have socket support!\n";
1260 #endif
1261
1262 } else if (!strcmp(argv[i], "-q")) {
1263 quiet = true;
1264 } else {
1265 kernel_error_stream << "Unkown command line argument '" << argv[i] << "'. Simulation run aborted!\n";
1266 exit(1);
1267 }
1268 }
1269
1270 if (cmd_param)
1271 input_stream.bind_to_stream((istream&)cmd_stream);
1272
1273 // Call initialization functions. Note this does not inlcude the
1274 // init functions of the corresponding design units.
1275 run_init_funcs ();
1276
1277 // Initialize default translation table for printing VCD dumps
1278 mapping_translation_table = signal_dump::get_default_translation_table();
1279 // Elaborate the VHDL model: instantiate all components, signals
1280 // and processes
1281 kernel.elaborate_model (hinfo);
1282 // Optimize wait_elements in order to save memory and runtime
1283 kernel.compact_wait_elements();
1284 // Execute processe the first time.
1285 kernel.execute_processes();
1286 // Read in command and execute them
1287 scc(input_stream, kernel_output_stream);
1288 // Close waveform file
1289 file.close();
1290
1291 return 0;
1292 }
1293
1294
1295 int
ttt(int j)1296 ttt(int j)
1297 {
1298 for (int i = 0; i < j; i++)
1299 delete[] new char[i];
1300 return 0;
1301 }
1302