foreach loops around static arrays
Arrays with static dimensions can be handled specially. This also allows for arbitrary numbers of dimensions.
This commit is contained in:
parent
9fa764285a
commit
0cd6fbaf41
|
|
@ -453,6 +453,10 @@ class PForeach : public Statement {
|
||||||
virtual void elaborate_sig(Design*des, NetScope*scope) const;
|
virtual void elaborate_sig(Design*des, NetScope*scope) const;
|
||||||
virtual void dump(ostream&out, unsigned ind) const;
|
virtual void dump(ostream&out, unsigned ind) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
NetProc* elaborate_static_array_(Design*des, NetScope*scope,
|
||||||
|
NetNet*array_sig) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
perm_string array_var_;
|
perm_string array_var_;
|
||||||
std::vector<perm_string> index_vars_;
|
std::vector<perm_string> index_vars_;
|
||||||
|
|
|
||||||
94
elaborate.cc
94
elaborate.cc
|
|
@ -4591,6 +4591,25 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
||||||
*/
|
*/
|
||||||
NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
||||||
{
|
{
|
||||||
|
// Get the signal for the array variable
|
||||||
|
pform_name_t array_name;
|
||||||
|
array_name.push_back(name_component_t(array_var_));
|
||||||
|
NetNet*array_sig = des->find_signal(scope, array_name);
|
||||||
|
ivl_assert(*this, array_sig);
|
||||||
|
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": PForeach::elaborate: "
|
||||||
|
<< "Scan array " << array_sig->name()
|
||||||
|
<< " with " << array_sig->unpacked_dims().size() << " unpacked"
|
||||||
|
<< " and " << array_sig->packed_dims().size()
|
||||||
|
<< " packed dimensions." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_sig->data_type()==IVL_VT_BOOL)
|
||||||
|
return elaborate_static_array_(des, scope, array_sig);
|
||||||
|
if (array_sig->data_type()==IVL_VT_LOGIC)
|
||||||
|
return elaborate_static_array_(des, scope, array_sig);
|
||||||
|
|
||||||
if (index_vars_.size() != 1) {
|
if (index_vars_.size() != 1) {
|
||||||
cerr << get_fileline() << ": sorry: "
|
cerr << get_fileline() << ": sorry: "
|
||||||
<< "Multi-index foreach loops not supported." << endl;
|
<< "Multi-index foreach loops not supported." << endl;
|
||||||
|
|
@ -4603,18 +4622,12 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
||||||
NetNet*idx_sig = des->find_signal(scope, index_name);
|
NetNet*idx_sig = des->find_signal(scope, index_name);
|
||||||
ivl_assert(*this, idx_sig);
|
ivl_assert(*this, idx_sig);
|
||||||
|
|
||||||
NetESignal*idx_exp = new NetESignal(idx_sig);
|
|
||||||
idx_exp->set_line(*this);
|
|
||||||
|
|
||||||
// Get the signal for the array variable
|
|
||||||
pform_name_t array_name;
|
|
||||||
array_name.push_back(name_component_t(array_var_));
|
|
||||||
NetNet*array_sig = des->find_signal(scope, array_name);
|
|
||||||
ivl_assert(*this, array_sig);
|
|
||||||
|
|
||||||
NetESignal*array_exp = new NetESignal(array_sig);
|
NetESignal*array_exp = new NetESignal(array_sig);
|
||||||
array_exp->set_line(*this);
|
array_exp->set_line(*this);
|
||||||
|
|
||||||
|
NetESignal*idx_exp = new NetESignal(idx_sig);
|
||||||
|
idx_exp->set_line(*this);
|
||||||
|
|
||||||
// Make an initialization expression for the index.
|
// Make an initialization expression for the index.
|
||||||
NetESFunc*init_expr = new NetESFunc("$low", IVL_VT_BOOL, 32, 1);
|
NetESFunc*init_expr = new NetESFunc("$low", IVL_VT_BOOL, 32, 1);
|
||||||
init_expr->set_line(*this);
|
init_expr->set_line(*this);
|
||||||
|
|
@ -4645,6 +4658,69 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a variant of the PForeach::elaborate() method that handles
|
||||||
|
* the case that the array has static dimensions. We can use constants
|
||||||
|
* and possibly do some optimizations.
|
||||||
|
*/
|
||||||
|
NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope,
|
||||||
|
NetNet*array_sig) const
|
||||||
|
{
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": PForeach::elaborate_static_array_: "
|
||||||
|
<< "Handle as array with static dimensions." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
ivl_assert(*this, index_vars_.size() > 0);
|
||||||
|
ivl_assert(*this, array_sig->unpacked_dims().size() == index_vars_.size());
|
||||||
|
|
||||||
|
NetProc*sub = statement_->elaborate(des, scope);
|
||||||
|
NetForLoop*stmt = 0;
|
||||||
|
|
||||||
|
for (int idx_idx = index_vars_.size()-1 ; idx_idx >= 0 ; idx_idx -= 1) {
|
||||||
|
const netrange_t&idx_range = array_sig->unpacked_dims()[idx_idx];
|
||||||
|
|
||||||
|
// Get the $high and $low constant values for this slice
|
||||||
|
// of the array.
|
||||||
|
NetEConst*hig_expr = make_const_val_s(idx_range.get_msb());
|
||||||
|
NetEConst*low_expr = make_const_val_s(idx_range.get_lsb());
|
||||||
|
if (idx_range.get_msb() < idx_range.get_lsb()) {
|
||||||
|
NetEConst*tmp = hig_expr;
|
||||||
|
hig_expr = low_expr;
|
||||||
|
low_expr = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
hig_expr->set_line(*this);
|
||||||
|
low_expr->set_line(*this);
|
||||||
|
|
||||||
|
pform_name_t idx_name;
|
||||||
|
idx_name.push_back(name_component_t(index_vars_[idx_idx]));
|
||||||
|
NetNet*idx_sig = des->find_signal(scope, idx_name);
|
||||||
|
ivl_assert(*this, idx_sig);
|
||||||
|
|
||||||
|
// Make the condition expression <idx> <= $high(slice)
|
||||||
|
NetESignal*idx_expr = new NetESignal(idx_sig);
|
||||||
|
idx_expr->set_line(*this);
|
||||||
|
|
||||||
|
NetEBComp*cond_expr = new NetEBComp('L', idx_expr, hig_expr);
|
||||||
|
cond_expr->set_line(*this);
|
||||||
|
|
||||||
|
// Make the step statement: <idx> += 1
|
||||||
|
NetAssign_*idx_lv = new NetAssign_(idx_sig);
|
||||||
|
NetEConst*step_val = make_const_val_s(1);
|
||||||
|
NetAssign*step = new NetAssign(idx_lv, '+', step_val);
|
||||||
|
step->set_line(*this);
|
||||||
|
|
||||||
|
stmt = new NetForLoop(idx_sig, low_expr, cond_expr, sub, step);
|
||||||
|
stmt->set_line(*this);
|
||||||
|
stmt->wrap_up();
|
||||||
|
|
||||||
|
sub = stmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stmt? stmt : sub;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* elaborate the for loop as the equivalent while loop. This eases the
|
* elaborate the for loop as the equivalent while loop. This eases the
|
||||||
* task for the target code generator. The structure is:
|
* task for the target code generator. The structure is:
|
||||||
|
|
|
||||||
|
|
@ -667,6 +667,14 @@ NetEConst* make_const_val(unsigned long value)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetEConst* make_const_val_s(long value)
|
||||||
|
{
|
||||||
|
verinum tmp (value, integer_width);
|
||||||
|
tmp.has_sign(true);
|
||||||
|
NetEConst*res = new NetEConst(tmp);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid)
|
NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid)
|
||||||
{
|
{
|
||||||
verinum xxx (verinum::Vx, wid);
|
verinum xxx (verinum::Vx, wid);
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,7 @@ extern NetNet*sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig);
|
||||||
extern NetEConst*make_const_x(unsigned long wid);
|
extern NetEConst*make_const_x(unsigned long wid);
|
||||||
extern NetEConst*make_const_0(unsigned long wid);
|
extern NetEConst*make_const_0(unsigned long wid);
|
||||||
extern NetEConst*make_const_val(unsigned long val);
|
extern NetEConst*make_const_val(unsigned long val);
|
||||||
|
extern NetEConst*make_const_val_s(long val);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make A const net
|
* Make A const net
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue