diff --git a/Statement.h b/Statement.h index b37188c0f..1785d9b6f 100644 --- a/Statement.h +++ b/Statement.h @@ -453,6 +453,10 @@ class PForeach : public Statement { virtual void elaborate_sig(Design*des, NetScope*scope) const; virtual void dump(ostream&out, unsigned ind) const; + private: + NetProc* elaborate_static_array_(Design*des, NetScope*scope, + NetNet*array_sig) const; + private: perm_string array_var_; std::vector index_vars_; diff --git a/elaborate.cc b/elaborate.cc index b03ec3592..a09a3403f 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4591,6 +4591,25 @@ NetForce* PForce::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) { cerr << get_fileline() << ": sorry: " << "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); 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); array_exp->set_line(*this); + NetESignal*idx_exp = new NetESignal(idx_sig); + idx_exp->set_line(*this); + // Make an initialization expression for the index. NetESFunc*init_expr = new NetESFunc("$low", IVL_VT_BOOL, 32, 1); init_expr->set_line(*this); @@ -4645,6 +4658,69 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const 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 <= $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: += 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 * task for the target code generator. The structure is: diff --git a/netmisc.cc b/netmisc.cc index 585388f06..e4928ad76 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -667,6 +667,14 @@ NetEConst* make_const_val(unsigned long value) 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) { verinum xxx (verinum::Vx, wid); diff --git a/netmisc.h b/netmisc.h index 6b5db586f..3e682fdd2 100644 --- a/netmisc.h +++ b/netmisc.h @@ -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_0(unsigned long wid); extern NetEConst*make_const_val(unsigned long val); +extern NetEConst*make_const_val_s(long val); /* * Make A const net