Merge pull request #61 from orsonmmz/asserts

Asserts
This commit is contained in:
Stephen Williams 2015-05-13 09:56:27 -07:00
commit 0082795967
9 changed files with 263 additions and 46 deletions

View File

@ -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();

View File

@ -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;

View File

@ -105,9 +105,10 @@ bool ExpAttribute::evaluate(ScopeBase*scope, int64_t&val) const
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(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<const VTypeArray*>(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;
}

View File

@ -260,6 +260,8 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
Architecture::Statement* arch_statement;
std::list<Architecture::Statement*>* arch_statement_list;
ReportStmt::severity_t severity;
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> package_body_start
%type <text> identifier_opt identifier_colon_opt logical_name suffix instantiated_unit
%type <name_list> logical_name_list identifier_list
%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> case_statement procedure_call procedure_call_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_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 <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
: 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

View File

@ -263,3 +263,24 @@ BasicLoopStatement::BasicLoopStatement(perm_string lname, list<SequentialStmt*>*
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.");

View File

@ -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 */

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}