1 
2 /* VHDL to C++ translator
3 
4    Copyright (C) 1999, 2000 Edwin Naroska.
5 
6    V2CC is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    V2CC is distributed in the hope that it will be useful, but WITHOUT
12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14    License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with V2CC; see the file COPYING.  If not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.
20 
21  */
22 
23 /* This program translates the original VHDL source into C++.
24 
25    Usage:
26 
27    v2cc [-v] [-l lib] file...
28 
29        -v             verbose
30        -l lib         use lib as the WORK library, default is "."
31        -o file        write output to FILE
32        --depend=file  write dependency information to FILE
33 
34        file...        the design units to translate
35 
36 */
37 
38 using namespace std;
39 
40 #if HAVE_MALLOC_H
41 #include <malloc.h>
42 #endif
43 #if HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
46 #if HAVE_GETOPT_H
47 #include <getopt.h>
48 #endif
49 #include <stdlib.h>
50 #include <ctype.h>
51 #include <fstream>
52 #include <algorithm>
53 
54 #include <freehdl/vaul.h>
55 #include "mapping.h"
56 #include "v2cc-chunk.h"
57 #include "v2cc-util.h"
58 
59 
60 // Declare here for now -- TLD
61 void emit_includes(string &str);
62 string sprint_acl(list<string> &acl_list, const string acl_object);
63 pIIR_LibraryUnit get_library_unit(pIIR_DeclarativeRegion d);
64 
65 
66 // ******************************************************************************************
67 // Implementation of member functions declared in v2cc.h
68 // ******************************************************************************************
69 
70 // Returns true if range r and the current instance cover the same
71 // range
72 bool
is_equal_to(const RangeDescriptor & r)73 RangeDescriptor::is_equal_to(const RangeDescriptor &r)
74 {
75   assert(range_attribute == NULL);// Currently not supported
76   return (left == r.left) && (right == r.right) && (direction == r.direction);
77 }
78 
79 // Convert a RangeDescriptor into corresponding integer values and
80 // the direction. A boolean vector is returned where each item stores
81 // whether the corresponding bound could be statically determined
82 // (true).
83 StaticRangeDescriptor<lint, IR_Direction>
rangedes_to_lint(RegionStack & rstack)84 RangeDescriptor::rangedes_to_lint(RegionStack &rstack)
85 {
86   StaticRangeDescriptor<lint, IR_Direction> range;
87   range.valid.resize (3);
88 
89   string str;
90   bool ok = true;
91 
92   // If range is not explicit then return false
93   if (!is_explicit_range()) {
94     fill(range.valid.begin(), range.valid.end(), false);
95     return range;
96   }
97 
98   // Try to convert the left bounds to integer values
99   constant_fold(left, rstack);
100   if (valid_folded_value(left))
101     range.left = get_folded_value(left).long_value();
102   else
103     ok = false; // If the expression is not simple then flag an error
104 
105   range.valid [0] = ok;
106 
107   // Store range direction
108   range.dir = direction;
109   range.valid [1] = true;
110 
111   // Try to convert the right bounds to integer values
112   ok = true;
113   constant_fold(right, rstack);
114   if (valid_folded_value(right))
115     range.right = get_folded_value(right).long_value();
116   else
117     ok = false; // If the expression is not simple then flag an error
118 
119   range.valid [2] = ok;
120 
121   return range;
122 }
123 
124 
125 // Convert a RangeDescriptor into corresponding double values and
126 // the direction. A boolean vector is returned where each item stores
127 // whether the corresponding bound could be statically determined
128 // (true).
129 StaticRangeDescriptor<double, IR_Direction>
rangedes_to_double(RegionStack & rstack)130 RangeDescriptor::rangedes_to_double(RegionStack &rstack)
131 {
132   StaticRangeDescriptor<double, IR_Direction> range;
133   range.valid.resize (3);
134 
135   string str;
136   bool ok = true;
137 
138   // If range is not explicit then return false
139   if (!is_explicit_range()) {
140     fill(range.valid.begin(), range.valid.end(), false);
141     return range;
142   }
143 
144   // Try to convert the left bounds to integer values
145   constant_fold(left, rstack);
146   if (valid_folded_value(left))
147     range.left = get_folded_value(left).double_value();
148   else
149     ok = false; // If the expression is not simple then flag an error
150 
151   range.valid [0] = ok;
152 
153   // Store range direction
154   range.dir = direction;
155   range.valid [1] = true;
156 
157   // Try to convert the right bounds to integer values
158   ok = true;
159   constant_fold(right, rstack);
160   if (valid_folded_value(right))
161     range.right = get_folded_value(right).double_value();
162   else
163     ok = false; // If the expression is not simple then flag an error
164 
165   range.valid [2] = ok;
166 
167   return range;
168 }
169 
170 
171 // Convert a RangeDescriptor into corresponding integer value strings
172 // and the direction strings. If a bound is not locally static then
173 // appropriate code is emitted to extract the corresponding values
174 // from the object. A boolean vector is returned where each item
175 // stores whether the corresponding bound could be statically
176 // determined (true).
177 StaticRangeDescriptor<string, string>
rangedes_to_string(RegionStack & rstack,id_type t)178 RangeDescriptor::rangedes_to_string(RegionStack &rstack, id_type t)
179 {
180   StaticRangeDescriptor<string, string> range;
181   range.valid.resize (3);
182 
183   bool ok = true;
184 
185   // First, try to constant fold the range attribute expression
186   constant_fold_rangedes(rstack);
187 
188   if (range_attribute != NULL) {
189     // Range is specified via the RANGE or REVERSE_RANGE attribute
190 
191     bool reverse_range;
192     if (range_attribute->is(IR_ATTR_ARRAY_RANGE))
193       reverse_range = false;
194     else if (range_attribute->is(IR_ATTR_ARRAY_REVERSE_RANGE))
195       reverse_range = true;
196     else
197       assert(false);
198 
199     string info_instance_str;
200     if (range_attribute->array != NULL) {
201       // The range attribute has been applied on an array
202       // instance. First, emit code to extract the info instance from
203       // the array.
204       emit_expr (range_attribute->array, info_instance_str, rstack, t);
205       info_instance_str += ".info";
206 
207     } else {
208       // The range attribute has been applied on an array type. Emit
209       // code to reference the range corresponding info instance.
210       info_instance_str += qid(get_declaration(range_attribute->array_type), rstack, INFO) + "_INFO";
211 
212     }
213 
214     // Get index number. Note that the index number must be locally
215     // static.
216     int index_number = 1;
217     if (range_attribute->index != NULL)
218       index_number = (int)get_folded_value(range_attribute->index).long_value();
219     // Build code to access the array info instance which
220     // corresponds with the index_number
221     for (int i = 1; i < index_number; i++)
222       info_instance_str = "((array_info*)" + info_instance_str + "->element_type)";
223 
224     // Print left, right and direction string depending on whether the
225     // attribute RANGE or REVERSE_RANGE is used. When printing the
226     // bounds check whether the bounds can be determined at compile
227     // time.
228     if (left != NULL) {
229       constant_fold(left, rstack);
230       range.valid [0] = emit_expr (left, range.left, rstack, t);
231     } else {
232       if (reverse_range)
233 	range.left = info_instance_str + "->right_bound";
234       else
235 	range.left = info_instance_str + "->left_bound";
236       range.valid [0] = false;
237     }
238 
239     if (right != NULL && left != NULL) {
240       range.dir = direction == IR_DIRECTION_UP? "to" : "downto";
241       range.valid [1] = true;
242     } else {
243       if (reverse_range)
244 	range.dir =  "(" + info_instance_str + "->index_direction==to?downto:to)";
245       else
246 	range.dir = info_instance_str + "->index_direction";
247       range.valid [1] = false;
248     }
249 
250     if (right != NULL) {
251       constant_fold(right, rstack);
252       range.valid [2] = emit_expr (right, range.right, rstack, t);
253     } else {
254       if (reverse_range)
255 	range.right = info_instance_str + "->left_bound";
256       else
257 	range.right = info_instance_str + "->right_bound";
258       range.valid [2] = false;
259     }
260 
261   } else {
262     // Range is explicit defined
263 
264     // Convert the left bounds to integer values
265     constant_fold(left, rstack);
266     range.valid [0] = emit_expr (left, range.left, rstack, t);
267 
268     // Store range direction
269     range.dir = direction == IR_DIRECTION_UP? "to" : "downto";
270     range.valid [1] = true;
271 
272     constant_fold(right, rstack);
273     range.valid [2] = emit_expr (right, range.right, rstack, t);
274   }
275 
276   return range;
277 }
278 
279 
280 
281 // Same as previos method. However, string are generated according
282 // to CDFG rules.
283 StaticRangeDescriptor<string, string>
cdfg_rangedes_to_string(RegionStack & rstack,id_type t)284 RangeDescriptor::cdfg_rangedes_to_string(RegionStack &rstack, id_type t)
285 {
286   StaticRangeDescriptor<string, string> range;
287   range.valid.resize (3);
288   bool ok = true;
289 
290   // First, try to constant fold the range attribute expression
291   constant_fold_rangedes(rstack);
292 
293   if (range_attribute != NULL) {
294     // Range is specified via the RANGE or REVERSE_RANGE attribute
295 
296     bool reverse_range;
297     if (range_attribute->is(IR_ATTR_ARRAY_RANGE))
298       reverse_range = false;
299     else if (range_attribute->is(IR_ATTR_ARRAY_REVERSE_RANGE))
300       reverse_range = true;
301     else
302       assert(false);
303 
304     string info_instance_str;
305     if (range_attribute->array != NULL) {
306       // The range attribute has been applied on an array
307       // instance. First, emit code to extract the info instance from
308       // the array.
309       cdfg_emit_expr (range_attribute->array, info_instance_str, rstack, t);
310 
311     } else {
312       // The range attribute has been applied on an array type. Emit
313       // code to reference the range corresponding info instance.
314       info_instance_str =
315 	get_escaped_string(get_long_name(get_declaration(range_attribute->array_type)));
316 
317     }
318 
319     // Get index number. Note that the index number must be locally
320     // static.
321     int index_number = 1;
322     if (range_attribute->index != NULL)
323       index_number = (int)get_folded_value(range_attribute->index).long_value();
324     string index_number_string = to_string(index_number);
325 
326     // Print left, right and direction string depending on whether the
327     // attribute RANGE or REVERSE_RANGE is used. When printing the
328     // bounds check whether the bounds can be determined directly.
329     if (left != NULL) {
330       constant_fold(left, rstack);
331       range.valid [0] = cdfg_emit_expr (left, range.left, rstack, t);
332     } else {
333       if (reverse_range)
334 	range.left = "(create-array-attribute-call right " + info_instance_str + " " + index_number_string + ")";
335       else
336 	range.left = "(create-array-attribute-call left " + info_instance_str + " " + index_number_string + ")";
337       range.valid [0] = false;
338     }
339 
340     if (right != NULL && left != NULL) {
341       range.dir = direction == IR_DIRECTION_UP? "to" : "downto";
342       range.valid [1] = true;
343     } else {
344       if (reverse_range)
345 	range.dir = "(create-array-attribute-call-reverse direction " + info_instance_str + " " + index_number_string + ")";
346       else
347 	range.dir = "(create-array-attribute-call direction " + info_instance_str + " " + index_number_string + ")";
348       range.valid [1] = false;
349     }
350 
351     if (right != NULL) {
352       constant_fold(right, rstack);
353       range.valid [2] = cdfg_emit_expr (right, range.right, rstack, t);
354     } else {
355       if (reverse_range)
356 	range.right = "(create-array-attribute-call left " + info_instance_str + " " + index_number_string + ")";
357       else
358 	range.right = "(create-array-attribute-call right " + info_instance_str + " " + index_number_string + ")";
359       range.valid [2] = false;
360     }
361 
362   } else {
363     // Range is explicit defined
364 
365     // Convert the left bounds to integer values
366     constant_fold(left, rstack);
367     range.valid [0] = cdfg_emit_expr (left, range.left, rstack, t);
368 
369     // Store range direction
370     range.dir = direction == IR_DIRECTION_UP? "to" : "downto";
371     range.valid [1] = true;
372 
373     constant_fold(right, rstack);
374     range.valid [2] = cdfg_emit_expr (right, range.right, rstack, t);
375   }
376 
377   return range;
378 }
379 
380 
381 
382 int
constant_fold_rangedes(RegionStack & rstack)383 RangeDescriptor::constant_fold_rangedes(RegionStack &rstack)
384 {
385   int error_count = 0;
386 
387   if (range_attribute != NULL) {
388     vector<RangeDescriptor> range_des_vec;
389 
390     if (range_attribute->array != NULL) {
391       // There is nothing to do if the array subtype is an
392       // unconstrained array type
393       if (!is_constrained_array_type(range_attribute->array->subtype))
394 	return 0;
395       // Get range descriptors from array object
396       range_des_vec = get_discrete_range(range_attribute->array->subtype, rstack, IR_NOT_STATIC);
397     } else if (range_attribute->array_type != NULL)
398       // Get range descriptors from array type
399       range_des_vec = get_discrete_range(range_attribute->array_type, rstack, IR_NOT_STATIC);
400     else
401       assert(false);
402 
403     // Constant fold corresponding range descriptor
404     int dim_number = 1;
405     if (range_attribute->index) {
406       constant_fold(range_attribute->index, rstack);
407       assert(valid_folded_value(range_attribute->index));
408       dim_number = folded_value(range_attribute->index).long_value();
409     }
410     RangeDescriptor &range_des = range_des_vec[dim_number - 1];
411     error_count += range_des.constant_fold_rangedes(rstack);
412 
413     if (range_des.range_attribute != NULL)
414       return error_count;
415 
416     if (range_attribute->is(IR_ATTR_ARRAY_RANGE)) {
417       left = range_des.left;
418       direction = range_des.direction;
419       right = range_des.right;
420     } else if (range_attribute->is(IR_ATTR_ARRAY_REVERSE_RANGE)) {
421       left = range_des.right;
422       direction = range_des.direction == IR_DIRECTION_UP? IR_DIRECTION_DOWN : IR_DIRECTION_UP;
423       right = range_des.left;
424     } else
425       assert(false);
426   }
427 
428   if (left != NULL)
429     if (left->is(IR_EXPRESSION))
430       error_count += constant_fold(pIIR_Expression(left), rstack);
431     else
432       error_count += constant_fold(pIIR_Literal(left), rstack);
433 
434   if (right != NULL)
435     if (right->is(IR_EXPRESSION))
436       error_count += constant_fold(pIIR_Expression(right), rstack);
437     else
438       error_count += constant_fold(pIIR_Literal(right), rstack);
439 
440   return error_count;
441 }
442 
443 
444 
445 /* Exit the program with a usage message.  */
446 void
usage()447 usage ()
448 {
449   fprintf (stderr, "usage: %s [-v] [-l lib] [-L libdir] file...\n", vaul_application_name);
450   exit (1);
451 }
452 
453 vaul_parser_options parser_options;
454 
try_vhdl_source(char * fn)455 bool try_vhdl_source (char *fn)
456 {
457   for (char *cp = fn; *cp; cp++)
458     *cp = tolower(*cp);
459   return access (fn, R_OK) == 0;
460 }
461 
462 char *
find_vhdl_source(char * l,char * n)463 find_vhdl_source (char *l, char *n)
464 {
465   char *fn = vaul_aprintf ("../libvaul/vlib/%s/%s.vhd", l, n);
466   if (try_vhdl_source (fn))
467     return fn;
468   free (fn);
469   fn = vaul_aprintf ("../libvaul/vlib/%s/%s.vhdl", l, n);
470   try_vhdl_source (fn);
471   return fn;
472 }
473 
mypool()474 mypool::mypool () {
475   mapper = make_v2cc_mapper ();
476   dependencies_file = NULL;
477 }
478 
479 vaul_design_unit *
get(char * l,char * n)480 mypool::get (char *l, char *n)
481 {
482   vaul_design_unit *du = vaul_pool::get (l, n);
483   if (du == NULL)
484     {
485       char *fn = mapper->find_design_file (l, n);
486 
487       if (fn == NULL)
488 	return NULL;
489 
490       if (codegen_options.get_verbose ())
491 	fprintf (stderr, "reading %s.%s from %s\n", l, n, fn);
492 
493       // We are only interested in packages and entities, so we
494       // instruct the parser to skip over the rest.
495       vaul_parser_options opts = parser_options;
496       opts.set_skip_bodies (true);
497       vaul_design_file df(fn, NULL, opts);
498 
499       begin_session (l);
500       while (vaul_design_unit * du = df.read_design_unit (this))
501 	{
502 	  insert (du);
503 	  if (du->is_error ())
504 	    du->print_err (fn);
505 	  du->release ();
506 	}
507       if (df.is_error ())
508 	df.print_err (fn);
509       end_session ();
510 
511       du = vaul_pool::get (l, n);
512 
513       if (dependencies_file && du && !du->is_error ())
514 	fprintf (dependencies_file, " %s", fn);
515 
516       delete[] fn;
517     }
518 
519   return du;
520 }
521 
522 mypool vaul;
523 
524 #ifndef HAVE_GETOPT_H
525 struct option {
526   const char *name;
527   int has_arg;
528   int *flag;
529   int val;
530 };
531 
532 #define no_argument       0
533 #define required_argument 1
534 #define optional_argument 2
535 
536 extern "C" int getopt_long (int argc, char * const argv[],
537 			    const char *optstring,
538 			    const struct option *longopts, int *longindex);
539 #endif /* HAVE_GETOPT_H */
540 
541 extern int optind, opterr;
542 extern char *optarg;
543 
544 /* Parse FILE and output translation of all contained units to
545    strings. Return true on success, false otherwise.
546 */
547 bool emit (vaul_pool *pool, char *file, string &str, string &cdfg_str, string &main_cc_str);
548 
549 void init_v2cc_chunk ();
550 
551 bool dry_run = false;
552 
553 struct option long_options[] = {
554   { "relaxed-component-visibility", 0, 0, 0 },
555   { "depend", required_argument, 0, 0 },
556   { 0, 0, 0, 0 }
557 };
558 
559 int
main(int argc,char * argv[])560 main (int argc, char *argv[])
561 {
562   int opt, option_index;
563   const char *libname = "work";
564   char *generated_cc_file_name = NULL;
565   char *main_cc_file_name = NULL;
566 
567   vaul_application_name = "v2cc";
568 
569   opterr = 0;
570 
571   while ((opt=getopt_long (argc, argv, "vnl:L:RgDo:m:",
572 			   long_options, &option_index)) != -1)
573     {
574       switch (opt)
575 	{
576 	case 0:
577 	  {
578 	    switch (option_index)
579 	      {
580 	      case 0:  // allow_invisible_default_bindings_from_work
581 		parser_options.
582 		  set_allow_invisible_default_bindings_from_work (true);
583 		break;
584 	      case 1:  // depend
585 		{
586 		  FILE *depf = fopen (optarg, "w");
587 		  if (depf == NULL)
588 		    {
589 		      perror (optarg);
590 		      exit (1);
591 		    }
592 		  vaul.dependencies_file = depf;
593 		}
594 		break;
595 	      }
596 	  }
597 	  break;
598 	case 'v':
599 	  codegen_options.set_verbose (true);
600 	  parser_options.set_debug (true);
601 	  parser_options.set_fullnames (true);
602 	  tree_set_verbose (true);
603 	  break;
604 	case 'l':
605 	  libname =  optarg;
606 	  break;
607 	case 'L':
608 	  vaul.mapper->add_libdir (optarg);
609 	  break;
610 	case 'm':
611 	  codegen_options.set_emit_main_cc_code (true);
612 	  codegen_options.set_main_cc_filename (optarg);
613 	  break;
614 	case 'n':
615 	  dry_run = true;
616 	  break;
617 	case 'R':
618 	  codegen_options.set_emit_register_code (true);
619 	  break;
620 	case 'g':
621 	  codegen_options.set_emit_debug_code (true);
622 	  break;
623 	case 'D':
624 	  codegen_options.set_emit_cdfg_code (true);
625 	  break;
626 	case 'o':
627 	  generated_cc_file_name = strdup (optarg);
628 	  break;
629 	case '?':
630 	  usage ();
631 	  break;
632 	}
633     }
634 
635   vaul.mapper->add_default_libdirs ();
636 
637   if (optind >= argc || argc-1 > optind)
638     usage ();
639 
640   init_v2cc_chunk ();
641 
642   if (vaul.dependencies_file)
643     fprintf (vaul.dependencies_file, "%s:", generated_cc_file_name);
644 
645   bool success = true;
646   vaul.begin_session ((char*)libname);
647   string str, cdfg_str, main_cc_str;
648   vector<string> source_file_names; // Stores vhdl source files names
649   emit_includes (str);					// #includes for sim
650   while (optind < argc)
651     {
652       if (vaul.dependencies_file)
653 	fprintf (vaul.dependencies_file, " %s", argv[optind]);
654       source_file_names.push_back (string (argv [optind]));
655       success = emit (&vaul, argv[optind], str, cdfg_str, main_cc_str) && success;
656       optind++;
657     }
658 
659   if (success)
660     {
661       if (generated_cc_file_name != NULL) {
662 	ofstream outfile(generated_cc_file_name);
663 	outfile << str;
664 	outfile.close();
665       } else {
666 	cout << str;
667 	cout.flush();
668       }
669 
670       // If CDFG code shall be emitted ...
671       if (codegen_options.get_emit_cdfg_code ())
672 	{
673 	  ofstream cdfg_file;
674 	  // Generate file name for CDFG code. Usually, the .vhdl
675 	  // extension is replaced by .cdfg.lsp
676 	  string file_name = source_file_names.front ();
677 	  file_name.erase(file_name.rfind('.'));
678 	  // If the file did not have any extension then use the first
679 	  // entire file name as base for the output file name
680 	  if (file_name == "")
681 	    file_name = source_file_names.front ();
682 	  file_name += ".cdfg.lsp";
683 	  cdfg_file.open(file_name.c_str());
684 
685 	  // Write string to file
686 	  cdfg_file << cdfg_str;
687 	  cdfg_file.close(); // Close CDFG file
688 	}
689 
690       // If the main routine shall be emitted, then...
691       if (codegen_options.get_emit_main_cc_code () &&
692 	  codegen_options.get_main_cc_filename () != "")
693 	{
694 	  ofstream main_cc_file;
695 	  main_cc_file.open (codegen_options.get_main_cc_filename ().c_str());
696 
697 	  // Write string to file
698 	  main_cc_file << main_cc_str;
699 	  main_cc_file.close(); // Close CDFG file
700 	}
701     }
702 
703   vaul.end_session ();
704 
705   if (vaul.dependencies_file)
706     {
707       fprintf (vaul.dependencies_file, "\n");
708       fclose (vaul.dependencies_file);
709       vaul.dependencies_file = NULL;
710     }
711 
712   return success? 0 : 1;
713 }
714 
715 
716 bool
emit(vaul_pool * pool,char * file,string & str,string & cdfg_str,string & main_cc_str)717 emit (vaul_pool *pool, char *file, string &str, string &cdfg_str, string &main_cc_str)
718 {
719   vaul_design_file df(file, NULL, parser_options);
720 
721   // Create a root node to store global code. Note that it is
722   // important to have an SINGLE root node for all designs stored in
723   // the design file in order to keep track of global definitions
724   // common to all current designs.
725   pIIR_DeclarativeRegion root_node = new IIR_DeclarativeRegion(NULL, NULL, NULL, NULL, 0, NULL, NULL);
726   // Protect node so that it it is not removed by the garbage
727   // collector
728   tree_protect(root_node);
729 
730   bool success = true;
731 
732   // Vector to store all design units that are found in the source
733   // file.
734   vector<vaul_design_unit *> du_vec;
735 
736   // First, parse *all* design units. This is done in order to be able
737   // to find out which design units are dublicate and shall not be
738   // emitted.
739   while (vaul_design_unit *du = df.read_design_unit (pool))
740     {
741       pool->insert (du);
742       if (du->is_error ())
743 	{
744 	  du->print_err (file);
745 	  success = false;
746 	}
747       du_vec.push_back (du);
748     }
749 
750   // Check for duplicate design units. Note that it is legal in VHDL
751   // to redefine a enitity. In this case, the last definition should
752   // overide any previous ones... First, generate an id string for
753   // each library unit.
754   vector<string> ids (du_vec.size ());
755   for (unsigned int i = 0; i < du_vec.size (); i++)
756     {
757       RegionStack rstack;
758       rstack.push(root_node);
759       // Generate a unique id string from
760       ids [i] = qid (du_vec [i]->get_tree (), rstack, id_type ());
761     }
762   // Finally, search for dublicates and mark all dublicates with the
763   // exception of the last one.
764   for (int i = du_vec.size () - 1; i >= 1; i--)
765     {
766       for (int j = i - 1; j >= 0; j--)
767 	if (ids [j] == ids [i])
768 	  {
769 	    codegen_error.info("%:warning: definition of library unit %n is overwritten by same named unit defined in line %;.",
770 			       du_vec [j]->get_tree (), du_vec [j]->get_tree (),
771 			       du_vec [i]->get_tree ());
772 	    generate_code (du_vec [j]->get_tree ()) = false;
773 	  }
774     }
775 
776 
777   if (success && !dry_run)
778     for (unsigned int i = 0; i < du_vec.size (); i++)
779       {
780 	vaul_design_unit *du = du_vec [i];
781 
782 	if (codegen_options.get_verbose ())
783 	  fprintf (stderr, "emitting %s/%s\n",
784 		   du->get_library (), du->get_name ());
785 
786 	RegionStack rstack;
787 	// Remove declarations from root node and push it on the
788 	// context stack
789 	root_node->declarations = NULL;
790 	extended_declarations(root_node) = NULL;
791 	rstack.push(root_node);
792 
793 	// Set prefix name for internal variables
794 	set_internal_prefix_start(du->get_tree(), rstack);
795 
796 	// Check VHDL code and prepare code for code generation!
797 	pIIR_LibraryUnit lu = du->get_tree();
798 	if (explore_and_check(lu, rstack, true))
799 	  success = false;
800 
801 	// Generate code if no error occured and if code shall be
802 	// generated for this library unit.
803 	if (success && generate_code (lu))
804 	  {
805 	    string code;
806 	    if (codegen_options.get_emit_debug_code ())
807 	      code = "#line 1000000 __FILE__\n";
808 
809 	    emit_decl (lu, code, rstack, 0);
810 	    str += code;
811 	  }
812 
813 	// If CDFG code shall be emitted ...
814 	if (success && codegen_options.get_emit_cdfg_code ())
815 	  {
816 	    // Call cdfg_emit_impl to print CDFG code into a string
817 	    cdfg_emit_impl(lu, cdfg_str, rstack, 0);
818 	  }
819 
820 	// If main code shall be emitted ...
821 	if (success && codegen_options.get_emit_main_cc_code ())
822 	  {
823 	    main_cc_str = ""; // Only the last emitted main code is
824 	    // needed. Hence, clear string before
825 	    // calling emit_main.
826 	    emit_main (lu, main_cc_str, rstack, 0);
827 	  }
828 
829 	// Push context from stack
830 	rstack.pop();
831 
832 	if (codegen_error.n_errors)
833 	  exit(1);
834       }
835 
836   for (unsigned int i = 0; i < du_vec.size (); i++)
837     du_vec [i]->release();
838 
839   // Allow garbage collector to destroy root node
840   tree_unprotect(root_node);
841 
842   return success;
843 }
844 
845 
846 
847 
848 /*
849  * Utility
850  */
851 
852 void
emit_includes(string & str)853 emit_includes(string &str)
854 {
855   str += string ("#include <freehdl/kernel.h>\n") +
856     string ("#include <freehdl/std.h>\n\n\n")
857     // +
858     //string ("#ifdef CC_FILE_NAME\n") +
859     //string ("#undef CC_FILE_NAME\n") +
860     //string ("#endif\n") +
861     //string ("#define CC_FILE_NAME __FILE__\n")
862     ;
863 }
864 
865 
866 // ******************************************************************************************
867 // Name: get_library_unit
868 //
869 // Description: returns library unit a declarative region belongs to
870 //
871 // Parameter: pIIR_DeclarativeRegion d = declarative region
872 //
873 // Return value: library unit
874 //
875 // ******************************************************************************************
876 
877 pIIR_LibraryUnit
get_library_unit(pIIR_DeclarativeRegion d)878 get_library_unit(pIIR_DeclarativeRegion d)
879 {
880   while (d != NULL && !d->is(IR_LIBRARY_UNIT)) {
881     d = d->declarative_region;
882   }
883 
884   return (pIIR_LibraryUnit)d;
885 }
886 
887 // returns name of the libraray
888 char *
get_lib_name(pIIR_DeclarativeRegion r)889 get_lib_name(pIIR_DeclarativeRegion r)
890 {
891   pIIR_LibraryUnit lu = get_library_unit(r);
892 
893   return lu->library_name->text.to_chars();
894 }
895 
896 
897 // ******************************************************************************************
898 // Name: m_get_operator_type (generic function)
899 //
900 // Description: returns type of an operator. Possible values are:
901 //   - NO_OP if the function does not denote an operator
902 //   - STD_OP if the funcion denotes an predefined VHDL operator
903 //   - BASIC_OP if the function denotes an operator defined in an
904 //           IEEE library (e.g. numeric_std)
905 //   - USER_OP an user defined operator
906 //
907 // Parameter: pIIR_FunctionDeclaration f = pointer to function declaration
908 //
909 // Return value: op_type
910 //
911 // ******************************************************************************************
912 
913 op_type
m_get_operator_type(pIIR_ProcedureDeclaration pd)914 m_get_operator_type(pIIR_ProcedureDeclaration pd)
915 {
916   return NO_OP;
917 }
918 
919 op_type
m_get_operator_type(pIIR_FunctionDeclaration fd)920 m_get_operator_type(pIIR_FunctionDeclaration fd)
921 {
922   char *function_str = fd->declarator->text.to_chars(); // Get function name
923 
924   if (function_str[0] != '"') // Is function not an operator?
925     return NO_OP;
926 
927   char *libname = get_lib_name(fd->declarative_region);
928 
929   if (!strcmp(libname, "std") ||
930       fd->is(IR_PREDEFINED_FUNCTION_DECLARATION))
931     // Function is defined in library "std" or a predefined VHDL
932     // operator
933     return STD_OP;
934   else if (!strcmp(libname, "ieee"))
935     // Function is defined in library "ieee"
936     return BASIC_OP;
937   else
938     return USER_OP;
939 }
940 
941 
942 
943 
944 
945