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