From 79f38b8c56cd29d738b2f5c26fe5464ef98d3f11 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 7 Jan 2016 16:14:41 +0100 Subject: [PATCH 01/76] vhdlpp: Basic loop support (loop..end loop). --- vhdlpp/parse.y | 1 - vhdlpp/sequential.h | 2 ++ vhdlpp/sequential_elaborate.cc | 4 ++-- vhdlpp/sequential_emit.cc | 18 ++++++++++++++++++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index dbc561867..970f21617 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -1660,7 +1660,6 @@ loop_statement BasicLoopStatement* tmp = new BasicLoopStatement(loop_name, $3); FILE_NAME(tmp, @2); - sorrymsg(@1, "Loop statements are not supported.\n"); $$ = tmp; }; diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index ce68bcc3e..43f3ac344 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -273,6 +273,8 @@ class BasicLoopStatement : public LoopStatement { ~BasicLoopStatement(); int elaborate(Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope); + void write_to_stream(std::ostream&fd); void dump(ostream&out, int indent) const; }; diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 98b8766c0..8646fd9a7 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -212,9 +212,9 @@ int WhileLoopStatement::elaborate(Entity*ent, ScopeBase*scope) return errors; } -int BasicLoopStatement::elaborate(Entity*, ScopeBase*) +int BasicLoopStatement::elaborate(Entity*ent, ScopeBase*scope) { - return 0; + return elaborate_substatements(ent, scope); } int ReportStmt::elaborate(Entity*ent, ScopeBase*scope) diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 0431a1f53..f5454c1f3 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -477,6 +477,24 @@ int ForLoopStatement::emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope) return errors; } +int BasicLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) +{ + int errors = 0; + + out << "forever begin" << endl; + errors += emit_substatements(out, ent, scope); + out << "end" << endl; + + return errors; +} + +void BasicLoopStatement::write_to_stream(std::ostream&fd) +{ + fd << "loop" << endl; + write_to_stream_substatements(fd); + fd << "end loop;" << endl; +} + int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) { out << "$display(\"** "; From b6f1cb221ecdc49b07f14804361b637bd2f4bf26 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 8 Jan 2016 14:30:58 +0100 Subject: [PATCH 02/76] vhdlpp: Fixes for subtypes handling. --- vhdlpp/architec_emit.cc | 14 ++++++++------ vhdlpp/package.cc | 30 ++---------------------------- vhdlpp/parse.y | 18 ++++++++++++++++-- vhdlpp/vtype.h | 22 +++++++++++++++++----- vhdlpp/vtype_stream.cc | 19 +++++++++++++++++++ 5 files changed, 62 insertions(+), 41 deletions(-) diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index e041d99cd..42e9ab035 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -23,6 +23,7 @@ # include "sequential.h" # include "subprogram.h" # include "vsignal.h" +# include "std_types.h" # include # include # include @@ -70,15 +71,16 @@ int Architecture::emit(ostream&out, Entity*entity) // of the full definition. typedef_context_t typedef_ctx; - //for (map::iterator cur = use_types_.begin() - //; cur != use_types_.end() ; ++cur) { + for (map::iterator cur = use_types_.begin() + ; cur != use_types_.end() ; ++cur) { + if(is_global_type(cur->first)) + continue; - //if(const VTypeDef*def = dynamic_cast(cur->second)) - //errors += def->emit_typedef(out, typedef_ctx); - //} + if(const VTypeDef*def = dynamic_cast(cur->second)) + errors += def->emit_typedef(out, typedef_ctx); + } for (map::iterator cur = cur_types_.begin() ; cur != cur_types_.end() ; ++cur) { - if(const VTypeDef*def = dynamic_cast(cur->second)) errors += def->emit_typedef(out, typedef_ctx); } diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 40730f026..63215fee3 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -67,9 +67,6 @@ void Package::write_to_stream(ostream&fd) const // and identifiers. for (map::const_iterator cur = use_types_.begin() ; cur != use_types_.end() ; ++cur) { - const VTypeDef*def = dynamic_cast (cur->second); - if (def == 0) - continue; // Do not include global types in types dump if (is_global_type(cur->first)) @@ -79,9 +76,6 @@ void Package::write_to_stream(ostream&fd) const } for (map::const_iterator cur = cur_types_.begin() ; cur != cur_types_.end() ; ++cur) { - const VTypeDef*def = dynamic_cast (cur->second); - if (def == 0) - continue; // Do not include global types in types dump if (is_global_type(cur->first)) @@ -92,31 +86,11 @@ void Package::write_to_stream(ostream&fd) const for (map::const_iterator cur = use_types_.begin() ; cur != use_types_.end() ; ++cur) { - - // Do not include global types in types dump - if (is_global_type(cur->first)) - continue; - - if(!dynamic_cast(cur->second)) - fd << "sub"; - - fd << "type " << cur->first << " is "; - cur->second->write_type_to_stream(fd); - fd << "; -- imported" << endl; + cur->second->write_typedef_to_stream(fd, cur->first); } for (map::const_iterator cur = cur_types_.begin() ; cur != cur_types_.end() ; ++cur) { - - // Do not include global types in types dump - if (is_global_type(cur->first)) - continue; - - if(!dynamic_cast(cur->second)) - fd << "sub"; - - fd << "type " << cur->first << " is "; - cur->second->write_type_to_stream(fd); - fd << ";" << endl; + cur->second->write_typedef_to_stream(fd, cur->first); } for (map::const_iterator cur = cur_constants_.begin() diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 970f21617..612d6acf4 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -547,6 +547,8 @@ block_declarative_item | subprogram_body + | subtype_declaration + | type_declaration | use_clause_lib @@ -2606,12 +2608,24 @@ subprogram_statement_part subtype_declaration : K_subtype IDENTIFIER K_is subtype_indication ';' { perm_string name = lex_strings.make($2); - delete[] $2; if ($4 == 0) { errormsg(@1, "Failed to declare type name %s.\n", name.str()); } else { - active_scope->bind_name(name, $4); + VTypeDef*tmp; + map::iterator cur = active_scope->incomplete_types.find(name); + if (cur == active_scope->incomplete_types.end()) { + tmp = new VSubTypeDef(name, $4); + active_scope->bind_name(name, tmp); + } else { + tmp = cur->second; + tmp->set_definition($4); + active_scope->incomplete_types.erase(cur); + } + if(const VTypeEnum*enum_type = dynamic_cast($4)) { + active_scope->use_enum(enum_type); + } } + delete[]$2; } ; diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index cc310ad90..b2212b6d6 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -72,6 +72,10 @@ class VType { // definitions. Most types accept the default definition of this. virtual void write_type_to_stream(std::ostream&fd) const; + // Emits a type definition. This is used to distinguish types and + // subtypes. + virtual void write_typedef_to_stream(std::ostream&fd, perm_string name) const; + // This virtual method writes a human-readable version of the // type to a given file for debug purposes. (Question: is this // really necessary given the write_to_stream method?) @@ -383,7 +387,7 @@ class VTypeDef : public VType { public: explicit VTypeDef(perm_string name); explicit VTypeDef(perm_string name, const VType*is); - ~VTypeDef(); + virtual ~VTypeDef(); VType*clone() const { return new VTypeDef(*this); } @@ -399,7 +403,7 @@ class VTypeDef : public VType { // type, and this method gets it for us. inline const VType* peek_definition(void) const { return type_; } - void write_to_stream(std::ostream&fd) const; + virtual void write_to_stream(std::ostream&fd) const; void write_type_to_stream(std::ostream&fd) const; int get_width(ScopeBase*scope) const { return type_->get_width(scope); } int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; @@ -409,12 +413,20 @@ class VTypeDef : public VType { bool can_be_packed() const { return type_->can_be_packed(); } bool is_unbounded() const { return type_->is_unbounded(); } - private: - int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; - private: + protected: perm_string name_; const VType*type_; + + private: + int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; +}; + +class VSubTypeDef : public VTypeDef { + public: + explicit VSubTypeDef(perm_string name) : VTypeDef(name) {} + explicit VSubTypeDef(perm_string name, const VType*is) : VTypeDef(name, is) {} + void write_typedef_to_stream(std::ostream&fd, perm_string name) const; }; #endif /* IVL_vtype_H */ diff --git a/vhdlpp/vtype_stream.cc b/vhdlpp/vtype_stream.cc index 96d9eff4d..2869d6772 100644 --- a/vhdlpp/vtype_stream.cc +++ b/vhdlpp/vtype_stream.cc @@ -36,6 +36,16 @@ void VType::write_type_to_stream(ostream&fd) const write_to_stream(fd); } +void VType::write_typedef_to_stream(ostream&fd, perm_string name) const +{ + if(is_global_type(name)) + return; + + fd << "type " << name << " is "; + write_type_to_stream(fd); + fd << ";" << endl; +} + void VTypeArray::write_to_stream(ostream&fd) const { if(write_special_case(fd)) @@ -238,3 +248,12 @@ void VTypeEnum::write_to_stream(std::ostream&fd) const fd << ")"; } +void VSubTypeDef::write_typedef_to_stream(ostream&fd, perm_string name) const +{ + if(is_global_type(name)) + return; + + fd << "subtype " << name << " is "; + write_type_to_stream(fd); + fd << ";" << endl; +} From f52de62729bf5ea2ee6edeaddfa295416d03dbd3 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 8 Jan 2016 15:17:17 +0100 Subject: [PATCH 03/76] vhdlpp: Elaborate if statement condition as bool. --- vhdlpp/sequential_elaborate.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 8646fd9a7..f60eb0759 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -99,7 +99,7 @@ int IfSequential::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; - errors += cond_->elaborate_expr(ent, scope, 0); + errors += cond_->elaborate_expr(ent, scope, &type_BOOLEAN); for (list::iterator cur = if_.begin() ; cur != if_.end() ; ++cur) { @@ -123,7 +123,7 @@ int IfSequential::Elsif::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; - errors += cond_->elaborate_expr(ent, scope, 0); + errors += cond_->elaborate_expr(ent, scope, &type_BOOLEAN); for (list::iterator cur = if_.begin() ; cur != if_.end() ; ++cur) { From 054dfdf0cf5a57769990cf1f578e563c3782fd1d Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 8 Jan 2016 15:17:47 +0100 Subject: [PATCH 04/76] vhdlpp: Simpler enum definitions storage. --- vhdlpp/parse.y | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 612d6acf4..99b97ca7a 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -2621,9 +2621,6 @@ subtype_declaration tmp->set_definition($4); active_scope->incomplete_types.erase(cur); } - if(const VTypeEnum*enum_type = dynamic_cast($4)) { - active_scope->use_enum(enum_type); - } } delete[]$2; } @@ -2710,9 +2707,6 @@ type_declaration tmp->set_definition($4); active_scope->incomplete_types.erase(cur); } - if(const VTypeEnum*enum_type = dynamic_cast($4)) { - active_scope->use_enum(enum_type); - } } delete[]$2; } @@ -2737,6 +2731,7 @@ type_declaration type_definition : '(' enumeration_literal_list ')' { VTypeEnum*tmp = new VTypeEnum($2); + active_scope->use_enum(tmp); delete $2; $$ = tmp; } From b08ae23d0d6974a1bcab2bbf542ff728208245b9 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 8 Jan 2016 15:41:29 +0100 Subject: [PATCH 05/76] vhdlpp: line feed character (LF). --- vhdlpp/parse.y | 6 +++++- vhdlpp/parse_misc.cc | 12 ++++++++++++ vhdlpp/parse_misc.h | 8 ++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 99b97ca7a..37a914a38 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -1675,7 +1675,11 @@ mode_opt : mode {$$ = $1;} | {$$ = PORT_NONE;} ; name /* IEEE 1076-2008 P8.1 */ : IDENTIFIER /* simple_name (IEEE 1076-2008 P8.2) */ - { Expression*tmp = new ExpName(lex_strings.make($1)); + { Expression*tmp; + /* Check if the IDENTIFIER is one of CHARACTER enums (LF, CR, etc.) */ + tmp = parse_char_enums($1); + if(!tmp) + tmp = new ExpName(lex_strings.make($1)); FILE_NAME(tmp, @1); delete[]$1; $$ = tmp; diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index cc9de0a1e..eefe5296b 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -29,6 +29,7 @@ # include "compiler.h" # include # include +# include using namespace std; @@ -153,3 +154,14 @@ const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, return subtype; } + +ExpString*parse_char_enums(const char*str) +{ + if(!strcasecmp(str, "LF")) + return new ExpString("\\n"); + + if(!strcasecmp(str, "CR")) + return new ExpString("\\r"); + + return NULL; +} diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index 195264298..d15a8d445 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -27,6 +27,7 @@ class Architecture; class Expression; class Package; class ExpRange; +class ExpString; class ScopeBase; class VType; @@ -63,4 +64,11 @@ extern void library_import(const YYLTYPE&loc, const std::list*names extern void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*pack, const char*ident); +/* + * Converts CHARACTER enums to an ExpString* if applicable. + * See the standard VHDL library (package STANDARD) or VHDL-2008/16.3 + * for more details). + */ +extern ExpString*parse_char_enums(const char*str); + #endif /* IVL_parse_misc_H */ From 52c912c4af437f27a7a897dce8371ac5b7c72d9c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 15 Jan 2016 15:30:21 +0100 Subject: [PATCH 06/76] vhdlpp: Allow calling functions without parameters and brackets. --- vhdlpp/parse.y | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 37a914a38..014ba0bdd 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -7,7 +7,7 @@ %{ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) - * Copyright CERN 2012-2014 / Stephen Williams (steve@icarus.com), + * Copyright CERN 2012-2016 / Stephen Williams (steve@icarus.com), * @author Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it @@ -1678,8 +1678,13 @@ name /* IEEE 1076-2008 P8.1 */ { Expression*tmp; /* Check if the IDENTIFIER is one of CHARACTER enums (LF, CR, etc.) */ tmp = parse_char_enums($1); - if(!tmp) - tmp = new ExpName(lex_strings.make($1)); + if(!tmp) { + perm_string name = lex_strings.make($1); + if(active_scope->find_subprogram(name) && !parse_type_by_name(name)) + tmp = new ExpFunc(name); + else + tmp = new ExpName(name); + } FILE_NAME(tmp, @1); delete[]$1; $$ = tmp; @@ -1693,16 +1698,15 @@ name /* IEEE 1076-2008 P8.1 */ left context, namely whether the name is a type name or function name. If none of the above, treat it as a array element select. */ | IDENTIFIER argument_list - { perm_string name = lex_strings.make($1); + { Expression*tmp; + perm_string name = lex_strings.make($1); delete[]$1; - if (active_scope->is_vector_name(name) || is_subprogram_param(name)) { - ExpName*tmp = new ExpName(name, $2); - $$ = tmp; - } else { - ExpFunc*tmp = new ExpFunc(name, $2); - $$ = tmp; - } - FILE_NAME($$, @1); + if (active_scope->is_vector_name(name) || is_subprogram_param(name)) + tmp = new ExpName(name, $2); + else + tmp = new ExpFunc(name, $2); + FILE_NAME(tmp, @1); + $$ = tmp; } | IDENTIFIER '(' range ')' { ExpName*tmp = new ExpName(lex_strings.make($1), $3->msb(), $3->lsb()); From 2606d0e897373c41c609020fca7d0c946d354556 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 15 Jan 2016 15:47:31 +0100 Subject: [PATCH 07/76] vhdlpp: Minor code clean up. --- vhdlpp/std_funcs.cc | 107 +++++++++++++++++-------------------------- vhdlpp/std_funcs.h | 2 +- vhdlpp/subprogram.cc | 10 ---- vhdlpp/subprogram.h | 21 +++++++-- vpi/vhdl_table.c | 36 +++++++-------- 5 files changed, 76 insertions(+), 100 deletions(-) diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index 5b875d98f..6373d730c 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -1,5 +1,5 @@ /* - * Copyright CERN 2015 + * Copyright CERN 2016 * @author Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it @@ -24,17 +24,20 @@ static std::map std_subprograms; +static inline void register_std_subprogram(SubprogramHeader*header) +{ + std_subprograms[header->name()] = header; +} + // Special case: to_integer function -static class SubprogramToInteger : public SubprogramHeader { +static class SubprogramToInteger : public SubprogramStdHeader { public: SubprogramToInteger() - : SubprogramHeader(perm_string::literal("to_integer"), NULL, &primitive_REAL) { + : SubprogramStdHeader(perm_string::literal("to_integer"), NULL, &primitive_REAL) { ports_ = new std::list(); ports_->push_back(new InterfacePort(&primitive_INTEGER)); } - bool is_std() const { return true; } - int emit_name(const std::vector&argv, std::ostream&out, Entity*ent, ScopeBase*scope) const { bool signed_flag = false; @@ -59,17 +62,15 @@ static class SubprogramToInteger : public SubprogramHeader { }*fn_to_integer; // Special case: size casting (e.g. conv_std_logic_vector() / resize()). -static class SubprogramSizeCast : public SubprogramHeader { +static class SubprogramSizeCast : public SubprogramStdHeader { public: explicit SubprogramSizeCast(perm_string nam) - : SubprogramHeader(nam, NULL, &primitive_STDLOGIC_VECTOR) { + : SubprogramStdHeader(nam, NULL, &primitive_STDLOGIC_VECTOR) { ports_ = new std::list(); ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); ports_->push_back(new InterfacePort(&primitive_INTEGER)); } - bool is_std() const { return true; } - int emit_name(const std::vector&argv, std::ostream&out, Entity*ent, ScopeBase*scope) const { int64_t use_size; @@ -102,8 +103,6 @@ static class SubprogramReadWrite : public SubprogramBuiltin { ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); } - bool is_std() const { return true; } - // Format types handled by $ivlh_read/write (see vpi/vhdl_textio.c) enum format_t { FORMAT_STD, FORMAT_BOOL, FORMAT_TIME, FORMAT_HEX, FORMAT_STRING }; @@ -146,8 +145,6 @@ static class SubprogramHexReadWrite : public SubprogramBuiltin { ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); } - bool is_std() const { return true; } - int emit_args(const std::vector&argv, std::ostream&out, Entity*ent, ScopeBase*scope) const { @@ -164,24 +161,6 @@ static class SubprogramHexReadWrite : public SubprogramBuiltin { } }*fn_hread, *fn_hwrite; -static SubprogramBuiltin*fn_std_logic_vector; -static SubprogramBuiltin*fn_to_unsigned; -static SubprogramBuiltin*fn_unsigned; -static SubprogramBuiltin*fn_integer; - -static SubprogramBuiltin*fn_rising_edge; -static SubprogramBuiltin*fn_falling_edge; - -static SubprogramBuiltin*fn_and_reduce; -static SubprogramBuiltin*fn_or_reduce; - -static SubprogramBuiltin*fn_file_open; -static SubprogramBuiltin*fn_file_close; -static SubprogramBuiltin*fn_endfile; - -static SubprogramBuiltin*fn_readline; -static SubprogramBuiltin*fn_writeline; - void preload_std_funcs(void) { /* numeric_std library @@ -189,19 +168,19 @@ void preload_std_funcs(void) */ std::list*fn_unsigned_args = new std::list(); fn_unsigned_args->push_back(new InterfacePort(&primitive_INTEGER)); - fn_unsigned = new SubprogramBuiltin(perm_string::literal("unsigned"), + SubprogramBuiltin*fn_unsigned = new SubprogramBuiltin(perm_string::literal("unsigned"), perm_string::literal("$unsigned"), fn_unsigned_args, &primitive_UNSIGNED); - std_subprograms[fn_unsigned->name()] = fn_unsigned; + register_std_subprogram(fn_unsigned); /* function integer */ std::list*fn_integer_args = new std::list(); fn_integer_args->push_back(new InterfacePort(&primitive_INTEGER)); - fn_integer = new SubprogramBuiltin(perm_string::literal("integer"), + SubprogramBuiltin*fn_integer = new SubprogramBuiltin(perm_string::literal("integer"), perm_string::literal("$signed"), fn_integer_args, &primitive_INTEGER); - std_subprograms[fn_integer->name()] = fn_integer; + register_std_subprogram(fn_integer); /* function std_logic_vector Special case: The std_logic_vector function casts its @@ -210,68 +189,68 @@ void preload_std_funcs(void) */ std::list*fn_std_logic_vector_args = new std::list(); fn_std_logic_vector_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); - fn_std_logic_vector = new SubprogramBuiltin(perm_string::literal("std_logic_vector"), + SubprogramBuiltin*fn_std_logic_vector = new SubprogramBuiltin(perm_string::literal("std_logic_vector"), empty_perm_string, fn_std_logic_vector_args, &primitive_STDLOGIC_VECTOR); - std_subprograms[fn_std_logic_vector->name()] = fn_std_logic_vector; + register_std_subprogram(fn_std_logic_vector); /* function resize */ fn_resize = new SubprogramSizeCast(perm_string::literal("resize")); - std_subprograms[fn_resize->name()] = fn_resize; + register_std_subprogram(fn_resize); /* std_logic_arith library * function conv_std_logic_vector(arg: integer; size: integer) return std_logic_vector; */ fn_conv_std_logic_vector = new SubprogramSizeCast(perm_string::literal("conv_std_logic_vector")); - std_subprograms[fn_conv_std_logic_vector->name()] = fn_conv_std_logic_vector; + register_std_subprogram(fn_conv_std_logic_vector); /* numeric_bit library * function to_integer (arg: unsigned) return natural; * function to_integer (arg: signed) return integer; */ fn_to_integer = new SubprogramToInteger(); - std_subprograms[fn_to_integer->name()] = fn_to_integer; + register_std_subprogram(fn_to_integer); /* std_logic_1164 library * function rising_edge (signal s : std_ulogic) return boolean; */ std::list*fn_rising_edge_args = new std::list(); fn_rising_edge_args->push_back(new InterfacePort(&primitive_STDLOGIC)); - fn_rising_edge = new SubprogramBuiltin(perm_string::literal("rising_edge"), + SubprogramBuiltin*fn_rising_edge = new SubprogramBuiltin(perm_string::literal("rising_edge"), perm_string::literal("$ivlh_rising_edge"), fn_rising_edge_args, &type_BOOLEAN); - std_subprograms[fn_rising_edge->name()] = fn_rising_edge; + register_std_subprogram(fn_rising_edge); /* std_logic_1164 library * function falling_edge (signal s : std_ulogic) return boolean; */ std::list*fn_falling_edge_args = new std::list(); fn_falling_edge_args->push_back(new InterfacePort(&primitive_STDLOGIC)); - fn_falling_edge = new SubprogramBuiltin(perm_string::literal("falling_edge"), + SubprogramBuiltin*fn_falling_edge = new SubprogramBuiltin(perm_string::literal("falling_edge"), perm_string::literal("$ivlh_falling_edge"), fn_falling_edge_args, &type_BOOLEAN); - std_subprograms[fn_falling_edge->name()] = fn_falling_edge; + register_std_subprogram(fn_falling_edge); /* reduce_pack library * function or_reduce(arg : std_logic_vector) return std_logic; */ std::list*fn_or_reduce_args = new std::list(); fn_or_reduce_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); - fn_or_reduce = new SubprogramBuiltin(perm_string::literal("or_reduce"), + SubprogramBuiltin*fn_or_reduce = new SubprogramBuiltin(perm_string::literal("or_reduce"), perm_string::literal("|"), fn_or_reduce_args, &primitive_STDLOGIC); - std_subprograms[fn_or_reduce->name()] = fn_or_reduce; + register_std_subprogram(fn_or_reduce); /* reduce_pack library * function and_reduce(arg : std_logic_vector) return std_logic; */ std::list*fn_and_reduce_args = new std::list(); fn_and_reduce_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); - fn_and_reduce = new SubprogramBuiltin(perm_string::literal("and_reduce"), + SubprogramBuiltin*fn_and_reduce = new SubprogramBuiltin(perm_string::literal("and_reduce"), perm_string::literal("&"), fn_and_reduce_args, &primitive_STDLOGIC); - std_subprograms[fn_and_reduce->name()] = fn_and_reduce; + register_std_subprogram(fn_and_reduce); /* fixed_pkg library * function to_unsigned ( @@ -282,10 +261,10 @@ void preload_std_funcs(void) std::list*fn_to_unsigned_args = new std::list(); fn_to_unsigned_args->push_back(new InterfacePort(&primitive_REAL)); fn_to_unsigned_args->push_back(new InterfacePort(&primitive_NATURAL)); - fn_to_unsigned = new SubprogramBuiltin(perm_string::literal("to_unsigned"), + SubprogramBuiltin*fn_to_unsigned = new SubprogramBuiltin(perm_string::literal("to_unsigned"), perm_string::literal("$ivlh_to_unsigned"), fn_to_unsigned_args, &primitive_UNSIGNED); - std_subprograms[fn_to_unsigned->name()] = fn_to_unsigned; + register_std_subprogram(fn_to_unsigned); /* procedure file_open (file f: text; filename: in string, file_open_kind: in mode); */ @@ -293,48 +272,48 @@ void preload_std_funcs(void) fn_file_open_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); fn_file_open_args->push_back(new InterfacePort(&primitive_STRING, PORT_IN)); fn_file_open_args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN)); - fn_file_open = new SubprogramBuiltin(perm_string::literal("file_open"), + SubprogramBuiltin*fn_file_open = new SubprogramBuiltin(perm_string::literal("file_open"), perm_string::literal("$ivlh_file_open"), fn_file_open_args, NULL); - std_subprograms[fn_file_open->name()] = fn_file_open; + register_std_subprogram(fn_file_open); /* std.textio library * procedure file_close (file f: text); */ std::list*fn_file_close_args = new std::list(); fn_file_close_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); - fn_file_close = new SubprogramBuiltin(perm_string::literal("file_close"), + SubprogramBuiltin*fn_file_close = new SubprogramBuiltin(perm_string::literal("file_close"), perm_string::literal("$fclose"), fn_file_close_args, NULL); - std_subprograms[fn_file_close->name()] = fn_file_close; + register_std_subprogram(fn_file_close); /* std.textio library * procedure read (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); */ fn_read = new SubprogramReadWrite(perm_string::literal("read"), perm_string::literal("$ivlh_read")); - std_subprograms[fn_read->name()] = fn_read; + register_std_subprogram(fn_read); /* std.textio library * procedure write (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); */ fn_write = new SubprogramReadWrite(perm_string::literal("write"), perm_string::literal("$ivlh_write")); - std_subprograms[fn_write->name()] = fn_write; + register_std_subprogram(fn_write); /* std.textio library * procedure hread (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); */ fn_hread = new SubprogramHexReadWrite(perm_string::literal("hread"), perm_string::literal("$ivlh_read")); - std_subprograms[fn_hread->name()] = fn_hread; + register_std_subprogram(fn_hread); /* std.textio library * procedure hwrite (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); */ fn_hwrite = new SubprogramHexReadWrite(perm_string::literal("hwrite"), perm_string::literal("$ivlh_write")); - std_subprograms[fn_hwrite->name()] = fn_hwrite; + register_std_subprogram(fn_hwrite); /* std.textio library * procedure readline (file f: text; l: inout line); @@ -342,10 +321,10 @@ void preload_std_funcs(void) std::list*fn_readline_args = new std::list(); fn_readline_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); fn_readline_args->push_back(new InterfacePort(&primitive_STRING, PORT_OUT)); - fn_readline = new SubprogramBuiltin(perm_string::literal("readline"), + SubprogramBuiltin*fn_readline = new SubprogramBuiltin(perm_string::literal("readline"), perm_string::literal("$ivlh_readline"), fn_readline_args, NULL); - std_subprograms[fn_readline->name()] = fn_readline; + register_std_subprogram(fn_readline); /* std.textio library * procedure writeline (file f: text; l: inout line); @@ -353,19 +332,19 @@ void preload_std_funcs(void) std::list*fn_writeline_args = new std::list(); fn_writeline_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); fn_writeline_args->push_back(new InterfacePort(&primitive_STRING, PORT_IN)); - fn_writeline = new SubprogramBuiltin(perm_string::literal("writeline"), + SubprogramBuiltin*fn_writeline = new SubprogramBuiltin(perm_string::literal("writeline"), perm_string::literal("$ivlh_writeline"), fn_writeline_args, NULL); - std_subprograms[fn_writeline->name()] = fn_writeline; + register_std_subprogram(fn_writeline); /* function endline (file f: text) return boolean; */ std::list*fn_endfile_args = new std::list(); fn_endfile_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); - fn_endfile = new SubprogramBuiltin(perm_string::literal("endfile"), + SubprogramBuiltin*fn_endfile = new SubprogramBuiltin(perm_string::literal("endfile"), perm_string::literal("$feof"), fn_endfile_args, &type_BOOLEAN); - std_subprograms[fn_endfile->name()] = fn_endfile; + register_std_subprogram(fn_endfile); } void delete_std_funcs() diff --git a/vhdlpp/std_funcs.h b/vhdlpp/std_funcs.h index c966f6591..0f5645aa3 100644 --- a/vhdlpp/std_funcs.h +++ b/vhdlpp/std_funcs.h @@ -1,7 +1,7 @@ #ifndef IVL_std_funcs_H #define IVL_std_funcs_H /* - * Copyright CERN 2015 + * Copyright CERN 2016 * @author Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 80839b557..9441591a2 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -334,13 +334,3 @@ void SubprogramHeader::write_to_stream(ostream&fd) const return_type_->write_to_stream(fd); } } - -SubprogramBuiltin::SubprogramBuiltin(perm_string vhdl_name, perm_string sv_name, - std::list*ports, const VType*return_type) - : SubprogramHeader(vhdl_name, ports, return_type), sv_name_(sv_name) -{ -} - -SubprogramBuiltin::~SubprogramBuiltin() -{ -} diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index a07570fac..50db83d86 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -133,14 +133,25 @@ class SubprogramHeader : public LineInfo { }; // Class to define functions headers defined in the standard VHDL libraries. -class SubprogramBuiltin : public SubprogramHeader +class SubprogramStdHeader : public SubprogramHeader +{ + public: + SubprogramStdHeader(perm_string name, std::list*ports, + const VType*return_type) : + SubprogramHeader(name, ports, return_type) {} + virtual ~SubprogramStdHeader() {}; + + bool is_std() const { return true; } +}; + +// The simplest case, when only function name has to be changed. +class SubprogramBuiltin : public SubprogramStdHeader { public: SubprogramBuiltin(perm_string vhdl_name, perm_string sv_name, - std::list*ports, const VType*return_type); - ~SubprogramBuiltin(); - - bool is_std() const { return true; } + std::list*ports, const VType*return_type) : + SubprogramStdHeader(vhdl_name, ports, return_type), sv_name_(sv_name) {} + ~SubprogramBuiltin() {} int emit_name(const std::vector&, std::ostream&out, Entity*, ScopeBase*) const; diff --git a/vpi/vhdl_table.c b/vpi/vhdl_table.c index fdbb68829..a6db9c717 100644 --- a/vpi/vhdl_table.c +++ b/vpi/vhdl_table.c @@ -40,11 +40,16 @@ struct monitor_data { static struct monitor_data **mdata = 0; static unsigned mdata_count = 0; -typedef enum { EVENT = 0, RISING_EDGE = 1, FALLING_EDGE = 2 } event_type_t; -static const char* func_names[] = { - "$ivlh_attribute_event", - "$ivlh_rising_edge", - "$ivlh_falling_edge" +typedef enum { + EVENT = 0, + RISING_EDGE = 1, + FALLING_EDGE = 2 +} event_type_t; +static const char* attr_func_names[] = { + "$ivlh_attribute_event", + "$ivlh_rising_edge", + "$ivlh_falling_edge" +}; }; /* To keep valgrind happy free the allocated memory. */ @@ -93,7 +98,7 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*data) vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), (int)vpi_get(vpiLineNo, sys)); vpi_printf("(compiler error) %s requires a single argument.\n", - func_names[type]); + attr_func_names[type]); vpi_control(vpiFinish, 1); return 0; } @@ -127,7 +132,7 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*data) vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), (int)vpi_get(vpiLineNo, sys)); vpi_printf("(compiler error) %s only takes a single argument.\n", - func_names[type]); + attr_func_names[type]); vpi_free_object(argv); vpi_control(vpiFinish, 1); } @@ -186,32 +191,23 @@ static void vhdl_register(void) s_cb_data cb; vpiHandle res; + /* Event attribute functions */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiSizedFunc; tf_data.calltf = ivlh_attribute_event_calltf; tf_data.compiletf = ivlh_attribute_event_compiletf; tf_data.sizetf = ivlh_attribute_event_sizetf; - tf_data.tfname = func_names[EVENT]; + tf_data.tfname = attr_func_names[EVENT]; tf_data.user_data = (PLI_BYTE8*) EVENT; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); - tf_data.type = vpiSysFunc; - tf_data.sysfunctype = vpiSizedFunc; - tf_data.calltf = ivlh_attribute_event_calltf; - tf_data.compiletf = ivlh_attribute_event_compiletf; - tf_data.sizetf = ivlh_attribute_event_sizetf; - tf_data.tfname = func_names[RISING_EDGE]; + tf_data.tfname = attr_func_names[RISING_EDGE]; tf_data.user_data = (PLI_BYTE8*) RISING_EDGE; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); - tf_data.type = vpiSysFunc; - tf_data.sysfunctype = vpiSizedFunc; - tf_data.calltf = ivlh_attribute_event_calltf; - tf_data.compiletf = ivlh_attribute_event_compiletf; - tf_data.sizetf = ivlh_attribute_event_sizetf; - tf_data.tfname = func_names[FALLING_EDGE]; + tf_data.tfname = attr_func_names[FALLING_EDGE]; tf_data.user_data = (PLI_BYTE8*) FALLING_EDGE; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); From 3af3c12b117b411eeee63367ec96e03b3e780ad9 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 15 Jan 2016 15:47:42 +0100 Subject: [PATCH 08/76] vhdlpp: Added system function NOW. --- vhdlpp/std_funcs.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index 6373d730c..93da71b82 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -163,6 +163,11 @@ static class SubprogramHexReadWrite : public SubprogramBuiltin { void preload_std_funcs(void) { + /* function now */ + SubprogramBuiltin*fn_now = new SubprogramBuiltin(perm_string::literal("now"), + perm_string::literal("$time"), NULL, NULL); + register_std_subprogram(fn_now); + /* numeric_std library * function unsigned */ From 03434efed3ae151fffa870a30678e1e061893dac Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 15 Jan 2016 16:24:13 +0100 Subject: [PATCH 09/76] vhdlpp: Elaborate ExpAttribute arguments. --- vhdlpp/expression.cc | 1 + vhdlpp/expression.h | 3 +++ vhdlpp/expression_elaborate.cc | 28 ++++++++++++++++++++++++---- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 49e19242e..8c2061968 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -1,6 +1,7 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2015 / Stephen Williams (steve@icarus.com), + * Copyright CERN 2016 * @author Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 7ad596e23..bed415af5 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -3,6 +3,7 @@ /* * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2015 / Stephen Williams (steve@icarus.com), + * Copyright CERN 2016 * @author Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it @@ -366,7 +367,9 @@ class ExpAttribute : public Expression { protected: std::list*clone_args() const; + int elaborate_args(Entity*ent, ScopeBase*scope, const VType*ltype); void visit_args(ExprVisitor& func); + bool evaluate_type_attr(const VType*type, Entity*ent, ScopeBase*scope, int64_t&val) const; bool test_array_type(const VType*type) const; diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index a84bfbdd9..9f0fe5164 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -1,6 +1,8 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) + * Copyright CERN 2016 + * @author Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -583,10 +585,29 @@ const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t return 0; } +int ExpAttribute::elaborate_args(Entity*ent, ScopeBase*scope, const VType*ltype) +{ + int errors = 0; + + if(args_) { + for(list::iterator it = args_->begin(); + it != args_->end(); ++it) { + errors += (*it)->elaborate_expr(ent, scope, ltype); + } + } + + return errors; +} + int ExpObjAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) { + int errors = 0; const VType*sub_type = base_->probe_type(ent, scope); - return base_->elaborate_expr(ent, scope, sub_type); + + errors += elaborate_args(ent, scope, sub_type); + errors += base_->elaborate_expr(ent, scope, sub_type); + + return errors; } const VType* ExpObjAttribute::probe_type(Entity*, ScopeBase*) const @@ -597,10 +618,9 @@ const VType* ExpObjAttribute::probe_type(Entity*, ScopeBase*) const return NULL; } -int ExpTypeAttribute::elaborate_expr(Entity*, ScopeBase*, const VType*) +int ExpTypeAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { - // This is just to mute warnings, there is nothing to elaborate here - return 0; + return elaborate_args(ent, scope, ltype); } const VType* ExpTypeAttribute::probe_type(Entity*, ScopeBase*) const From 2e6fb9b3f64764938d0be2f149364165981a70f9 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 18 Jan 2016 14:38:59 +0100 Subject: [PATCH 10/76] vhdlpp: shift_left/right() functions. --- vhdlpp/std_funcs.cc | 22 ++++++++++++++++ vpi/Makefile.in | 2 +- vpi/vhdl_sys.sft | 3 +++ vpi/vhdl_table.c | 62 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index 93da71b82..7dab67cc7 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -199,6 +199,28 @@ void preload_std_funcs(void) fn_std_logic_vector_args, &primitive_STDLOGIC_VECTOR); register_std_subprogram(fn_std_logic_vector); + /* numeric_std library + * function shift_left (arg: unsigned; count: natural) return unsigned; + */ + std::list*fn_shift_left_args = new std::list(); + fn_shift_left_args->push_back(new InterfacePort(&primitive_UNSIGNED)); + fn_shift_left_args->push_back(new InterfacePort(&primitive_UNSIGNED)); + SubprogramBuiltin*fn_shift_left = new SubprogramBuiltin(perm_string::literal("shift_left"), + perm_string::literal("$ivlh_shift_left"), + fn_shift_left_args, &primitive_UNSIGNED); + register_std_subprogram(fn_shift_left); + + /* numeric_std library + * function shift_right (arg: unsigned; count: natural) return unsigned; + */ + std::list*fn_shift_right_args = new std::list(); + fn_shift_right_args->push_back(new InterfacePort(&primitive_UNSIGNED)); + fn_shift_right_args->push_back(new InterfacePort(&primitive_UNSIGNED)); + SubprogramBuiltin*fn_shift_right = new SubprogramBuiltin(perm_string::literal("shift_right"), + perm_string::literal("$ivlh_shift_right"), + fn_shift_right_args, &primitive_UNSIGNED); + register_std_subprogram(fn_shift_right); + /* function resize */ fn_resize = new SubprogramSizeCast(perm_string::literal("resize")); diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 4a5502902..aebdb70b2 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -75,7 +75,7 @@ V = va_math.o V2009 = v2009_table.o v2009_array.o v2009_enum.o v2009_string.o -VHDL_SYS = vhdl_table.o +VHDL_SYS = vhdl_table.o sys_priv.o VHDL_TEXTIO = vhdl_textio.o sys_priv.o diff --git a/vpi/vhdl_sys.sft b/vpi/vhdl_sys.sft index d0d452212..86903476f 100644 --- a/vpi/vhdl_sys.sft +++ b/vpi/vhdl_sys.sft @@ -1,3 +1,6 @@ $ivlh_attribute_event vpiSysFuncSized 1 unsigned $ivlh_rising_edge vpiSysFuncSized 1 unsigned $ivlh_falling_edge vpiSysFuncSized 1 unsigned + +$ivlh_shift_left vpiSysFuncSized 32 unsigned +$ivlh_shift_right vpiSysFuncSized 32 unsigned diff --git a/vpi/vhdl_table.c b/vpi/vhdl_table.c index a6db9c717..64cfe0386 100644 --- a/vpi/vhdl_table.c +++ b/vpi/vhdl_table.c @@ -21,6 +21,7 @@ # include "vpi_user.h" # include # include "ivl_alloc.h" +# include "sys_priv.h" /* * The $ivlh_attribute_event implements the VHDL 'event @@ -50,6 +51,14 @@ static const char* attr_func_names[] = { "$ivlh_rising_edge", "$ivlh_falling_edge" }; + +typedef enum { + SHIFT_LEFT = 0, + SHIFT_RIGHT = 1, +} shift_type_t; +static const char* shift_func_names[] = { + "$ivlh_shift_left", + "$ivlh_shift_right", }; /* To keep valgrind happy free the allocated memory. */ @@ -185,6 +194,43 @@ static PLI_INT32 ivlh_attribute_event_sizetf(ICARUS_VPI_CONST PLI_BYTE8*type) return 1; } +static PLI_INT32 ivlh_shift_calltf(ICARUS_VPI_CONST PLI_BYTE8*data) +{ + shift_type_t shift_type = (shift_type_t) data; + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle argh = vpi_scan(argv); + vpiHandle counth = vpi_scan(argv); + s_vpi_value val; + PLI_INT32 count; + + vpi_free_object(argv); + + val.format = vpiIntVal; + vpi_get_value(counth, &val); + count = val.value.integer; + + val.format = vpiIntVal; + vpi_get_value(argh, &val); + + if(shift_type == SHIFT_LEFT) + val.value.integer <<= count; + else if(shift_type == SHIFT_RIGHT) + val.value.integer >>= count; + else + assert(0); + + vpi_put_value(callh, &val, 0, vpiNoDelay); + + return 0; +} + +static PLI_INT32 ivlh_shift_sizetf(ICARUS_VPI_CONST PLI_BYTE8*type) +{ + (void) type; /* Parameter is not used. */ + return 32; +} + static void vhdl_register(void) { s_vpi_systf_data tf_data; @@ -210,6 +256,22 @@ static void vhdl_register(void) tf_data.tfname = attr_func_names[FALLING_EDGE]; tf_data.user_data = (PLI_BYTE8*) FALLING_EDGE; res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + /* Shift functions */ + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiSizedFunc; + tf_data.calltf = ivlh_shift_calltf; + tf_data.compiletf = sys_two_numeric_args_compiletf; + tf_data.sizetf = ivlh_shift_sizetf; + tf_data.tfname = shift_func_names[SHIFT_LEFT]; + tf_data.user_data = (PLI_BYTE8*) SHIFT_LEFT; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.tfname = shift_func_names[SHIFT_RIGHT]; + tf_data.user_data = (PLI_BYTE8*) SHIFT_RIGHT; + res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); /* Create a callback to clear the monitor data memory when the From f6ee5d0f22afc487024a5416a434754da166f679 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 18 Jan 2016 14:50:01 +0100 Subject: [PATCH 11/76] vhdlpp: Corrected an error message. --- vhdlpp/expression_evaluate.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 577defb8b..97a1e4470 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -147,12 +147,13 @@ bool ExpName::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const if (ent) { const InterfacePort*gen = ent->find_generic(name_); if (gen) { - cerr << get_fileline() << ": sorry: I don't necessarily " - << "handle generic overrides." << endl; - // Evaluate the default expression and use that. - if (gen->expr) - return gen->expr->evaluate(ent, scope, val); + if (gen->expr && gen->expr->evaluate(ent, scope, val)) + return true; + + cerr << get_fileline() << ": sorry: I could not evaluate " + << "generic override." << endl; + return false; } } From 5748018409de67f952dcf07710e79cbae08a27a2 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 19 Jan 2016 11:20:17 +0100 Subject: [PATCH 12/76] vhdlpp: Limited support for final wait statement. --- vhdlpp/architec_emit.cc | 11 ++++++++++- vhdlpp/parse.y | 5 +++++ vhdlpp/sequential.h | 4 +++- vhdlpp/sequential_debug.cc | 14 ++++++++++++-- vhdlpp/sequential_elaborate.cc | 2 ++ vhdlpp/sequential_emit.cc | 8 ++++++++ 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 42e9ab035..22f37dcc4 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -288,7 +288,16 @@ int FinalStatement::emit(ostream&out, Entity*ent, Architecture*arc) */ int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc) { - out << "always begin" << endl; + /* Check if the process has no sensitivity list and ends up with + * a final wait. If so, convert the process to an initial block. */ + const WaitStmt*wait_stmt = NULL; + if (! stmt_list().empty()) + wait_stmt = dynamic_cast(stmt_list().back()); + + if (wait_stmt && wait_stmt->type() == WaitStmt::FINAL) + out << "initial begin" << endl; + else + out << "always begin" << endl; int errors = StatementList::emit(out, ent, arc); diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 014ba0bdd..d6d7acb8f 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -2837,6 +2837,11 @@ wait_statement FILE_NAME(tmp, @1); $$ = tmp; } + | K_wait ';' + { WaitStmt*tmp = new WaitStmt(WaitStmt::FINAL, NULL); + FILE_NAME(tmp, @1); + $$ = tmp; + } ; waveform diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 43f3ac344..612a19b73 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -332,7 +332,7 @@ class WaitForStmt : public SequentialStmt { class WaitStmt : public SequentialStmt { public: - typedef enum { ON, UNTIL } wait_type_t; + typedef enum { ON, UNTIL, FINAL } wait_type_t; WaitStmt(wait_type_t type, Expression*expression); void dump(ostream&out, int indent) const; @@ -340,6 +340,8 @@ class WaitStmt : public SequentialStmt { int emit(ostream&out, Entity*entity, ScopeBase*scope); void write_to_stream(std::ostream&fd); + inline wait_type_t type() const { return type_; } + private: wait_type_t type_; Expression*expr_; diff --git a/vhdlpp/sequential_debug.cc b/vhdlpp/sequential_debug.cc index 7abb63d6f..ac4096568 100644 --- a/vhdlpp/sequential_debug.cc +++ b/vhdlpp/sequential_debug.cc @@ -199,6 +199,16 @@ void WaitForStmt::dump(ostream&out, int indent) const void WaitStmt::dump(ostream&out, int indent) const { out << setw(indent) << "" << "WaitStmt at file=" << get_fileline() << endl; - out << setw(indent+3) << "" << "expression: "; - expr_->dump(out, indent+3); + out << setw(indent+3) << "type = "; + + switch(type_) { + case ON: out << "ON" << endl; break; + case UNTIL: out << "UNTIL" << endl; break; + case FINAL: out << "FINAL" << endl; break; + } + + if(type_ != FINAL) { + out << setw(indent+3) << "" << "expression: "; + expr_->dump(out, indent+3); + } } diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index f60eb0759..6756becaf 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -253,6 +253,8 @@ int WaitStmt::elaborate(Entity*ent, ScopeBase*scope) // Fill the sensitivity list expr_->visit(fill_sens_list); + } else if(type_ == FINAL) { + return 0; // nothing to be elaborated } return expr_->elaborate_expr(ent, scope, 0); diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index f5454c1f3..389063744 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -602,6 +602,10 @@ int WaitStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) out << "wait("; break; + + case FINAL: + out << "/* final wait */" << endl; + return 0; // no expression to be emitted } errors += expr_->emit(out, ent, scope); @@ -620,6 +624,10 @@ void WaitStmt::write_to_stream(std::ostream&fd) case UNTIL: fd << "wait until "; break; + + case FINAL: + fd << "wait"; + return; // no expression to be emitted } expr_->write_to_stream(fd); From 730fdaf0f0943a01cd2be6e4864aad90d26e9512 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 18 Jan 2016 17:00:58 +0100 Subject: [PATCH 13/76] vhdlpp: Concurrent assertion statements. --- vhdlpp/parse.y | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index d6d7acb8f..5818b84d2 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -318,6 +318,7 @@ static void touchup_interface_for_functions(std::list*ports) %type concurrent_statement component_instantiation_statement %type concurrent_conditional_signal_assignment %type concurrent_signal_assignment_statement concurrent_simple_signal_assignment +%type concurrent_assertion_statement %type for_generate_statement generate_statement if_generate_statement %type process_statement selected_signal_assignment %type architecture_statement_part generate_statement_body @@ -768,6 +769,19 @@ composite_type_definition { $$ = $1; } ; +concurrent_assertion_statement + : assertion_statement + { + /* See more explanations at IEEE 1076-2008 P11.5 */ + std::list stmts; + stmts.push_back($1); + stmts.push_back(new WaitStmt(WaitStmt::FINAL, NULL)); + ProcessStatement*tmp = new ProcessStatement(empty_perm_string, NULL, &stmts); + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + /* The when...else..when...else syntax is not a general expression in VHDL but a specific sort of assignment statement model. We create Expression objects for it, but the parser will only @@ -877,6 +891,7 @@ concurrent_signal_assignment_statement /* IEEE 1076-2008 P11.6 */ concurrent_statement : component_instantiation_statement | concurrent_signal_assignment_statement + | concurrent_assertion_statement | generate_statement | process_statement ; @@ -2060,7 +2075,7 @@ process_statement process_declarative_part_opt K_begin sequence_of_statements K_end K_postponed_opt K_process identifier_opt ';' - { perm_string iname = $1? lex_strings.make($1) : perm_string(); + { perm_string iname = $1? lex_strings.make($1) : empty_perm_string; if ($1) delete[]$1; if ($12) { if (iname.nil()) { From eeb5728e20ac529179017ca5f191cb2372e7b140 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 20 Jan 2016 16:41:26 +0100 Subject: [PATCH 14/76] vhdlpp: emit() methods are const. --- vhdlpp/expression.cc | 2 +- vhdlpp/expression.h | 80 +++++++++++++++++------------------ vhdlpp/expression_emit.cc | 88 +++++++++++++++++++-------------------- 3 files changed, 85 insertions(+), 85 deletions(-) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 8c2061968..7029092ac 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -659,7 +659,7 @@ void ExpName::visit(ExprVisitor& func) func(this); } -int ExpName::index_t::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpName::index_t::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index bed415af5..1df357f4d 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -97,11 +97,11 @@ class Expression : public LineInfo { // The emit virtual method is called by architecture emit to // output the generated code for the expression. The derived // class fills in the details of what exactly happened. - virtual int emit(ostream&out, Entity*ent, ScopeBase*scope) =0; + virtual int emit(ostream&out, Entity*ent, ScopeBase*scope) const =0; // The emit_package virtual message is similar, but is called // in a package context and to emit SV packages. - virtual int emit_package(std::ostream&out); + virtual int emit_package(std::ostream&out) const; // The evaluate virtual method tries to evaluate expressions // to constant literal values. Return true and set the val @@ -176,7 +176,7 @@ class ExpUnary : public Expression { inline void write_to_stream_operand1(std::ostream&fd) const { operand1_->write_to_stream(fd); } - int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope); + int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) const; void dump_operand1(ostream&out, int indent = 0) const; private: @@ -202,8 +202,8 @@ class ExpBinary : public Expression { protected: int elaborate_exprs(Entity*, ScopeBase*, const VType*); - int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope); - int emit_operand2(ostream&out, Entity*ent, ScopeBase*scope); + int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) const; + int emit_operand2(ostream&out, Entity*ent, ScopeBase*scope) const; bool eval_operand1(Entity*ent, ScopeBase*scope, int64_t&val) const; bool eval_operand2(Entity*ent, ScopeBase*scope, int64_t&val) const; @@ -308,15 +308,15 @@ class ExpAggregate : public Expression { const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; void visit(ExprVisitor& func); private: int elaborate_expr_array_(Entity*ent, ScopeBase*scope, const VTypeArray*ltype); int elaborate_expr_record_(Entity*ent, ScopeBase*scope, const VTypeRecord*ltype); - int emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*ltype); - int emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeRecord*ltype); + int emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*ltype) const; + int emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeRecord*ltype) const; private: // This is the elements as directly parsed. @@ -342,7 +342,7 @@ class ExpArithmetic : public ExpBinary { int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; @@ -386,7 +386,7 @@ class ExpObjAttribute : public ExpAttribute { inline const ExpName* peek_base() const { return base_; } - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; const VType*probe_type(Entity*ent, ScopeBase*scope) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; @@ -408,7 +408,7 @@ class ExpTypeAttribute : public ExpAttribute { inline const VType* peek_base() const { return base_; } - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; const VType*probe_type(Entity*ent, ScopeBase*scope) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; @@ -434,7 +434,7 @@ class ExpBitstring : public Expression { const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; private: @@ -454,7 +454,7 @@ class ExpCharacter : public Expression { const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; @@ -462,7 +462,7 @@ class ExpCharacter : public Expression { private: int emit_primitive_bit_(ostream&out, Entity*ent, ScopeBase*scope, - const VTypePrimitive*etype); + const VTypePrimitive*etype) const; private: char value_; @@ -482,7 +482,7 @@ class ExpConcat : public Expression { const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; void visit(ExprVisitor& func); @@ -513,8 +513,8 @@ class ExpConditional : public Expression { inline void set_condition(Expression*cond) { cond_ = cond; } int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*lt); - int emit_option(ostream&out, Entity*ent, ScopeBase*scope); - int emit_default(ostream&out, Entity*ent, ScopeBase*scope); + int emit_option(ostream&out, Entity*ent, ScopeBase*scope) const; + int emit_default(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; std::list& extract_true_clause() { return true_clause_; } void visit(ExprVisitor& func); @@ -534,7 +534,7 @@ class ExpConditional : public Expression { const VType*probe_type(Entity*ent, ScopeBase*scope) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; void visit(ExprVisitor& func); @@ -574,7 +574,7 @@ class ExpEdge : public ExpUnary { inline fun_t edge_fun() const { return fun_; } void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; private: @@ -600,7 +600,7 @@ class ExpFunc : public Expression { const VType*probe_type(Entity*ent, ScopeBase*scope) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; void visit(ExprVisitor& func); // NOTE: does not handle expressions in subprogram @@ -622,8 +622,8 @@ class ExpInteger : public Expression { const VType*probe_type(Entity*ent, ScopeBase*scope) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); - int emit_package(std::ostream&out); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; + int emit_package(std::ostream&out) const; bool is_primary(void) const { return true; } bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; @@ -645,8 +645,8 @@ class ExpReal : public Expression { const VType*probe_type(Entity*ent, ScopeBase*scope) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); - int emit_package(std::ostream&out); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; + int emit_package(std::ostream&out) const; bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; virtual ostream& dump_inline(ostream&out) const; @@ -672,7 +672,7 @@ class ExpLogical : public ExpBinary { int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; private: @@ -705,7 +705,7 @@ class ExpName : public Expression { const VType* fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*host) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; bool is_primary(void) const; bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; bool symbolic_compare(const Expression*that) const; @@ -726,7 +726,7 @@ class ExpName : public Expression { delete offset_; } - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; private: Expression*idx_; @@ -740,14 +740,14 @@ class ExpName : public Expression { const VType* probe_prefix_type_(Entity*ent, ScopeBase*scope) const; const VType* probe_prefixed_type_(Entity*ent, ScopeBase*scope) const; - int emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope); + int emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) const; // There are some workarounds required for constant arrays/records, as // they are currently emitted as flat localparams (without any type // information). The following workarounds adjust the access indices // to select appropriate parts of the localparam. bool try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, - list&indices, int&data_size); + list&indices, int&data_size) const; bool check_const_array_workaround_(const VTypeArray*arr, ScopeBase*scope, list&indices, int&data_size) const; @@ -756,7 +756,7 @@ class ExpName : public Expression { list&indices, int&data_size) const; int emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope, - const list&indices, int field_size); + const list&indices, int field_size) const; private: std::auto_ptr prefix_; @@ -793,7 +793,7 @@ class ExpRelation : public ExpBinary { const VType* probe_type(Entity*ent, ScopeBase*scope) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; private: @@ -813,7 +813,7 @@ class ExpShift : public ExpBinary { int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; @@ -833,7 +833,7 @@ class ExpString : public Expression { const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; const std::string& get_value() const { return value_; } @@ -843,7 +843,7 @@ class ExpString : public Expression { static std::string escape_quot(const std::string& str); private: - int emit_as_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*arr); + int emit_as_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*arr) const; private: std::string value_; @@ -858,7 +858,7 @@ class ExpUAbs : public ExpUnary { Expression*clone() const { return new ExpUAbs(peek_operand()->clone()); } void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; }; @@ -871,7 +871,7 @@ class ExpUNot : public ExpUnary { Expression*clone() const { return new ExpUNot(peek_operand()->clone()); } void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; }; @@ -890,7 +890,7 @@ class ExpCast : public Expression { return base_->elaborate_expr(ent, scope, type_); } void write_to_stream(std::ostream&fd) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; void visit(ExprVisitor& func); @@ -913,7 +913,7 @@ class ExpNew : public Expression { // There is no 'new' in VHDL - do not emit anything void write_to_stream(std::ostream&) const {}; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; void visit(ExprVisitor& func); @@ -931,7 +931,7 @@ class ExpTime : public Expression { int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; //bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; @@ -966,7 +966,7 @@ class ExpRange : public Expression { int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&) const; - int emit(ostream&out, Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; private: // Regular range related fields diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 8a22c5500..a940a32cc 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -62,7 +62,7 @@ inline static int emit_logic(char val, ostream& out, const VTypePrimitive::type_ return 0; } -int Expression::emit(ostream&out, Entity*, ScopeBase*) +int Expression::emit(ostream&out, Entity*, ScopeBase*) const { out << " /* " << get_fileline() << ": internal error: " << "I don't know how to emit this expression! " @@ -70,7 +70,7 @@ int Expression::emit(ostream&out, Entity*, ScopeBase*) return 1; } -int Expression::emit_package(ostream&out) +int Expression::emit_package(ostream&out) const { out << " /* " << get_fileline() << ": internal error: " << "I don't know how to emit_package this expression! " @@ -83,7 +83,7 @@ bool Expression::is_primary(void) const return false; } -int ExpBinary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) +int ExpBinary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; bool oper_primary = operand1_->is_primary(); @@ -93,7 +93,7 @@ int ExpBinary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpBinary::emit_operand2(ostream&out, Entity*ent, ScopeBase*scope) +int ExpBinary::emit_operand2(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; bool oper_primary = operand2_->is_primary(); @@ -103,14 +103,14 @@ int ExpBinary::emit_operand2(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpUnary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) +int ExpUnary::emit_operand1(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; errors += operand1_->emit(out, ent, scope); return errors; } -int ExpAggregate::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpAggregate::emit(ostream&out, Entity*ent, ScopeBase*scope) const { if (peek_type() == 0) { out << "/* " << get_fileline() << ": internal error: " @@ -134,7 +134,7 @@ int ExpAggregate::emit(ostream&out, Entity*ent, ScopeBase*scope) return 1; } -int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*atype) +int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*atype) const { int errors = 0; @@ -194,8 +194,8 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VT if(use_msb < use_lsb) swap(use_msb, use_lsb); - map element_map; - choice_element*element_other = 0; + map element_map; + const choice_element*element_other = 0; bool positional_section = true; int64_t positional_idx = use_msb; @@ -283,7 +283,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VT out << "{"; for (int64_t idx = use_msb ; idx >= use_lsb ; idx -= 1) { - choice_element*cur = element_map[idx]; + const choice_element*cur = element_map[idx]; if (cur == 0) cur = element_other; @@ -303,7 +303,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VT return errors; } -int ExpAggregate::emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeRecord*) +int ExpAggregate::emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeRecord*) const { int errors = 0; @@ -331,7 +331,7 @@ int ExpAggregate::emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const V return errors; } -int ExpObjAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpObjAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; @@ -372,7 +372,7 @@ int ExpObjAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; @@ -409,7 +409,7 @@ int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; @@ -463,7 +463,7 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpBitstring::emit(ostream&out, Entity*, ScopeBase*) +int ExpBitstring::emit(ostream&out, Entity*, ScopeBase*) const { int errors = 0; @@ -475,7 +475,7 @@ int ExpBitstring::emit(ostream&out, Entity*, ScopeBase*) } int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, ScopeBase*, - const VTypePrimitive*etype) + const VTypePrimitive*etype) const { out << "1'b"; int res = emit_logic(value_, out, etype->type()); @@ -488,7 +488,7 @@ int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, ScopeBase*, return res; } -int ExpCharacter::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpCharacter::emit(ostream&out, Entity*ent, ScopeBase*scope) const { const VType*etype = peek_type(); const VTypeArray*array; @@ -519,7 +519,7 @@ bool ExpConcat::is_primary(void) const return true; } -int ExpConcat::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpConcat::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; out << "{"; @@ -530,7 +530,7 @@ int ExpConcat::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpConditional::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpConditional::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; out << "("; @@ -538,10 +538,10 @@ int ExpConditional::emit(ostream&out, Entity*ent, ScopeBase*scope) // Draw out any when-else expressions. These are all the else_ // clauses besides the last. if (options_.size() > 1) { - list::iterator last = options_.end(); + list::const_iterator last = options_.end(); --last; - for (list::iterator cur = options_.begin() + for (list::const_iterator cur = options_.begin() ; cur != last ; ++cur) { errors += (*cur)->emit_option(out, ent, scope); } @@ -560,7 +560,7 @@ int ExpConditional::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpConditional::case_t::emit_option(ostream&out, Entity*ent, ScopeBase*scope) +int ExpConditional::case_t::emit_option(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; assert(cond_ != 0); @@ -582,7 +582,7 @@ int ExpConditional::case_t::emit_option(ostream&out, Entity*ent, ScopeBase*scope return errors; } -int ExpConditional::case_t::emit_default(ostream&out, Entity*ent, ScopeBase*scope) +int ExpConditional::case_t::emit_default(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; // Trailing else must have no condition. @@ -599,7 +599,7 @@ int ExpConditional::case_t::emit_default(ostream&out, Entity*ent, ScopeBase*scop return errors; } -int ExpEdge::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpEdge::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; switch (fun_) { @@ -616,7 +616,7 @@ int ExpEdge::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; @@ -642,25 +642,25 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpInteger::emit(ostream&out, Entity*, ScopeBase*) +int ExpInteger::emit(ostream&out, Entity*, ScopeBase*) const { out << "32'd" << value_; return 0; } -int ExpInteger::emit_package(ostream&out) +int ExpInteger::emit_package(ostream&out) const { out << value_; return 0; } -int ExpReal::emit(ostream&out, Entity*, ScopeBase*) +int ExpReal::emit(ostream&out, Entity*, ScopeBase*) const { out << value_; return 0; } -int ExpReal::emit_package(ostream&out) +int ExpReal::emit_package(ostream&out) const { out << value_; return 0; @@ -671,7 +671,7 @@ bool ExpReal::is_primary(void) const return true; } -int ExpLogical::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpLogical::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; @@ -703,7 +703,7 @@ int ExpLogical::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) +int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; if (prefix_.get()) { @@ -721,7 +721,7 @@ int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; int field_size = 0; @@ -763,7 +763,7 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) } bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, - list& indices, int& data_size) + list& indices, int& data_size) const { Expression*exp = NULL; bool wrkand_required = false; @@ -860,7 +860,7 @@ bool ExpName::check_const_record_workaround_(const VTypeRecord*rec, } int ExpName::emit_workaround_(ostream&out, Entity*ent, ScopeBase*scope, - const list& indices, int field_size) + const list& indices, int field_size) const { int errors = 0; @@ -882,7 +882,7 @@ bool ExpName::is_primary(void) const return true; } -int ExpRelation::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpRelation::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; errors += emit_operand1(out, ent, scope); @@ -912,7 +912,7 @@ int ExpRelation::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpShift::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpShift::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; @@ -947,7 +947,7 @@ bool ExpString::is_primary(void) const return true; } -int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope) +int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope) const { const VTypeArray*arr; const VType*type = peek_type(); @@ -962,7 +962,7 @@ int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope) return 0; } -int ExpString::emit_as_array_(ostream& out, Entity*, ScopeBase*, const VTypeArray*arr) +int ExpString::emit_as_array_(ostream& out, Entity*, ScopeBase*, const VTypeArray*arr) const { int errors = 0; assert(arr->dimensions() == 1); @@ -1010,7 +1010,7 @@ std::string ExpString::escape_quot(const std::string& str) return result; } -int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; out << "abs("; @@ -1019,7 +1019,7 @@ int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpUNot::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpUNot::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; @@ -1035,7 +1035,7 @@ int ExpUNot::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpCast::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpCast::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; errors += type_->emit_def(out, empty_perm_string); @@ -1045,7 +1045,7 @@ int ExpCast::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpNew::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpNew::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; out << "new["; @@ -1054,7 +1054,7 @@ int ExpNew::emit(ostream&out, Entity*ent, ScopeBase*scope) return errors; } -int ExpTime::emit(ostream&out, Entity*, ScopeBase*) +int ExpTime::emit(ostream&out, Entity*, ScopeBase*) const { out << amount_; @@ -1070,7 +1070,7 @@ int ExpTime::emit(ostream&out, Entity*, ScopeBase*) return 0; } -int ExpRange::emit(ostream&out, Entity*ent, ScopeBase*scope) +int ExpRange::emit(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; From a884faa8c13219369b09033802767f26e7960856 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 21 Jan 2016 10:52:18 +0100 Subject: [PATCH 15/76] vhdlpp: Delayed assignment statements. --- vhdlpp/architec_emit.cc | 12 ++++++++---- vhdlpp/expression.cc | 11 +++++++++++ vhdlpp/expression.h | 21 +++++++++++++++++++++ vhdlpp/expression_debug.cc | 8 ++++++++ vhdlpp/expression_elaborate.cc | 10 ++++++++++ vhdlpp/expression_emit.cc | 12 ++++++++++++ vhdlpp/expression_stream.cc | 7 +++++++ vhdlpp/parse.y | 2 ++ 8 files changed, 79 insertions(+), 4 deletions(-) diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 22f37dcc4..60b0dfac4 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -132,16 +132,21 @@ int SignalAssignment::emit(ostream&out, Entity*ent, Architecture*arc) int errors = 0; ivl_assert(*this, rval_.size() == 1); - Expression*rval = rval_.front(); + const Expression*rval = rval_.front(); out << "// " << get_fileline() << endl; out << "assign "; + if(const ExpDelay*delayed = dynamic_cast(rval)) { + out << "#("; + delayed->peek_delay()->emit(out, ent, arc); + out << ") "; + rval = delayed->peek_expr(); + } errors += lval_->emit(out, ent, arc); out << " = "; - errors += rval->emit(out, ent, arc); - out << ";" << endl; + return errors; } @@ -316,5 +321,4 @@ int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc) out << "end" << endl; return errors; - } diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 7029092ac..1a0475f27 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -846,3 +846,14 @@ Expression*ExpRange::right() ExpAttribute::RIGHT, NULL); return right_; } + +ExpDelay::ExpDelay(Expression*expr, Expression*delay) +: expr_(expr), delay_(delay) +{ +} + +ExpDelay::~ExpDelay() +{ + delete expr_; + delete delay_; +} diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 1df357f4d..cb66a8286 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -982,6 +982,27 @@ class ExpRange : public Expression { bool range_reverse_; }; +// Helper class that wraps other expression to specify delay. +class ExpDelay : public Expression { +public: + ExpDelay(Expression*expr, Expression*delay); + ~ExpDelay(); + + Expression*clone() const { return new ExpDelay(expr_->clone(), delay_->clone()); } + + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); + void write_to_stream(std::ostream&) const; + int emit(ostream&out, Entity*ent, ScopeBase*scope) const; + void dump(ostream&out, int indent = 0) const; + + const Expression*peek_expr() const { return expr_; } + const Expression*peek_delay() const { return delay_; } + +private: + Expression*expr_; + Expression*delay_; +}; + // Elaborates an expression used as an argument in a procedure/function call. int elaborate_argument(Expression*expr, const SubprogramHeader*subp, int idx, Entity*ent, ScopeBase*scope); diff --git a/vhdlpp/expression_debug.cc b/vhdlpp/expression_debug.cc index c2bc38125..e3f70fd5d 100644 --- a/vhdlpp/expression_debug.cc +++ b/vhdlpp/expression_debug.cc @@ -123,3 +123,11 @@ void ExpRange::dump(ostream&out, int indent) const out << setw(indent) << "" << "Range "; write_to_stream(out); } + +void ExpDelay::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "Expression "; + expr_->write_to_stream(out); + out << " delayed by "; + delay_->write_to_stream(out); +} diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 9f0fe5164..b80d25b9d 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -1100,6 +1100,16 @@ int ExpRange::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) return errors; } +int ExpDelay::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) +{ + int errors = 0; + + errors += expr_->elaborate_expr(ent, scope, ltype); + errors += delay_->elaborate_expr(ent, scope, ltype); + + return errors; +} + int elaborate_argument(Expression*expr, const SubprogramHeader*subp, int idx, Entity*ent, ScopeBase*scope) { diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index a940a32cc..1f24ba586 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -1091,3 +1091,15 @@ int ExpRange::emit(ostream&out, Entity*ent, ScopeBase*scope) const return 0; } + +int ExpDelay::emit(ostream&out, Entity*ent, ScopeBase*scope) const +{ + int errors = 0; + + out << "#("; + errors += delay_->emit(out, ent, scope); + out << ") "; + errors += expr_->emit(out, ent, scope); + + return errors; +} diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index b62225dd3..865640614 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -334,3 +334,10 @@ void ExpRange::write_to_stream(ostream&fd) const right_->write_to_stream(fd); } } + +void ExpDelay::write_to_stream(ostream&out) const +{ + expr_->write_to_stream(out); + out << " after "; + delay_->write_to_stream(out); +} diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 5818b84d2..23f35a072 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -2882,6 +2882,8 @@ waveform_elements waveform_element : expression { $$ = $1; } + | expression K_after expression + { $$ = new ExpDelay($1, $3); } | K_null { $$ = 0; } ; From 7f6f4157d14e6dfdf7268f9769ffdb4f7f955d2e Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 21 Jan 2016 10:52:36 +0100 Subject: [PATCH 16/76] vhdlpp: ExpRange::emit() now returns the number of errors. --- vhdlpp/expression_emit.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 1f24ba586..3454c7772 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -1089,7 +1089,7 @@ int ExpRange::emit(ostream&out, Entity*ent, ScopeBase*scope) const errors += right_->emit(out, ent, scope); } - return 0; + return errors; } int ExpDelay::emit(ostream&out, Entity*ent, ScopeBase*scope) const From db77fafe72c2f0fa3e9cde1fa3de1727524ac519 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 21 Jan 2016 11:51:52 +0100 Subject: [PATCH 17/76] vhdlpp: Clone the initializing expression in signal declarations. --- vhdlpp/parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 23f35a072..b1d4aeb85 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -533,7 +533,7 @@ block_declarative_item { /* Save the signal declaration in the block_signals map. */ for (std::list::iterator cur = $2->begin() ; cur != $2->end() ; ++cur) { - Signal*sig = new Signal(*cur, $4, $5); + Signal*sig = new Signal(*cur, $4, $5 ? $5->clone() : 0); FILE_NAME(sig, @1); active_scope->bind_name(*cur, sig); } From 19a187fa90946da7867254cb055b534c66271df7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 22 Jan 2016 10:15:12 +0100 Subject: [PATCH 18/76] vhdlpp: Fixed the Expression visitor code. --- vhdlpp/expression.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 1a0475f27..811d42457 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -88,11 +88,13 @@ list*ExpAttribute::clone_args() const { void ExpAttribute::visit_args(ExprVisitor& func) { if(args_) { - for(list::iterator it = args_->begin(); + for(list::iterator it = args_->begin(); it != args_->end(); ++it) { - func(*it); - } + (*it)->visit(func); + } } + + func(this); } ExpObjAttribute::ExpObjAttribute(ExpName*base, perm_string name, list*args) @@ -405,9 +407,8 @@ Expression*ExpConditional::clone() const void ExpConditional::visit(ExprVisitor& func) { for(std::list::iterator it = options_.begin(); - it != options_.end(); ++it) { + it != options_.end(); ++it) (*it)->visit(func); - } func(this); } @@ -474,12 +475,11 @@ Expression*ExpSelected::clone() const void ExpConditional::case_t::visit(ExprVisitor& func) { if(cond_) - func(cond_); + cond_->visit(func); for(std::list::iterator it = true_clause_.begin(); - it != true_clause_.end(); ++it) { - func(*it); - } + it != true_clause_.end(); ++it) + (*it)->visit(func); } ExpEdge::ExpEdge(ExpEdge::fun_t typ, Expression*op) From daed47eb45578e1c55979f3690486a0daf6671b5 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 22 Jan 2016 10:20:03 +0100 Subject: [PATCH 19/76] vhdlpp: Improved conditional assignments. Now they handle expressions without the final 'else'. --- vhdlpp/architec.cc | 15 +++++++++++ vhdlpp/architec.h | 19 ++++++++++++++ vhdlpp/architec_debug.cc | 12 +++++++++ vhdlpp/architec_elaborate.cc | 45 ++++++++++++++++++++++++++++++++ vhdlpp/architec_emit.cc | 50 ++++++++++++++++++++++++++++++++++++ vhdlpp/expression.h | 3 ++- vhdlpp/parse.y | 28 ++++++++++++-------- 7 files changed, 160 insertions(+), 12 deletions(-) diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index 2f1cea235..b8eecea85 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -178,6 +178,21 @@ SignalAssignment::~SignalAssignment() delete lval_; } +CondSignalAssignment::CondSignalAssignment(ExpName*target, std::list&options) +: lval_(target) +{ + options_.splice(options_.end(), options); +} + +CondSignalAssignment::~CondSignalAssignment() +{ + delete lval_; + for(list::iterator it = options_.begin(); + it != options_.end(); ++it) { + delete *it; + } +} + ComponentInstantiation::ComponentInstantiation(perm_string i, perm_string c, list*parms, list*ports) diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index d33a33e57..221092aa8 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -189,6 +189,25 @@ class SignalAssignment : public Architecture::Statement { std::list rval_; }; +class CondSignalAssignment : public Architecture::Statement { + + public: + CondSignalAssignment(ExpName*target, std::list&options); + ~CondSignalAssignment(); + + int elaborate(Entity*ent, Architecture*arc); + int emit(ostream&out, Entity*entity, Architecture*arc); + void dump(ostream&out, int ident =0) const; + + private: + ExpName*lval_; + std::list options_; + + // List of signals that should be emitted in the related process + // sensitivity list. It is filled during the elaboration step. + std::listsens_list_; +}; + class ComponentInstantiation : public Architecture::Statement { public: diff --git a/vhdlpp/architec_debug.cc b/vhdlpp/architec_debug.cc index 630da357c..1a42aea28 100644 --- a/vhdlpp/architec_debug.cc +++ b/vhdlpp/architec_debug.cc @@ -95,6 +95,18 @@ void SignalAssignment::dump(ostream&out, int indent) const } } +void CondSignalAssignment::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "CondSignalAssignment file=" << get_fileline() << endl; + lval_->dump(out, indent+1); + out << setw(indent+2) << "" << "<= ..." << endl; + + for(list::const_iterator it = options_.begin(); + it != options_.end(); ++it) { + (*it)->dump(out, indent+2); + } +} + void StatementList::dump(ostream&out, int indent) const { out << setw(indent+3) << "" << "sequence of statements:" << endl; diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index cfedeb467..472ec317b 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -353,3 +353,48 @@ int SignalAssignment::elaborate(Entity*ent, Architecture*arc) return errors; } + +int CondSignalAssignment::elaborate(Entity*ent, Architecture*arc) +{ + int errors = 0; + + // Visitor to extract signal names occuring in the conditional + // statements to create the sensitivity list + struct name_extractor_t : public ExprVisitor { + name_extractor_t(list& name_list) + : name_list_(name_list) {} + void operator() (Expression*s) { + if(const ExpName*name = dynamic_cast(s)) + name_list_.push_back(name); + } + + private: + list& name_list_; + } name_extractor(sens_list_); + + // Elaborate the l-value expression. + errors += lval_->elaborate_lval(ent, arc, true); + + // The elaborate_lval should have resolved the type of the + // l-value expression. We'll use that type to elaborate the + // r-value. + const VType*lval_type = lval_->peek_type(); + if (lval_type == 0) { + if (errors == 0) { + errors += 1; + cerr << get_fileline() + << ": error: Unable to calculate type for l-value expression." + << endl; + } + return errors; + } + + for(list::iterator it = options_.begin(); + it != options_.end(); ++it) { + ExpConditional::case_t*cas = (*it); + cas->elaborate_expr(ent, arc, lval_type); + cas->visit(name_extractor); + } + + return errors; +} diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 60b0dfac4..42e5e2c5c 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -150,6 +150,56 @@ int SignalAssignment::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } +int CondSignalAssignment::emit(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + + out << "// " << get_fileline() << endl; + out << "always @("; + + bool first = true; + for(list::const_iterator it = sens_list_.begin(); + it != sens_list_.end(); ++it) { + if(first) + first = false; + else + out << ","; + + errors += (*it)->emit(out, ent, arc); + } + + out << ") begin" << endl; + + first = true; + for(list::iterator it = options_.begin(); + it != options_.end(); ++it) { + ExpConditional::case_t*cas = *it; + ivl_assert(*this, cas->true_clause().size() == 1); + const Expression*rval = cas->true_clause().front(); + + if(first) + first = false; + else + out << "else "; + + if(Expression*cond = cas->condition()) { + out << "if("; + cond->emit(out, ent, arc); + out << ") "; + } + + out << endl; + lval_->emit(out, ent, arc); + out << " = "; + rval->emit(out, ent, arc); + out << ";" << endl; + } + + out << "end" << endl; + + return errors; +} + int ComponentInstantiation::emit(ostream&out, Entity*ent, Architecture*arc) { const char*comma = ""; diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index cb66a8286..85703ce42 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -509,8 +509,9 @@ class ExpConditional : public Expression { case_t(const case_t&other); ~case_t(); - inline Expression*condition() { return cond_; } + inline Expression*condition() const { return cond_; } inline void set_condition(Expression*cond) { cond_ = cond; } + inline const std::list& true_clause() const { return true_clause_; } int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*lt); int emit_option(ostream&out, Entity*ent, ScopeBase*scope) const; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index b1d4aeb85..5bd0e3977 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -377,7 +377,7 @@ static void touchup_interface_for_functions(std::list*ports) %type if_statement_elsif_list if_statement_elsif_list_opt %type else_when_waveform selected_waveform -%type else_when_waveforms selected_waveform_list +%type else_when_waveforms else_when_waveforms_opt selected_waveform_list %type function_specification procedure_specification %type subprogram_specification subprogram_body_start @@ -787,18 +787,18 @@ concurrent_assertion_statement create Expression objects for it, but the parser will only recognize it it in specific situations. */ concurrent_conditional_signal_assignment /* IEEE 1076-2008 P11.6 */ - : name LEQ waveform K_when expression else_when_waveforms ';' - { ExpConditional*tmp = new ExpConditional($5, $3, $6); - FILE_NAME(tmp, @3); - delete $3; - delete $6; + : name LEQ waveform K_when expression else_when_waveforms_opt ';' + { std::list*options; + options = $6 ? $6 : new std::list; + options->push_front(new ExpConditional::case_t($5, $3)); - ExpName*name = dynamic_cast ($1); - assert(name); - SignalAssignment*tmpa = new SignalAssignment(name, tmp); - FILE_NAME(tmpa, @1); + ExpName*name = dynamic_cast($1); + assert(name); + CondSignalAssignment*tmp = new CondSignalAssignment(name, *options); - $$ = tmpa; + FILE_NAME(tmp, @1); + delete options; + $$ = tmp; } /* Error recovery rules. */ @@ -842,6 +842,12 @@ else_when_waveforms } ; +else_when_waveforms_opt + : else_when_waveforms { $$ = $1; } + | { $$ = 0; } + ; + + else_when_waveform : K_else waveform K_when expression { ExpConditional::case_t*tmp = new ExpConditional::case_t($4, $2); From b79f0d763fbce1c92cf8beca1f9d4fc82d68ba7b Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 22 Jan 2016 10:53:59 +0100 Subject: [PATCH 20/76] vhdlpp: Implemented ExpLogical::write_to_stream() method. --- vhdlpp/expression_stream.cc | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index 865640614..d545df69f 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -181,9 +181,32 @@ void ExpReal::write_to_stream(ostream&fd) const fd << value_; } -void ExpLogical::write_to_stream(ostream&) const +void ExpLogical::write_to_stream(ostream&out) const { - ivl_assert(*this, !"Not supported"); + peek_operand1()->write_to_stream(out); + + switch (fun_) { + case AND: + out << " and "; + break; + case OR: + out << " or "; + break; + case XOR: + out << " xor "; + break; + case NAND: + out << " nand "; + break; + case NOR: + out << " nor "; + break; + case XNOR: + out << " xnor "; + break; + } + + peek_operand2()->write_to_stream(out); } void ExpName::write_to_stream(ostream&fd) const From 00f5785f2cf9f60b7a8b053c25959ac992bcdd71 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 22 Jan 2016 10:58:35 +0100 Subject: [PATCH 21/76] vhdlpp: Minor changes to write_to_stream functions. --- vhdlpp/sequential_emit.cc | 2 +- vhdlpp/subprogram.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 389063744..2a417d2eb 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -82,7 +82,7 @@ void IfSequential::write_to_stream(std::ostream&fd) { fd << "if "; cond_->write_to_stream(fd); - fd << " then " << endl; + fd << " then" << endl; for (list::iterator cur = if_.begin() ; cur != if_.end() ; ++cur) diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 9441591a2..3ddb47de8 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -82,7 +82,8 @@ void SubprogramBody::write_to_stream(ostream&fd) const } else { fd << "--empty body" << endl; } - fd << "end function;" << endl; + + fd << "end function " << header_->name() << ";" << endl; } SubprogramHeader::SubprogramHeader(perm_string nam, list*ports, From f1c07b86a3b8b58f0b6b8ec66196381a219d3be7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 22 Jan 2016 11:26:14 +0100 Subject: [PATCH 22/76] vhdlpp: Implemented ReturnStmt::elaborate() method. --- vhdlpp/sequential.h | 1 + vhdlpp/sequential_elaborate.cc | 16 ++++++++++++++++ vhdlpp/subprogram.h | 2 ++ 3 files changed, 19 insertions(+) diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 612a19b73..13a3f5947 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -135,6 +135,7 @@ class ReturnStmt : public SequentialStmt { ~ReturnStmt(); public: + int elaborate(Entity*ent, ScopeBase*scope); int emit(ostream&out, Entity*entity, ScopeBase*scope); void write_to_stream(std::ostream&fd); void dump(ostream&out, int indent) const; diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 6756becaf..6509d6ae7 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -133,6 +133,22 @@ int IfSequential::Elsif::elaborate(Entity*ent, ScopeBase*scope) return errors; } +int ReturnStmt::elaborate(Entity*ent, ScopeBase*scope) +{ + const VType*ltype = NULL; + + // Try to determine the expression type by + // looking up the function return type. + const SubprogramBody*subp = dynamic_cast(scope); + if(subp) { + if(const SubprogramHeader*header = subp->header()) { + ltype = header->peek_return_type(); + } + } + + return val_->elaborate_expr(ent, scope, ltype); +} + int SignalSeqAssignment::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 50db83d86..c8898f86f 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -54,6 +54,8 @@ class SubprogramBody : public LineInfo, public ScopeBase { void write_to_stream(std::ostream&fd) const; void dump(std::ostream&fd) const; + const SubprogramHeader*header() const { return header_; } + private: std::list*statements_; SubprogramHeader*header_; From 3b165a5f25de89a39e18d33edc5645f323d6738e Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 22 Jan 2016 11:55:53 +0100 Subject: [PATCH 23/76] vhdlpp: Skip package name emission when calling functions from the same package. --- vhdlpp/expression_emit.cc | 11 +---------- vhdlpp/sequential_emit.cc | 25 +++++++++++++------------ vhdlpp/subprogram.h | 6 +++++- vhdlpp/subprogram_emit.cc | 18 ++++++++++++++++++ 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 3454c7772..5104e502a 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -625,16 +625,7 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) const return 1; } - // If this function has an elaborated definition, and if - // that definition is in a package, then include the - // package name as a scope qualifier. This assures that - // the SV elaborator finds the correct VHDL elaborated - // definition. - const Package*pkg = dynamic_cast (def_->get_parent()); - if (pkg != 0) - out << "\\" << pkg->name() << " ::"; - - errors += def_->emit_name(argv_, out, ent, scope); + def_->emit_full_name(argv_, out, ent, scope); out << " ("; def_->emit_args(argv_, out, ent, scope); out << ")"; diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 2a417d2eb..c0d7b67f1 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -210,26 +210,27 @@ void VariableSeqAssignment::write_to_stream(ostream&fd) int ProcedureCall::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; - std::vectorparams; + vectorargv; + if(!def_) { + cerr << get_fileline() << ": error: unknown procedure: " << name_ << endl; + return 1; + } + + // Convert the parameter list to vector if(param_list_) { - params.reserve(param_list_->size()); + argv.reserve(param_list_->size()); for(std::list::iterator it = param_list_->begin(); it != param_list_->end(); ++it) - params.push_back((*it)->expr()); + argv.push_back((*it)->expr()); } - const Package*pkg = dynamic_cast (def_->get_parent()); - if (pkg != 0) - out << "\\" << pkg->name() << " ::"; - - errors += def_->emit_name(params, out, ent, scope); - + def_->emit_full_name(argv, out, ent, scope); out << " ("; - if(param_list_) { - errors += def_->emit_args(params, out, ent, scope); - } + + if(param_list_) + errors += def_->emit_args(argv, out, ent, scope); out << ");" << endl; return errors; diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index c8898f86f..f5bdbb3ec 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -94,11 +94,15 @@ class SubprogramHeader : public LineInfo { int elaborate() { return (body_ ? body_->elaborate() : 0); } + // Emits the function name, including the package if required. + int emit_full_name(const std::vector&argv, + std::ostream&out, Entity*, ScopeBase*) const; + // Function name used in the emission step. The main purpose of this // method is to handle functions offered by standard VHDL libraries. // Allows to return different function names depending on the arguments // (think of size casting or signed/unsigned functions). - virtual int emit_name(const std::vector&, + virtual int emit_name(const std::vector&argv, std::ostream&out, Entity*, ScopeBase*) const; // Emit arguments for a specific call. It allows to reorder or skip diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc index 907550475..18ab855a3 100644 --- a/vhdlpp/subprogram_emit.cc +++ b/vhdlpp/subprogram_emit.cc @@ -21,6 +21,7 @@ # include "subprogram.h" # include "sequential.h" # include "vtype.h" +# include "package.h" # include using namespace std; @@ -97,6 +98,23 @@ int SubprogramHeader::emit_package(ostream&fd) const return errors; } +int SubprogramHeader::emit_full_name(const std::vector&argv, + std::ostream&out, Entity*ent, ScopeBase*scope) const +{ + // If this function has an elaborated definition, and if + // that definition is in a package, then include the + // package name as a scope qualifier. This assures that + // the SV elaborator finds the correct VHDL elaborated + // definition. It should not be emitted only if we call another + // function from the same package. + const Package*pkg = dynamic_cast(parent_); + const SubprogramBody*subp = dynamic_cast(scope); + if (pkg != 0 && (!subp || !subp->header() || subp->header()->get_parent() != pkg)) + out << "\\" << pkg->name() << " ::"; + + return emit_name(argv, out, ent, scope); +} + int SubprogramHeader::emit_name(const std::vector&, std::ostream&out, Entity*, ScopeBase*) const { From f2c8fb0479f2f26742feb22bacfce27647d79eb3 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 22 Jan 2016 12:10:39 +0100 Subject: [PATCH 24/76] vhdlpp: Display an error message when calling a function with too many arguments. --- vhdlpp/expression_elaborate.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index b80d25b9d..69dc36494 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -1118,6 +1118,13 @@ int elaborate_argument(Expression*expr, const SubprogramHeader*subp, if(subp) { const InterfacePort*param = subp->peek_param(idx); + if(!param) { + cerr << expr->get_fileline() + << ": error: Too many arguments when calling " + << subp->name() << "." << endl; + return 1; + } + // Enable reg_flag for variables that might be modified in subprograms if(param->mode == PORT_OUT || param->mode == PORT_INOUT) { if(const ExpName*e = dynamic_cast(expr)) { From b7072281717bfa95ac03812d62490aa6fc8d3d84 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 22 Jan 2016 12:12:55 +0100 Subject: [PATCH 25/76] vhdlpp: file_open_status enum. --- vhdlpp/library.cc | 1 + vhdlpp/std_types.cc | 12 ++++++++++++ vhdlpp/std_types.h | 1 + 3 files changed, 14 insertions(+) diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index f10b60404..beb0838d3 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -370,6 +370,7 @@ static void import_std_use(const YYLTYPE&loc, ActiveScope*res, perm_string packa res->use_name(perm_string::literal("text"), &primitive_INTEGER); res->use_name(perm_string::literal("line"), &primitive_STRING); res->use_name(type_FILE_OPEN_KIND.peek_name(), &type_FILE_OPEN_KIND); + res->use_name(type_FILE_OPEN_STATUS.peek_name(), &type_FILE_OPEN_STATUS); return; } else { sorrymsg(loc, "package %s of library %s not yet supported", package.str(), name.str()); diff --git a/vhdlpp/std_types.cc b/vhdlpp/std_types.cc index 9bb9744dd..e3990d10c 100644 --- a/vhdlpp/std_types.cc +++ b/vhdlpp/std_types.cc @@ -34,6 +34,7 @@ const VTypePrimitive primitive_TIME(VTypePrimitive::TIME); VTypeDef type_BOOLEAN(perm_string::literal("boolean")); VTypeDef type_FILE_OPEN_KIND(perm_string::literal("file_open_kind")); +VTypeDef type_FILE_OPEN_STATUS(perm_string::literal("file_open_status")); const VTypeArray primitive_CHARACTER(&primitive_BIT, 7, 0); const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector (1)); @@ -64,6 +65,17 @@ void generate_global_types(ActiveScope*res) std_types[type_FILE_OPEN_KIND.peek_name()] = &type_FILE_OPEN_KIND; std_enums.push_back(enum_FILE_OPEN_KIND); + // file_open_status + list enum_FILE_OPEN_STATUS_vals; + enum_FILE_OPEN_STATUS_vals.push_back(perm_string::literal("open_ok")); + enum_FILE_OPEN_STATUS_vals.push_back(perm_string::literal("status_error")); + enum_FILE_OPEN_STATUS_vals.push_back(perm_string::literal("name_error")); + enum_FILE_OPEN_STATUS_vals.push_back(perm_string::literal("mode_error")); + VTypeEnum*enum_FILE_OPEN_STATUS = new VTypeEnum(&enum_FILE_OPEN_STATUS_vals); + type_FILE_OPEN_STATUS.set_definition(enum_FILE_OPEN_STATUS); + std_types[type_FILE_OPEN_STATUS.peek_name()] = &type_FILE_OPEN_STATUS; + std_enums.push_back(enum_FILE_OPEN_STATUS); + res->use_name(type_BOOLEAN.peek_name(), &type_BOOLEAN); res->use_name(perm_string::literal("bit"), &primitive_BIT); res->use_name(perm_string::literal("bit_vector"), &primitive_BIT_VECTOR); diff --git a/vhdlpp/std_types.h b/vhdlpp/std_types.h index b00dd503f..8a91890a3 100644 --- a/vhdlpp/std_types.h +++ b/vhdlpp/std_types.h @@ -39,6 +39,7 @@ extern const VTypePrimitive primitive_LINE; extern VTypeDef type_BOOLEAN; extern VTypeDef type_FILE_OPEN_KIND; +extern VTypeDef type_FILE_OPEN_STATUS; extern const VTypeArray primitive_CHARACTER; extern const VTypeArray primitive_BIT_VECTOR; From 8298c96dee4f3d5aef2ada68bc2f4d6b052441e6 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 22 Jan 2016 14:33:26 +0100 Subject: [PATCH 26/76] vhdlpp: Turned elaborate_argument() into a SubprogramHeader method. --- vhdlpp/expression.h | 4 ---- vhdlpp/expression_elaborate.cc | 34 +--------------------------------- vhdlpp/sequential_elaborate.cc | 2 +- vhdlpp/subprogram.cc | 29 +++++++++++++++++++++++++++++ vhdlpp/subprogram.h | 3 +++ 5 files changed, 34 insertions(+), 38 deletions(-) diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 85703ce42..488c30421 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -1004,8 +1004,4 @@ private: Expression*delay_; }; -// Elaborates an expression used as an argument in a procedure/function call. -int elaborate_argument(Expression*expr, const SubprogramHeader*subp, - int idx, Entity*ent, ScopeBase*scope); - #endif /* IVL_expression_H */ diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 69dc36494..82fd1e6d8 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -817,7 +817,7 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) // Elaborate arguments for (size_t idx = 0; idx < argv_.size(); ++idx) { - errors += elaborate_argument(argv_[idx], prog, idx, ent, scope); + errors += prog->elaborate_argument(argv_[idx], idx, ent, scope); } // SystemVerilog functions work only with defined size data types, therefore @@ -1109,35 +1109,3 @@ int ExpDelay::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) return errors; } - -int elaborate_argument(Expression*expr, const SubprogramHeader*subp, - int idx, Entity*ent, ScopeBase*scope) -{ - const VType*type = expr->probe_type(ent, scope); - - if(subp) { - const InterfacePort*param = subp->peek_param(idx); - - if(!param) { - cerr << expr->get_fileline() - << ": error: Too many arguments when calling " - << subp->name() << "." << endl; - return 1; - } - - // Enable reg_flag for variables that might be modified in subprograms - if(param->mode == PORT_OUT || param->mode == PORT_INOUT) { - if(const ExpName*e = dynamic_cast(expr)) { - if(Signal*sig = scope->find_signal(e->peek_name())) - sig->count_ref_sequ(); - else if(Variable*var = scope->find_variable(e->peek_name())) - var->count_ref_sequ(); - } - } - - if(!type) - type = param->type; - } - - return expr->elaborate_expr(ent, scope, type); -} diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 6509d6ae7..d3e1e493a 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -190,7 +190,7 @@ int ProcedureCall::elaborate(Entity*ent, ScopeBase*scope) if(param_list_) { for(list::iterator cur = param_list_->begin() ; cur != param_list_->end() ; ++cur) { - errors += elaborate_argument((*cur)->expr(), def_, idx, ent, scope); + errors += def_->elaborate_argument((*cur)->expr(), idx, ent, scope); ++idx; } } diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 3ddb47de8..f93ed1439 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -201,6 +201,35 @@ void SubprogramHeader::set_body(SubprogramBody*bdy) bdy->header_ = this; } +int SubprogramHeader::elaborate_argument(Expression*expr, int idx, + Entity*ent, ScopeBase*scope) +{ + const VType*type = expr->probe_type(ent, scope); + const InterfacePort*param = peek_param(idx); + + if(!param) { + cerr << expr->get_fileline() + << ": error: Too many arguments when calling " + << name_ << "." << endl; + return 1; + } + + // Enable reg_flag for variables that might be modified in subprograms + if(param->mode == PORT_OUT || param->mode == PORT_INOUT) { + if(const ExpName*e = dynamic_cast(expr)) { + if(Signal*sig = scope->find_signal(e->peek_name())) + sig->count_ref_sequ(); + else if(Variable*var = scope->find_variable(e->peek_name())) + var->count_ref_sequ(); + } + } + + if(!type) + type = param->type; + + return expr->elaborate_expr(ent, scope, type); +} + SubprogramHeader*SubprogramHeader::make_instance(std::vector arguments, ScopeBase*scope) const { assert(arguments.size() == ports_->size()); diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index f5bdbb3ec..ba10f6e56 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -94,6 +94,9 @@ class SubprogramHeader : public LineInfo { int elaborate() { return (body_ ? body_->elaborate() : 0); } + // Elaborates an argument basing on the types stored in the subprogram header. + int elaborate_argument(Expression*expr, int idx, Entity*ent, ScopeBase*scope); + // Emits the function name, including the package if required. int emit_full_name(const std::vector&argv, std::ostream&out, Entity*, ScopeBase*) const; From cc729e8dd9c42810cfe82fb46846db8251b8e878 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 26 Jan 2016 16:43:14 +0100 Subject: [PATCH 27/76] vhdlpp: Removed redundant ActiveScope::bind_name() for subprograms. --- vhdlpp/parse.y | 4 ++-- vhdlpp/scope.h | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 5bd0e3977..95853a03a 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -2578,7 +2578,7 @@ subprogram_body /* IEEE 1076-2008 P4.3 */ body->set_statements($4); prog->set_body(body); - active_scope->bind_name(prog->name(), prog); + active_scope->bind_subprogram(prog->name(), prog); active_sub = NULL; } @@ -2596,7 +2596,7 @@ subprogram_body /* IEEE 1076-2008 P4.3 */ subprogram_declaration : subprogram_specification ';' - { if ($1) active_scope->bind_name($1->name(), $1); } + { if ($1) active_scope->bind_subprogram($1->name(), $1); } ; subprogram_declarative_item /* IEEE 1079-2008 P4.3 */ diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index df1f1daba..a95d1e4cd 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -240,13 +240,6 @@ class ActiveScope : public ScopeBase { cur_constants_[name] = new const_t(obj, val); } - inline void bind_name(perm_string name, SubprogramHeader*obj) - { map::iterator it; - if((it = use_subprograms_.find(name)) != use_subprograms_.end() ) - use_subprograms_.erase(it); - cur_subprograms_[name] = obj; - } - void bind(Entity*ent) { context_entity_ = ent; } From 414f24069421d1d6c3f844bede256287a822f37a Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 27 Jan 2016 11:06:09 +0100 Subject: [PATCH 28/76] vhdlpp: Code cleaning (std_funcs). --- vhdlpp/std_funcs.cc | 204 ++++++++++++++++++++------------------------ 1 file changed, 92 insertions(+), 112 deletions(-) diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index 7dab67cc7..50d6c1803 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -30,11 +30,11 @@ static inline void register_std_subprogram(SubprogramHeader*header) } // Special case: to_integer function -static class SubprogramToInteger : public SubprogramStdHeader { +class SubprogramToInteger : public SubprogramStdHeader { public: SubprogramToInteger() : SubprogramStdHeader(perm_string::literal("to_integer"), NULL, &primitive_REAL) { - ports_ = new std::list(); + ports_ = new list(); ports_->push_back(new InterfacePort(&primitive_INTEGER)); } @@ -59,14 +59,14 @@ static class SubprogramToInteger : public SubprogramStdHeader { out << (signed_flag ? "$signed" : "$unsigned"); return 0; } -}*fn_to_integer; +}; // Special case: size casting (e.g. conv_std_logic_vector() / resize()). -static class SubprogramSizeCast : public SubprogramStdHeader { +class SubprogramSizeCast : public SubprogramStdHeader { public: explicit SubprogramSizeCast(perm_string nam) : SubprogramStdHeader(nam, NULL, &primitive_STDLOGIC_VECTOR) { - ports_ = new std::list(); + ports_ = new list(); ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); ports_->push_back(new InterfacePort(&primitive_INTEGER)); } @@ -91,13 +91,13 @@ static class SubprogramSizeCast : public SubprogramStdHeader { return argv[0]->emit(out, ent, scope); } -}*fn_conv_std_logic_vector, *fn_resize; +}; -static class SubprogramReadWrite : public SubprogramBuiltin { +class SubprogramReadWrite : public SubprogramBuiltin { public: SubprogramReadWrite(perm_string nam, perm_string newnam) : SubprogramBuiltin(nam, newnam, NULL, NULL) { - ports_ = new std::list(); + ports_ = new list(); ports_->push_back(new InterfacePort(&primitive_STRING, PORT_INOUT)); ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR, PORT_INOUT)); ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); @@ -133,13 +133,13 @@ static class SubprogramReadWrite : public SubprogramBuiltin { return errors; } -}*fn_read, *fn_write; +}; -static class SubprogramHexReadWrite : public SubprogramBuiltin { +class SubprogramHexReadWrite : public SubprogramBuiltin { public: SubprogramHexReadWrite(perm_string nam, perm_string newnam) : SubprogramBuiltin(nam, newnam, NULL, NULL) { - ports_ = new std::list(); + ports_ = new list(); ports_->push_back(new InterfacePort(&primitive_STRING, PORT_INOUT)); ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR, PORT_INOUT)); ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); @@ -159,10 +159,12 @@ static class SubprogramHexReadWrite : public SubprogramBuiltin { return errors; } -}*fn_hread, *fn_hwrite; +}; void preload_std_funcs(void) { + list*args; + /* function now */ SubprogramBuiltin*fn_now = new SubprogramBuiltin(perm_string::literal("now"), perm_string::literal("$time"), NULL, NULL); @@ -171,113 +173,101 @@ void preload_std_funcs(void) /* numeric_std library * function unsigned */ - std::list*fn_unsigned_args = new std::list(); - fn_unsigned_args->push_back(new InterfacePort(&primitive_INTEGER)); - SubprogramBuiltin*fn_unsigned = new SubprogramBuiltin(perm_string::literal("unsigned"), + args = new list(); + args->push_back(new InterfacePort(&primitive_INTEGER)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("unsigned"), perm_string::literal("$unsigned"), - fn_unsigned_args, &primitive_UNSIGNED); - register_std_subprogram(fn_unsigned); + args, &primitive_UNSIGNED)); /* function integer */ - std::list*fn_integer_args = new std::list(); - fn_integer_args->push_back(new InterfacePort(&primitive_INTEGER)); - SubprogramBuiltin*fn_integer = new SubprogramBuiltin(perm_string::literal("integer"), + args = new list(); + args->push_back(new InterfacePort(&primitive_INTEGER)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("integer"), perm_string::literal("$signed"), - fn_integer_args, &primitive_INTEGER); - register_std_subprogram(fn_integer); + args, &primitive_INTEGER)); /* function std_logic_vector Special case: The std_logic_vector function casts its argument to std_logic_vector. Internally, we don't have to do anything for that to work. */ - std::list*fn_std_logic_vector_args = new std::list(); - fn_std_logic_vector_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); - SubprogramBuiltin*fn_std_logic_vector = new SubprogramBuiltin(perm_string::literal("std_logic_vector"), + args = new list(); + args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("std_logic_vector"), empty_perm_string, - fn_std_logic_vector_args, &primitive_STDLOGIC_VECTOR); - register_std_subprogram(fn_std_logic_vector); + args, &primitive_STDLOGIC_VECTOR)); /* numeric_std library * function shift_left (arg: unsigned; count: natural) return unsigned; */ - std::list*fn_shift_left_args = new std::list(); - fn_shift_left_args->push_back(new InterfacePort(&primitive_UNSIGNED)); - fn_shift_left_args->push_back(new InterfacePort(&primitive_UNSIGNED)); - SubprogramBuiltin*fn_shift_left = new SubprogramBuiltin(perm_string::literal("shift_left"), + args = new list(); + args->push_back(new InterfacePort(&primitive_UNSIGNED)); + args->push_back(new InterfacePort(&primitive_UNSIGNED)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_left"), perm_string::literal("$ivlh_shift_left"), - fn_shift_left_args, &primitive_UNSIGNED); - register_std_subprogram(fn_shift_left); + args, &primitive_UNSIGNED)); /* numeric_std library * function shift_right (arg: unsigned; count: natural) return unsigned; */ - std::list*fn_shift_right_args = new std::list(); - fn_shift_right_args->push_back(new InterfacePort(&primitive_UNSIGNED)); - fn_shift_right_args->push_back(new InterfacePort(&primitive_UNSIGNED)); - SubprogramBuiltin*fn_shift_right = new SubprogramBuiltin(perm_string::literal("shift_right"), + args = new list(); + args->push_back(new InterfacePort(&primitive_UNSIGNED)); + args->push_back(new InterfacePort(&primitive_UNSIGNED)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_right"), perm_string::literal("$ivlh_shift_right"), - fn_shift_right_args, &primitive_UNSIGNED); - register_std_subprogram(fn_shift_right); + args, &primitive_UNSIGNED)); /* function resize */ - fn_resize = new SubprogramSizeCast(perm_string::literal("resize")); - register_std_subprogram(fn_resize); + register_std_subprogram(new SubprogramSizeCast(perm_string::literal("resize"))); /* std_logic_arith library * function conv_std_logic_vector(arg: integer; size: integer) return std_logic_vector; */ - fn_conv_std_logic_vector = new SubprogramSizeCast(perm_string::literal("conv_std_logic_vector")); - register_std_subprogram(fn_conv_std_logic_vector); + register_std_subprogram(new SubprogramSizeCast(perm_string::literal("conv_std_logic_vector"))); /* numeric_bit library * function to_integer (arg: unsigned) return natural; * function to_integer (arg: signed) return integer; */ - fn_to_integer = new SubprogramToInteger(); - register_std_subprogram(fn_to_integer); + register_std_subprogram(new SubprogramToInteger()); /* std_logic_1164 library * function rising_edge (signal s : std_ulogic) return boolean; */ - std::list*fn_rising_edge_args = new std::list(); - fn_rising_edge_args->push_back(new InterfacePort(&primitive_STDLOGIC)); - SubprogramBuiltin*fn_rising_edge = new SubprogramBuiltin(perm_string::literal("rising_edge"), + args = new list(); + args->push_back(new InterfacePort(&primitive_STDLOGIC)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("rising_edge"), perm_string::literal("$ivlh_rising_edge"), - fn_rising_edge_args, &type_BOOLEAN); - register_std_subprogram(fn_rising_edge); + args, &type_BOOLEAN)); /* std_logic_1164 library * function falling_edge (signal s : std_ulogic) return boolean; */ - std::list*fn_falling_edge_args = new std::list(); - fn_falling_edge_args->push_back(new InterfacePort(&primitive_STDLOGIC)); - SubprogramBuiltin*fn_falling_edge = new SubprogramBuiltin(perm_string::literal("falling_edge"), + args = new list(); + args->push_back(new InterfacePort(&primitive_STDLOGIC)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("falling_edge"), perm_string::literal("$ivlh_falling_edge"), - fn_falling_edge_args, &type_BOOLEAN); - register_std_subprogram(fn_falling_edge); + args, &type_BOOLEAN)); /* reduce_pack library * function or_reduce(arg : std_logic_vector) return std_logic; */ - std::list*fn_or_reduce_args = new std::list(); - fn_or_reduce_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); - SubprogramBuiltin*fn_or_reduce = new SubprogramBuiltin(perm_string::literal("or_reduce"), + args = new list(); + args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("or_reduce"), perm_string::literal("|"), - fn_or_reduce_args, &primitive_STDLOGIC); - register_std_subprogram(fn_or_reduce); + args, &primitive_STDLOGIC)); /* reduce_pack library * function and_reduce(arg : std_logic_vector) return std_logic; */ - std::list*fn_and_reduce_args = new std::list(); - fn_and_reduce_args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); - SubprogramBuiltin*fn_and_reduce = new SubprogramBuiltin(perm_string::literal("and_reduce"), + args = new list(); + args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("and_reduce"), perm_string::literal("&"), - fn_and_reduce_args, &primitive_STDLOGIC); - register_std_subprogram(fn_and_reduce); + args, &primitive_STDLOGIC)); /* fixed_pkg library * function to_unsigned ( @@ -285,93 +275,83 @@ void preload_std_funcs(void) * constant size : natural) -- length of output * return unsigned; */ - std::list*fn_to_unsigned_args = new std::list(); - fn_to_unsigned_args->push_back(new InterfacePort(&primitive_REAL)); - fn_to_unsigned_args->push_back(new InterfacePort(&primitive_NATURAL)); - SubprogramBuiltin*fn_to_unsigned = new SubprogramBuiltin(perm_string::literal("to_unsigned"), + args = new list(); + args->push_back(new InterfacePort(&primitive_REAL)); + args->push_back(new InterfacePort(&primitive_NATURAL)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_unsigned"), perm_string::literal("$ivlh_to_unsigned"), - fn_to_unsigned_args, &primitive_UNSIGNED); - register_std_subprogram(fn_to_unsigned); + args, &primitive_UNSIGNED)); /* procedure file_open (file f: text; filename: in string, file_open_kind: in mode); */ - std::list*fn_file_open_args = new std::list(); - fn_file_open_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); - fn_file_open_args->push_back(new InterfacePort(&primitive_STRING, PORT_IN)); - fn_file_open_args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN)); - SubprogramBuiltin*fn_file_open = new SubprogramBuiltin(perm_string::literal("file_open"), + args = new list(); + args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + args->push_back(new InterfacePort(&primitive_STRING, PORT_IN)); + args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("file_open"), perm_string::literal("$ivlh_file_open"), - fn_file_open_args, NULL); - register_std_subprogram(fn_file_open); + args, NULL)); /* std.textio library * procedure file_close (file f: text); */ - std::list*fn_file_close_args = new std::list(); - fn_file_close_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); - SubprogramBuiltin*fn_file_close = new SubprogramBuiltin(perm_string::literal("file_close"), + args = new list(); + args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("file_close"), perm_string::literal("$fclose"), - fn_file_close_args, NULL); - register_std_subprogram(fn_file_close); + args, NULL)); /* std.textio library * procedure read (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); */ - fn_read = new SubprogramReadWrite(perm_string::literal("read"), - perm_string::literal("$ivlh_read")); - register_std_subprogram(fn_read); + register_std_subprogram(new SubprogramReadWrite(perm_string::literal("read"), + perm_string::literal("$ivlh_read"))); /* std.textio library * procedure write (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); */ - fn_write = new SubprogramReadWrite(perm_string::literal("write"), - perm_string::literal("$ivlh_write")); - register_std_subprogram(fn_write); + register_std_subprogram(new SubprogramReadWrite(perm_string::literal("write"), + perm_string::literal("$ivlh_write"))); /* std.textio library * procedure hread (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); */ - fn_hread = new SubprogramHexReadWrite(perm_string::literal("hread"), - perm_string::literal("$ivlh_read")); - register_std_subprogram(fn_hread); + register_std_subprogram(new SubprogramHexReadWrite(perm_string::literal("hread"), + perm_string::literal("$ivlh_read"))); /* std.textio library * procedure hwrite (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); */ - fn_hwrite = new SubprogramHexReadWrite(perm_string::literal("hwrite"), - perm_string::literal("$ivlh_write")); - register_std_subprogram(fn_hwrite); + register_std_subprogram(new SubprogramHexReadWrite(perm_string::literal("hwrite"), + perm_string::literal("$ivlh_write"))); /* std.textio library * procedure readline (file f: text; l: inout line); */ - std::list*fn_readline_args = new std::list(); - fn_readline_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); - fn_readline_args->push_back(new InterfacePort(&primitive_STRING, PORT_OUT)); - SubprogramBuiltin*fn_readline = new SubprogramBuiltin(perm_string::literal("readline"), + args = new list(); + args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + args->push_back(new InterfacePort(&primitive_STRING, PORT_OUT)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("readline"), perm_string::literal("$ivlh_readline"), - fn_readline_args, NULL); - register_std_subprogram(fn_readline); + args, NULL)); /* std.textio library * procedure writeline (file f: text; l: inout line); */ - std::list*fn_writeline_args = new std::list(); - fn_writeline_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); - fn_writeline_args->push_back(new InterfacePort(&primitive_STRING, PORT_IN)); - SubprogramBuiltin*fn_writeline = new SubprogramBuiltin(perm_string::literal("writeline"), + args = new list(); + args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + args->push_back(new InterfacePort(&primitive_STRING, PORT_IN)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("writeline"), perm_string::literal("$ivlh_writeline"), - fn_writeline_args, NULL); - register_std_subprogram(fn_writeline); + args, NULL)); /* function endline (file f: text) return boolean; */ - std::list*fn_endfile_args = new std::list(); - fn_endfile_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); - SubprogramBuiltin*fn_endfile = new SubprogramBuiltin(perm_string::literal("endfile"), + args = new list(); + args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("endfile"), perm_string::literal("$feof"), - fn_endfile_args, &type_BOOLEAN); - register_std_subprogram(fn_endfile); + args, &type_BOOLEAN)); } void delete_std_funcs() From 42ead3a48284c6dc2f4cf62e3f02f05a63c1fbf4 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 28 Jan 2016 10:22:24 +0100 Subject: [PATCH 29/76] vhdlpp: Elaborate types for signals & variables. --- vhdlpp/architec_elaborate.cc | 8 ++++---- vhdlpp/vsignal.cc | 7 ++++--- vhdlpp/vsignal.h | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 472ec317b..806519c51 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -45,19 +45,19 @@ int Architecture::elaborate(Entity*entity) // Elaborate initializer expressions for signals & variables for (map::iterator cur = old_signals_.begin() ; cur != old_signals_.end() ; ++cur) { - cur->second->elaborate_init_expr(entity, this); + cur->second->elaborate(entity, this); } for (map::iterator cur = new_signals_.begin() ; cur != new_signals_.end() ; ++cur) { - cur->second->elaborate_init_expr(entity, this); + cur->second->elaborate(entity, this); } for (map::iterator cur = old_variables_.begin() ; cur != old_variables_.end() ; ++cur) { - cur->second->elaborate_init_expr(entity, this); + cur->second->elaborate(entity, this); } for (map::iterator cur = new_variables_.begin() ; cur != new_variables_.end() ; ++cur) { - cur->second->elaborate_init_expr(entity, this); + cur->second->elaborate(entity, this); } // Elaborate subprograms diff --git a/vhdlpp/vsignal.cc b/vhdlpp/vsignal.cc index 68cec4c4a..e39142f6b 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -35,11 +35,12 @@ SigVarBase::~SigVarBase() { } -void SigVarBase::elaborate_init_expr(Entity*ent, ScopeBase*scope) +void SigVarBase::elaborate(Entity*ent, ScopeBase*scope) { - if(init_expr_) { + if(init_expr_) init_expr_->elaborate_expr(ent, scope, peek_type()); - } + + type_->elaborate(ent, scope); } void SigVarBase::type_elaborate_(VType::decl_t&decl) diff --git a/vhdlpp/vsignal.h b/vhdlpp/vsignal.h index 6aa225d14..9beda6cef 100644 --- a/vhdlpp/vsignal.h +++ b/vhdlpp/vsignal.h @@ -42,8 +42,8 @@ class SigVarBase : public LineInfo { void dump(ostream&out, int indent = 0) const; - // Elaborates initializer expressions if needed. - void elaborate_init_expr(Entity*ent, ScopeBase*scope); + // Elaborates type & initializer expressions. + void elaborate(Entity*ent, ScopeBase*scope); perm_string peek_name() const { return name_; } From 32f202bddc9c93e6b11afed221d1fc6cdb195edf Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 28 Jan 2016 10:22:43 +0100 Subject: [PATCH 30/76] vhdlpp: VTypeRangeExpr::elaborate() --- vhdlpp/vtype.h | 4 ++-- vhdlpp/vtype_elaborate.cc | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index b2212b6d6..800c0bbd3 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -282,7 +282,7 @@ class VTypeRange : public VType { // Get the type that is limited by the range. inline const VType*base_type() const { return base_; } - private: + protected: const VType*base_; }; @@ -295,7 +295,6 @@ class VTypeRangeConst : public VTypeRange { return new VTypeRangeConst(base_type()->clone(), start_, end_); } - public: // Virtual methods void write_to_stream(std::ostream&fd) const; private: @@ -309,6 +308,7 @@ class VTypeRangeExpr : public VTypeRange { ~VTypeRangeExpr(); VType*clone() const; + int elaborate(Entity*end, ScopeBase*scope) const; public: // Virtual methods void write_to_stream(std::ostream&fd) const; diff --git a/vhdlpp/vtype_elaborate.cc b/vhdlpp/vtype_elaborate.cc index b3b4cfd9d..e32d4d28e 100644 --- a/vhdlpp/vtype_elaborate.cc +++ b/vhdlpp/vtype_elaborate.cc @@ -29,7 +29,8 @@ int VType::elaborate(Entity*, ScopeBase*) const int VTypeArray::elaborate(Entity*ent, ScopeBase*scope) const { int errors = 0; - etype_->elaborate(ent, scope); + + errors += etype_->elaborate(ent, scope); for (vector::const_iterator cur = ranges_.begin() ; cur != ranges_.end() ; ++ cur) { @@ -43,3 +44,14 @@ int VTypeArray::elaborate(Entity*ent, ScopeBase*scope) const return errors; } + +int VTypeRangeExpr::elaborate(Entity*ent, ScopeBase*scope) const +{ + int errors = 0; + + errors += base_->elaborate(ent, scope); + errors += start_->elaborate_expr(ent, scope, 0); + errors += end_->elaborate_expr(ent, scope, 0); + + return errors; +} From 6b1e08cdb0aa523c68ecb63c73059295527a8567 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 28 Jan 2016 15:50:10 +0100 Subject: [PATCH 31/76] vhdlpp: Removed a non-existing method declaration. --- vhdlpp/package.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/vhdlpp/package.h b/vhdlpp/package.h index 3f75c8820..7ae45120a 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -36,8 +36,6 @@ class Package : public Scope, public LineInfo { perm_string name() const { return name_; } - SubprogramHeader* recall_subprogram(perm_string name) const; - // This method writes a package header to a library file. void write_to_stream(std::ostream&fd) const; From 25671048f6c0ade9cb0dada86e021853baa17061 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 28 Jan 2016 15:50:50 +0100 Subject: [PATCH 32/76] vhdlpp: ExpInteger::probe_type() returns either INTEGER or NATURAL, depending on the value. --- vhdlpp/expression_elaborate.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 82fd1e6d8..6454f8f85 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -843,7 +843,10 @@ const VType* ExpFunc::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*) c const VType* ExpInteger::probe_type(Entity*, ScopeBase*) const { - return &primitive_INTEGER; + if(value_ >= 0) + return &primitive_NATURAL; + else + return &primitive_INTEGER; } int ExpInteger::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) From 8d3f559b38f148035aa3ade8146c807fac64ee40 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 28 Jan 2016 15:52:08 +0100 Subject: [PATCH 33/76] vhdlpp: ExpName::probe_prefixed() returns correct type for complex expressions. E.g. array_of_records(2).fieldname --- vhdlpp/expression_elaborate.cc | 51 ++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 6454f8f85..348b47cea 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -911,40 +911,49 @@ const VType* ExpName::probe_prefix_type_(Entity*ent, ScopeBase*scope) const */ const VType* ExpName::probe_prefixed_type_(Entity*ent, ScopeBase*scope) const { - // First, get the type of the prefix. + // First, get the type of the prefix. const VType*prefix_type = prefix_->probe_prefix_type_(ent, scope); if (prefix_type == 0) { - return 0; + return 0; } while (const VTypeDef*def = dynamic_cast (prefix_type)) { - prefix_type = def->peek_definition(); + prefix_type = def->peek_definition(); } - // If the prefix type is a record, then the current name is - // the name of a member. - if (const VTypeRecord*pref_record = dynamic_cast (prefix_type)) { - const VTypeRecord::element_t*element = pref_record->element_by_name(name_); - ivl_assert(*this, element); + const VType*element_type = prefix_type; + bool type_changed = true; - const VType*element_type = element->peek_type(); - ivl_assert(*this, element_type); + // Keep unwinding the type until we find the basic element type + while (type_changed) { + type_changed = false; - return element_type; + // If the prefix type is a record, then the current name is + // the name of a member. + if (const VTypeRecord*pref_record = dynamic_cast(element_type)) { + const VTypeRecord::element_t*element = pref_record->element_by_name(name_); + ivl_assert(*this, element); + + element_type = element->peek_type(); + ivl_assert(*this, element_type); + type_changed = true; + } + + if (const VTypeArray*pref_array = dynamic_cast(element_type)) { + element_type = pref_array->basic_type(false); + ivl_assert(*this, element_type); + type_changed = true; + } } - if (const VTypeArray*pref_array = dynamic_cast (prefix_type)) { - const VType*element_type = pref_array->element_type(); - ivl_assert(*this, element_type); - - return element_type; + if(!element_type) { + cerr << get_fileline() << ": sorry: I don't know how to probe " + << "prefix type " << typeid(*prefix_type).name() + << " of " << name_ << "." << endl; + return NULL; } - cerr << get_fileline() << ": sorry: I don't know how to probe " - << "prefix type " << typeid(*prefix_type).name() - << " of " << name_ << "." << endl; - - return 0; + return element_type; } const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const From ad5b003488db7209bd925ce7617e159e1dfe4cd7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 28 Jan 2016 17:03:29 +0100 Subject: [PATCH 34/76] vhdlpp: Improved handling for subprogram-related errors. --- vhdlpp/expression_elaborate.cc | 16 +++++++++------- vhdlpp/sequential_elaborate.cc | 7 ++++++- vhdlpp/subprogram.h | 4 ++++ vhdlpp/subprogram_emit.cc | 20 ++++++++++++++++++++ 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 348b47cea..76850aafd 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -795,7 +795,9 @@ const VType*ExpFunc::probe_type(Entity*, ScopeBase*scope) const prog = library_find_subprogram(name_); if(!prog) { - cerr << get_fileline() << ": sorry: VHDL function " << name_ << " not yet implemented" << endl; + cerr << get_fileline() << ": sorry: could not find function "; + emit_subprogram_sig(cerr, name_, arg_types); + cerr << endl; ivl_assert(*this, false); } @@ -812,8 +814,13 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) if(!prog) prog = library_find_subprogram(name_); - ivl_assert(*this, def_==0); def_ = prog; + if(!def_) { + cerr << get_fileline() << ": error: could not find function "; + emit_subprogram_sig(cerr, name_, arg_types); + cerr << endl; + return 1; + } // Elaborate arguments for (size_t idx = 0; idx < argv_.size(); ++idx) { @@ -828,11 +835,6 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) name_ = def_->name(); } - if(!def_) { - cerr << get_fileline() << ": error: could not find function " << name_ << endl; - ++errors; - } - return errors; } diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index d3e1e493a..4d67daa65 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -183,7 +183,12 @@ int ProcedureCall::elaborate(Entity*ent, ScopeBase*scope) if(!def_) def_ = library_find_subprogram(name_); - assert(def_); + if(!def_) { + cerr << get_fileline() << ": error: could not find procedure "; + emit_subprogram_sig(cerr, name_, arg_types); + cerr << endl; + return 1; + } // Elaborate arguments size_t idx = 0; diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index ba10f6e56..6eb0446c9 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -169,4 +169,8 @@ class SubprogramBuiltin : public SubprogramStdHeader perm_string sv_name_; }; +// Helper function to print out a human-readable function signature. +void emit_subprogram_sig(std::ostream&out, perm_string name, + const std::list&arg_types); + #endif /* IVL_subprogram_H */ diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc index 18ab855a3..0aa02973e 100644 --- a/vhdlpp/subprogram_emit.cc +++ b/vhdlpp/subprogram_emit.cc @@ -142,3 +142,23 @@ int SubprogramBuiltin::emit_name(const std::vector&, out << sv_name_; return 0; } + +void emit_subprogram_sig(ostream&out, perm_string name, + const list&arg_types) +{ + out << name << "("; + bool first = true; + for(list::const_iterator it = arg_types.begin(); + it != arg_types.end(); ++it) { + if(first) + first = false; + else + out << ", "; + + if(*it) + (*it)->write_to_stream(out); + else + out << ""; + } + out << ")"; +} From cfa038e75c6fd0b232938fa4b35d9eac0e7fa4da Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 28 Jan 2016 17:48:38 +0100 Subject: [PATCH 35/76] vhdlpp: VType::type_match() fixes. --- vhdlpp/vtype.h | 2 ++ vhdlpp/vtype_match.cc | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 800c0bbd3..3b9356e60 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -168,6 +168,7 @@ class VTypePrimitive : public VType { VType*clone() const { return new VTypePrimitive(*this); } + bool type_match(const VType*that) const; void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; int get_width(ScopeBase*scope) const; @@ -221,6 +222,7 @@ class VTypeArray : public VType { VType*clone() const; int elaborate(Entity*ent, ScopeBase*scope) const; + bool type_match(const VType*that) const; void write_to_stream(std::ostream&fd) const; void write_type_to_stream(std::ostream&fd) const; void show(std::ostream&) const; diff --git a/vhdlpp/vtype_match.cc b/vhdlpp/vtype_match.cc index 86c8f90ff..459217879 100644 --- a/vhdlpp/vtype_match.cc +++ b/vhdlpp/vtype_match.cc @@ -38,5 +38,43 @@ bool VTypeDef::type_match(const VType*that) const if(VType::type_match(that)) return true; - return VType::type_match(type_); + return type_->type_match(that); +} + +bool VTypePrimitive::type_match(const VType*that) const +{ + if(VType::type_match(that)) + return true; + + if(const VTypePrimitive*prim = dynamic_cast(that)) { + // TODO it is not always true, but works for many cases + type_t that_type = prim->type(); + return ((type_ == NATURAL || type_ == INTEGER) && + (that_type == NATURAL || that_type == INTEGER)); + } + + return false; +} + +bool VTypeArray::type_match(const VType*that) const +{ + if(VType::type_match(that)) + return true; + + // Check if both arrays are of the same size + if(const VTypeArray*arr = dynamic_cast(that)) { + if(!element_type()->type_match(arr->element_type())) + return false; + + int this_width = get_width(NULL); + int that_width = arr->get_width(NULL); + + // Either one of the sizes is undefined, or both are the same size + if(this_width > 0 && that_width > 0 && this_width != that_width) + return false; + + return true; + } + + return false; } From 2c4deee0c3d3f3c63ef0e9816ca9f39fdad45af8 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 29 Jan 2016 16:34:10 +0100 Subject: [PATCH 36/76] vhdlpp: Support for subprogram overloading. --- vhdlpp/architec_elaborate.cc | 9 ++- vhdlpp/architec_emit.cc | 15 +++- vhdlpp/debug.cc | 39 ++++++---- vhdlpp/expression_elaborate.cc | 49 +++++++----- vhdlpp/library.cc | 8 +- vhdlpp/library.h | 11 ++- vhdlpp/package.cc | 44 +++++++---- vhdlpp/package_emit.cc | 25 +++++-- vhdlpp/parse.y | 9 +-- vhdlpp/scope.cc | 131 +++++++++++++++++++++++++++------ vhdlpp/scope.h | 20 +++-- vhdlpp/sequential_elaborate.cc | 16 +++- vhdlpp/std_funcs.cc | 23 +++--- vhdlpp/std_funcs.h | 2 +- vhdlpp/subprogram.h | 2 +- 15 files changed, 288 insertions(+), 115 deletions(-) diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 806519c51..e35209f33 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -61,9 +61,14 @@ int Architecture::elaborate(Entity*entity) } // Elaborate subprograms - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++cur) { - errors += cur->second->elaborate(); + const SubHeaderList& subp_list = cur->second; + + for(SubHeaderList::const_iterator it = subp_list.begin(); + it != subp_list.end(); ++it) { + errors += (*it)->elaborate(); + } } // Create 'initial' and 'final' blocks for implicit // initalization and clean-up actions diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 42e5e2c5c..8fd0ee569 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -103,11 +103,18 @@ int Architecture::emit(ostream&out, Entity*entity) errors += emit_signals(out, entity, this); errors += emit_variables(out, entity, this); - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++ cur) { - // Do not emit unbounded functions, we will just need fixed instances later - if(!cur->second->unbounded()) - errors += cur->second->emit_package(out); + const SubHeaderList& subp_list = cur->second; + + for(SubHeaderList::const_iterator it = subp_list.begin(); + it != subp_list.end(); ++it) { + SubprogramHeader*subp = *it; + + // Do not emit unbounded functions, we will just need fixed instances later + if(!subp->unbounded()) + errors += subp->emit_package(out); + } } for (list::iterator cur = statements_.begin() diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 6f044b2e8..3669fd489 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -150,22 +150,35 @@ void ScopeBase::dump_scope(ostream&out) const } // Dump subprograms out << " -- Imported Subprograms" << endl; - for (map::const_iterator cur = use_subprograms_.begin() - ; cur != use_subprograms_.end() ; ++cur) { - out << " subprogram " << cur->first << " is" << endl; - cur->second->dump(out); - if(cur->second->body()) - cur->second->body()->dump(out); - out << " end subprogram " << cur->first << endl; + for (map::const_iterator cur = use_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++ cur) { + const SubHeaderList& subp_list = cur->second; + + for(SubHeaderList::const_iterator it = subp_list.begin(); + it != subp_list.end(); ++it) { + const SubprogramHeader*subp = *it; + out << " subprogram " << cur->first << " is" << endl; + subp->dump(out); + if(subp->body()) + subp->body()->dump(out); + out << " end subprogram " << cur->first << endl; + } } + out << " -- Subprograms from this scope" << endl; - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++cur) { - out << " subprogram " << cur->first << " is" << endl; - cur->second->dump(out); - if(cur->second->body()) - cur->second->body()->dump(out); - out << " end subprogram " << cur->first << endl; + const SubHeaderList& subp_list = cur->second; + + for(SubHeaderList::const_iterator it = subp_list.begin(); + it != subp_list.end(); ++it) { + const SubprogramHeader*subp = *it; + out << " subprogram " << cur->first << " is" << endl; + subp->dump(out); + if(subp->body()) + subp->body()->dump(out); + out << " end subprogram " << cur->first << endl; + } } // Dump component declarations out << " -- Components" << endl; diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 76850aafd..c95a26077 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -783,22 +783,29 @@ int ExpConditional::case_t::elaborate_expr(Entity*ent, ScopeBase*scope, const VT return errors; } -const VType*ExpFunc::probe_type(Entity*, ScopeBase*scope) const +const VType*ExpFunc::probe_type(Entity*ent, ScopeBase*scope) const { SubprogramHeader*prog = def_; if(!prog) { - prog = scope->find_subprogram(name_); - } + list arg_types; - if(!prog) - prog = library_find_subprogram(name_); + for(vector::const_iterator it = argv_.begin(); + it != argv_.end(); ++it) { + arg_types.push_back((*it)->probe_type(ent, scope)); + } - if(!prog) { - cerr << get_fileline() << ": sorry: could not find function "; - emit_subprogram_sig(cerr, name_, arg_types); - cerr << endl; - ivl_assert(*this, false); + prog = scope->match_subprogram(name_, &arg_types); + + if(!prog) + prog = library_match_subprogram(name_, &arg_types); + + if(!prog) { + cerr << get_fileline() << ": sorry: could not find function "; + emit_subprogram_sig(cerr, name_, arg_types); + cerr << endl; + ivl_assert(*this, false); + } } return prog->peek_return_type(); @@ -808,13 +815,19 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) { int errors = 0; - ivl_assert(*this, scope); - SubprogramHeader*prog = scope->find_subprogram(name_); + ivl_assert(*this, def_ == 0); // do not elaborate twice - if(!prog) - prog = library_find_subprogram(name_); + // Create a list of argument types to find a matching subprogram + list arg_types; + for(vector::iterator it = argv_.begin(); + it != argv_.end(); ++it) + arg_types.push_back((*it)->probe_type(ent, scope)); + + def_ = scope->match_subprogram(name_, &arg_types); + + if(!def_) + def_ = library_match_subprogram(name_, &arg_types); - def_ = prog; if(!def_) { cerr << get_fileline() << ": error: could not find function "; emit_subprogram_sig(cerr, name_, arg_types); @@ -824,15 +837,15 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*) // Elaborate arguments for (size_t idx = 0; idx < argv_.size(); ++idx) { - errors += prog->elaborate_argument(argv_[idx], idx, ent, scope); + errors += def_->elaborate_argument(argv_[idx], idx, ent, scope); } // SystemVerilog functions work only with defined size data types, therefore // if header does not specify argument or return type size, create a function // instance that work with this particular size. if(def_ && !def_->is_std() && def_->unbounded()) { - def_ = prog->make_instance(argv_, scope); - name_ = def_->name(); + def_ = def_->make_instance(argv_, scope); + name_ = def_->name(); // TODO necessary? } return errors; diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index beb0838d3..fb015feab 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -1,6 +1,8 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * Copyright CERN 2016 + * @author Maciej Suminski * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -73,9 +75,9 @@ void library_add_directory(const char*directory) library_search_path.push_front(directory); } -SubprogramHeader*library_find_subprogram(perm_string name) +SubprogramHeader*library_match_subprogram(perm_string name, const list*params) { - SubprogramHeader*subp = NULL; + SubprogramHeader*subp; map::const_iterator lib_it; for(lib_it = libraries.begin(); lib_it != libraries.end(); ++lib_it) { @@ -83,7 +85,7 @@ SubprogramHeader*library_find_subprogram(perm_string name) map::const_iterator pack_it; for(pack_it = lib.packages.begin(); pack_it != lib.packages.end(); ++pack_it) { - if((subp = pack_it->second->find_subprogram(name))) + if((subp = pack_it->second->match_subprogram(name, params))) return subp; } } diff --git a/vhdlpp/library.h b/vhdlpp/library.h index 7fb95851e..5596db870 100644 --- a/vhdlpp/library.h +++ b/vhdlpp/library.h @@ -19,15 +19,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -class SubprogramHeader; +#include -extern void library_set_work_path(const char*work_path); -extern void library_add_directory(const char*directory); +class SubprogramHeader; +class VType; + +void library_set_work_path(const char*work_path); +void library_add_directory(const char*directory); int elaborate_libraries(void); int emit_packages(void); -extern SubprogramHeader*library_find_subprogram(perm_string name); +SubprogramHeader*library_match_subprogram(perm_string name, const list*params); #endif /* IVL_library_H */ diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 63215fee3..d58f82093 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -24,6 +24,8 @@ # include "parse_misc.h" # include "std_types.h" # include "ivl_assert.h" +# include +# include Package::Package(perm_string n, const ActiveScope&ref) : Scope(ref), name_(n) @@ -45,9 +47,14 @@ int Package::elaborate() { int errors = 0; - for (map::const_iterator cur = cur_subprograms_.begin() - ; cur != cur_subprograms_.end() ; ++cur) { - errors += cur->second->elaborate(); + for (map::iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++ cur) { + SubHeaderList& subp_list = cur->second; + + for(SubHeaderList::iterator it = subp_list.begin(); + it != subp_list.end(); ++it) { + errors += (*it)->elaborate(); + } } return errors; @@ -108,10 +115,15 @@ void Package::write_to_stream(ostream&fd) const fd << ";" << endl; } - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++cur) { - cur->second->write_to_stream(fd); - fd << ";" << endl; + const SubHeaderList& subp_list = cur->second; + + for(SubHeaderList::const_iterator it = subp_list.begin(); + it != subp_list.end(); ++it) { + (*it)->write_to_stream(fd); + fd << ";" << endl; + } } for (map::const_iterator cur = old_components_.begin() @@ -128,14 +140,20 @@ void Package::write_to_stream(ostream&fd) const fd << "end package " << name_ << ";" << endl; fd << "package body " << name_ << " is" << endl; - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++cur) { - SubprogramHeader*subp = cur->second; - if(subp->body()) { - subp->write_to_stream(fd); - fd << " is" << endl; - subp->body()->write_to_stream(fd); + const SubHeaderList& subp_list = cur->second; + + for(SubHeaderList::const_iterator it = subp_list.begin(); + it != subp_list.end(); ++it) { + const SubprogramHeader*subp = *it; + + if(subp->body()) { + subp->write_to_stream(fd); + fd << " is" << endl; + subp->body()->write_to_stream(fd); + } } - } + } fd << "end " << name_ << ";" << endl; } diff --git a/vhdlpp/package_emit.cc b/vhdlpp/package_emit.cc index 77d314231..962f68a65 100644 --- a/vhdlpp/package_emit.cc +++ b/vhdlpp/package_emit.cc @@ -20,8 +20,9 @@ # include "package.h" # include "subprogram.h" -# include # include "ivl_assert.h" +# include +# include using namespace std; @@ -64,14 +65,22 @@ int Package::emit_package(ostream&fd) const //} fd << "package \\" << name() << " ;" << endl; - for (map::const_iterator cur = cur_subprograms_.begin() + for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++ cur) { - // Do not emit unbounded functions, we will just need fixed instances later - if(!cur->second->unbounded()) - errors += cur->second->emit_package(fd); - else - fd << "/* function " << cur->second->name() << - " has to be instantiated, skipping */" << endl; + const SubHeaderList& subp_list = cur->second; + + for(SubHeaderList::const_iterator it = subp_list.begin(); + it != subp_list.end(); ++it) { + SubprogramHeader*header = *it; + + // Do not emit unbounded functions, we will just need fixed instances later + if(!header->unbounded()) + errors += header->emit_package(fd); + else + fd << "/* function " << header->name() + << " has to be instantiated, skipping */" << endl; + } + } fd << "endpackage /* " << name() << " */" << endl; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 95853a03a..0d7b706a9 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -1701,7 +1701,8 @@ name /* IEEE 1076-2008 P8.1 */ tmp = parse_char_enums($1); if(!tmp) { perm_string name = lex_strings.make($1); - if(active_scope->find_subprogram(name) && !parse_type_by_name(name)) + /* There are functions that have the same name types, e.g. integer */ + if(!active_scope->find_subprogram(name).empty() && !parse_type_by_name(name)) tmp = new ExpFunc(name); else tmp = new ExpName(name); @@ -2565,12 +2566,10 @@ subprogram_body /* IEEE 1076-2008 P4.3 */ K_begin subprogram_statement_part K_end subprogram_kind_opt identifier_opt ';' { SubprogramHeader*prog = $1; - SubprogramHeader*tmp = active_scope->recall_subprogram(prog->name()); - if (tmp && prog->compare_specification(tmp)) { + SubprogramHeader*tmp = active_scope->recall_subprogram(prog); + if (tmp) { delete prog; prog = tmp; - } else if (tmp) { - errormsg(@1, "Subprogram specification for %s doesn't match specification in package header.\n", prog->name().str()); } SubprogramBody*body = new SubprogramBody(); diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 5084986a3..395804962 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -70,9 +70,14 @@ ScopeBase::ScopeBase(const ActiveScope&ref) // an active scope and is making the actual scope. At this point // we know that "this" is the parent scope for the subprograms, // so set it now. - for (map::iterator cur = cur_subprograms_.begin() - ; cur != cur_subprograms_.end(); ++cur) { - cur->second->set_parent(this); + for (map::iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end(); ++cur) { + SubHeaderList& subp_list = cur->second; + + for (SubHeaderList::iterator it = subp_list.begin(); + it != subp_list.end(); ++it) { + (*it)->set_parent(this); + } } } @@ -94,7 +99,10 @@ void ScopeBase::cleanup() delete_all(new_components_); delete_all(cur_types_); delete_all(cur_constants_); - delete_all(cur_subprograms_); + for (map::iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { + delete_all(cur->second); + } } const VType*ScopeBase::find_type(perm_string by_name) @@ -157,32 +165,42 @@ const InterfacePort* ScopeBase::find_param(perm_string) const const InterfacePort* ScopeBase::find_param_all(perm_string by_name) const { - for(map::const_iterator it = use_subprograms_.begin(); - it != use_subprograms_.end(); ++it) { - if(const InterfacePort*port = it->second->find_param(by_name)) - return port; + for(map::const_iterator cur = use_subprograms_.begin(); + cur != use_subprograms_.end(); ++cur) { + const SubHeaderList& subp_list = cur->second; + + for(SubHeaderList::const_iterator it = subp_list.begin(); + it != subp_list.end(); ++it) { + if(const InterfacePort*port = (*it)->find_param(by_name)) + return port; + } } - for(map::const_iterator it = cur_subprograms_.begin(); - it != cur_subprograms_.end(); ++it) { - if(const InterfacePort*port = it->second->find_param(by_name)) - return port; + for(map::const_iterator cur = cur_subprograms_.begin(); + cur != cur_subprograms_.end(); ++cur) { + const SubHeaderList& subp_list = cur->second; + + for(SubHeaderList::const_iterator it = subp_list.begin(); + it != subp_list.end(); ++it) { + if(const InterfacePort*port = (*it)->find_param(by_name)) + return port; + } } return NULL; } -SubprogramHeader* ScopeBase::find_subprogram(perm_string name) const +SubHeaderList ScopeBase::find_subprogram(perm_string name) const { - map::const_iterator cur; + map::const_iterator cur; cur = cur_subprograms_.find(name); if (cur != cur_subprograms_.end()) - return cur->second; + return cur->second; cur = use_subprograms_.find(name); if (cur != use_subprograms_.end()) - return cur->second; + return cur->second; return find_std_subprogram(name); } @@ -217,9 +235,9 @@ void ScopeBase::do_use_from(const ScopeBase*that) old_components_[cur->first] = cur->second; } - for (map::const_iterator cur = that->cur_subprograms_.begin() + for (map::const_iterator cur = that->cur_subprograms_.begin() ; cur != that->cur_subprograms_.end() ; ++ cur) { - if (cur->second == 0) + if (cur->second.empty()) continue; use_subprograms_[cur->first] = cur->second; } @@ -266,21 +284,86 @@ void ScopeBase::transfer_from(ScopeBase&ref, transfer_type_t what) } } +SubprogramHeader*ScopeBase::match_subprogram(perm_string name, + const list*params) const +{ + int req_param_count = params ? params->size() : 0; + + // Find all subprograms with matching name + SubHeaderList l = find_std_subprogram(name); + map::const_iterator cur; + + cur = use_subprograms_.find(name); + if (cur != use_subprograms_.end()) + copy(cur->second.begin(), cur->second.end(), + front_insert_iterator(l)); + + cur = cur_subprograms_.find(name); + if(cur != cur_subprograms_.end()) + copy(cur->second.begin(), cur->second.end(), + front_insert_iterator(l)); + + // Find the matching one + for(SubHeaderList::iterator it = l.begin(); it != l.end(); ++it) { + SubprogramHeader*subp = *it; + + if(req_param_count != subp->param_count()) + continue; + + // Do not check the return type here, it might depend on the arguments + + if(params) { + list::const_iterator p = params->begin(); + bool ok = true; + + for(int i = 0; i < req_param_count; ++i) { + const VType*param_type = subp->peek_param_type(i); + + if(*p && param_type && !param_type->type_match(*p)) { + ok = false; + break; + } + + ++p; + } + + if(!ok) + continue; // check another function + } + + // Yay, we have a match! + return subp; + } + + return NULL; +} + void ActiveScope::set_package_header(Package*pkg) { assert(package_header_ == 0); package_header_ = pkg; } -SubprogramHeader* ActiveScope::recall_subprogram(perm_string name) const +SubprogramHeader* ActiveScope::recall_subprogram(const SubprogramHeader*subp) const { - if (SubprogramHeader*tmp = find_subprogram(name)) - return tmp; + list arg_types; + SubprogramHeader*tmp; - if (package_header_) - return package_header_->find_subprogram(name); + for(int i = 0; i < subp->param_count(); ++i) + arg_types.push_back(subp->peek_param_type(i)); - return 0; + if ((tmp = match_subprogram(subp->name(), &arg_types))) { + assert(!tmp->body()); + return tmp; + } + + if (package_header_) { + tmp = package_header_->match_subprogram(subp->name(), &arg_types); + assert(!tmp || !tmp->body()); + return tmp; + } + + return NULL; } bool ActiveScope::is_vector_name(perm_string name) const diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index a95d1e4cd..3563692d9 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -36,6 +36,8 @@ class SubprogramHeader; class VType; class SequentialStmt; +typedef list SubHeaderList; + template struct delete_object{ void operator()(T* item) { delete item; } @@ -59,7 +61,7 @@ class ScopeBase { Variable* find_variable(perm_string by_name) const; virtual const InterfacePort* find_param(perm_string by_name) const; const InterfacePort* find_param_all(perm_string by_name) const; - SubprogramHeader* find_subprogram(perm_string by_name) const; + SubHeaderList find_subprogram(perm_string by_name) const; // Checks if a string is one of possible enum values. If so, the enum // type is returned, otherwise NULL. const VTypeEnum* is_enum_name(perm_string name) const; @@ -70,10 +72,10 @@ class ScopeBase { void transfer_from(ScopeBase&ref, transfer_type_t what = ALL); inline void bind_subprogram(perm_string name, SubprogramHeader*obj) - { map::iterator it; + { map::iterator it; if((it = use_subprograms_.find(name)) != use_subprograms_.end() ) - use_subprograms_.erase(it); - cur_subprograms_[name] = obj; + it->second.remove(obj); + cur_subprograms_[name].push_back(obj); } // Adds a statement to implicit initializers list @@ -92,6 +94,10 @@ class ScopeBase { void dump_scope(ostream&out) const; + // Looks for a subprogram with specified name and parameter types. + SubprogramHeader*match_subprogram(perm_string name, + const list*params) const; + protected: void cleanup(); @@ -134,8 +140,8 @@ class ScopeBase { std::map use_constants_; //imported constants std::map cur_constants_; //current constants - std::map use_subprograms_; //imported - std::map cur_subprograms_; //current + std::map use_subprograms_; //imported + std::map cur_subprograms_; //current std::list use_enums_; @@ -191,7 +197,7 @@ class ActiveScope : public ScopeBase { // Locate the subprogram by name. The subprogram body uses // this to locate the subprogram declaration. Note that the // subprogram may be in a package header. - SubprogramHeader* recall_subprogram(perm_string name) const; + SubprogramHeader* recall_subprogram(const SubprogramHeader*subp) const; /* All bind_name function check if the given name was present * in previous scopes. If it is found, it is erased (but the pointer diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 4d67daa65..93d185bfd 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -178,10 +178,22 @@ int ProcedureCall::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; - def_ = scope->find_subprogram(name_); + assert(!def_); // do not elaborate twice + + // Create a list of argument types to find a matching subprogram + list arg_types; + if(param_list_) { + for(list::iterator it = param_list_->begin(); + it != param_list_->end(); ++it) { + named_expr_t* e = *it; + arg_types.push_back(e->expr()->probe_type(ent, scope)); + } + } + + def_ = scope->match_subprogram(name_, &arg_types); if(!def_) - def_ = library_find_subprogram(name_); + def_ = library_match_subprogram(name_, &arg_types); if(!def_) { cerr << get_fileline() << ": error: could not find procedure "; diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index 50d6c1803..f3a4fb441 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -22,11 +22,11 @@ #include "std_types.h" #include "scope.h" -static std::map std_subprograms; +static std::map std_subprograms; static inline void register_std_subprogram(SubprogramHeader*header) { - std_subprograms[header->name()] = header; + std_subprograms[header->name()].push_back(header); } // Special case: to_integer function @@ -356,17 +356,20 @@ void preload_std_funcs(void) void delete_std_funcs() { - for(std::map::iterator it = std_subprograms.begin(); - it != std_subprograms.end(); ++it) { - delete it->second; + for(std::map::iterator cur = std_subprograms.begin(); + cur != std_subprograms.end(); ++cur) { + for(SubHeaderList::const_iterator it = cur->second.begin(); + it != cur->second.end(); ++it) { + delete *it; + } } } -SubprogramHeader*find_std_subprogram(perm_string name) +SubHeaderList find_std_subprogram(perm_string name) { - map::const_iterator cur = std_subprograms.find(name); - if (cur != std_subprograms.end()) - return cur->second; + map::const_iterator cur = std_subprograms.find(name); + if(cur != std_subprograms.end()) + return cur->second; - return NULL; + return SubHeaderList(); } diff --git a/vhdlpp/std_funcs.h b/vhdlpp/std_funcs.h index 0f5645aa3..f3a904d44 100644 --- a/vhdlpp/std_funcs.h +++ b/vhdlpp/std_funcs.h @@ -29,6 +29,6 @@ void preload_std_funcs(); void delete_std_funcs(); // Returns subprogram header for a requested function or NULL if it does not exist. -SubprogramHeader*find_std_subprogram(perm_string name); +SubHeaderList find_std_subprogram(perm_string name); #endif /* IVL_std_funcs_H */ diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 6eb0446c9..0338dc002 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -32,7 +32,6 @@ class InterfacePort; class SequentialStmt; class VType; -class SubprogramHeader; class SubprogramBody : public LineInfo, public ScopeBase { @@ -73,6 +72,7 @@ class SubprogramHeader : public LineInfo { // matches this subprogram and that subprogram. bool compare_specification(SubprogramHeader*that) const; + int param_count() const { return ports_ ? ports_->size() : 0; } const InterfacePort*find_param(perm_string nam) const; const InterfacePort*peek_param(int idx) const; const VType*peek_param_type(int idx) const; From 609f266a8c4c94e0e31c00d48b3f782663cfa262 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 29 Jan 2016 16:34:36 +0100 Subject: [PATCH 37/76] vhdlpp: Additional variants for standard library functions. --- vhdlpp/std_funcs.cc | 118 +++++++++++++++++++++++++++----------------- 1 file changed, 72 insertions(+), 46 deletions(-) diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index f3a4fb441..dfc0ce1f6 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -64,10 +64,10 @@ class SubprogramToInteger : public SubprogramStdHeader { // Special case: size casting (e.g. conv_std_logic_vector() / resize()). class SubprogramSizeCast : public SubprogramStdHeader { public: - explicit SubprogramSizeCast(perm_string nam) - : SubprogramStdHeader(nam, NULL, &primitive_STDLOGIC_VECTOR) { + explicit SubprogramSizeCast(perm_string nam, const VType*base, const VType*target) + : SubprogramStdHeader(nam, NULL, target) { ports_ = new list(); - ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); + ports_->push_back(new InterfacePort(base)); ports_->push_back(new InterfacePort(&primitive_INTEGER)); } @@ -95,12 +95,11 @@ class SubprogramSizeCast : public SubprogramStdHeader { class SubprogramReadWrite : public SubprogramBuiltin { public: - SubprogramReadWrite(perm_string nam, perm_string newnam) - : SubprogramBuiltin(nam, newnam, NULL, NULL) { + SubprogramReadWrite(perm_string nam, perm_string newnam, bool hex = false) + : SubprogramBuiltin(nam, newnam, NULL, NULL), hex_format_(hex) { ports_ = new list(); - ports_->push_back(new InterfacePort(&primitive_STRING, PORT_INOUT)); - ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR, PORT_INOUT)); - ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + ports_->push_back(new InterfacePort(&primitive_STRING)); + ports_->push_back(new InterfacePort(NULL)); } // Format types handled by $ivlh_read/write (see vpi/vhdl_textio.c) @@ -121,7 +120,9 @@ class SubprogramReadWrite : public SubprogramBuiltin { const VTypePrimitive*prim = dynamic_cast(arg_type); // Pick the right format - if(prim && prim->type() == VTypePrimitive::TIME) + if(hex_format_) + out << FORMAT_HEX; + else if(prim && prim->type() == VTypePrimitive::TIME) out << FORMAT_TIME; else if(arg_type && arg_type->type_match(&type_BOOLEAN)) out << FORMAT_BOOL; @@ -133,32 +134,9 @@ class SubprogramReadWrite : public SubprogramBuiltin { return errors; } -}; -class SubprogramHexReadWrite : public SubprogramBuiltin { - public: - SubprogramHexReadWrite(perm_string nam, perm_string newnam) - : SubprogramBuiltin(nam, newnam, NULL, NULL) { - ports_ = new list(); - ports_->push_back(new InterfacePort(&primitive_STRING, PORT_INOUT)); - ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR, PORT_INOUT)); - ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); - } - - int emit_args(const std::vector&argv, - std::ostream&out, Entity*ent, ScopeBase*scope) const { - - int errors = 0; - - for(int i = 0; i < 2; ++i) { - errors += argv[i]->emit(out, ent, scope); - out << ", "; - } - - out << SubprogramReadWrite::FORMAT_HEX; - - return errors; - } + private: + bool hex_format_; }; void preload_std_funcs(void) @@ -179,10 +157,16 @@ void preload_std_funcs(void) perm_string::literal("$unsigned"), args, &primitive_UNSIGNED)); + args = new list(); + args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("unsigned"), + perm_string::literal("$unsigned"), + args, &primitive_UNSIGNED)); + /* function integer */ args = new list(); - args->push_back(new InterfacePort(&primitive_INTEGER)); + args->push_back(new InterfacePort(&primitive_REAL)); register_std_subprogram(new SubprogramBuiltin(perm_string::literal("integer"), perm_string::literal("$signed"), args, &primitive_INTEGER)); @@ -200,38 +184,61 @@ void preload_std_funcs(void) /* numeric_std library * function shift_left (arg: unsigned; count: natural) return unsigned; + * function shift_left (arg: signed; count: natural) return signed; */ args = new list(); args->push_back(new InterfacePort(&primitive_UNSIGNED)); - args->push_back(new InterfacePort(&primitive_UNSIGNED)); + args->push_back(new InterfacePort(&primitive_NATURAL)); register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_left"), perm_string::literal("$ivlh_shift_left"), args, &primitive_UNSIGNED)); + args = new list(); + args->push_back(new InterfacePort(&primitive_SIGNED)); + args->push_back(new InterfacePort(&primitive_NATURAL)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_left"), + perm_string::literal("$ivlh_shift_left"), + args, &primitive_SIGNED)); + /* numeric_std library * function shift_right (arg: unsigned; count: natural) return unsigned; + * function shift_right (arg: signed; count: natural) return signed; */ args = new list(); - args->push_back(new InterfacePort(&primitive_UNSIGNED)); - args->push_back(new InterfacePort(&primitive_UNSIGNED)); + args->push_back(new InterfacePort(&primitive_SIGNED)); + args->push_back(new InterfacePort(&primitive_NATURAL)); register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_right"), perm_string::literal("$ivlh_shift_right"), - args, &primitive_UNSIGNED)); + args, &primitive_SIGNED)); /* function resize */ - register_std_subprogram(new SubprogramSizeCast(perm_string::literal("resize"))); + register_std_subprogram(new SubprogramSizeCast(perm_string::literal("resize"), + &primitive_STDLOGIC_VECTOR, &primitive_STDLOGIC_VECTOR)); /* std_logic_arith library * function conv_std_logic_vector(arg: integer; size: integer) return std_logic_vector; */ - register_std_subprogram(new SubprogramSizeCast(perm_string::literal("conv_std_logic_vector"))); + register_std_subprogram(new SubprogramSizeCast(perm_string::literal("conv_std_logic_vector"), + &primitive_INTEGER, &primitive_STDLOGIC_VECTOR)); /* numeric_bit library * function to_integer (arg: unsigned) return natural; + */ + args = new list(); + args->push_back(new InterfacePort(&primitive_UNSIGNED)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_integer"), + perm_string::literal("$unsigned"), + args, &primitive_NATURAL)); + + /* numeric_bit library * function to_integer (arg: signed) return integer; */ - register_std_subprogram(new SubprogramToInteger()); + args = new list(); + args->push_back(new InterfacePort(&primitive_SIGNED)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_integer"), + perm_string::literal("$signed"), + args, &primitive_INTEGER)); /* std_logic_1164 library * function rising_edge (signal s : std_ulogic) return boolean; @@ -278,6 +285,25 @@ void preload_std_funcs(void) args = new list(); args->push_back(new InterfacePort(&primitive_REAL)); args->push_back(new InterfacePort(&primitive_NATURAL)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_unsigned"), + perm_string::literal("$ivlh_to_unsigned"), + args, &primitive_UNSIGNED)); + /* numeric_std library + * function to_unsigned(arg, size : natural) return unsigned; + */ + args = new list(); + args->push_back(new InterfacePort(&primitive_NATURAL)); + args->push_back(new InterfacePort(&primitive_NATURAL)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_unsigned"), + perm_string::literal("$ivlh_to_unsigned"), + args, &primitive_UNSIGNED)); + + /* numeric_std library + * function to_unsigned(arg : std_logic_vector, size : natural) return unsigned; + */ + args = new list(); + args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR)); + args->push_back(new InterfacePort(&primitive_NATURAL)); register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_unsigned"), perm_string::literal("$ivlh_to_unsigned"), args, &primitive_UNSIGNED)); @@ -316,14 +342,14 @@ void preload_std_funcs(void) /* std.textio library * procedure hread (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); */ - register_std_subprogram(new SubprogramHexReadWrite(perm_string::literal("hread"), - perm_string::literal("$ivlh_read"))); + register_std_subprogram(new SubprogramReadWrite(perm_string::literal("hread"), + perm_string::literal("$ivlh_read"), true)); /* std.textio library * procedure hwrite (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time); */ - register_std_subprogram(new SubprogramHexReadWrite(perm_string::literal("hwrite"), - perm_string::literal("$ivlh_write"))); + register_std_subprogram(new SubprogramReadWrite(perm_string::literal("hwrite"), + perm_string::literal("$ivlh_write"), true)); /* std.textio library * procedure readline (file f: text; l: inout line); From 08150eae83c28d27a01ee9f8267754a31140b77e Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 29 Jan 2016 16:44:34 +0100 Subject: [PATCH 38/76] vhdlpp: Add line information for procedure calls. --- vhdlpp/parse.y | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 0d7b706a9..3ce3c0db7 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -2018,18 +2018,21 @@ procedure_call : IDENTIFIER ';' { ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1)); + FILE_NAME(tmp, @1); delete[] $1; $$ = tmp; } | IDENTIFIER '(' association_list ')' ';' { ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $3); + FILE_NAME(tmp, @1); delete[] $1; $$ = tmp; } | IDENTIFIER argument_list ';' { ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $2); + FILE_NAME(tmp, @1); delete[] $1; delete $2; // parameters are copied in this variant $$ = tmp; From 0f3f8907c3a8179d07c2bbba75b60f27ff2d0dc7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 29 Jan 2016 16:46:42 +0100 Subject: [PATCH 39/76] vhdlpp: Removed an unnecessary check. --- vhdlpp/expression_elaborate.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index c95a26077..e1cb258f2 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -579,8 +579,6 @@ const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t if (t1->type_match(t2)) return t1; - if (t2->type_match(t2)) - return t2; return 0; } From 34b5834a84c5b51fd761a0af05145c43fb9ece8e Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 1 Feb 2016 13:50:08 +0100 Subject: [PATCH 40/76] vhdlpp: Added file_open() variant that returns status. --- vhdlpp/std_funcs.cc | 11 +++++ vpi/vhdl_textio.c | 101 +++++++++++++++++++++++++++++++++----------- 2 files changed, 87 insertions(+), 25 deletions(-) diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index dfc0ce1f6..9129124e5 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -318,6 +318,17 @@ void preload_std_funcs(void) perm_string::literal("$ivlh_file_open"), args, NULL)); + /* procedure file_open (status: out file_open_status, file f: text; filename: in string, file_open_kind: in mode); + */ + args = new list(); + args->push_back(new InterfacePort(&type_FILE_OPEN_STATUS, PORT_OUT)); + args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + args->push_back(new InterfacePort(&primitive_STRING, PORT_IN)); + args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("file_open"), + perm_string::literal("$ivlh_file_open"), + args, NULL)); + /* std.textio library * procedure file_close (file f: text); */ diff --git a/vpi/vhdl_textio.c b/vpi/vhdl_textio.c index e6a9a8411..c0879cc64 100644 --- a/vpi/vhdl_textio.c +++ b/vpi/vhdl_textio.c @@ -48,6 +48,7 @@ # include # include # include +# include # include "ivl_alloc.h" /* additional parameter values to distinguish between integer, boolean and @@ -55,6 +56,7 @@ enum format_t { FORMAT_STD, FORMAT_BOOL, FORMAT_TIME, FORMAT_HEX, FORMAT_STRING }; enum file_mode_t { FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND, FILE_MODE_LAST }; +enum file_open_status_t { FS_OPEN_OK, FS_STATUS_ERROR, FS_NAME_ERROR, FS_MODE_ERROR }; /* bits per vector, in a single s_vpi_vecval struct */ static const size_t BPW = 8 * sizeof(PLI_INT32); @@ -67,6 +69,11 @@ static int is_integer_var(vpiHandle obj) type == vpiIntVar || type == vpiLongIntVar); } +static int is_const(vpiHandle obj) +{ + return vpi_get(vpiType, obj) == vpiConstant; +} + static void show_error_line(vpiHandle callh) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -281,40 +288,44 @@ static int write_time(char *string, const s_vpi_value* val, static PLI_INT32 ivlh_file_open_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv; + vpiHandle argv, arg; assert(callh != 0); + int ok = 1; argv = vpi_iterate(vpiArgument, callh); /* Check that there is a file name argument and that it is a string. */ - if (argv == 0) { - show_error_line(callh); - vpi_printf("%s requires a string file name argument.\n", name); - vpi_control(vpiFinish, 1); - return 0; - } + if (argv == 0) + ok = 0; - if(!is_integer_var(vpi_scan(argv))) { - show_error_line(callh); - vpi_printf("%s's first argument has to be an integer variable (file handle).\n", name); - vpi_control(vpiFinish, 1); - } + arg = vpi_scan(argv); + if (!arg || !is_integer_var(arg)) + ok = 0; - if(!is_string_obj(vpi_scan(argv))) { - show_error_line(callh); - vpi_printf("%s's second argument argument must be a string (file name).\n", name); - vpi_control(vpiFinish, 1); - } + arg = vpi_scan(argv); + if (arg && is_integer_var(arg)) + arg = vpi_scan(argv); - /* When provided, the type argument must be a string. */ - if(!vpi_scan(argv)) { + // no vpi_scan() here, if we had both 'status' and 'file' arguments, + // then the next arg is read in the above if, otherwise we are going + // to check the second argument once again + if (!arg || !is_string_obj(arg)) + ok = 0; + + arg = vpi_scan(argv); + if (arg && !is_const(arg)) + ok = 0; + + if (!ok) { show_error_line(callh); - vpi_printf("%s's third argument must be an integer (open mode).\n", name); + vpi_printf("%s() function is available in following variants:\n", name); + vpi_printf("* (file f: text; filename: in string, file_open_kind: in mode)\n"); + vpi_printf("* (status: out file_open_status, file f: text; filename: in string, file_open_kind: in mode)\n"); vpi_control(vpiFinish, 1); } /* Make sure there are no extra arguments. */ - check_for_extra_args(argv, callh, name, "three arguments", 1); + check_for_extra_args(argv, callh, name, "four arguments", 1); return 0; } @@ -330,15 +341,25 @@ static PLI_INT32 ivlh_file_open_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) int mode; char *fname; + vpiHandle fstatush = vpi_scan(argv); vpiHandle fhandleh = vpi_scan(argv); vpiHandle fnameh = vpi_scan(argv); vpiHandle modeh = vpi_scan(argv); + if(!modeh) { + /* There are only three arguments, so rearrange handles */ + modeh = fnameh; + fnameh = fhandleh; + fhandleh = fstatush; + fstatush = 0; + } else { + vpi_free_object(argv); + } + /* Get the mode handle */ val.format = vpiIntVal; vpi_get_value(modeh, &val); mode = val.value.integer; - vpi_free_object(argv); if(mode < 0 || mode >= FILE_MODE_LAST) { show_error_line(callh); @@ -355,21 +376,51 @@ static PLI_INT32 ivlh_file_open_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) } /* Open file and save the handle */ + PLI_INT32 result = -1; switch(mode) { case FILE_MODE_READ: - val.value.integer = vpi_fopen(fname, "r"); + result = vpi_fopen(fname, "r"); break; case FILE_MODE_WRITE: - val.value.integer = vpi_fopen(fname, "w"); + result = vpi_fopen(fname, "w"); break; case FILE_MODE_APPEND: - val.value.integer = vpi_fopen(fname, "a"); + result = vpi_fopen(fname, "a"); break; } + if(fstatush) { + val.format = vpiIntVal; + + if(!result) { + switch(errno) { + case ENOENT: + case ENAMETOOLONG: + val.value.integer = FS_NAME_ERROR; + break; + + case EINVAL: + case EACCES: + case EEXIST: + case EISDIR: + val.value.integer = FS_MODE_ERROR; + break; + + default: + val.value.integer = FS_STATUS_ERROR; + break; + } + } else { + val.value.integer = FS_OPEN_OK; + } + + vpi_put_value(fstatush, &val, 0, vpiNoDelay); + } + val.format = vpiIntVal; + val.value.integer = result; vpi_put_value(fhandleh, &val, 0, vpiNoDelay); free(fname); From 5488ea1e2c96c6dcc5a304a05fc964b97c4812bf Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 2 Feb 2016 16:24:02 +0100 Subject: [PATCH 41/76] vhdlpp: Support for ExpNames with multiple indices. --- vhdlpp/debug.cc | 11 ++-- vhdlpp/expression.cc | 113 ++++++++++++++++++++++----------- vhdlpp/expression.h | 17 ++--- vhdlpp/expression_elaborate.cc | 39 +++++++----- vhdlpp/expression_emit.cc | 50 +++++++++------ vhdlpp/expression_stream.cc | 22 ++++--- vhdlpp/parse.y | 50 ++++++++------- 7 files changed, 183 insertions(+), 119 deletions(-) diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 3669fd489..af4fd7a32 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -395,10 +395,13 @@ void ExpName::dump(ostream&out, int indent) const << " at " << get_fileline() << endl; if (prefix_.get()) prefix_->dump(out, indent+8); - if (index_) - index_->dump(out, indent+6); - if (lsb_) - lsb_->dump(out, indent+6); + + if (indices_) { + for(list::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + (*it)->dump(out, indent+6); + } + } } void ExpNameALL::dump(ostream&out, int indent) const diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 811d42457..7bb97642f 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -578,41 +578,54 @@ ExpLogical::~ExpLogical() } ExpName::ExpName(perm_string nn) -: name_(nn), index_(0), lsb_(0) +: name_(nn), indices_(NULL) { } ExpName::ExpName(perm_string nn, list*indices) -: name_(nn), index_(0), lsb_(0) -{ - /* For now, assume a single index. */ - ivl_assert(*this, indices->size() == 1); - - index_ = indices->front(); - indices->pop_front(); -} - -ExpName::ExpName(perm_string nn, Expression*msb, Expression*lsb) -: name_(nn), index_(msb), lsb_(lsb) -{ - ivl_assert(*this, !msb || msb != lsb); -} - -ExpName::ExpName(ExpName*prefix, perm_string nn) -: prefix_(prefix), name_(nn), index_(0), lsb_(0) +: name_(nn), indices_(indices) { } -ExpName::ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb) -: prefix_(prefix), name_(nn), index_(msb), lsb_(lsb) +ExpName::ExpName(ExpName*prefix, perm_string nn, std::list*indices) +: prefix_(prefix), name_(nn), indices_(indices) { - ivl_assert(*this, !msb || msb != lsb); } ExpName::~ExpName() { - delete index_; - delete lsb_; + if(indices_) { + for(list::iterator it = indices_->begin(); + it != indices_->end(); ++it) { + delete *it; + } + + delete indices_; + } +} + +Expression*ExpName::clone() const { + list*new_indices = NULL; + + if(indices_) { + new_indices = new list(); + + for(list::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + new_indices->push_back((*it)->clone()); + } + } + + return new ExpName(static_cast(safe_clone(prefix_.get())), + name_, new_indices); +} + +void ExpName::add_index(std::list*idx) +{ + if(!indices_) + indices_ = new list(); + + indices_->splice(indices_->end(), *idx); } bool ExpName::symbolic_compare(const Expression*that) const @@ -624,25 +637,48 @@ bool ExpName::symbolic_compare(const Expression*that) const if (name_ != that_name->name_) return false; - if (that_name->index_ && !index_) + if (that_name->indices_ && !indices_) return false; - if (index_ && !that_name->index_) + if (indices_ && !that_name->indices_) return false; - if (index_) { - assert(that_name->index_); - return index_->symbolic_compare(that_name->index_); + if (indices_) { + assert(that_name->indices_); + + if(indices_->size() != that_name->indices_->size()) + return false; + + list::const_iterator it, jt; + it = indices_->begin(); + jt = that_name->indices_->begin(); + + for(unsigned int i = 0; i < indices_->size(); ++i) { + if(!(*it)->symbolic_compare(*jt)) + return false; + + ++it; + ++jt; + } } return true; } -void ExpName::set_range(Expression*msb, Expression*lsb) +Expression*ExpName::index(unsigned int number) const { - assert(index_==0); - index_ = msb; - assert(lsb_==0); - lsb_ = lsb; + if(!indices_) + return NULL; + + if(number >= indices_->size()) + return NULL; + + if(number == 0) + return indices_->front(); + + list::const_iterator it = indices_->begin(); + advance(it, number); + + return *it; } void ExpName::visit(ExprVisitor& func) @@ -650,11 +686,12 @@ void ExpName::visit(ExprVisitor& func) if(prefix_.get()) prefix_.get()->visit(func); - if(index_) - index_->visit(func); - - if(lsb_) - lsb_->visit(func); + if(indices_) { + for(list::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + (*it)->visit(func); + } + } func(this); } diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 488c30421..8dc5d1126 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -690,22 +690,18 @@ class ExpName : public Expression { public: explicit ExpName(perm_string nn); ExpName(perm_string nn, std::list*indices); - ExpName(perm_string nn, Expression*msb, Expression*lsb); - ExpName(ExpName*prefix, perm_string nn); - ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb); + ExpName(ExpName*prefix, perm_string nn, std::list*indices = NULL); ~ExpName(); public: // Base methods - Expression*clone() const { - return new ExpName(static_cast(safe_clone(prefix_.get())), - name_, safe_clone(index_), safe_clone(lsb_)); - } + Expression*clone() const; int elaborate_lval(Entity*ent, ScopeBase*scope, bool); int elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*); const VType* probe_type(Entity*ent, ScopeBase*scope) const; const VType* fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*host) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); void write_to_stream(std::ostream&fd) const; + int emit_indices(ostream&out, Entity*ent, ScopeBase*scope) const; int emit(ostream&out, Entity*ent, ScopeBase*scope) const; bool is_primary(void) const; bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; @@ -713,7 +709,7 @@ class ExpName : public Expression { void dump(ostream&out, int indent = 0) const; inline const char* name() const { return name_; } inline const perm_string& peek_name() const { return name_; } - void set_range(Expression*msb, Expression*lsb); + void add_index(std::list*idx); void visit(ExprVisitor& func); private: @@ -760,10 +756,11 @@ class ExpName : public Expression { const list&indices, int field_size) const; private: + Expression*index(unsigned int number) const; + std::auto_ptr prefix_; perm_string name_; - Expression*index_; - Expression*lsb_; + std::list*indices_; }; class ExpNameALL : public ExpName { diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index e1cb258f2..fa6a16841 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -68,24 +68,26 @@ const VType*ExpName::elaborate_adjust_type_with_range_(Entity*ent, ScopeBase*sco } if (const VTypeArray*array = dynamic_cast(type)) { - if (index_ && !lsb_) { - // If the name is an array or a vector, then an - // indexed name has the type of the element. - type = array->element_type(); + Expression*idx = index(0); - } else if (index_ && lsb_) { + if (ExpRange*range = dynamic_cast(idx)) { // If the name is an array, then a part select is // also an array, but with different bounds. int64_t use_msb, use_lsb; bool flag; - flag = index_->evaluate(ent, scope, use_msb); + flag = range->msb()->evaluate(ent, scope, use_msb); ivl_assert(*this, flag); - flag = lsb_->evaluate(ent, scope, use_lsb); + flag = range->lsb()->evaluate(ent, scope, use_lsb); ivl_assert(*this, flag); type = new VTypeArray(array->element_type(), use_msb, use_lsb); } + else if(idx) { + // If the name is an array or a vector, then an + // indexed name has the type of the element. + type = array->element_type(); + } } return type; @@ -99,10 +101,14 @@ int ExpName::elaborate_lval_(Entity*ent, ScopeBase*scope, bool is_sequ, ExpName* debug_log_file << get_fileline() << ": ExpName::elaborate_lval_: " << "name_=" << name_ << ", suffix->name()=" << suffix->name(); - if (index_) - debug_log_file << ", index_=" << *index_; - if (lsb_) - debug_log_file << ", lsb_=" << *lsb_; + if (indices_) { + for(list::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + debug_log_file << "["; + debug_log_file << **it; + debug_log_file << "]"; + } + } debug_log_file << endl; } @@ -1032,11 +1038,12 @@ int ExpName::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) if(prefix_.get()) prefix_.get()->elaborate_expr(ent, scope, NULL); - if(index_) - index_->elaborate_expr(ent, scope, &primitive_INTEGER); - - if(lsb_) - lsb_->elaborate_expr(ent, scope, &primitive_INTEGER); + if (indices_) { + for(list::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + (*it)->elaborate_expr(ent, scope, &primitive_INTEGER); + } + } return 0; } diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 5104e502a..a66ee5e72 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -694,6 +694,22 @@ int ExpLogical::emit(ostream&out, Entity*ent, ScopeBase*scope) const return errors; } +int ExpName::emit_indices(ostream&out, Entity*ent, ScopeBase*scope) const +{ + int errors = 0; + + if (indices_) { + for(list::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + out << "["; + errors += (*it)->emit(out, ent, scope); + out << "]"; + } + } + + return errors; +} + int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) const { int errors = 0; @@ -702,12 +718,7 @@ int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) const } out << "\\" << name_ << " "; - if (index_) { - out << "["; - errors += index_->emit(out, ent, scope); - out << "]"; - ivl_assert(*this, lsb_ == 0); - } + errors += emit_indices(out, ent, scope); out << "."; return errors; } @@ -739,16 +750,7 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) const else out << "\\" << name_ << " "; - if (index_) { - out << "["; - errors += index_->emit(out, ent, scope); - - if (lsb_) { - out << ":"; - errors += lsb_->emit(out, ent, scope); - } - out << "]"; - } + errors += emit_indices(out, ent, scope); return errors; } @@ -759,6 +761,8 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, Expression*exp = NULL; bool wrkand_required = false; const VType*type = NULL; + Expression*idx = index(0); + ExpRange*range = dynamic_cast(idx); if(!scope) return false; @@ -766,7 +770,7 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, if(prefix_.get()) prefix_->try_workarounds_(out, ent, scope, indices, data_size); - if(index_ && !lsb_ && scope->find_constant(name_, type, exp)) { + if(idx && !range && scope->find_constant(name_, type, exp)) { while(const VTypeDef*type_def = dynamic_cast(type)) { type = type_def->peek_definition(); } @@ -778,7 +782,7 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, if(prefix_.get() && scope->find_constant(prefix_->name_, type, exp)) { // Handle the case of array of records - if(prefix_->index_) { + if(prefix_->index(0)) { const VTypeArray*arr = dynamic_cast(type); assert(arr); type = arr->element_type(); @@ -795,17 +799,23 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope, wrkand_required |= check_const_record_workaround_(rec, scope, indices, data_size); } + // Workarounds are currently implemented only for one-dimensional arrays + assert(!indices_ || indices_->size() == 1 || !wrkand_required); + return wrkand_required; } bool ExpName::check_const_array_workaround_(const VTypeArray*arr, ScopeBase*scope, list&indices, int&data_size) const { + assert(indices_ && indices_->size() == 1); + const VType*element = arr->element_type(); data_size = element->get_width(scope); if(data_size < 0) return false; - indices.push_back(new index_t(index_->clone(), new ExpInteger(data_size))); + + indices.push_back(new index_t(index(0)->clone(), new ExpInteger(data_size))); return true; } @@ -830,7 +840,7 @@ bool ExpName::check_const_record_workaround_(const VTypeRecord*rec, data_size = tmp_field; indices.push_back(new index_t(NULL, NULL, new ExpInteger(tmp_offset))); - if(index_) { + if(index(0)) { const VTypeArray*arr = dynamic_cast(type); assert(arr); return check_const_array_workaround_(arr, scope, indices, data_size); diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index d545df69f..43756922a 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -217,14 +217,20 @@ void ExpName::write_to_stream(ostream&fd) const } fd << name_; - if (index_) { - fd << "("; - index_->write_to_stream(fd); - if (lsb_) { - fd << " downto "; - lsb_->write_to_stream(fd); - } - fd << ")"; + + if (indices_) { + fd << "("; + bool first = true; + for(list::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + if(first) + first = false; + else + fd << ","; + + (*it)->write_to_stream(fd); + } + fd << ")"; } } diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 3ce3c0db7..c080be9ff 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -331,7 +331,7 @@ static void touchup_interface_for_functions(std::list*ports) %type expression factor primary relation %type expression_logical expression_logical_and expression_logical_or %type expression_logical_xnor expression_logical_xor -%type name prefix selected_name +%type name prefix selected_name indexed_name %type shift_expression signal_declaration_assign_opt %type simple_expression simple_expression_2 term %type variable_declaration_assign_opt waveform_element interface_element_expression @@ -1715,36 +1715,40 @@ name /* IEEE 1076-2008 P8.1 */ | selected_name { $$ = $1; } + | indexed_name + { $$ = $1; } + + + | selected_name '(' expression_list ')' + { + ExpName*name = dynamic_cast($1); + assert(name); + name->add_index($3); + delete $3; // contents of the list is moved to the selected_name + } + ; + +indexed_name /* Note that this rule can match array element selects and various function calls. The only way we can tell the difference is from left context, namely whether the name is a type name or function name. If none of the above, treat it as a array element select. */ - | IDENTIFIER argument_list + : IDENTIFIER '(' expression_list ')' { Expression*tmp; perm_string name = lex_strings.make($1); - delete[]$1; - if (active_scope->is_vector_name(name) || is_subprogram_param(name)) - tmp = new ExpName(name, $2); - else - tmp = new ExpFunc(name, $2); - FILE_NAME(tmp, @1); + delete[]$1; + if (active_scope->is_vector_name(name) || is_subprogram_param(name)) + tmp = new ExpName(name, $3); + else + tmp = new ExpFunc(name, $3); + FILE_NAME(tmp, @1); $$ = tmp; } - | IDENTIFIER '(' range ')' - { ExpName*tmp = new ExpName(lex_strings.make($1), $3->msb(), $3->lsb()); - FILE_NAME(tmp, @1); - delete[]$1; - $$ = tmp; - } - | selected_name '(' range ')' - { ExpName*tmp = dynamic_cast ($1); - tmp->set_range($3->msb(), $3->lsb()); - $$ = tmp; - } - | selected_name '(' expression ')' - { ExpName*tmp = dynamic_cast ($1); - tmp->set_range($3, NULL); - $$ = tmp; + | indexed_name '(' expression_list ')' + { ExpName*name = dynamic_cast($1); + assert(name); + name->add_index($3); + $$ = $1; } ; From f584b4ea50ce49ffabfda3c1d4c988a66956e9dd Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 2 Feb 2016 16:24:24 +0100 Subject: [PATCH 42/76] vhdlpp: Treat range as an expression. --- vhdlpp/parse.y | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index c080be9ff..d3f9baa21 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -1149,6 +1149,8 @@ expression_list expression : expression_logical { $$ = $1; } + | range + { $$ = $1; } ; /* From 78bd9a389d7f35b383ad6a68484a31dd09a0ce6a Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 2 Feb 2016 17:06:43 +0100 Subject: [PATCH 43/76] vhdlpp: Handle multidimensional arrays based on typedefs. --- vhdlpp/vtype_emit.cc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index c33c68304..15bae48e3 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -98,9 +98,21 @@ int VTypeArray::emit_with_dims_(std::ostream&out, bool packed, perm_string name) list dims; const VTypeArray*cur = this; - while (const VTypeArray*sub = dynamic_cast (cur->element_type())) { - dims.push_back(cur); - cur = sub; + bool added_dim = true; + + while(added_dim) { + added_dim = false; + const VType*el_type = cur->element_type(); + + while(const VTypeDef*tdef = dynamic_cast(el_type)) { + el_type = tdef->peek_definition(); + } + + if(const VTypeArray*sub = dynamic_cast(el_type)) { + dims.push_back(cur); + cur = sub; + added_dim = true; + } } dims.push_back(cur); From bba312fee1b1d0cfa992c87e0cccf0c55a8dffb7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 3 Feb 2016 17:37:01 +0100 Subject: [PATCH 44/76] vhdlpp: Minor code formatting. --- vhdlpp/vtype_emit.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index 15bae48e3..d657c1735 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -134,9 +134,9 @@ int VTypeArray::emit_with_dims_(std::ostream&out, bool packed, perm_string name) } out << "["; - if (!cur->dimension(i).is_box()) { // if not unbounded { + if (!cur->dimension(i).is_box()) { // if not unbounded errors += cur->dimension(i).msb()->emit(out, 0, 0); - out << ":"; + out << ":"; errors += cur->dimension(i).lsb()->emit(out, 0, 0); } out << "]"; From d20549b27a9645519ed86d573b934e5e70094ffb Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 3 Feb 2016 17:37:15 +0100 Subject: [PATCH 45/76] vhdlpp: Fixed a crash in case of dynamic_cast failure. --- vhdlpp/architec_elaborate.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index e35209f33..87294ebfb 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -258,6 +258,8 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*) return -1; const ExpCharacter*op2b = dynamic_cast(op2b_raw); + if (op2b == 0) + return -1; if (op2b->value() != '1' && op2b->value() != '0') return -1; From f88b48c7dab37a4b0f65f447af53af037f78f9bf Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 10 Feb 2016 15:43:29 +0100 Subject: [PATCH 46/76] vhdlpp: Do not emit explicit 'reg' for user-defined types. --- vhdlpp/vtype_emit.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index d657c1735..53fb612bb 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -245,8 +245,8 @@ int VTypeDef::emit_decl(ostream&out, perm_string name, bool reg_flag) const { int errors = 0; - if (!dynamic_cast(type_)) - out << (reg_flag ? "reg " : "wire "); + if(!reg_flag) + out << "wire "; if(dynamic_cast(type_)) { errors += type_->emit_def(out, name); From f802c782b8dee13b5141d92d8350d35e0a803c9d Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 10 Feb 2016 15:59:06 +0100 Subject: [PATCH 47/76] vhdlpp: Elaborate wait statement argument as time type. --- vhdlpp/sequential_elaborate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 93d185bfd..84a48f55b 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -265,7 +265,7 @@ int AssertStmt::elaborate(Entity*ent, ScopeBase*scope) int WaitForStmt::elaborate(Entity*ent, ScopeBase*scope) { - return delay_->elaborate_expr(ent, scope, 0); + return delay_->elaborate_expr(ent, scope, &primitive_TIME); } int WaitStmt::elaborate(Entity*ent, ScopeBase*scope) From 1647e192e5a9726d21d944fa38d08408befb28f0 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 11 Feb 2016 13:41:38 +0100 Subject: [PATCH 48/76] vhdlpp: Added ExpDelay::visit() method. --- vhdlpp/expression.cc | 8 ++++++++ vhdlpp/expression.h | 1 + 2 files changed, 9 insertions(+) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 7bb97642f..b8c1113d4 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -894,3 +894,11 @@ ExpDelay::~ExpDelay() delete expr_; delete delay_; } + +void ExpDelay::visit(ExprVisitor& func) +{ + expr_->visit(func); + delay_->visit(func); + + func(this); +} diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 8dc5d1126..b09b5fdd2 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -992,6 +992,7 @@ public: void write_to_stream(std::ostream&) const; int emit(ostream&out, Entity*ent, ScopeBase*scope) const; void dump(ostream&out, int indent = 0) const; + void visit(ExprVisitor& func); const Expression*peek_expr() const { return expr_; } const Expression*peek_delay() const { return delay_; } From 996201a745e16303187f1ec8f5104093364257cd Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 11 Feb 2016 15:23:41 +0100 Subject: [PATCH 49/76] vhdlpp: Time type can be packed. --- vhdlpp/std_types.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vhdlpp/std_types.cc b/vhdlpp/std_types.cc index e3990d10c..51f6eaa2d 100644 --- a/vhdlpp/std_types.cc +++ b/vhdlpp/std_types.cc @@ -30,7 +30,7 @@ const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER); const VTypePrimitive primitive_NATURAL(VTypePrimitive::NATURAL); const VTypePrimitive primitive_REAL(VTypePrimitive::REAL); const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true); -const VTypePrimitive primitive_TIME(VTypePrimitive::TIME); +const VTypePrimitive primitive_TIME(VTypePrimitive::TIME, true); VTypeDef type_BOOLEAN(perm_string::literal("boolean")); VTypeDef type_FILE_OPEN_KIND(perm_string::literal("file_open_kind")); From 5f1cd624fe4f097c58b4a8764a851ad9f0230707 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 11 Feb 2016 15:23:52 +0100 Subject: [PATCH 50/76] vhdlpp: Set reg flag only for arrays of unpacked types. --- vhdlpp/vsignal.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vhdlpp/vsignal.cc b/vhdlpp/vsignal.cc index e39142f6b..0b2d2323c 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -54,7 +54,10 @@ int Signal::emit(ostream&out, Entity*ent, ScopeBase*scope) VType::decl_t decl; type_elaborate_(decl); - if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed()) + + const VType*type = peek_type(); + if (peek_refcnt_sequ_() > 0 + || (!type->can_be_packed() && dynamic_cast(type))) decl.reg_flag = true; errors += decl.emit(out, peek_name()); From 248275e5e11e9e753aef0445b48c6282e0bc8576 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 11 Feb 2016 15:47:06 +0100 Subject: [PATCH 51/76] vhdlpp: Refactored VType::emit_decl(). --- vhdlpp/vtype.h | 6 +----- vhdlpp/vtype_emit.cc | 19 +++---------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 3b9356e60..a4bdf9baf 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -109,8 +109,6 @@ class VType { // to evaluate. virtual int get_width(ScopeBase*) const { return -1; } - private: - friend struct decl_t; // This virtual method is called to emit the declaration. This // is used by the decl_t object to emit variable/wire/port declarations. virtual int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; @@ -411,6 +409,7 @@ class VTypeDef : public VType { int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; int emit_def(std::ostream&out, perm_string name) const; + int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; bool can_be_packed() const { return type_->can_be_packed(); } @@ -419,9 +418,6 @@ class VTypeDef : public VType { protected: perm_string name_; const VType*type_; - - private: - int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; }; class VSubTypeDef : public VTypeDef { diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index 53fb612bb..48ffd50d7 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -235,28 +235,15 @@ int VTypeRecord::emit_def(ostream&out, perm_string name) const */ int VTypeDef::emit_def(ostream&out, perm_string name) const { - int errors = 0; emit_name(out, name_); emit_name(out, name); - return errors; + + return 0; } int VTypeDef::emit_decl(ostream&out, perm_string name, bool reg_flag) const { - int errors = 0; - - if(!reg_flag) - out << "wire "; - - if(dynamic_cast(type_)) { - errors += type_->emit_def(out, name); - } else { - assert(name_ != empty_perm_string); - cout << "\\" << name_; - emit_name(out, name); - } - - return errors; + return type_->emit_decl(out, name, reg_flag); } int VTypeDef::emit_typedef(ostream&out, typedef_context_t&ctx) const From a40d1a65c48ed71d8aad20ce6293a2d4de521f09 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 11 Feb 2016 15:47:26 +0100 Subject: [PATCH 52/76] vhdlpp: Emit enum type as int. --- vhdlpp/vtype.h | 1 + vhdlpp/vtype_emit.cc | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index a4bdf9baf..fc1d52c0e 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -334,6 +334,7 @@ class VTypeEnum : public VType { int get_width(ScopeBase*) const { return 32; } int emit_def(std::ostream&out, perm_string name) const; + int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; // Checks if the name is stored in the enum. bool has_name(perm_string name) const; diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index 48ffd50d7..8327af50c 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -153,7 +153,7 @@ int VTypeArray::emit_with_dims_(std::ostream&out, bool packed, perm_string name) int VTypeEnum::emit_def(ostream&out, perm_string name) const { int errors = 0; - out << "enum integer {"; + out << "enum int {"; assert(names_.size() >= 1); out << "\\" << names_[0] << " "; for (size_t idx = 1 ; idx < names_.size() ; idx += 1) @@ -165,6 +165,17 @@ int VTypeEnum::emit_def(ostream&out, perm_string name) const return errors; } +int VTypeEnum::emit_decl(std::ostream&out, perm_string name, bool reg_flag) const +{ + if (!reg_flag) + out << "wire "; + + out << "int"; + emit_name(out, name); + + return 0; +} + int VTypePrimitive::emit_primitive_type(ostream&out) const { int errors = 0; From 69b7c000d0df9e60642bd8a4523e22355fdb7270 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 11 Feb 2016 17:46:41 +0100 Subject: [PATCH 53/76] vvp: Implemented vvp_net_fun_t::recv_vec4_pv(). --- vvp/vvp_net.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index bf8edffff..79034e215 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -3249,14 +3249,11 @@ void vvp_net_fun_t::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&, assert(0); } -void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t, const vvp_vector4_t&bit, +void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, unsigned base, unsigned wid, unsigned vwid, - vvp_context_t) + vvp_context_t ctx) { - cerr << "internal error: " << typeid(*this).name() << ": " - << "recv_vec4_pv(" << bit << ", " << base - << ", " << wid << ", " << vwid << ") not implemented" << endl; - assert(0); + ptr.ptr()->send_vec4_pv(bit, base, wid, vwid, ctx); } void vvp_net_fun_t::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) From 045d9e7117b0df2ba5dd0683f0d6c7ff10972ba6 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 12 Feb 2016 15:17:03 +0100 Subject: [PATCH 54/76] vhdlpp: Improved type matching rules. --- vhdlpp/expression_elaborate.cc | 4 +++- vhdlpp/vtype.h | 3 +++ vhdlpp/vtype_match.cc | 7 +++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index fa6a16841..e11a5e328 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -350,8 +350,10 @@ const VType* ExpBinary::probe_type(Entity*ent, ScopeBase*scope) const if (t2 == 0) return t1; - if (t1 == t2) + if (t1->type_match(t2)) return t1; + if (t2->type_match(t1)) + return t2; if (const VType*tb = resolve_operand_types_(t1, t2)) return tb; diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index fc1d52c0e..89b794a13 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -295,6 +295,9 @@ class VTypeRangeConst : public VTypeRange { return new VTypeRangeConst(base_type()->clone(), start_, end_); } + int64_t start() const { return start_; } + int64_t end() const { return end_; } + void write_to_stream(std::ostream&fd) const; private: diff --git a/vhdlpp/vtype_match.cc b/vhdlpp/vtype_match.cc index 459217879..3ceb4b231 100644 --- a/vhdlpp/vtype_match.cc +++ b/vhdlpp/vtype_match.cc @@ -53,6 +53,13 @@ bool VTypePrimitive::type_match(const VType*that) const (that_type == NATURAL || that_type == INTEGER)); } + if(const VTypeRangeConst*range = dynamic_cast(that)) { + if (type_ == INTEGER) + return true; + if (type_ == NATURAL && range->start() >= 0 && range->end() >= 0) + return true; + } + return false; } From b4baace4b1bb89dbf16e31445b5c0b0d2cbdc1c3 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 15 Feb 2016 15:12:40 +0100 Subject: [PATCH 55/76] ivl: Support for part selection in multidimensional packed ports assignment. --- elab_net.cc | 87 +++++++++++++++++++++++++++++++++++------------------ netmisc.cc | 2 +- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/elab_net.cc b/elab_net.cc index 09a38f454..55bdbce9c 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -328,39 +328,66 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, return false; } - long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb); - long midx_tmp = sig->sb_to_idx(prefix_indices, msb); - /* Detect reversed indices of a part select. */ - if (lidx_tmp > midx_tmp) { - cerr << get_fileline() << ": error: Part select " - << sig->name() << "[" << msb << ":" - << lsb << "] indices reversed." << endl; - cerr << get_fileline() << ": : Did you mean " - << sig->name() << "[" << lsb << ":" - << msb << "]?" << endl; - long tmp = midx_tmp; - midx_tmp = lidx_tmp; - lidx_tmp = tmp; - des->errors += 1; - } + if (prefix_indices.size()+1 < sig->packed_dims().size()) { + // Here we have a slice that doesn't have enough indices + // to get to a single slice. For example: + // wire [9:0][5:1] foo + // ... foo[4:3] ... + // Make this work by finding the indexed slices and + // creating a generated slice that spans the whole + // range. + long loff, moff; + unsigned long lwid, mwid; + bool lrc; + lrc = sig->sb_to_slice(prefix_indices, lsb, loff, lwid); + ivl_assert(*this, lrc); + lrc = sig->sb_to_slice(prefix_indices, msb, moff, mwid); + ivl_assert(*this, lrc); + ivl_assert(*this, lwid == mwid); - /* Warn about a part select that is out of range. */ - if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) { - cerr << get_fileline() << ": warning: Part select " - << sig->name(); - if (sig->unpacked_dimensions() > 0) { - cerr << "[]"; + if (moff > loff) { + lidx = loff; + midx = moff + mwid - 1; + } else { + lidx = moff; + midx = loff + lwid - 1; } - cerr << "[" << msb << ":" << lsb - << "] is out of range." << endl; - } - /* This is completely out side the signal so just skip it. */ - if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) { - return false; - } + } else { + long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb); + long midx_tmp = sig->sb_to_idx(prefix_indices, msb); - midx = midx_tmp; - lidx = lidx_tmp; + /* Detect reversed indices of a part select. */ + if (lidx_tmp > midx_tmp) { + cerr << get_fileline() << ": error: Part select " + << sig->name() << "[" << msb << ":" + << lsb << "] indices reversed." << endl; + cerr << get_fileline() << ": : Did you mean " + << sig->name() << "[" << lsb << ":" + << msb << "]?" << endl; + long tmp = midx_tmp; + midx_tmp = lidx_tmp; + lidx_tmp = tmp; + des->errors += 1; + } + + /* Warn about a part select that is out of range. */ + if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) { + cerr << get_fileline() << ": warning: Part select " + << sig->name(); + if (sig->unpacked_dimensions() > 0) { + cerr << "[]"; + } + cerr << "[" << msb << ":" << lsb + << "] is out of range." << endl; + } + /* This is completely out side the signal so just skip it. */ + if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) { + return false; + } + + midx = midx_tmp; + lidx = lidx_tmp; + } break; } diff --git a/netmisc.cc b/netmisc.cc index 2ced04acb..81ad82488 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1412,7 +1412,7 @@ bool evaluate_index_prefix(Design*des, NetScope*scope, return false; } - prefix_indices .push_back(tmp); + prefix_indices.push_back(tmp); delete texpr; } From f62072755533d1410c224983725a4439b04cbf76 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 15 Feb 2016 16:53:49 +0100 Subject: [PATCH 56/76] vhdlpp: Added a few missing FILE_NAME directives in the parser. --- vhdlpp/parse.y | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index d3f9baa21..31aa8fe5f 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -760,9 +760,11 @@ composite_type_definition | K_array '(' index_subtype_definition_list ')' K_of subtype_indication { std::list r; // NULL boundaries indicate unbounded array type - r.push_back(new ExpRange(NULL, NULL, ExpRange::DOWNTO)); - VTypeArray*tmp = new VTypeArray($6, &r); - $$ = tmp; + ExpRange*tmp = new ExpRange(NULL, NULL, ExpRange::DOWNTO); + r.push_back(tmp); + FILE_NAME(tmp, @1); + VTypeArray*arr = new VTypeArray($6, &r); + $$ = arr; } | record_type_definition @@ -1317,6 +1319,7 @@ file_open_information { ExpName*mode = new ExpName(lex_strings.make($2)); delete[]$2; + FILE_NAME(mode, @1); $$ = new file_open_info_t(new ExpString($4), mode); } | K_is STRING_LITERAL @@ -1720,7 +1723,6 @@ name /* IEEE 1076-2008 P8.1 */ | indexed_name { $$ = $1; } - | selected_name '(' expression_list ')' { ExpName*name = dynamic_cast($1); @@ -1924,7 +1926,7 @@ primary | name '\'' IDENTIFIER argument_list_opt { ExpAttribute*tmp = NULL; perm_string attr = lex_strings.make($3); - ExpName*base = dynamic_cast($1); + ExpName*base = dynamic_cast($1); const VType*type = parse_type_by_name(base->peek_name()); if(type) { @@ -1933,7 +1935,7 @@ primary tmp = new ExpObjAttribute(base, attr, $4); } - FILE_NAME(tmp, @3); + FILE_NAME(tmp, @1); delete[]$3; $$ = tmp; } @@ -1950,8 +1952,8 @@ primary } | REAL_LITERAL { ExpReal*tmp = new ExpReal($1); - FILE_NAME(tmp, @1); - $$ = tmp; + FILE_NAME(tmp, @1); + $$ = tmp; } | STRING_LITERAL { ExpString*tmp = new ExpString($1); @@ -2153,6 +2155,7 @@ process_sensitivity_list range : simple_expression direction simple_expression { ExpRange* tmp = new ExpRange($1, $3, $2); + FILE_NAME(tmp, @1); $$ = tmp; } | name '\'' K_range @@ -2161,6 +2164,7 @@ range ExpName*name = NULL; if((name = dynamic_cast($1))) { tmp = new ExpRange(name, false); + FILE_NAME(tmp, @1); } else { errormsg(@1, "'range attribute can be used with named expressions only"); } @@ -2172,6 +2176,7 @@ range ExpName*name = NULL; if((name = dynamic_cast($1))) { tmp = new ExpRange(name, true); + FILE_NAME(tmp, @1); } else { errormsg(@1, "'reverse_range attribute can be used with named expressions only"); } @@ -2515,6 +2520,7 @@ simple_expression_2 tmp = new ExpArithmetic(item.op, tmp, item.term); } delete lst; + FILE_NAME(tmp, @1); $$ = tmp; } ; @@ -2897,7 +2903,9 @@ waveform_element : expression { $$ = $1; } | expression K_after expression - { $$ = new ExpDelay($1, $3); } + { ExpDelay*tmp = new ExpDelay($1, $3); + FILE_NAME(tmp, @1); + $$ = tmp; } | K_null { $$ = 0; } ; From c23f970a5f60d943f2bbc4ea493c407a17e84c17 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 15 Feb 2016 16:54:06 +0100 Subject: [PATCH 57/76] vhdlpp: Do not display an error message when probing type without a context. --- vhdlpp/expression_elaborate.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index e11a5e328..7888f162a 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -1020,8 +1020,14 @@ const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const } } - cerr << get_fileline() << ": error: Signal/variable " << name_ - << " not found in this context." << endl; + if(ent || scope) { + // Do not display error messages if there was no entity or scope + // specified. There are functions that are called without any specific + // context and they still may want to probe the expression type. + cerr << get_fileline() << ": error: Signal/variable " << name_ + << " not found in this context." << endl; + } + return 0; } From 9cf1dcbae205dc251b1fbd11acc5eb8f38550f21 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 24 Feb 2016 16:34:18 +0100 Subject: [PATCH 58/76] vvp: Corrected vvp_net_fun_t::recv_vec4_pv() (commit de968e18) --- vvp/part.cc | 9 +++++++++ vvp/part.h | 4 ++++ vvp/vvp_net.cc | 9 ++++++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/vvp/part.cc b/vvp/part.cc index 930e51868..d9ec018b3 100644 --- a/vvp/part.cc +++ b/vvp/part.cc @@ -208,6 +208,15 @@ void vvp_fun_part_pv::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, port.ptr()->send_vec4_pv(bit, base_, wid_, vwid_, context); } +void vvp_fun_part_pv::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t ctx) +{ + assert(port.port() == 0); + + port.ptr()->send_vec4_pv(bit, base, wid, vwid, ctx); +} + void vvp_fun_part_pv::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) { assert(port.port() == 0); diff --git a/vvp/part.h b/vvp/part.h index 445cc24f5..c0459ee2d 100644 --- a/vvp/part.h +++ b/vvp/part.h @@ -109,6 +109,10 @@ class vvp_fun_part_pv : public vvp_net_fun_t { void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t context); + void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, + unsigned, unsigned, unsigned, + vvp_context_t); + void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit); private: diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 79034e215..bf8edffff 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -3249,11 +3249,14 @@ void vvp_net_fun_t::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&, assert(0); } -void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, +void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t, const vvp_vector4_t&bit, unsigned base, unsigned wid, unsigned vwid, - vvp_context_t ctx) + vvp_context_t) { - ptr.ptr()->send_vec4_pv(bit, base, wid, vwid, ctx); + cerr << "internal error: " << typeid(*this).name() << ": " + << "recv_vec4_pv(" << bit << ", " << base + << ", " << wid << ", " << vwid << ") not implemented" << endl; + assert(0); } void vvp_net_fun_t::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) From a7f4d65aaaaad13017b766830ae9004a15a2e83a Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 16 Feb 2016 11:48:22 +0100 Subject: [PATCH 59/76] vhdlpp: More robust report messages display. --- vhdlpp/sequential_emit.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index c0d7b67f1..8d63b901f 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -498,7 +498,7 @@ void BasicLoopStatement::write_to_stream(std::ostream&fd) int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) { - out << "$display(\"** "; + out << "$display(\"%s\", {\"** "; switch(severity_) { @@ -512,7 +512,7 @@ int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) out << ": \","; msg_->emit(out, ent, scope); - out << ",\" (" << get_fileline() << ")\");"; + out << ",\" (" << get_fileline() << ")\"});"; if(severity_ == FAILURE) out << "$finish();"; From 83330c22fbf8f207a76cd0fd4871851c857f1000 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 17 Feb 2016 13:47:50 +0100 Subject: [PATCH 60/76] vhdlpp: Refactored code for format matching in read/write() sys functions. --- vhdlpp/std_funcs.cc | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index 9129124e5..fa417904e 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -116,21 +116,31 @@ class SubprogramReadWrite : public SubprogramBuiltin { } const VType*arg_type = argv[1]->probe_type(ent, scope); - const VTypeArray*arr = dynamic_cast(arg_type); - const VTypePrimitive*prim = dynamic_cast(arg_type); + + while(const VTypeDef*tdef = dynamic_cast(arg_type)) + arg_type = tdef->peek_definition(); // Pick the right format - if(hex_format_) + if(hex_format_) { out << FORMAT_HEX; - else if(prim && prim->type() == VTypePrimitive::TIME) - out << FORMAT_TIME; - else if(arg_type && arg_type->type_match(&type_BOOLEAN)) - out << FORMAT_BOOL; - else if((arg_type && arg_type->type_match(&primitive_CHARACTER)) || - (arr && arr->element_type() == &primitive_CHARACTER)) - out << FORMAT_STRING; - else + } else if(arg_type) { + if(arg_type->type_match(&primitive_TIME)) { + out << FORMAT_TIME; + } else if(arg_type->type_match(&type_BOOLEAN)) { + out << FORMAT_BOOL; + } else if(arg_type->type_match(&primitive_CHARACTER)) { + out << FORMAT_STRING; + } else { + const VTypeArray*arr = dynamic_cast(arg_type); + + if(arr && arr->element_type() == &primitive_CHARACTER) + out << FORMAT_STRING; + else + out << FORMAT_STD; + } + } else { out << FORMAT_STD; + } return errors; } From 1ed4603a18571f99501798b1ddb428e89abc084c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 17 Feb 2016 13:55:19 +0100 Subject: [PATCH 61/76] vhdlpp: Set EOF flag right after reaching the end of file. --- vpi/vhdl_textio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vpi/vhdl_textio.c b/vpi/vhdl_textio.c index c0879cc64..cff0845b5 100644 --- a/vpi/vhdl_textio.c +++ b/vpi/vhdl_textio.c @@ -522,6 +522,11 @@ static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) vpi_put_value(stringh, &val, 0, vpiNoDelay); free(text); + /* Set end-of-file flag if we have just reached the end of the file. + * Otherwise the flag would be set only after the next read operation. */ + int c = fgetc(fp); + ungetc(c, fp); + return 0; } From fca2fff24e8ca3fac4005c53639a78e858d7d1fb Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 17 Feb 2016 13:56:25 +0100 Subject: [PATCH 62/76] vhdlpp: VTypeRange::type_match() --- vhdlpp/vtype.h | 1 + vhdlpp/vtype_match.cc | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 89b794a13..7c5ec3aac 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -278,6 +278,7 @@ class VTypeRange : public VType { bool write_std_types(std::ostream&fd) const; int emit_def(std::ostream&out, perm_string name) const; + bool type_match(const VType*that) const; // Get the type that is limited by the range. inline const VType*base_type() const { return base_; } diff --git a/vhdlpp/vtype_match.cc b/vhdlpp/vtype_match.cc index 3ceb4b231..a4a49b1b5 100644 --- a/vhdlpp/vtype_match.cc +++ b/vhdlpp/vtype_match.cc @@ -85,3 +85,14 @@ bool VTypeArray::type_match(const VType*that) const return false; } + +bool VTypeRange::type_match(const VType*that) const +{ + if(VType::type_match(that)) + return true; + + if(base_->type_match(that)) + return true; + + return false; +} From cef45ff21a780a420494d512d7be7993f8b7500f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 17 Feb 2016 13:57:58 +0100 Subject: [PATCH 63/76] vhdlpp: Emit init values for wires as a weak assignment. --- vhdlpp/vsignal.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vhdlpp/vsignal.cc b/vhdlpp/vsignal.cc index 0b2d2323c..82c5f0760 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -63,8 +63,12 @@ int Signal::emit(ostream&out, Entity*ent, ScopeBase*scope) Expression*init_expr = peek_init_expr(); if (init_expr) { - out << " = "; - init_expr->emit(out, ent, scope); + /* Emit initialization value for wires as a weak assignment */ + if(!decl.reg_flag) + out << ";" << endl << "/*init*/ assign (weak1, weak0) " << peek_name(); + + out << " = "; + init_expr->emit(out, ent, scope); } out << ";" << endl; return errors; From e4bc404e99956b40a532fe8826da41ac2432ccda Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 17 Feb 2016 16:19:33 +0100 Subject: [PATCH 64/76] vhdlpp: ExprVisitor stores the recursion level. --- vhdlpp/expression.cc | 91 ++++++++++++++++++++++++++++++-------------- vhdlpp/expression.h | 21 +++++++++- 2 files changed, 81 insertions(+), 31 deletions(-) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index b8c1113d4..0bf306a2f 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -87,6 +87,9 @@ list*ExpAttribute::clone_args() const { void ExpAttribute::visit_args(ExprVisitor& func) { + func.down(); + func(this); + if(args_) { for(list::iterator it = args_->begin(); it != args_->end(); ++it) { @@ -94,7 +97,7 @@ void ExpAttribute::visit_args(ExprVisitor& func) } } - func(this); + func.up(); } ExpObjAttribute::ExpObjAttribute(ExpName*base, perm_string name, list*args) @@ -113,11 +116,13 @@ Expression*ExpObjAttribute::clone() const name_, clone_args()); } -void ExpObjAttribute::visit(ExprVisitor& func) +void ExpObjAttribute::visit(ExprVisitor&func) { + func.down(); + func(this); visit_args(func); base_->visit(func); - func(this); + func.up(); } ExpTypeAttribute::ExpTypeAttribute(const VType*base, perm_string name, list*args) @@ -130,10 +135,12 @@ Expression*ExpTypeAttribute::clone() const return new ExpTypeAttribute(base_, name_, clone_args()); } -void ExpTypeAttribute::visit(ExprVisitor& func) +void ExpTypeAttribute::visit(ExprVisitor&func) { - visit_args(func); + func.down(); func(this); + visit_args(func); + func.up(); } const perm_string ExpAttribute::LEFT = perm_string::literal("left"); @@ -160,11 +167,13 @@ bool ExpBinary::eval_operand2(Entity*ent, ScopeBase*scope, int64_t&val) const return operand2_->evaluate(ent, scope, val); } -void ExpBinary::visit(ExprVisitor& func) +void ExpBinary::visit(ExprVisitor&func) { + func.down(); + func(this); operand1_->visit(func); operand2_->visit(func); - func(this); + func.up(); } ExpUnary::ExpUnary(Expression*op1) @@ -177,10 +186,12 @@ ExpUnary::~ExpUnary() delete operand1_; } -void ExpUnary::visit(ExprVisitor& func) +void ExpUnary::visit(ExprVisitor&func) { - operand1_->visit(func); + func.down(); func(this); + operand1_->visit(func); + func.up(); } ExpAggregate::ExpAggregate(std::list*el) @@ -227,8 +238,11 @@ Expression* ExpAggregate::clone() const return new ExpAggregate(new_elements); } -void ExpAggregate::visit(ExprVisitor& func) +void ExpAggregate::visit(ExprVisitor&func) { + func.down(); + func(this); + for(std::vector::iterator it = elements_.begin(); it != elements_.end(); ++it) { (*it)->extract_expression()->visit(func); @@ -242,7 +256,7 @@ void ExpAggregate::visit(ExprVisitor& func) it->expr->visit(func); } - func(this); + func.up(); } ExpAggregate::choice_t::choice_t(Expression*exp) @@ -366,11 +380,13 @@ ExpConcat::~ExpConcat() delete operand2_; } -void ExpConcat::visit(ExprVisitor& func) +void ExpConcat::visit(ExprVisitor&func) { - operand1_->visit(func); - operand2_->visit(func); - func(this); + func.down(); + func(this); + operand1_->visit(func); + operand2_->visit(func); + func.up(); } ExpConditional::ExpConditional(Expression*co, list*tru, @@ -404,13 +420,16 @@ Expression*ExpConditional::clone() const return new ExpConditional(NULL, NULL, new_options); } -void ExpConditional::visit(ExprVisitor& func) +void ExpConditional::visit(ExprVisitor&func) { + func.down(); + func(this); + for(std::list::iterator it = options_.begin(); it != options_.end(); ++it) (*it)->visit(func); - func(this); + func.up(); } ExpConditional::case_t::case_t(Expression*cond, std::list*tru) @@ -472,14 +491,16 @@ Expression*ExpSelected::clone() const return new ExpSelected(selector_->clone(), new_options); } -void ExpConditional::case_t::visit(ExprVisitor& func) +void ExpConditional::case_t::visit(ExprVisitor&func) { + func.down(); if(cond_) cond_->visit(func); for(std::list::iterator it = true_clause_.begin(); it != true_clause_.end(); ++it) (*it)->visit(func); + func.up(); } ExpEdge::ExpEdge(ExpEdge::fun_t typ, Expression*op) @@ -529,14 +550,18 @@ Expression*ExpFunc::clone() const { return f; } -void ExpFunc::visit(ExprVisitor& func) { +void ExpFunc::visit(ExprVisitor&func) +{ + func.down(); + func(this); + if(!argv_.empty()) { for(std::vector::iterator it = argv_.begin(); it != argv_.end(); ++it) (*it)->visit(func); } - func(this); + func.up(); } const VType* ExpFunc::func_ret_type() const @@ -681,8 +706,11 @@ Expression*ExpName::index(unsigned int number) const return *it; } -void ExpName::visit(ExprVisitor& func) +void ExpName::visit(ExprVisitor&func) { + func.down(); + func(this); + if(prefix_.get()) prefix_.get()->visit(func); @@ -693,7 +721,7 @@ void ExpName::visit(ExprVisitor& func) } } - func(this); + func.up(); } int ExpName::index_t::emit(ostream&out, Entity*ent, ScopeBase*scope) const @@ -768,10 +796,12 @@ ExpCast::~ExpCast() { } -void ExpCast::visit(ExprVisitor& func) +void ExpCast::visit(ExprVisitor&func) { - base_->visit(func); + func.down(); func(this); + base_->visit(func); + func.up(); } ExpNew::ExpNew(Expression*size) : @@ -784,10 +814,12 @@ ExpNew::~ExpNew() delete size_; } -void ExpNew::visit(ExprVisitor& func) +void ExpNew::visit(ExprVisitor&func) { - size_->visit(func); + func.down(); func(this); + size_->visit(func); + func.up(); } ExpTime::ExpTime(uint64_t amount, timeunit_t unit) @@ -895,10 +927,11 @@ ExpDelay::~ExpDelay() delete delay_; } -void ExpDelay::visit(ExprVisitor& func) +void ExpDelay::visit(ExprVisitor&func) { + func.down(); + func(this); expr_->visit(func); delay_->visit(func); - - func(this); + func.up(); } diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index b09b5fdd2..c513c7f89 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -29,6 +29,7 @@ # include # include # include +# include class ExpRange; class ScopeBase; @@ -38,9 +39,25 @@ class VTypeArray; class VTypePrimitive; class ExpName; +/* + * Helper class to recursively traverse an expression tree + * (i.e. complex expressions). + */ struct ExprVisitor { - virtual ~ExprVisitor() {}; + ExprVisitor() : level_(0) {} + virtual ~ExprVisitor() {} virtual void operator() (Expression*s) = 0; + + // Methods to manage recursion depth. Every Expression::visit() method + // should call down() in the beginning and up() in the end. + inline void down() { ++level_; } + inline void up() { --level_; assert(level_ >= 0); } + +protected: + int level() const { return level_; } + +private: + int level_; }; /* @@ -126,7 +143,7 @@ class Expression : public LineInfo { virtual ostream& dump_inline(ostream&out) const; // Recursively visits a tree of expressions (useful for complex expressions). - virtual void visit(ExprVisitor& func) { func(this); } + virtual void visit(ExprVisitor& func) { func.down(); func(this); func.up(); } protected: // This function is called by the derived class during From 7cbb275ffefc7d9c4582d325f530192f130031b0 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 17 Feb 2016 16:20:03 +0100 Subject: [PATCH 65/76] vhdlpp: Handle limited-length strings in reports. Currently limited-length strings (e.g. string(1 to 4)) are emulated using 2D array of bits (e.g. bit [1:4][7:0]). Because of that, ivl treats them as standard vectors and $display() does not show them as strings. Now, they are wrapped with $sformatf("%s", ..) to fix it. --- vhdlpp/sequential_emit.cc | 47 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 8d63b901f..25dc6f60d 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -26,9 +26,11 @@ # include "package.h" # include "compiler.h" # include "subprogram.h" +# include "std_types.h" # include # include # include +# include # include int SequentialStmt::emit(ostream&out, Entity*, ScopeBase*) @@ -498,7 +500,7 @@ void BasicLoopStatement::write_to_stream(std::ostream&fd) int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) { - out << "$display(\"%s\", {\"** "; + out << "$display(\"** "; switch(severity_) { @@ -511,8 +513,47 @@ int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) out << ": \","; - msg_->emit(out, ent, scope); - out << ",\" (" << get_fileline() << ")\"});"; + struct emitter : public ExprVisitor { + emitter(ostream&outp, Entity*enti, ScopeBase*scop) + : out_(outp), ent_(enti), scope_(scop), + level_lock_(numeric_limits::max()) {} + + void operator() (Expression*s) { + if(!dynamic_cast(s)) { + if(level() > level_lock_) + return; + + if(dynamic_cast(s)) { + level_lock_ = level(); + } else { + level_lock_ = numeric_limits::max(); + } + + const VType*type = s->probe_type(ent_, scope_); + + if(dynamic_cast(s) && type + && type->type_match(&primitive_STRING)) { + out_ << "$sformatf(\"%s\", ("; + s->emit(out_, ent_, scope_); + out_ << "))"; + } else { + s->emit(out_, ent_, scope_); + } + + out_ << ", "; + } + } + + private: + ostream&out_; + Entity*ent_; + ScopeBase*scope_; + int level_lock_; + } emit_visitor(out, ent, scope); + + msg_->visit(emit_visitor); + + out << "\" (" << get_fileline() << ")\");"; if(severity_ == FAILURE) out << "$finish();"; From 25cd0827ba9d2c1e346b1dd74d45a4e11678a41f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 17 Feb 2016 17:20:02 +0100 Subject: [PATCH 66/76] vhdlpp: Removed ProcessStatement::rewrite_as_always_edge_() & extract_anyedge_(). Processes sensitive to edges are now handled with $ivlh_{rising,falling}_edge(). --- vhdlpp/architec.h | 3 - vhdlpp/architec_elaborate.cc | 126 ----------------------------------- 2 files changed, 129 deletions(-) diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 221092aa8..8a1902b76 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -284,9 +284,6 @@ class ProcessStatement : public StatementList { void dump(ostream&out, int indent =0) const; private: - int rewrite_as_always_edge_(Entity*ent, Architecture*arc); - int extract_anyedge_(Entity*ent, Architecture*arc); - perm_string iname_; std::list sensitivity_list_; }; diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 87294ebfb..a538da132 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -186,109 +186,6 @@ int IfGenerate::elaborate(Entity*ent, Architecture*arc) return errors; } -/* - * This method attempts to rewrite the process content as an - * always-@(n-edge ) version of the same statement. This makes - * for a more natural translation to Verilog, if it comes to that. - */ -int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*) -{ - // If there are multiple sensitivity expressions, I give up. - if (sensitivity_list_.size() != 1) - return -1; - - // If there are multiple statements, I give up. - if (stmt_list().size() != 1) - return -1; - - Expression*se = sensitivity_list_.front(); - SequentialStmt*stmt_raw = stmt_list().front(); - - // If the statement is not an if-statement, I give up. - IfSequential*stmt = dynamic_cast (stmt_raw); - if (stmt == 0) - return -1; - - // If the "if" statement has a false clause, then give up. - if (stmt->false_size() != 0) - return -1; - - const Expression*ce_raw = stmt->peek_condition(); - - // Here we expect the condition to be - // 'event AND ='1'. - // So if ce_raw is not a logical AND, I give up. - const ExpLogical*ce = dynamic_cast (ce_raw); - if (ce == 0) - return -1; - if (ce->logic_fun() != ExpLogical::AND) - return -1; - - const Expression*op1_raw = ce->peek_operand1(); - const Expression*op2_raw = ce->peek_operand2(); - if (dynamic_cast(op2_raw)) { - const Expression*tmp = op1_raw; - op1_raw = op2_raw; - op2_raw = tmp; - } - - // If operand1 is not an 'event attribute, I give up. - const ExpObjAttribute*op1 = dynamic_cast(op1_raw); - if (op1 == 0) - return -1; - if (op1->peek_attribute() != "event") - return -1; - - const ExpRelation*op2 = dynamic_cast(op2_raw); - if (op2 == 0) - return -1; - if (op2->relation_fun() != ExpRelation::EQ) - return -1; - - const Expression*op2a_raw = op2->peek_operand1(); - const Expression*op2b_raw = op2->peek_operand2(); - - if (dynamic_cast(op2a_raw)) { - const Expression*tmp = op2b_raw; - op2b_raw = op2a_raw; - op2a_raw = tmp; - } - - if (! se->symbolic_compare(op1->peek_base())) - return -1; - - const ExpCharacter*op2b = dynamic_cast(op2b_raw); - if (op2b == 0) - return -1; - if (op2b->value() != '1' && op2b->value() != '0') - return -1; - - // We've matched this pattern: - // process () if ('event and = ) then ... - // And we can convert it to: - // always @(edge ) ... - - // Replace the sensitivity expression with an edge - // expression. The ExpEdge expression signals that this is an - // always-@(edge) statement. - ExpEdge*edge = new ExpEdge(op2b->value()=='1'? ExpEdge::POSEDGE : ExpEdge::NEGEDGE, se); - assert(sensitivity_list_.size() == 1); - sensitivity_list_.pop_front(); - sensitivity_list_.push_front(edge); - - // Replace the statement with the body of the always - // statement, which is the true clause of the top "if" - // statement. There should be no "else" clause. - assert(stmt_list().size() == 1); - stmt_list().pop_front(); - - stmt->extract_true(stmt_list()); - - delete stmt; - - return 0; -} - int StatementList::elaborate(Entity*ent, Architecture*arc) { int errors = 0; @@ -301,33 +198,10 @@ int StatementList::elaborate(Entity*ent, Architecture*arc) return errors; } -/* - * Change the "process () " into "always @() ..." - */ -int ProcessStatement::extract_anyedge_(Entity*, Architecture*) -{ - vector se; - while (! sensitivity_list_.empty()) { - se.push_back(sensitivity_list_.front()); - sensitivity_list_.pop_front(); - } - - for (size_t idx = 0 ; idx < se.size() ; idx += 1) { - ExpEdge*edge = new ExpEdge(ExpEdge::ANYEDGE, se[idx]); - FILE_NAME(edge, se[idx]); - sensitivity_list_.push_back(edge); - } - - return 0; -} - int ProcessStatement::elaborate(Entity*ent, Architecture*arc) { int errors = 0; - if (rewrite_as_always_edge_(ent, arc) >= 0) { - extract_anyedge_(ent, arc); - } StatementList::elaborate(ent, arc); From b037d533f9b985d3b2aed8e6706368f8b67f116d Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 18 Feb 2016 10:32:51 +0100 Subject: [PATCH 67/76] vhdlpp: ProcessStatement inherits after ScopeBase. --- vhdlpp/architec.cc | 3 ++- vhdlpp/architec.h | 3 ++- vhdlpp/architec_elaborate.cc | 1 - vhdlpp/architec_emit.cc | 2 ++ vhdlpp/parse.y | 29 ++++++++++++++++++----------- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index b8eecea85..4fb2f8e6a 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -260,9 +260,10 @@ StatementList::~StatementList() } ProcessStatement::ProcessStatement(perm_string iname, + const ActiveScope&ref, std::list*sensitivity_list, std::list*statements_list) -: StatementList(statements_list), iname_(iname) +: StatementList(statements_list), Scope(ref), iname_(iname) { if (sensitivity_list) sensitivity_list_.splice(sensitivity_list_.end(), *sensitivity_list); diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 8a1902b76..2b0ffb12d 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -271,10 +271,11 @@ class FinalStatement : public StatementList { void dump(ostream&out, int indent =0) const; }; -class ProcessStatement : public StatementList { +class ProcessStatement : public StatementList, public Scope { public: ProcessStatement(perm_string iname, + const ActiveScope&ref, std::list*sensitivity_list, std::list*statement_list); ~ProcessStatement(); diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index a538da132..10ad46669 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -202,7 +202,6 @@ int ProcessStatement::elaborate(Entity*ent, Architecture*arc) { int errors = 0; - StatementList::elaborate(ent, arc); return errors; diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 8fd0ee569..e0d567f9d 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -361,6 +361,8 @@ int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc) else out << "always begin" << endl; + emit_variables(out, ent, arc); + int errors = StatementList::emit(out, ent, arc); if (! sensitivity_list_.empty()) { diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 31aa8fe5f..efec20360 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -778,7 +778,10 @@ concurrent_assertion_statement std::list stmts; stmts.push_back($1); stmts.push_back(new WaitStmt(WaitStmt::FINAL, NULL)); - ProcessStatement*tmp = new ProcessStatement(empty_perm_string, NULL, &stmts); + push_scope(); + ProcessStatement*tmp = new ProcessStatement(empty_perm_string, *active_scope, + NULL, &stmts); + pop_scope(); FILE_NAME(tmp, @1); $$ = tmp; } @@ -2089,26 +2092,30 @@ process_declarative_part_opt process_statement : identifier_colon_opt K_postponed_opt K_process + { + push_scope(); + } process_sensitivity_list_opt K_is_opt process_declarative_part_opt K_begin sequence_of_statements K_end K_postponed_opt K_process identifier_opt ';' { perm_string iname = $1? lex_strings.make($1) : empty_perm_string; if ($1) delete[]$1; - if ($12) { + if ($13) { if (iname.nil()) { - errormsg(@12, "Process end name %s for un-named processes.\n", $12); - } else if (iname != $12) { - errormsg(@12, "Process name %s does not match opening name %s.\n", - $12, $1); + errormsg(@13, "Process end name %s for un-named processes.\n", $13); + } else if (iname != $13) { + errormsg(@13, "Process name %s does not match opening name %s.\n", + $13, $1); } - delete[]$12; + delete[]$13; } - ProcessStatement*tmp = new ProcessStatement(iname, $4, $8); - FILE_NAME(tmp, @3); - delete $4; - delete $8; + ProcessStatement*tmp = new ProcessStatement(iname, *active_scope, $5, $9); + pop_scope(); + FILE_NAME(tmp, @4); + delete $5; + delete $9; $$ = tmp; } From 03e85850e126c702cc4a24bffe14ae94fda89aed Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 24 Feb 2016 10:14:50 +0100 Subject: [PATCH 68/76] vhdlpp: Variables are moved to respective process scopes. --- vhdlpp/architec.cc | 10 ++- vhdlpp/architec.h | 35 ++++++++-- vhdlpp/architec_elaborate.cc | 13 +++- vhdlpp/architec_emit.cc | 71 ++++++++++----------- vhdlpp/compiler.cc | 2 + vhdlpp/compiler.h | 5 ++ vhdlpp/parse.y | 60 ++++++++++-------- vhdlpp/scope.cc | 120 +++++++++++++++++++---------------- vhdlpp/scope.h | 31 +++++++-- 9 files changed, 211 insertions(+), 136 deletions(-) diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index 4fb2f8e6a..488ee9cd5 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -29,7 +29,7 @@ using namespace std; Architecture::Architecture(perm_string name, const ActiveScope&ref, list&s) -: Scope(ref), name_(name), cur_component_(NULL) +: Scope(ref), name_(name), cur_component_(NULL), cur_process_(NULL) { statements_.splice(statements_.end(), s); } @@ -68,6 +68,14 @@ bool Architecture::find_constant(perm_string by_name, const VType*&typ, Expressi return false; } +Variable* Architecture::find_variable(perm_string by_name) const +{ + if(cur_process_) + return cur_process_->find_variable(by_name); + + return ScopeBase::find_variable(by_name); +} + void Architecture::push_genvar_type(perm_string gname, const VType*gtype) { genvar_type_t tmp; diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 2b0ffb12d..3d9ef1f05 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -30,6 +30,7 @@ class Entity; class Expression; class ExpName; class GenerateStatement; +class ProcessStatement; class SequentialStmt; class Signal; class named_expr_t; @@ -65,9 +66,20 @@ class Architecture : public Scope, public LineInfo { perm_string get_name() const { return name_; } - // Sets the currently processed component (to be able to reach its parameters). - void set_cur_component(ComponentInstantiation*component) { cur_component_ = component; } bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const; + Variable* find_variable(perm_string by_name) const; + + // Sets the currently processed component (to be able to reach its parameters). + void set_cur_component(ComponentInstantiation*component) { + assert(!cur_component_ || !component); + cur_component_ = component; + } + + // Sets the currently elaborated process (to use its scope for variable resolving). + void set_cur_process(ProcessStatement*process) { + assert(!cur_process_ || !process); + cur_process_ = process; + } // Elaborate this architecture in the context of the given entity. int elaborate(Entity*entity); @@ -113,7 +125,8 @@ class Architecture : public Scope, public LineInfo { // Currently processed component (or NULL if none). ComponentInstantiation*cur_component_; - private: // Not implemented + // Currently elaborated process (or NULL if none). + ProcessStatement*cur_process_; }; /* @@ -239,8 +252,16 @@ class StatementList : public Architecture::Statement { StatementList(std::list*statement_list); virtual ~StatementList(); - virtual int elaborate(Entity*ent, Architecture*arc); - virtual int emit(ostream&out, Entity*entity, Architecture*arc); + int elaborate(Entity*ent, Architecture*arc) { + return elaborate(ent, static_cast(arc)); + } + + int emit(ostream&out, Entity*ent, Architecture*arc) { + return emit(out, ent, static_cast(arc)); + } + + virtual int elaborate(Entity*ent, ScopeBase*scope); + virtual int emit(ostream&out, Entity*entity, ScopeBase*scope); virtual void dump(ostream&out, int indent =0) const; std::list& stmt_list() { return statements_; } @@ -256,7 +277,7 @@ class InitialStatement : public StatementList { InitialStatement(std::list*statement_list) : StatementList(statement_list) {} - int emit(ostream&out, Entity*entity, Architecture*arc); + int emit(ostream&out, Entity*entity, ScopeBase*scope); void dump(ostream&out, int indent =0) const; }; @@ -267,7 +288,7 @@ class FinalStatement : public StatementList { FinalStatement(std::list*statement_list) : StatementList(statement_list) {} - int emit(ostream&out, Entity*entity, Architecture*arc); + int emit(ostream&out, Entity*entity, ScopeBase*scope); void dump(ostream&out, int indent =0) const; }; diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 10ad46669..5ec87becc 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -186,13 +186,13 @@ int IfGenerate::elaborate(Entity*ent, Architecture*arc) return errors; } -int StatementList::elaborate(Entity*ent, Architecture*arc) +int StatementList::elaborate(Entity*ent, ScopeBase*scope) { int errors = 0; for (std::list::iterator it = statements_.begin(); it != statements_.end(); ++it) { - errors += (*it)->elaborate(ent, arc); + errors += (*it)->elaborate(ent, scope); } return errors; @@ -202,8 +202,17 @@ int ProcessStatement::elaborate(Entity*ent, Architecture*arc) { int errors = 0; + arc->set_cur_process(this); + + for (map::iterator cur = new_variables_.begin() + ; cur != new_variables_.end() ; ++cur) { + cur->second->elaborate(ent, arc); + } + StatementList::elaborate(ent, arc); + arc->set_cur_process(NULL); + return errors; } diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index e0d567f9d..e5a3a1c61 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -28,38 +28,28 @@ # include # include -int Scope::emit_signals(ostream&out, Entity*entity, Architecture*arc) +int Scope::emit_signals(ostream&out, Entity*entity, ScopeBase*scope) { - int errors = 0; + int errors = 0; - for (map::iterator cur = old_signals_.begin() - ; cur != old_signals_.end() ; ++cur) { + for (map::iterator cur = new_signals_.begin() + ; cur != new_signals_.end() ; ++cur) { + errors += cur->second->emit(out, entity, scope); + } - errors += cur->second->emit(out, entity, arc); - } - for (map::iterator cur = new_signals_.begin() - ; cur != new_signals_.end() ; ++cur) { - - errors += cur->second->emit(out, entity, arc); - } - return errors; + return errors; } -int Scope::emit_variables(ostream&out, Entity*entity, Architecture*arc) +int Scope::emit_variables(ostream&out, Entity*entity, ScopeBase*scope) { - int errors = 0; + int errors = 0; - for (map::iterator cur = old_variables_.begin() - ; cur != old_variables_.end() ; ++cur) { + for (map::iterator cur = new_variables_.begin() + ; cur != new_variables_.end() ; ++cur) { + errors += cur->second->emit(out, entity, scope); + } - errors += cur->second->emit(out, entity, arc); - } - for (map::iterator cur = new_variables_.begin() - ; cur != new_variables_.end() ; ++cur) { - - errors += cur->second->emit(out, entity, arc); - } - return errors; + return errors; } int Architecture::emit(ostream&out, Entity*entity) @@ -310,31 +300,31 @@ int IfGenerate::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } -int StatementList::emit(ostream&out, Entity*ent, Architecture*arc) +int StatementList::emit(ostream&out, Entity*ent, ScopeBase*scope) { int errors = 0; for (std::list::iterator it = statements_.begin(); it != statements_.end(); ++it) { - errors += (*it)->emit(out, ent, arc); + errors += (*it)->emit(out, ent, scope); } return errors; } -int InitialStatement::emit(ostream&out, Entity*ent, Architecture*arc) +int InitialStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) { out << "initial begin" << endl; - int errors = StatementList::emit(out, ent, arc); + int errors = StatementList::emit(out, ent, scope); out << "end" << endl; return errors; } -int FinalStatement::emit(ostream&out, Entity*ent, Architecture*arc) +int FinalStatement::emit(ostream&out, Entity*ent, ScopeBase*scope) { out << "final begin" << endl; - int errors = StatementList::emit(out, ent, arc); + int errors = StatementList::emit(out, ent, scope); out << "end" << endl; return errors; @@ -348,22 +338,25 @@ int FinalStatement::emit(ostream&out, Entity*ent, Architecture*arc) * beginning. In VHDL, all the statements are initially executed once * before blocking in the first wait on the sensitivity list. */ -int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc) +int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*) { + int errors = 0; + /* Check if the process has no sensitivity list and ends up with * a final wait. If so, convert the process to an initial block. */ const WaitStmt*wait_stmt = NULL; - if (! stmt_list().empty()) + if (!stmt_list().empty()) wait_stmt = dynamic_cast(stmt_list().back()); if (wait_stmt && wait_stmt->type() == WaitStmt::FINAL) - out << "initial begin" << endl; + out << "initial begin : "; else - out << "always begin" << endl; + out << "always begin : "; - emit_variables(out, ent, arc); + out << peek_name() << endl; - int errors = StatementList::emit(out, ent, arc); + errors += emit_variables(out, ent, this); + errors += StatementList::emit(out, ent, this); if (! sensitivity_list_.empty()) { out << "@("; @@ -372,12 +365,12 @@ int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc) ; cur != sensitivity_list_.end() ; ++cur) { if (comma) out << comma; - errors += (*cur)->emit(out, ent, arc); + errors += (*cur)->emit(out, ent, this); comma = ", "; } - out << ") /* sensitivity list for process */;" << endl; + out << "); /* sensitivity list for process */" << endl; } - out << "end" << endl; + out << "end /* " << peek_name() << " */" << endl; return errors; } diff --git a/vhdlpp/compiler.cc b/vhdlpp/compiler.cc index 66193a370..9a1a6279e 100644 --- a/vhdlpp/compiler.cc +++ b/vhdlpp/compiler.cc @@ -21,3 +21,5 @@ StringHeapLex lex_strings; StringHeapLex filename_strings; + +StringHeapLex gen_strings; diff --git a/vhdlpp/compiler.h b/vhdlpp/compiler.h index 3cd1b820a..477d33928 100644 --- a/vhdlpp/compiler.h +++ b/vhdlpp/compiler.h @@ -30,8 +30,13 @@ extern bool verbose_flag; extern bool debug_elaboration; extern std::ofstream debug_log_file; +// Stores strings created by the lexer extern StringHeapLex lex_strings; +// Stores file names extern StringHeapLex filename_strings; +// Stores generated strigns (e.g. scope names) +extern StringHeapLex gen_strings; + #endif /* IVL_compiler_H */ diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index efec20360..82ccde7e3 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -86,6 +86,7 @@ extern int yylex(union YYSTYPE*yylvalp,YYLTYPE*yyllocp,yyscan_t yyscanner); static ActiveScope*active_scope = new ActiveScope; static stack scope_stack; static SubprogramHeader*active_sub = NULL; +static ActiveScope*arc_scope = NULL; /* * When a scope boundary starts, call the push_scope function to push @@ -353,7 +354,7 @@ static void touchup_interface_for_functions(std::list*ports) %type element_declaration element_declaration_list %type architecture_body_start package_declaration_start -%type package_body_start +%type package_body_start process_start %type identifier_opt identifier_colon_opt logical_name suffix instantiated_unit %type logical_name_list identifier_list @@ -412,6 +413,8 @@ architecture_body delete[]$3; delete $8; pop_scope(); + assert(arc_scope); + arc_scope = NULL; if ($11) delete[]$11; } ; @@ -420,6 +423,8 @@ architecture_body_start : K_architecture IDENTIFIER { $$ = $2; push_scope(); + assert(!arc_scope); + arc_scope = active_scope; } ; /* @@ -1293,17 +1298,19 @@ file_declaration std::list params; // add file_open() call in 'initial' block - params.push_back(new ExpName(*cur)); + params.push_back(new ExpScopedName(active_scope->peek_name(), new ExpName(*cur))); params.push_back($5->filename()->clone()); params.push_back($5->kind()->clone()); - ProcedureCall*fopen_call = new ProcedureCall(perm_string::literal("file_open"), ¶ms); - active_scope->add_initializer(fopen_call); + ProcedureCall*fopen_call = new ProcedureCall( + perm_string::literal("file_open"), ¶ms); + arc_scope->add_initializer(fopen_call); // add file_close() call in 'final' block params.clear(); - params.push_back(new ExpName(*cur)); - ProcedureCall*fclose_call = new ProcedureCall(perm_string::literal("file_close"), ¶ms); - active_scope->add_finalizer(fclose_call); + params.push_back(new ExpScopedName(active_scope->peek_name(), new ExpName(*cur))); + ProcedureCall*fclose_call = new ProcedureCall( + perm_string::literal("file_close"), ¶ms); + arc_scope->add_finalizer(fclose_call); delete $5; } @@ -2090,37 +2097,40 @@ process_declarative_part_opt | ; -process_statement +process_start : identifier_colon_opt K_postponed_opt K_process - { - push_scope(); - } - process_sensitivity_list_opt K_is_opt + { push_scope(); + $$ = $1; + } + ; + +process_statement + : process_start process_sensitivity_list_opt K_is_opt process_declarative_part_opt K_begin sequence_of_statements K_end K_postponed_opt K_process identifier_opt ';' { perm_string iname = $1? lex_strings.make($1) : empty_perm_string; if ($1) delete[]$1; - if ($13) { + if ($10) { if (iname.nil()) { - errormsg(@13, "Process end name %s for un-named processes.\n", $13); - } else if (iname != $13) { - errormsg(@13, "Process name %s does not match opening name %s.\n", - $13, $1); + errormsg(@10, "Process end name %s for un-named processes.\n", $10); + } else if (iname != $10) { + errormsg(@10, "Process name %s does not match opening name %s.\n", + $10, $1); } - delete[]$13; + delete[]$10; } - ProcessStatement*tmp = new ProcessStatement(iname, *active_scope, $5, $9); - pop_scope(); - FILE_NAME(tmp, @4); - delete $5; - delete $9; + ProcessStatement*tmp = new ProcessStatement(iname, *active_scope, $2, $6); + arc_scope->bind_scope(tmp->peek_name(), tmp); + pop_scope(); + FILE_NAME(tmp, @3); + delete $2; + delete $6; $$ = tmp; } - | identifier_colon_opt K_postponed_opt K_process - process_sensitivity_list_opt K_is_opt + | process_start process_sensitivity_list_opt K_is_opt process_declarative_part_opt K_begin error K_end K_postponed_opt K_process identifier_opt ';' diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 395804962..cbee2bea4 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -24,61 +24,30 @@ # include "entity.h" # include "std_funcs.h" # include "std_types.h" +# include "compiler.h" # include # include # include +# include +# include # include +# include using namespace std; -/* - * If the merge_flag is passed in, then the new scope is a merge of - * the parent scopes. This brings in all of the parent scopes into the - * "old_*_" variables. This clears up the "new_*_" variables to - * accumulate new scope values. - */ +static int scope_counter = 0; + ScopeBase::ScopeBase(const ActiveScope&ref) -: use_constants_(ref.use_constants_), cur_constants_(ref.cur_constants_) +: old_signals_(ref.old_signals_), new_signals_(ref.new_signals_), + old_variables_(ref.old_variables_), new_variables_(ref.new_variables_), + old_components_(ref.old_components_), new_components_(ref.new_components_), + use_types_(ref.use_types_), cur_types_(ref.cur_types_), + use_constants_(ref.use_constants_), cur_constants_(ref.cur_constants_), + use_subprograms_(ref.use_subprograms_), cur_subprograms_(ref.cur_subprograms_), + scopes_(ref.scopes_), use_enums_(ref.use_enums_), + initializers_(ref.initializers_), finalizers_(ref.finalizers_), + name_(ref.name_) { - merge(ref.old_signals_.begin(), ref.old_signals_.end(), - ref.new_signals_.begin(), ref.new_signals_.end(), - insert_iterator >( - old_signals_, old_signals_.end()) - ); - merge(ref.old_variables_.begin(), ref.old_variables_.end(), - ref.new_variables_.begin(), ref.new_variables_.end(), - insert_iterator >( - old_variables_, old_variables_.end()) - ); - merge(ref.old_components_.begin(), ref.old_components_.end(), - ref.new_components_.begin(), ref.new_components_.end(), - insert_iterator >( - old_components_, old_components_.end()) - ); - use_types_ = ref.use_types_; - cur_types_ = ref.cur_types_; - - use_subprograms_ = ref.use_subprograms_; - cur_subprograms_ = ref.cur_subprograms_; - - use_enums_ = ref.use_enums_; - - initializers_ = ref.initializers_; - finalizers_ = ref.finalizers_; - - // This constructor is invoked when the parser is finished with - // an active scope and is making the actual scope. At this point - // we know that "this" is the parent scope for the subprograms, - // so set it now. - for (map::iterator cur = cur_subprograms_.begin() - ; cur != cur_subprograms_.end(); ++cur) { - SubHeaderList& subp_list = cur->second; - - for (SubHeaderList::iterator it = subp_list.begin(); - it != subp_list.end(); ++it) { - (*it)->set_parent(this); - } - } } ScopeBase::~ScopeBase() @@ -105,6 +74,16 @@ void ScopeBase::cleanup() } } +ScopeBase*ScopeBase::find_scope(perm_string name) const +{ + map::const_iterator it = scopes_.find(name); + + if(it != scopes_.end()) + return it->second; + + return NULL; +} + const VType*ScopeBase::find_type(perm_string by_name) { map::const_iterator cur = cur_types_.find(by_name); @@ -339,9 +318,15 @@ SubprogramHeader*ScopeBase::match_subprogram(perm_string name, } void ActiveScope::set_package_header(Package*pkg) +void ScopeBase::generate_name() { assert(package_header_ == 0); package_header_ = pkg; + char buf[64]; + + // Generate a name for the scope + snprintf(buf, sizeof(buf), "__scope_%d", scope_counter++); + name_ = gen_strings.make(buf); } SubprogramHeader* ActiveScope::recall_subprogram(const SubprogramHeader*subp) const @@ -384,15 +369,6 @@ bool ActiveScope::is_vector_name(perm_string name) const return false; } -Scope::Scope(const ActiveScope&ref) -: ScopeBase(ref) -{ -} - -Scope::~Scope() -{ -} - ComponentBase* Scope::find_component(perm_string by_name) { map::const_iterator cur = new_components_.find(by_name); @@ -405,3 +381,37 @@ ComponentBase* Scope::find_component(perm_string by_name) } else return cur->second; } + +ActiveScope::ActiveScope(const ActiveScope*par) +: ScopeBase(*par), context_entity_(par->context_entity_) +{ + generate_name(); + + // Move all the objects available in higher level scopes to use*/old* maps. + // This way we can store the new items in now empty cur*/new* maps. + merge(par->old_signals_.begin(), par->old_signals_.end(), + par->new_signals_.begin(), par->new_signals_.end(), + insert_iterator >( + old_signals_, old_signals_.end()) + ); + merge(par->old_variables_.begin(), par->old_variables_.end(), + par->new_variables_.begin(), par->new_variables_.end(), + insert_iterator >( + old_variables_, old_variables_.end()) + ); + merge(par->old_components_.begin(), par->old_components_.end(), + par->new_components_.begin(), par->new_components_.end(), + insert_iterator >( + old_components_, old_components_.end()) + ); + merge(par->use_types_.begin(), par->use_types_.end(), + par->cur_types_.begin(), par->cur_types_.end(), + insert_iterator >( + use_types_, use_types_.end()) + ); + merge(par->use_subprograms_.begin(), par->use_subprograms_.end(), + par->cur_subprograms_.begin(), par->cur_subprograms_.end(), + insert_iterator >( + use_subprograms_, use_subprograms_.end()) + ); +} diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 3563692d9..4f1c13d47 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -55,10 +55,11 @@ class ScopeBase { explicit ScopeBase(const ActiveScope&ref); virtual ~ScopeBase() =0; + ScopeBase* find_scope(perm_string name) const; const VType* find_type(perm_string by_name); virtual bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const; Signal* find_signal(perm_string by_name) const; - Variable* find_variable(perm_string by_name) const; + virtual Variable* find_variable(perm_string by_name) const; virtual const InterfacePort* find_param(perm_string by_name) const; const InterfacePort* find_param_all(perm_string by_name) const; SubHeaderList find_subprogram(perm_string by_name) const; @@ -98,6 +99,8 @@ class ScopeBase { SubprogramHeader*match_subprogram(perm_string name, const list*params) const; + perm_string peek_name() const { return name_; } + protected: void cleanup(); @@ -143,6 +146,8 @@ class ScopeBase { std::map use_subprograms_; //imported std::map cur_subprograms_; //current + std::map scopes_; + std::list use_enums_; // List of statements that should be emitted in a 'initial' block @@ -152,20 +157,26 @@ class ScopeBase { std::list finalizers_; void do_use_from(const ScopeBase*that); + + // Generates an unique name for the scope + void generate_name(); + +private: + perm_string name_; }; class Scope : public ScopeBase { public: - explicit Scope(const ActiveScope&ref); - ~Scope(); + explicit Scope(const ActiveScope&ref) : ScopeBase(ref) {} + virtual ~Scope() {} ComponentBase* find_component(perm_string by_name); protected: // Helper method for emitting signals in the scope. - int emit_signals(ostream&out, Entity*ent, Architecture*arc); - int emit_variables(ostream&out, Entity*ent, Architecture*arc); + int emit_signals(ostream&out, Entity*ent, ScopeBase*scope); + int emit_variables(ostream&out, Entity*ent, ScopeBase*scope); }; /* @@ -177,8 +188,8 @@ class Scope : public ScopeBase { class ActiveScope : public ScopeBase { public: - ActiveScope() : package_header_(0), context_entity_(0) { } - explicit ActiveScope(ActiveScope*par) : ScopeBase(*par), package_header_(0), context_entity_(0) { } + ActiveScope() : context_entity_(0) { } + explicit ActiveScope(const ActiveScope*par); ~ActiveScope() { } @@ -233,6 +244,12 @@ class ActiveScope : public ScopeBase { cur_types_[name] = t; } + void bind_scope(perm_string name, ScopeBase*scope) + { + assert(scopes_.find(name) == scopes_.end()); + scopes_[name] = scope; + } + inline void use_enum(const VTypeEnum* t) { use_enums_.push_back(t); } From 7bb4cef9bc4d555212dda76f9e237362b2154b1c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 24 Feb 2016 10:17:39 +0100 Subject: [PATCH 69/76] vhdlpp: ExpScopedName class to handle names with a specified scope. --- vhdlpp/expression.cc | 31 +++++++++++++++++++ vhdlpp/expression.h | 62 ++++++++++++++++++++++++++++++++++++-- vhdlpp/expression_debug.cc | 11 +++++-- 3 files changed, 100 insertions(+), 4 deletions(-) diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 0bf306a2f..d52fa4d11 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -755,6 +755,37 @@ ExpRelation::~ExpRelation() { } +ExpScopedName::ExpScopedName(perm_string scope, ExpName*exp) +: scope_name_(scope), scope_(NULL), name_(exp) +{ +} + +ExpScopedName::~ExpScopedName() +{ + delete name_; +} + +void ExpScopedName::visit(ExprVisitor&func) +{ + func.down(); + func(this); + name_->visit(func); + func.up(); +} + +ScopeBase*ExpScopedName::get_scope(const ScopeBase*scope) +{ + if(!scope_) + scope_ = scope->find_scope(scope_name_); + + return scope_; +} + +ScopeBase*ExpScopedName::get_scope(const ScopeBase*scope) const +{ + return scope_ ? scope_ : scope->find_scope(scope_name_); +} + ExpShift::ExpShift(ExpShift::shift_t op, Expression*op1, Expression*op2) : ExpBinary(op1, op2), shift_(op) { diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index c513c7f89..b1b6ae244 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -708,7 +708,7 @@ class ExpName : public Expression { explicit ExpName(perm_string nn); ExpName(perm_string nn, std::list*indices); ExpName(ExpName*prefix, perm_string nn, std::list*indices = NULL); - ~ExpName(); + virtual ~ExpName(); public: // Base methods Expression*clone() const; @@ -783,7 +783,7 @@ class ExpName : public Expression { class ExpNameALL : public ExpName { public: - ExpNameALL() : ExpName(perm_string()) { } + ExpNameALL() : ExpName(empty_perm_string) { } public: const VType* probe_type(Entity*ent, ScopeBase*scope) const; @@ -815,6 +815,64 @@ class ExpRelation : public ExpBinary { fun_t fun_; }; +/* + * Helper class to handle name expressions coming from another scope. As such, + * we get more information regarding their type, etc. from the associated scope. + */ +class ExpScopedName : public Expression { + public: + ExpScopedName(perm_string scope, ExpName*exp); + ~ExpScopedName(); + + Expression*clone() const + { return new ExpScopedName(scope_name_, static_cast(name_->clone())); } + + int elaborate_lval(Entity*ent, ScopeBase*scope, bool is_sequ) + { return name_->elaborate_lval(ent, get_scope(scope), is_sequ); } + + int elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lval) + { return name_->elaborate_rval(ent, get_scope(scope), lval); } + + const VType* probe_type(Entity*ent, ScopeBase*scope) const + { return name_->probe_type(ent, get_scope(scope)); } + + const VType* fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*host) const + { return name_->fit_type(ent, get_scope(scope), host); } + + int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) + { return name_->elaborate_expr(ent, get_scope(scope), ltype); } + + void write_to_stream(std::ostream&fd) const + { name_->write_to_stream(fd); } + + int emit(ostream&out, Entity*ent, ScopeBase*scope) const { + out << scope_name_ << "."; + return name_->emit(out, ent, scope); + } + + bool is_primary(void) const + { return name_->is_primary(); } + + bool evaluate(Entity*ent, ScopeBase*, int64_t&val) const + { return name_->evaluate(ent, scope_, val); } + + bool symbolic_compare(const Expression*that) const + { return name_->symbolic_compare(that); } + + void dump(ostream&out, int indent = 0) const; + + void visit(ExprVisitor&func); + + private: + // Functions that resolve the origin scope for the name expression + ScopeBase*get_scope(const ScopeBase*scope); + ScopeBase*get_scope(const ScopeBase*scope) const; + + perm_string scope_name_; + ScopeBase*scope_; + ExpName*name_; +}; + class ExpShift : public ExpBinary { public: enum shift_t { SRL, SLL, SRA, SLA, ROL, ROR }; diff --git a/vhdlpp/expression_debug.cc b/vhdlpp/expression_debug.cc index e3f70fd5d..feaaf9510 100644 --- a/vhdlpp/expression_debug.cc +++ b/vhdlpp/expression_debug.cc @@ -71,7 +71,7 @@ void ExpConcat::dump(ostream&out, int indent) const void ExpCast::dump(ostream&out, int indent) const { - out << "Casting "; + out << setw(indent) << "" << "Casting "; base_->dump(out, indent+4); out << " to "; type_->emit_def(out, empty_perm_string); @@ -79,10 +79,17 @@ void ExpCast::dump(ostream&out, int indent) const void ExpNew::dump(ostream&out, int indent) const { - out << "New dynamic array size: "; + out << setw(indent) << "" << "New dynamic array size: " << endl; size_->dump(out, indent); } +void ExpScopedName::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "Scoped name expression: " << endl; + out << " scope " << scope_name_ << " " << scope_ << endl; + name_->dump(out, indent+4); +} + void ExpShift::dump(ostream&out, int indent) const { const char*fun_name = "?"; From 78d6ee26dd3647a70daf820f9a4d9fbe9f7744b9 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 24 Feb 2016 10:18:04 +0100 Subject: [PATCH 70/76] vhdlpp: Do not allow 'wire real' nets. --- vhdlpp/vsignal.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vhdlpp/vsignal.cc b/vhdlpp/vsignal.cc index 82c5f0760..ab949d7e1 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -22,6 +22,7 @@ # include "vsignal.h" # include "expression.h" # include "vtype.h" +# include "std_types.h" # include using namespace std; @@ -64,7 +65,7 @@ int Signal::emit(ostream&out, Entity*ent, ScopeBase*scope) Expression*init_expr = peek_init_expr(); if (init_expr) { /* Emit initialization value for wires as a weak assignment */ - if(!decl.reg_flag) + if(!decl.reg_flag && !type->type_match(&primitive_REAL)) out << ";" << endl << "/*init*/ assign (weak1, weak0) " << peek_name(); out << " = "; From 94f7504372f00682b3f9aac4fa64694190ad0055 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 24 Feb 2016 10:19:20 +0100 Subject: [PATCH 71/76] vhdlpp: Subprograms are linked to Package instead of generic Scope. --- vhdlpp/package.cc | 1 + vhdlpp/scope.cc | 3 --- vhdlpp/scope.h | 15 +++++++++------ vhdlpp/subprogram.cc | 10 ++-------- vhdlpp/subprogram.h | 7 ++++--- vhdlpp/subprogram_emit.cc | 5 ++--- 6 files changed, 18 insertions(+), 23 deletions(-) diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index d58f82093..c8ff5b466 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -53,6 +53,7 @@ int Package::elaborate() for(SubHeaderList::iterator it = subp_list.begin(); it != subp_list.end(); ++it) { + (*it)->set_package(this); errors += (*it)->elaborate(); } } diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index cbee2bea4..785ab1d98 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -317,11 +317,8 @@ SubprogramHeader*ScopeBase::match_subprogram(perm_string name, return NULL; } -void ActiveScope::set_package_header(Package*pkg) void ScopeBase::generate_name() { - assert(package_header_ == 0); - package_header_ = pkg; char buf[64]; // Generate a name for the scope diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 4f1c13d47..5f88b384c 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -101,6 +101,11 @@ class ScopeBase { perm_string peek_name() const { return name_; } + void set_package_header(Package*pkg) { + assert(package_header_ == 0); + package_header_ = pkg; + } + protected: void cleanup(); @@ -158,6 +163,10 @@ class ScopeBase { void do_use_from(const ScopeBase*that); + // If this is a package body, then there is a Package header + // already declared. + Package*package_header_; + // Generates an unique name for the scope void generate_name(); @@ -193,8 +202,6 @@ class ActiveScope : public ScopeBase { ~ActiveScope() { } - void set_package_header(Package*); - // Pull items from "that" scope into "this" scope as is // defined by a "use" directive. The parser uses this method // to implement the "use ::*" directive. @@ -276,10 +283,6 @@ class ActiveScope : public ScopeBase { std::map incomplete_types; private: - // If this is a package body, then there is a Package header - // already declared. - Package*package_header_; - Entity*context_entity_; }; diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index f93ed1439..bd7d832cc 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -88,7 +88,7 @@ void SubprogramBody::write_to_stream(ostream&fd) const SubprogramHeader::SubprogramHeader(perm_string nam, list*ports, const VType*return_type) -: name_(nam), ports_(ports), return_type_(return_type), body_(NULL), parent_(NULL) +: name_(nam), ports_(ports), return_type_(return_type), body_(NULL), package_(NULL) { } @@ -172,12 +172,6 @@ const VType*SubprogramHeader::peek_param_type(int idx) const return NULL; } -void SubprogramHeader::set_parent(const ScopeBase*par) -{ - ivl_assert(*this, !parent_); - parent_ = par; -} - bool SubprogramHeader::unbounded() const { if(return_type_ && return_type_->is_unbounded()) return true; @@ -263,7 +257,7 @@ SubprogramHeader*SubprogramHeader::make_instance(std::vector argume } body_inst->set_statements(body_->statements_); - instance->set_parent(scope); + instance->set_package(package_); instance->set_body(body_inst); instance->fix_return_type(); } diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 0338dc002..08473239e 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -31,6 +31,7 @@ class InterfacePort; class SequentialStmt; +class Package; class VType; class SubprogramBody : public LineInfo, public ScopeBase { @@ -78,8 +79,8 @@ class SubprogramHeader : public LineInfo { const VType*peek_param_type(int idx) const; const VType*peek_return_type() const { return return_type_; } - void set_parent(const ScopeBase*par); - inline const ScopeBase*get_parent() const { return parent_; } + inline void set_package(const Package*pkg) { assert(!package_); package_ = pkg; } + inline const Package*get_package() const { return package_; } // Checks if either return type or parameters are unbounded vectors. bool unbounded() const; @@ -138,7 +139,7 @@ class SubprogramHeader : public LineInfo { std::list*ports_; const VType*return_type_; SubprogramBody*body_; - const ScopeBase*parent_; + const Package*package_; }; // Class to define functions headers defined in the standard VHDL libraries. diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc index 0aa02973e..2dab34a89 100644 --- a/vhdlpp/subprogram_emit.cc +++ b/vhdlpp/subprogram_emit.cc @@ -107,10 +107,9 @@ int SubprogramHeader::emit_full_name(const std::vector&argv, // the SV elaborator finds the correct VHDL elaborated // definition. It should not be emitted only if we call another // function from the same package. - const Package*pkg = dynamic_cast(parent_); const SubprogramBody*subp = dynamic_cast(scope); - if (pkg != 0 && (!subp || !subp->header() || subp->header()->get_parent() != pkg)) - out << "\\" << pkg->name() << " ::"; + if (package_ && (!subp || !subp->header() || subp->header()->get_package() != package_)) + out << "\\" << package_->name() << " ::"; return emit_name(argv, out, ent, scope); } From 7c10de918e0463e5679fdffc9bf7e89cabdf8f45 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 26 Feb 2016 10:43:37 +0100 Subject: [PATCH 72/76] vhdlpp: read() takes into account the size of the destination variable. --- vpi/vhdl_textio.c | 67 +++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/vpi/vhdl_textio.c b/vpi/vhdl_textio.c index cff0845b5..fc6411b9a 100644 --- a/vpi/vhdl_textio.c +++ b/vpi/vhdl_textio.c @@ -61,6 +61,9 @@ enum file_open_status_t { FS_OPEN_OK, FS_STATUS_ERROR, FS_NAME_ERROR, FS_MODE_ER /* bits per vector, in a single s_vpi_vecval struct */ static const size_t BPW = 8 * sizeof(PLI_INT32); +/* string buffer size */ +static const size_t STRING_BUF_SIZE = 1024; + static int is_integer_var(vpiHandle obj) { PLI_INT32 type = vpi_get(vpiType, obj); @@ -224,11 +227,18 @@ static int read_time(const char *string, s_vpi_value *val, PLI_INT32 scope_unit) return processed_chars; } -static int read_string(const char *string, s_vpi_value *val) { - char buf[1024]; +static int read_string(const char *string, s_vpi_value *val, int count) { + char buf[STRING_BUF_SIZE]; int processed_chars; + char format_str[32]; - if(sscanf(string, "%1024s%n", buf, &processed_chars) != 1) + /* No string length limit imposed */ + if(count == 0) + count = STRING_BUF_SIZE; + + snprintf(format_str, 32, "%%%ds%%n", count); + + if(sscanf(string, format_str, buf, &processed_chars) != 1) return 0; val->format = vpiStringVal; @@ -473,8 +483,7 @@ static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) PLI_UINT32 fd; FILE *fp; char *text; - const int BUF_SIZE = 1024; - char buf[BUF_SIZE]; + char buf[STRING_BUF_SIZE]; /* Get the file descriptor. */ arg = vpi_scan(argv); @@ -496,7 +505,7 @@ static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) } /* Read in the bytes. Return 0 if there was an error. */ - if(fgets(buf, BUF_SIZE, fp) == 0) { + if(fgets(buf, STRING_BUF_SIZE, fp) == 0) { show_error_line(callh); vpi_printf("%s reading past the end of file.\n", name); @@ -509,7 +518,7 @@ static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) show_error_line(callh); vpi_printf("%s read 0 bytes.\n", name); return 0; - } else if(len == BUF_SIZE - 1) { + } else if(len == STRING_BUF_SIZE - 1) { show_warning_line(callh); vpi_printf("%s has reached the buffer limit, part of the " "processed string might have been skipped.\n", name); @@ -625,19 +634,15 @@ static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle stringh, varh, formath; s_vpi_value val; - PLI_INT32 type, format; + PLI_INT32 type, format, dest_size; char *string = 0; - int processed_chars = 0, fail = 0; + unsigned int processed_chars = 0, fail = 0; /* Get the string */ stringh = vpi_scan(argv); val.format = vpiStringVal; vpi_get_value(stringh, &val); - /* Get the destination variable */ - varh = vpi_scan(argv); - type = vpi_get(vpiType, varh); - if(strlen(val.value.str) == 0) { show_error_line(callh); vpi_printf("%s cannot read from an empty string.\n", name); @@ -646,6 +651,11 @@ static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) string = strdup(val.value.str); + /* Get the destination variable */ + varh = vpi_scan(argv); + type = vpi_get(vpiType, varh); + dest_size = vpi_get(vpiSize, varh); + /* Get the format (see enum format_t) */ formath = vpi_scan(argv); val.format = vpiIntVal; @@ -679,7 +689,7 @@ static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) break; case vpiStringVar: - processed_chars = read_string(string, &val); + processed_chars = read_string(string, &val, dest_size / 8); break; default: @@ -719,7 +729,7 @@ static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) break; case FORMAT_STRING: - processed_chars = read_string(string, &val); + processed_chars = read_string(string, &val, dest_size / 8); break; } @@ -727,7 +737,7 @@ static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) show_error_line(callh); vpi_printf("%s could not read a valid value.\n", name); fail = 1; - } else if(val.format == vpiStringVar && processed_chars == 1024) { + } else if(val.format == vpiStringVar && processed_chars == STRING_BUF_SIZE) { show_warning_line(callh); vpi_printf("%s has reached the buffer limit, part of the " "processed string might have been skipped.\n", name); @@ -815,9 +825,8 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_value val; PLI_INT32 type, format; char *string = 0; - int fail = 0, res = 0; - const int BUF_SIZE = 1024; - char buf[BUF_SIZE]; + unsigned int fail = 0, res = 0; + char buf[STRING_BUF_SIZE]; /* Get the string */ stringh = vpi_scan(argv); @@ -869,7 +878,7 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) case vpiIntegerVar: val.format = vpiIntVal; vpi_get_value(varh, &val); - res = snprintf(buf, BUF_SIZE, "%s%d", string, val.value.integer); + res = snprintf(buf, STRING_BUF_SIZE, "%s%d", string, val.value.integer); break; case vpiBitVar: /* bit, bit vector */ @@ -881,19 +890,19 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) for(size_t i = 0; i< strlen(val.value.str); ++i) val.value.str[i] = toupper(val.value.str[i]); - res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str); + res = snprintf(buf, STRING_BUF_SIZE, "%s%s", string, val.value.str); break; case vpiRealVar: val.format = vpiRealVal; vpi_get_value(varh, &val); - res = snprintf(buf, BUF_SIZE, "%s%lf", string, val.value.real); + res = snprintf(buf, STRING_BUF_SIZE, "%s%lf", string, val.value.real); break; case vpiStringVar: val.format = vpiStringVal; vpi_get_value(varh, &val); - res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str); + res = snprintf(buf, STRING_BUF_SIZE, "%s%s", string, val.value.str); break; default: @@ -907,7 +916,7 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) case FORMAT_BOOL: val.format = vpiIntVal; vpi_get_value(varh, &val); - res = snprintf(buf, BUF_SIZE, "%s%s", string, + res = snprintf(buf, STRING_BUF_SIZE, "%s%s", string, val.value.integer ? "TRUE" : "FALSE"); break; @@ -923,29 +932,29 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) break; } - res = snprintf(buf, BUF_SIZE, "%s%s", string, tmp); + res = snprintf(buf, STRING_BUF_SIZE, "%s%s", string, tmp); } break; case FORMAT_HEX: val.format = vpiIntVal; vpi_get_value(varh, &val); - res = snprintf(buf, BUF_SIZE, "%s%X", string, val.value.integer); + res = snprintf(buf, STRING_BUF_SIZE, "%s%X", string, val.value.integer); break; case FORMAT_STRING: val.format = vpiStringVal; vpi_get_value(varh, &val); - res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str); + res = snprintf(buf, STRING_BUF_SIZE, "%s%s", string, val.value.str); break; } - if(res > BUF_SIZE) + if(res > STRING_BUF_SIZE) fail = 1; if(!fail) { /* Strip the read token from the string */ - char* tmp = strndup(buf, BUF_SIZE); + char* tmp = strndup(buf, STRING_BUF_SIZE); val.format = vpiStringVal; val.value.str = tmp; vpi_put_value(stringh, &val, 0, vpiNoDelay); From 41a45a8db0aed728d9dfb5bdfd29528c6447f75b Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 29 Feb 2016 13:53:56 +0100 Subject: [PATCH 73/76] vhdlpp: Avoid unnecessary toupper() call. --- vpi/vhdl_textio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vpi/vhdl_textio.c b/vpi/vhdl_textio.c index fc6411b9a..7235d316c 100644 --- a/vpi/vhdl_textio.c +++ b/vpi/vhdl_textio.c @@ -92,7 +92,7 @@ static int set_vec_val(s_vpi_vecval* vector, char value, int idx) { s_vpi_vecval*v = &vector[idx / BPW]; PLI_INT32 bit = idx % BPW; - switch(toupper(value)) { + switch(value) { case '0': v->bval &= ~(1 << bit); v->aval &= ~(1 << bit); @@ -103,11 +103,13 @@ static int set_vec_val(s_vpi_vecval* vector, char value, int idx) { v->aval |= (1 << bit); break; + case 'z': case 'Z': v->bval |= (1 << bit); v->aval &= ~(1 << bit); break; + case 'x': case 'X': v->bval |= (1 << bit); v->aval |= (1 << bit); From c25be111a35e5d4cbcd2301f0827e0ae031d9f34 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 29 Feb 2016 16:48:10 +0100 Subject: [PATCH 74/76] vhdlpp: Apply case equality operator for logic type. --- vhdlpp/expression_emit.cc | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index a66ee5e72..f490cf4dd 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -888,9 +888,21 @@ int ExpRelation::emit(ostream&out, Entity*ent, ScopeBase*scope) const int errors = 0; errors += emit_operand1(out, ent, scope); + const VType*type1 = peek_operand1()->probe_type(ent, scope); + const VType*type2 = peek_operand2()->probe_type(ent, scope); + bool logical_compare = false; + + // Apply case equality operator if any of the operands is of logic type + if(((type1 && (type1->type_match(&primitive_STDLOGIC) || + type1->type_match(&primitive_STDLOGIC_VECTOR))) + || (type2 && (type2->type_match(&primitive_STDLOGIC) || + type2->type_match(&primitive_STDLOGIC_VECTOR))))) { + logical_compare = true; + } + switch (fun_) { case EQ: - out << " == "; + out << (logical_compare ? " === " : " == "); break; case LT: out << " < "; @@ -899,7 +911,7 @@ int ExpRelation::emit(ostream&out, Entity*ent, ScopeBase*scope) const out << " > "; break; case NEQ: - out << " != "; + out << (logical_compare ? " !== " : " != "); break; case LE: out << " <= "; From 770906ba0db3c6567dbbc379c5634078257643dd Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 1 Mar 2016 11:45:12 +0100 Subject: [PATCH 75/76] vhdlpp: Write binary constants as a string of bits. --- vpi/vhdl_textio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vpi/vhdl_textio.c b/vpi/vhdl_textio.c index 7235d316c..3892ef5b7 100644 --- a/vpi/vhdl_textio.c +++ b/vpi/vhdl_textio.c @@ -861,11 +861,14 @@ static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) break; case vpiDecConst: - case vpiBinaryConst: case vpiOctConst: case vpiHexConst: type = vpiIntVar; break; + + case vpiBinaryConst: + type = vpiBitVar; + break; } } From de775975e8d846c2a591a7889dd26c96b76acbc3 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 1 Mar 2016 16:17:07 +0100 Subject: [PATCH 76/76] ivl: Fixed slice base calculation when range is rising (e.g. logic [0:3] arr) or when it starts with a non-zero integer (e.g. logic [4:1] arr). --- netmisc.cc | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/netmisc.cc b/netmisc.cc index 81ad82488..5a36e124d 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -248,6 +248,25 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr) return res; } +/* + * Subtract a signed constant from an existing expression. + */ +static NetExpr* make_sub_expr(NetExpr*expr, long val) +{ + verinum val_v (val, expr->expr_width()); + val_v.has_sign(true); + + NetEConst*val_c = new NetEConst(val_v); + val_c->set_line(*expr); + + NetEBAdd*res = new NetEBAdd('-', expr, val_c, expr->expr_width(), + expr->has_sign()); + res->set_line(*expr); + + return res; +} + + /* * Multiple an existing expression by a signed positive number. * This does a lossless multiply, so the arguments will need to be @@ -434,17 +453,26 @@ NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, -- pcur; } - long sb; - if (pcur->get_msb() >= pcur->get_lsb()) - sb = pcur->get_lsb(); - else - sb = pcur->get_msb(); - + long sb = min(pcur->get_lsb(), pcur->get_msb()); long loff; reg->sb_to_slice(indices, sb, loff, lwid); + bool idx_incr = pcur->get_msb() < pcur->get_lsb(); + + if(pcur->get_lsb() != 0) { + // Adjust the base for the case when the array range does not start from 0 + if(idx_incr) + base = make_sub_expr(pcur->get_lsb(), base); + else + base = make_sub_expr(base, pcur->get_lsb()); + } + base = make_mult_expr(base, lwid); - base = make_add_expr(base, loff); + + // TODO I do not see any influence of the lines below to the test suite + if(!idx_incr) + base = make_add_expr(base, loff); + return base; }