vhdlpp: For-loop emission rewritten to handle 'range in subprograms.
This commit is contained in:
parent
bcca3cf395
commit
0592ba042e
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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*)
|
||||
|
|
|
|||
Loading…
Reference in New Issue