vhdlpp: Improved conditional assignments.

Now they handle expressions without the final 'else'.
This commit is contained in:
Maciej Suminski 2016-01-22 10:20:03 +01:00
parent 19a187fa90
commit daed47eb45
7 changed files with 160 additions and 12 deletions

View File

@ -178,6 +178,21 @@ SignalAssignment::~SignalAssignment()
delete lval_;
}
CondSignalAssignment::CondSignalAssignment(ExpName*target, std::list<ExpConditional::case_t*>&options)
: lval_(target)
{
options_.splice(options_.end(), options);
}
CondSignalAssignment::~CondSignalAssignment()
{
delete lval_;
for(list<ExpConditional::case_t*>::iterator it = options_.begin();
it != options_.end(); ++it) {
delete *it;
}
}
ComponentInstantiation::ComponentInstantiation(perm_string i, perm_string c,
list<named_expr_t*>*parms,
list<named_expr_t*>*ports)

View File

@ -189,6 +189,25 @@ class SignalAssignment : public Architecture::Statement {
std::list<Expression*> rval_;
};
class CondSignalAssignment : public Architecture::Statement {
public:
CondSignalAssignment(ExpName*target, std::list<ExpConditional::case_t*>&options);
~CondSignalAssignment();
int elaborate(Entity*ent, Architecture*arc);
int emit(ostream&out, Entity*entity, Architecture*arc);
void dump(ostream&out, int ident =0) const;
private:
ExpName*lval_;
std::list<ExpConditional::case_t*> options_;
// List of signals that should be emitted in the related process
// sensitivity list. It is filled during the elaboration step.
std::list<const ExpName*>sens_list_;
};
class ComponentInstantiation : public Architecture::Statement {
public:

View File

@ -95,6 +95,18 @@ void SignalAssignment::dump(ostream&out, int indent) const
}
}
void CondSignalAssignment::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "CondSignalAssignment file=" << get_fileline() << endl;
lval_->dump(out, indent+1);
out << setw(indent+2) << "" << "<= <expr>..." << endl;
for(list<ExpConditional::case_t*>::const_iterator it = options_.begin();
it != options_.end(); ++it) {
(*it)->dump(out, indent+2);
}
}
void StatementList::dump(ostream&out, int indent) const
{
out << setw(indent+3) << "" << "sequence of statements:" << endl;

View File

@ -353,3 +353,48 @@ int SignalAssignment::elaborate(Entity*ent, Architecture*arc)
return errors;
}
int CondSignalAssignment::elaborate(Entity*ent, Architecture*arc)
{
int errors = 0;
// Visitor to extract signal names occuring in the conditional
// statements to create the sensitivity list
struct name_extractor_t : public ExprVisitor {
name_extractor_t(list<const ExpName*>& name_list)
: name_list_(name_list) {}
void operator() (Expression*s) {
if(const ExpName*name = dynamic_cast<const ExpName*>(s))
name_list_.push_back(name);
}
private:
list<const ExpName*>& name_list_;
} name_extractor(sens_list_);
// Elaborate the l-value expression.
errors += lval_->elaborate_lval(ent, arc, true);
// The elaborate_lval should have resolved the type of the
// l-value expression. We'll use that type to elaborate the
// r-value.
const VType*lval_type = lval_->peek_type();
if (lval_type == 0) {
if (errors == 0) {
errors += 1;
cerr << get_fileline()
<< ": error: Unable to calculate type for l-value expression."
<< endl;
}
return errors;
}
for(list<ExpConditional::case_t*>::iterator it = options_.begin();
it != options_.end(); ++it) {
ExpConditional::case_t*cas = (*it);
cas->elaborate_expr(ent, arc, lval_type);
cas->visit(name_extractor);
}
return errors;
}

View File

@ -150,6 +150,56 @@ int SignalAssignment::emit(ostream&out, Entity*ent, Architecture*arc)
return errors;
}
int CondSignalAssignment::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
out << "// " << get_fileline() << endl;
out << "always @(";
bool first = true;
for(list<const ExpName*>::const_iterator it = sens_list_.begin();
it != sens_list_.end(); ++it) {
if(first)
first = false;
else
out << ",";
errors += (*it)->emit(out, ent, arc);
}
out << ") begin" << endl;
first = true;
for(list<ExpConditional::case_t*>::iterator it = options_.begin();
it != options_.end(); ++it) {
ExpConditional::case_t*cas = *it;
ivl_assert(*this, cas->true_clause().size() == 1);
const Expression*rval = cas->true_clause().front();
if(first)
first = false;
else
out << "else ";
if(Expression*cond = cas->condition()) {
out << "if(";
cond->emit(out, ent, arc);
out << ") ";
}
out << endl;
lval_->emit(out, ent, arc);
out << " = ";
rval->emit(out, ent, arc);
out << ";" << endl;
}
out << "end" << endl;
return errors;
}
int ComponentInstantiation::emit(ostream&out, Entity*ent, Architecture*arc)
{
const char*comma = "";

View File

@ -509,8 +509,9 @@ class ExpConditional : public Expression {
case_t(const case_t&other);
~case_t();
inline Expression*condition() { return cond_; }
inline Expression*condition() const { return cond_; }
inline void set_condition(Expression*cond) { cond_ = cond; }
inline const std::list<Expression*>& true_clause() const { return true_clause_; }
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*lt);
int emit_option(ostream&out, Entity*ent, ScopeBase*scope) const;

View File

@ -377,7 +377,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
%type <elsif_list> if_statement_elsif_list if_statement_elsif_list_opt
%type <exp_options> else_when_waveform selected_waveform
%type <exp_options_list> else_when_waveforms selected_waveform_list
%type <exp_options_list> else_when_waveforms else_when_waveforms_opt selected_waveform_list
%type <subprogram> function_specification procedure_specification
%type <subprogram> subprogram_specification subprogram_body_start
@ -787,18 +787,18 @@ concurrent_assertion_statement
create Expression objects for it, but the parser will only
recognize it it in specific situations. */
concurrent_conditional_signal_assignment /* IEEE 1076-2008 P11.6 */
: name LEQ waveform K_when expression else_when_waveforms ';'
{ ExpConditional*tmp = new ExpConditional($5, $3, $6);
FILE_NAME(tmp, @3);
delete $3;
delete $6;
: name LEQ waveform K_when expression else_when_waveforms_opt ';'
{ std::list<ExpConditional::case_t*>*options;
options = $6 ? $6 : new std::list<ExpConditional::case_t*>;
options->push_front(new ExpConditional::case_t($5, $3));
ExpName*name = dynamic_cast<ExpName*> ($1);
assert(name);
SignalAssignment*tmpa = new SignalAssignment(name, tmp);
FILE_NAME(tmpa, @1);
ExpName*name = dynamic_cast<ExpName*>($1);
assert(name);
CondSignalAssignment*tmp = new CondSignalAssignment(name, *options);
$$ = tmpa;
FILE_NAME(tmp, @1);
delete options;
$$ = tmp;
}
/* Error recovery rules. */
@ -842,6 +842,12 @@ else_when_waveforms
}
;
else_when_waveforms_opt
: else_when_waveforms { $$ = $1; }
| { $$ = 0; }
;
else_when_waveform
: K_else waveform K_when expression
{ ExpConditional::case_t*tmp = new ExpConditional::case_t($4, $2);