vhdlpp: For-loop emission rewritten to handle 'range in subprograms.

This commit is contained in:
Maciej Suminski 2015-01-13 18:00:41 +01:00
parent bcca3cf395
commit 0592ba042e
3 changed files with 100 additions and 60 deletions

View File

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

View File

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

View File

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