From cfa43c7742191502c73a2940e5c96f7a9a977803 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 22 Apr 2015 18:02:53 +0200 Subject: [PATCH] vhdlpp: Support for reports & asserts. --- vhdlpp/lexor_keyword.gperf | 4 +++ vhdlpp/parse.y | 51 +++++++++++++++++++++++++--- vhdlpp/sequential.cc | 21 ++++++++++++ vhdlpp/sequential.h | 35 +++++++++++++++++++ vhdlpp/sequential_debug.cc | 15 +++++++++ vhdlpp/sequential_elaborate.cc | 5 +++ vhdlpp/sequential_emit.cc | 61 ++++++++++++++++++++++++++++++++++ 7 files changed, 187 insertions(+), 5 deletions(-) diff --git a/vhdlpp/lexor_keyword.gperf b/vhdlpp/lexor_keyword.gperf index 42fd1bc0d..1b086f147 100644 --- a/vhdlpp/lexor_keyword.gperf +++ b/vhdlpp/lexor_keyword.gperf @@ -45,7 +45,9 @@ else, GN_KEYWORD_2008, K_else elsif, GN_KEYWORD_2008, K_elsif end, GN_KEYWORD_2008, K_end entity, GN_KEYWORD_2008, K_entity +error, GN_KEYWORD_2008, K_error exit, GN_KEYWORD_2008, K_exit +failure, GN_KEYWORD_2008, K_failure fairness, GN_KEYWORD_2008, K_fairness file, GN_KEYWORD_2008, K_file for, GN_KEYWORD_2008, K_for @@ -73,6 +75,7 @@ new, GN_KEYWORD_2008, K_new next, GN_KEYWORD_2008, K_next nor, GN_KEYWORD_2008, K_nor not, GN_KEYWORD_2008, K_not +note, GN_KEYWORD_2008, K_note null, GN_KEYWORD_2008, K_null of, GN_KEYWORD_2008, K_of on, GN_KEYWORD_2008, K_on @@ -124,6 +127,7 @@ vmode, GN_KEYWORD_2008, K_vmode vprop, GN_KEYWORD_2008, K_vprop vunit, GN_KEYWORD_2008, K_vunit wait, GN_KEYWORD_2008, K_wait +warning, GN_KEYWORD_2008, K_warning when, GN_KEYWORD_2008, K_when while, GN_KEYWORD_2008, K_while with, GN_KEYWORD_2008, K_with diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 146f984ac..40121df37 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; }; @@ -269,13 +271,13 @@ static void touchup_interface_for_functions(std::list*ports) %token K_begin K_block K_body K_buffer K_bus %token K_case K_component K_configuration K_constant K_context K_cover %token K_default K_disconnect K_downto -%token K_else K_elsif K_end K_entity K_exit -%token K_fairness K_file K_for K_force K_function +%token K_else K_elsif K_end K_entity K_error K_exit +%token K_failure K_fairness K_file K_for K_force K_function %token K_generate K_generic K_group K_guarded %token K_if K_impure K_in K_inertial K_inout K_is %token K_label K_library K_linkage K_literal K_loop %token K_map K_mod -%token K_nand K_new K_next K_nor K_not K_null +%token K_nand K_new K_next K_nor K_not K_note K_null %token K_of K_on K_open K_or K_others K_out %token K_package K_parameter K_port K_postponed K_procedure K_process %token K_property K_protected K_pure @@ -286,7 +288,7 @@ static void touchup_interface_for_functions(std::list*ports) %token K_then K_to K_transport K_type %token K_unaffected K_units K_until K_use %token K_variable K_vmode K_vprop K_vunit -%token K_wait K_when K_while K_with +%token K_wait K_warning K_when K_while K_with %token K_xnor K_xor /* Identifiers that are not keywords are identifiers. */ %token IDENTIFIER @@ -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,17 @@ sequential_statement } ; +severity + : K_severity K_note { $$ = ReportStmt::NOTE; } + | K_severity K_warning { $$ = ReportStmt::WARNING; } + | K_severity K_error { $$ = ReportStmt::ERROR; } + | K_severity K_failure { $$ = ReportStmt::FAILURE; } + ; + +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); +}