From 9de4ced133e79d4d6e918c95e145bd8de8c5cb4f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 20 Apr 2015 10:57:49 +0200 Subject: [PATCH 1/7] vhdlpp: Stop compilation on invalid attributes. --- vhdlpp/expression_evaluate.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 983c0ed6b..b67cbd5da 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -105,9 +105,10 @@ bool ExpAttribute::evaluate(ScopeBase*scope, int64_t&val) const const VTypeArray*arr = dynamic_cast(base_type); if (arr == 0) { - cerr << get_fileline() << ": error: " + cerr << endl << get_fileline() << ": error: " << "Cannot apply the 'length attribute to non-array objects" << endl; + ivl_assert(*this, false); return false; } @@ -145,9 +146,10 @@ bool ExpAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const const VTypeArray*arr = dynamic_cast(base_type); if (arr == 0) { - cerr << get_fileline() << ": error: " + cerr << endl << get_fileline() << ": error: " << "Cannot apply the '" << name_ << " attribute to non-array objects" << endl; + ivl_assert(*this, false); return false; } From 6df297999821dff1b5405094f67d5938b152f496 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 20 Apr 2015 22:36:14 +0200 Subject: [PATCH 2/7] vhdlpp: Added missing std_logic values in ExpChar and ExpString::emit(). --- vhdlpp/expression_emit.cc | 81 ++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 39e853a71..98b0ebe5c 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -34,6 +34,33 @@ using namespace std; +inline static int emit_logic(char val, ostream& out, const VTypePrimitive::type_t type) +{ +// TODO case 'W': case 'L': case 'H': + + switch (val) { + case '-': case 'U': + val = 'x'; + /* fall through */ + + case 'X': case 'Z': + assert(type == VTypePrimitive::STDLOGIC); + /* fall through */ + + case '0': + case '1': + out << (char) tolower(val); + break; + + default: + assert(false); + out << "x"; + return 1; + } + + return 0; +} + int Expression::emit(ostream&out, Entity*, ScopeBase*) { out << " /* " << get_fileline() << ": internal error: " @@ -396,23 +423,15 @@ int ExpBitstring::emit(ostream&out, Entity*, ScopeBase*) int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, ScopeBase*, const VTypePrimitive*etype) { - switch (etype->type()) { - case VTypePrimitive::BOOLEAN: - case VTypePrimitive::BIT: - case VTypePrimitive::STDLOGIC: - switch (value_) { - case '0': - case '1': - out << "1'b" << value_; - return 0; - default: - break; - } + out << "1'b"; + int res = emit_logic(value_, out, etype->type()); - default: - return 1; - } - return 1; + if(res) + cerr << get_fileline() << ": internal error: " + << "Don't know how to handle bit " << value_ + << " with etype==" << etype->type() << endl; + + return res; } int ExpCharacter::emit(ostream&out, Entity*ent, ScopeBase*scope) @@ -991,29 +1010,13 @@ int ExpString::emit_as_array_(ostream& out, Entity*, ScopeBase*, const VTypeArra assert(etype->type() != VTypePrimitive::INTEGER); out << value_.size() << "'b"; for (size_t idx = 0 ; idx < value_.size() ; idx += 1) { - switch (value_[idx]) { - case '0': - out << "0"; - break; - case '1': - out << "1"; - break; - case 'z': case 'Z': - assert(etype->type() == VTypePrimitive::STDLOGIC); - out << "z"; - break; - case '-': - assert(etype->type() == VTypePrimitive::STDLOGIC); - out << "x"; - break; - default: - cerr << get_fileline() << ": internal error: " - << "Don't know how to handle bit " << value_[idx] - << " with etype==" << etype->type() << endl; - assert(etype->type() == VTypePrimitive::STDLOGIC); - out << "x"; - break; - } + int res = emit_logic(value_[idx], out, etype->type()); + errors += res; + + if(res) + cerr << get_fileline() << ": internal error: " + << "Don't know how to handle bit " << value_[idx] + << " with etype==" << etype->type() << endl; } return errors; From 5438464d67960cf081f958a8eb51f14e9056ff47 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 22 Apr 2015 18:02:53 +0200 Subject: [PATCH 3/7] vhdlpp: Support for reports & asserts. --- vhdlpp/parse.y | 52 ++++++++++++++++++++++++++++- vhdlpp/sequential.cc | 21 ++++++++++++ vhdlpp/sequential.h | 35 +++++++++++++++++++ vhdlpp/sequential_debug.cc | 15 +++++++++ vhdlpp/sequential_elaborate.cc | 5 +++ vhdlpp/sequential_emit.cc | 61 ++++++++++++++++++++++++++++++++++ 6 files changed, 188 insertions(+), 1 deletion(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 146f984ac..0e0c0ce1e 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -260,6 +260,8 @@ static void touchup_interface_for_functions(std::list*ports) Architecture::Statement* arch_statement; std::list* arch_statement_list; + ReportStmt::severity_t severity; + Subprogram*subprogram; }; @@ -349,6 +351,7 @@ static void touchup_interface_for_functions(std::list*ports) %type architecture_body_start package_declaration_start %type package_body_start %type identifier_opt identifier_colon_opt logical_name suffix instantiated_unit + %type logical_name_list identifier_list %type enumeration_literal_list enumeration_literal @@ -356,7 +359,7 @@ static void touchup_interface_for_functions(std::list*ports) %type sequential_statement if_statement signal_assignment signal_assignment_statement %type case_statement procedure_call procedure_call_statement %type loop_statement variable_assignment variable_assignment_statement -%type return_statement +%type assertion_statement report_statement return_statement %type range %type range_list index_constraint @@ -371,6 +374,7 @@ static void touchup_interface_for_functions(std::list*ports) %type else_when_waveforms %type function_specification subprogram_specification subprogram_body_start +%type severity severity_opt %% @@ -433,6 +437,22 @@ architecture_statement_part } ; +assertion_statement + : K_assert expression report_statement + { ReportStmt*report = dynamic_cast($3); + assert(report); + AssertStmt*tmp = new AssertStmt($2, report->message().c_str(), report->severity()); + delete report; + FILE_NAME(tmp,@2); + $$ = tmp; + } + | K_assert expression severity_opt ';' + { AssertStmt*tmp = new AssertStmt($2, NULL, $3); + FILE_NAME(tmp,@2); + $$ = tmp; + } + ; + association_element : IDENTIFIER ARROW expression { named_expr_t*tmp = new named_expr_t(lex_strings.make($1), $3); @@ -2029,6 +2049,14 @@ relation } ; +report_statement + : K_report STRING_LITERAL severity_opt ';' + { ReportStmt*tmp = new ReportStmt($2, $3); + FILE_NAME(tmp,@2); + delete[]$2; + $$ = tmp; + } + return_statement : K_return expression ';' { ReturnStmt*tmp = new ReturnStmt($2); @@ -2136,6 +2164,8 @@ sequential_statement | procedure_call_statement { $$ = $1; } | loop_statement { $$ = $1; } | return_statement { $$ = $1; } + | report_statement { $$ = $1; } + | assertion_statement { $$ = $1; } | K_null ';' { $$ = 0; } | error ';' { errormsg(@1, "Syntax error in sequential statement.\n"); @@ -2144,6 +2174,26 @@ sequential_statement } ; +severity + : K_severity IDENTIFIER + { if(!strcasecmp($2, "NOTE")) + $$ = ReportStmt::NOTE; + else if(!strcasecmp($2, "WARNING")) + $$ = ReportStmt::WARNING; + else if(!strcasecmp($2, "ERROR")) + $$ = ReportStmt::ERROR; + else if(!strcasecmp($2, "FAILURE")) + $$ = ReportStmt::FAILURE; + else { + errormsg(@1, "Invalid severity level (possible values: NOTE, WARNING, ERROR, FAILURE).\n"); + $$ = ReportStmt::UNSPECIFIED; + } + } + +severity_opt + : severity { $$ = $1; } + | { $$ = ReportStmt::UNSPECIFIED; } + shift_expression : simple_expression | simple_expression K_srl simple_expression diff --git a/vhdlpp/sequential.cc b/vhdlpp/sequential.cc index f6fe41d0d..95497a987 100644 --- a/vhdlpp/sequential.cc +++ b/vhdlpp/sequential.cc @@ -263,3 +263,24 @@ BasicLoopStatement::BasicLoopStatement(perm_string lname, list* BasicLoopStatement::~BasicLoopStatement() { } + +ReportStmt::ReportStmt(const char*msg, severity_t sev) +: msg_(msg), severity_(sev) +{ + if(sev == ReportStmt::UNSPECIFIED) + severity_ = ReportStmt::NOTE; +} + +AssertStmt::AssertStmt(Expression*condition, const char*msg, ReportStmt::severity_t sev) +: ReportStmt("", sev), cond_(condition) +{ + if(msg == NULL) + msg_ = default_msg_; + else + msg_ = std::string(msg); + + if(sev == ReportStmt::UNSPECIFIED) + severity_ = ReportStmt::ERROR; +} + +const std::string AssertStmt::default_msg_ = std::string("Assertion violation."); diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index c9f039fea..d561b0559 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -273,4 +273,39 @@ class BasicLoopStatement : public LoopStatement { void dump(ostream&out, int indent) const; }; +class ReportStmt : public SequentialStmt { + public: + typedef enum { UNSPECIFIED, NOTE, WARNING, ERROR, FAILURE } severity_t; + + ReportStmt(const char*message, severity_t severity = NOTE); + virtual ~ReportStmt() {} + + void dump(ostream&out, int indent) const; + int emit(ostream&out, Entity*entity, ScopeBase*scope); + void write_to_stream(std::ostream&fd); + + inline const std::string& message() const { return msg_; } + inline severity_t severity() const { return severity_; } + + protected: + std::string msg_; + severity_t severity_; +}; + +class AssertStmt : public ReportStmt { + public: + AssertStmt(Expression*condition, const char*message, ReportStmt::severity_t severity = ReportStmt::ERROR); + + void dump(ostream&out, int indent) const; + int elaborate(Entity*ent, ScopeBase*scope); + int emit(ostream&out, Entity*entity, ScopeBase*scope); + void write_to_stream(std::ostream&fd); + + private: + Expression*cond_; + + // Message displayed when there is no report assigned. + static const std::string default_msg_; +}; + #endif /* IVL_sequential_H */ diff --git a/vhdlpp/sequential_debug.cc b/vhdlpp/sequential_debug.cc index 31f3655d2..786fa5cc6 100644 --- a/vhdlpp/sequential_debug.cc +++ b/vhdlpp/sequential_debug.cc @@ -165,3 +165,18 @@ void BasicLoopStatement::dump(ostream&out, int indent) const out << setw(indent) << "" << "BasicLoopStatement at file=" << get_fileline() << endl; LoopStatement::dump(out, indent+2); } + +void ReportStmt::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "ReportStmt at file=" << get_fileline() << endl; + out << setw(indent+3) << "" << "severity: " << severity_ << endl; + out << setw(indent+3) << "" << "message: " << msg_ << endl; +} + +void AssertStmt::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "AssertStmt at file=" << get_fileline() << endl; + out << setw(indent+3) << "" << "condition: "; + cond_->dump(out, indent+3); + ReportStmt::dump(out, indent+3); +} diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 29b4e4914..2c342030b 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -192,3 +192,8 @@ int BasicLoopStatement::elaborate(Entity*, ScopeBase*) { return 0; } + +int AssertStmt::elaborate(Entity*ent, ScopeBase*scope) +{ + return cond_->elaborate_expr(ent, scope, 0); +} diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 895d1d839..29f488b80 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -451,3 +451,64 @@ int ForLoopStatement::emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope) return errors; } + +int ReportStmt::emit(ostream&out, Entity*, ScopeBase*) +{ + out << "$display(\""; + + switch(severity_) + { + case NOTE: out << "** Note: "; break; + case WARNING: out << "** Warning: "; break; + case ERROR: out << "** Error: "; break; + case FAILURE: out << "** Failure: "; break; + case UNSPECIFIED: ivl_assert(*this, false); break; + } + + out << msg_; + out << " (" << get_fileline() << ")\");"; + + if(severity_ == FAILURE) + out << "$finish();"; + + out << std::endl; + + return 0; +} + +void ReportStmt::write_to_stream(std::ostream&fd) +{ + fd << "report \"" << msg_ << "\"" << std::endl; + + fd << "severity "; + switch(severity_) + { + case NOTE: fd << "NOTE"; break; + case WARNING: fd << "WARNING"; break; + case ERROR: fd << "ERROR"; break; + case FAILURE: fd << "FAILURE"; break; + case UNSPECIFIED: break; + } + fd << ";" << std::endl; +} + +int AssertStmt::emit(ostream&out, Entity*ent, ScopeBase*scope) +{ + int errors = 0; + + out << "if(!("; + errors += cond_->emit(out, ent, scope); + out << ")) begin" << std::endl; + errors += ReportStmt::emit(out, ent, scope); + out << "end" << std::endl; + + return errors; +} + +void AssertStmt::write_to_stream(std::ostream&fd) +{ + fd << "assert "; + cond_->write_to_stream(fd); + fd << std::endl; + ReportStmt::write_to_stream(fd); +} From 4304fd503e52aaf85af6781ebd2ff7eadb08f7eb Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Thu, 23 Apr 2015 17:08:26 -0700 Subject: [PATCH 4/7] vhdlpp: and_reduce() and or_reduce() functions. --- vhdlpp/expression_elaborate.cc | 7 +++++++ vhdlpp/expression_emit.cc | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 30ddd4e2f..4c64ff186 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -877,6 +877,12 @@ const VType* ExpFunc::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*) c return new VTypeArray(element, width, 0, sign); } + if(name_ == "and_reduce" || name_ == "or_reduce") { + ivl_assert(*this, argv_.size() == 1); + const VType*element = &primitive_STDLOGIC; + return new VTypeArray(element, 0, 0, false); + } + // Other cases Subprogram*prog = def_; @@ -888,6 +894,7 @@ const VType* ExpFunc::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*) c if(!prog) prog = library_find_subprogram(name_); + cerr << get_fileline() << ": sorry: VHDL function " << name_ << " not yet implemented" << endl; ivl_assert(*this, prog); return def_->peek_return_type(); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 98b0ebe5c..b0ccefc5e 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -647,6 +647,16 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope) errors += argv_[0]->emit(out, ent, scope); out << ")"; + } else if (name_ == "and_reduce" && argv_.size() == 1) { + out << "&("; + errors += argv_[0]->emit(out, ent, scope); + out << ")"; + + } else if (name_ == "or_reduce" && argv_.size() == 1) { + out << "|("; + errors += argv_[0]->emit(out, ent, scope); + out << ")"; + } else { // If this function has an elaborated definition, and if // that definition is in a package, then include the From 08e5aa021a0fc7e814c1ccea0b9e913afb9bca47 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 6 May 2015 15:07:53 +0200 Subject: [PATCH 5/7] vhdlpp: Emits typedef for boolean type. --- vhdlpp/library.cc | 8 ++++++++ vhdlpp/library.h | 1 + vhdlpp/main.cc | 2 ++ vhdlpp/vtype_emit.cc | 2 ++ 4 files changed, 13 insertions(+) diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 61ae426df..87cf41fa2 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -409,6 +409,14 @@ void generate_global_types(ActiveScope*res) res->use_name(perm_string::literal("natural"), &primitive_NATURAL); } +void emit_std_types(ostream&out) +{ + out << "`ifndef __VHDL_STD_TYPES" << endl; + out << "`define __VHDL_STD_TYPES" << endl; + out << "typedef enum bit { \\false , \\true } boolean ;" << endl; + out << "`endif" << endl; +} + bool is_global_type(perm_string name) { if (name == "boolean") return true; diff --git a/vhdlpp/library.h b/vhdlpp/library.h index ab6464f45..fe04aad23 100644 --- a/vhdlpp/library.h +++ b/vhdlpp/library.h @@ -26,6 +26,7 @@ extern void library_add_directory(const char*directory); extern Subprogram*library_find_subprogram(perm_string name); +extern void emit_std_types(ostream&out); extern int emit_packages(void); #endif /* IVL_library_H */ diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index b142d3845..418e73daa 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -232,6 +232,8 @@ int main(int argc, char*argv[]) return 3; } + emit_std_types(cout); + errors = emit_packages(); if (errors > 0) { fprintf(stderr, "%d errors emitting packages.\n", errors); diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index 64577e004..bfce8e215 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -149,6 +149,8 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const int errors = 0; switch (type_) { case BOOLEAN: + out << "boolean"; + break; case BIT: out << "bool"; break; From e4694cb6cb0c0fecc029136e289d49adbca1aae7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 6 May 2015 15:59:00 +0200 Subject: [PATCH 6/7] vhdlpp: Changed emitted type from 'bool' to 'bit'. --- vhdlpp/library.cc | 2 +- vhdlpp/vtype_emit.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 87cf41fa2..fda670a34 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -404,7 +404,7 @@ void generate_global_types(ActiveScope*res) res->use_name(perm_string::literal("real"), &primitive_REAL); res->use_name(perm_string::literal("std_logic"), &primitive_STDLOGIC); res->use_name(perm_string::literal("character"), &primitive_CHARACTER); - res->use_name(perm_string::literal("bit_vector"),&primitive_BOOL_VECTOR); + res->use_name(perm_string::literal("bit_vector"),&primitive_BIT_VECTOR); res->use_name(perm_string::literal("string"), &primitive_STRING); res->use_name(perm_string::literal("natural"), &primitive_NATURAL); } diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index bfce8e215..b97d00d7e 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -152,7 +152,7 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const out << "boolean"; break; case BIT: - out << "bool"; + out << "bit"; break; case STDLOGIC: out << "logic"; From 7db01d8ded694e5bc3fc0bb82d14158ba187b873 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 7 May 2015 14:42:31 +0200 Subject: [PATCH 7/7] vhdlpp: ScopeBase::is_enum_name() returns VTypeEnum* instead of bool. --- vhdlpp/expression_elaborate.cc | 15 +++++++-------- vhdlpp/scope.cc | 6 +++--- vhdlpp/scope.h | 4 +++- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 4c64ff186..5f54fc66a 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -1027,19 +1027,18 @@ const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const if (Variable*var = scope->find_variable(name_)) return var->peek_type(); - const VType*ctype = 0; + const VType*type = 0; Expression*cval = 0; - if (scope->find_constant(name_, ctype, cval)) - return ctype; + if (scope->find_constant(name_, type, cval)) + return type; - const VType*gtype = 0; Architecture*arc = dynamic_cast(scope); - if (arc && (gtype = arc->probe_genvar_type(name_))) { - return gtype; + if (arc && (type = arc->probe_genvar_type(name_))) { + return type; } - if (scope->is_enum_name(name_)) { - return &primitive_INTEGER; + if ((type = scope->is_enum_name(name_))) { + return type; } } diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 0682a45d0..49b422e89 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -188,15 +188,15 @@ Subprogram* ScopeBase::find_subprogram(perm_string name) const return 0; } -bool ScopeBase::is_enum_name(perm_string name) const +const VTypeEnum* ScopeBase::is_enum_name(perm_string name) const { for(list::const_iterator it = use_enums_.begin(); it != use_enums_.end(); ++it) { if((*it)->has_name(name)) - return true; + return *it; } - return false; + return NULL; } /* diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 69e859fb9..709e552ec 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -58,7 +58,9 @@ class ScopeBase { Variable* find_variable(perm_string by_name) const; virtual const InterfacePort* find_param(perm_string by_name) const; Subprogram* find_subprogram(perm_string by_name) const; - bool is_enum_name(perm_string 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; // Moves signals, variables and components from another scope to // this one. After the transfer new_* maps are cleared in the source scope.