diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index 2f1cea235..b8eecea85 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -178,6 +178,21 @@ SignalAssignment::~SignalAssignment() delete lval_; } +CondSignalAssignment::CondSignalAssignment(ExpName*target, std::list&options) +: lval_(target) +{ + options_.splice(options_.end(), options); +} + +CondSignalAssignment::~CondSignalAssignment() +{ + delete lval_; + for(list::iterator it = options_.begin(); + it != options_.end(); ++it) { + delete *it; + } +} + ComponentInstantiation::ComponentInstantiation(perm_string i, perm_string c, list*parms, list*ports) diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index d33a33e57..221092aa8 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -189,6 +189,25 @@ class SignalAssignment : public Architecture::Statement { std::list rval_; }; +class CondSignalAssignment : public Architecture::Statement { + + public: + CondSignalAssignment(ExpName*target, std::list&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 options_; + + // List of signals that should be emitted in the related process + // sensitivity list. It is filled during the elaboration step. + std::listsens_list_; +}; + class ComponentInstantiation : public Architecture::Statement { public: diff --git a/vhdlpp/architec_debug.cc b/vhdlpp/architec_debug.cc index 630da357c..1a42aea28 100644 --- a/vhdlpp/architec_debug.cc +++ b/vhdlpp/architec_debug.cc @@ -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) << "" << "<= ..." << endl; + + for(list::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; diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index cfedeb467..472ec317b 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -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& name_list) + : name_list_(name_list) {} + void operator() (Expression*s) { + if(const ExpName*name = dynamic_cast(s)) + name_list_.push_back(name); + } + + private: + list& 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::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; +} diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 60b0dfac4..42e5e2c5c 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -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_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::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 = ""; diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index cb66a8286..85703ce42 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -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& 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; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index b1d4aeb85..5bd0e3977 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -377,7 +377,7 @@ static void touchup_interface_for_functions(std::list*ports) %type if_statement_elsif_list if_statement_elsif_list_opt %type else_when_waveform selected_waveform -%type else_when_waveforms selected_waveform_list +%type else_when_waveforms else_when_waveforms_opt selected_waveform_list %type function_specification procedure_specification %type 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*options; + options = $6 ? $6 : new std::list; + options->push_front(new ExpConditional::case_t($5, $3)); - ExpName*name = dynamic_cast ($1); - assert(name); - SignalAssignment*tmpa = new SignalAssignment(name, tmp); - FILE_NAME(tmpa, @1); + ExpName*name = dynamic_cast($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);