vhdlpp: Support for reports & asserts.
This commit is contained in:
parent
6df2979998
commit
5438464d67
|
|
@ -260,6 +260,8 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
||||||
Architecture::Statement* arch_statement;
|
Architecture::Statement* arch_statement;
|
||||||
std::list<Architecture::Statement*>* arch_statement_list;
|
std::list<Architecture::Statement*>* arch_statement_list;
|
||||||
|
|
||||||
|
ReportStmt::severity_t severity;
|
||||||
|
|
||||||
Subprogram*subprogram;
|
Subprogram*subprogram;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -349,6 +351,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
||||||
%type <text> architecture_body_start package_declaration_start
|
%type <text> architecture_body_start package_declaration_start
|
||||||
%type <text> package_body_start
|
%type <text> package_body_start
|
||||||
%type <text> identifier_opt identifier_colon_opt logical_name suffix instantiated_unit
|
%type <text> identifier_opt identifier_colon_opt logical_name suffix instantiated_unit
|
||||||
|
|
||||||
%type <name_list> logical_name_list identifier_list
|
%type <name_list> logical_name_list identifier_list
|
||||||
%type <name_list> enumeration_literal_list enumeration_literal
|
%type <name_list> enumeration_literal_list enumeration_literal
|
||||||
|
|
||||||
|
|
@ -356,7 +359,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
||||||
%type <sequ> sequential_statement if_statement signal_assignment signal_assignment_statement
|
%type <sequ> sequential_statement if_statement signal_assignment signal_assignment_statement
|
||||||
%type <sequ> case_statement procedure_call procedure_call_statement
|
%type <sequ> case_statement procedure_call procedure_call_statement
|
||||||
%type <sequ> loop_statement variable_assignment variable_assignment_statement
|
%type <sequ> loop_statement variable_assignment variable_assignment_statement
|
||||||
%type <sequ> return_statement
|
%type <sequ> assertion_statement report_statement return_statement
|
||||||
|
|
||||||
%type <range> range
|
%type <range> range
|
||||||
%type <range_list> range_list index_constraint
|
%type <range_list> range_list index_constraint
|
||||||
|
|
@ -371,6 +374,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
||||||
%type <exp_else_list> else_when_waveforms
|
%type <exp_else_list> else_when_waveforms
|
||||||
|
|
||||||
%type <subprogram> function_specification subprogram_specification subprogram_body_start
|
%type <subprogram> function_specification subprogram_specification subprogram_body_start
|
||||||
|
%type <severity> severity severity_opt
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
|
@ -433,6 +437,22 @@ architecture_statement_part
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
assertion_statement
|
||||||
|
: K_assert expression report_statement
|
||||||
|
{ ReportStmt*report = dynamic_cast<ReportStmt*>($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
|
association_element
|
||||||
: IDENTIFIER ARROW expression
|
: IDENTIFIER ARROW expression
|
||||||
{ named_expr_t*tmp = new named_expr_t(lex_strings.make($1), $3);
|
{ 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
|
return_statement
|
||||||
: K_return expression ';'
|
: K_return expression ';'
|
||||||
{ ReturnStmt*tmp = new ReturnStmt($2);
|
{ ReturnStmt*tmp = new ReturnStmt($2);
|
||||||
|
|
@ -2136,6 +2164,8 @@ sequential_statement
|
||||||
| procedure_call_statement { $$ = $1; }
|
| procedure_call_statement { $$ = $1; }
|
||||||
| loop_statement { $$ = $1; }
|
| loop_statement { $$ = $1; }
|
||||||
| return_statement { $$ = $1; }
|
| return_statement { $$ = $1; }
|
||||||
|
| report_statement { $$ = $1; }
|
||||||
|
| assertion_statement { $$ = $1; }
|
||||||
| K_null ';' { $$ = 0; }
|
| K_null ';' { $$ = 0; }
|
||||||
| error ';'
|
| error ';'
|
||||||
{ errormsg(@1, "Syntax error in sequential statement.\n");
|
{ 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
|
shift_expression
|
||||||
: simple_expression
|
: simple_expression
|
||||||
| simple_expression K_srl simple_expression
|
| simple_expression K_srl simple_expression
|
||||||
|
|
|
||||||
|
|
@ -263,3 +263,24 @@ BasicLoopStatement::BasicLoopStatement(perm_string lname, list<SequentialStmt*>*
|
||||||
BasicLoopStatement::~BasicLoopStatement()
|
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.");
|
||||||
|
|
|
||||||
|
|
@ -273,4 +273,39 @@ class BasicLoopStatement : public LoopStatement {
|
||||||
void dump(ostream&out, int indent) const;
|
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 */
|
#endif /* IVL_sequential_H */
|
||||||
|
|
|
||||||
|
|
@ -165,3 +165,18 @@ void BasicLoopStatement::dump(ostream&out, int indent) const
|
||||||
out << setw(indent) << "" << "BasicLoopStatement at file=" << get_fileline() << endl;
|
out << setw(indent) << "" << "BasicLoopStatement at file=" << get_fileline() << endl;
|
||||||
LoopStatement::dump(out, indent+2);
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,3 +192,8 @@ int BasicLoopStatement::elaborate(Entity*, ScopeBase*)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AssertStmt::elaborate(Entity*ent, ScopeBase*scope)
|
||||||
|
{
|
||||||
|
return cond_->elaborate_expr(ent, scope, 0);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -451,3 +451,64 @@ int ForLoopStatement::emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
|
|
||||||
return errors;
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue