diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 2f506eb28..27baba7e7 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -112,10 +112,14 @@ bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const bool ExpAttribute::evaluate(Entity*ent, Architecture*arc, int64_t&val) const { + if (!ent || !arc) { // it's impossible to evaluate, probably it is inside a subprogram + return false; + } + if (name_ == "left" || name_ == "right") { const VType*base_type = base_->peek_type(); if (base_type == 0) - base_type = base_->probe_type(ent,arc); + base_type = base_->probe_type(ent, arc); ivl_assert(*this, base_type); @@ -130,7 +134,7 @@ bool ExpAttribute::evaluate(Entity*ent, Architecture*arc, int64_t&val) const ivl_assert(*this, arr->dimensions() == 1); if(name_ == "left") arr->dimension(0).msb()->evaluate(ent, arc, val); - else + else // "right" arr->dimension(0).lsb()->evaluate(ent, arc, val); return true; diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 9271e4ed3..51973d159 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -225,10 +225,14 @@ class ForLoopStatement : public LoopStatement { ~ForLoopStatement(); int elaborate(Entity*ent, Architecture*arc); - int emit(ostream&out, Entity*entity, Architecture*arc); + int emit(ostream&out, Entity*ent, Architecture*arc); void dump(ostream&out, int indent) const; private: + // Emits for-loop which direction is determined at run-time. + // It is used for 'range & 'reverse_range attributes. + int emit_runtime_(ostream&out, Entity*ent, Architecture*arc); + perm_string it_; prange_t* range_; }; diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 86a9a529c..3203eb704 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -200,76 +200,108 @@ int CaseSeqStmt::CaseStmtAlternative::emit(ostream&out, Entity*ent, Architecture int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc) { - int errors = 0; - ivl_assert(*this, range_); + int errors = 0; + ivl_assert(*this, range_); - int64_t start_val; - bool start_rc = range_->msb()->evaluate(ent, arc, start_val); + int64_t start_val; + bool start_rc = range_->msb()->evaluate(ent, arc, start_val); - int64_t finish_val; - bool finish_rc = range_->lsb()->evaluate(ent, arc, finish_val); + int64_t finish_val; + bool finish_rc = range_->lsb()->evaluate(ent, arc, finish_val); - ivl_assert(*this, start_rc); - ivl_assert(*this, finish_rc); + perm_string scope_name = loop_name(); + if (scope_name.nil()) { + char buf[80]; + snprintf(buf, sizeof buf, "__%p", this); + scope_name = lex_strings.make(buf); + } - bool dir = range_->is_downto(); + out << "begin : " << scope_name << endl; + out << "longint \\" << it_ << " ;" << endl; - if (!dir) { - int64_t tmp = start_val; - start_val = finish_val; - finish_val = tmp; - } + if(!start_rc || !finish_rc) { + // Could not evaluate one of the loop boundaries, it has to be + // determined during the run-time + errors += emit_runtime_(out, ent, arc); + } else { + bool dir = range_->is_downto(); - if (dir && (start_val < finish_val)) { - if(range_->is_auto_dir()) { - dir = false; - } else { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " downto " << finish_val << " */ end" << endl; - return errors; - } - } + if (!dir) { + int64_t tmp = start_val; + start_val = finish_val; + finish_val = tmp; + } - else if (!dir && start_val > finish_val) { - if(range_->is_auto_dir()) { - dir = true; - } else { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " to " << finish_val << " */ end" << endl; - return errors; - } - } + if (dir && (start_val < finish_val)) { + if(range_->is_auto_dir()) { + dir = false; + } else { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " downto " << finish_val << " */ end" << endl; + return errors; + } + } - perm_string scope_name = loop_name(); - if (scope_name.nil()) { - char buf[80]; - snprintf(buf, sizeof buf, "__%p", this); - scope_name = lex_strings.make(buf); - } + else if (!dir && start_val > finish_val) { + if(range_->is_auto_dir()) { + dir = true; + } else { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " to " << finish_val << " */ end" << endl; + return errors; + } + } - out << "begin : " << scope_name << endl; - out << "longint \\" << it_ << " ;" << endl; - out << "for (\\" << it_ << " = " << start_val << " ; "; - if (dir) - out << "\\" << it_ << " >= " << finish_val; - else - out << "\\" << it_ << " <= " << finish_val; - out << "; \\" << it_ << " = \\" << it_; - if (dir) - out << " - 1"; - else - out << " + 1"; + out << "for (\\" << it_ << " = " << start_val << " ; "; - out << ") begin" << endl; + if (dir) + out << "\\" << it_ << " >= " << finish_val; + else + out << "\\" << it_ << " <= " << finish_val; - errors += emit_substatements(out, ent, arc); + out << "; \\" << it_ << " = \\" << it_; - out << "end" << endl; - out << "end /* " << scope_name << " */" << endl; + if (dir) + out << " - 1)"; + else + out << " + 1)"; + } - return errors; + out << " begin" << endl; + + errors += emit_substatements(out, ent, arc); + + out << "end" << endl; + out << "end /* " << scope_name << " */" << endl; + + return errors; +} + +int ForLoopStatement::emit_runtime_(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + + out << "for (\\" << it_ << " = "; + errors += range_->expr_left()->emit(out, ent, arc); + + // Twisted way of determining the loop direction at runtime + out << " ;\n("; + errors += range_->expr_left()->emit(out, ent, arc); + out << " < "; + errors += range_->expr_right()->emit(out, ent, arc); + out << " ? \\" << it_ << " <= "; + errors += range_->expr_right()->emit(out, ent, arc); + out << " : \\" << it_ << " >= "; + errors += range_->expr_right()->emit(out, ent, arc); + out << ");\n\\" << it_ << " = \\" << it_ << " + ("; + errors += range_->expr_left()->emit(out, ent, arc); + out << " < "; + errors += range_->expr_right()->emit(out, ent, arc); + out << " ? 1 : -1))"; + + return errors; } int WhileLoopStatement::emit(ostream&out, Entity*, Architecture*)