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 39e853a71..b0ccefc5e 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) @@ -628,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 @@ -991,29 +1020,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; 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; } diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 146f984ac..9e60453b1 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); @@ -1570,10 +1590,17 @@ mode_opt : mode {$$ = $1;} | {$$ = PORT_NONE;} ; name /* IEEE 1076-2008 P8.1 */ : IDENTIFIER /* simple_name (IEEE 1076-2008 P8.2) */ - { ExpName*tmp = new ExpName(lex_strings.make($1)); - FILE_NAME(tmp, @1); - delete[]$1; - $$ = tmp; + { Expression*tmp; + if(!strcasecmp($1, "true")) + tmp = new ExpBitstring("1"); + else if(!strcasecmp($1, "false")) + tmp = new ExpBitstring("0"); + else + tmp = new ExpName(lex_strings.make($1)); + + FILE_NAME(tmp, @1); + delete[]$1; + $$ = tmp; } | selected_name @@ -1807,6 +1834,7 @@ primary delete[]$1; $$ = tmp; } + /*XXXX Caught up in element_association_list? | '(' expression ')' { $$ = $2; } @@ -2029,6 +2057,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 +2172,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 +2182,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); +}