From e19d077d44692b1177330e55e9b5270802871ec6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 5 Mar 2023 08:58:12 -0800 Subject: [PATCH] Iterate static arrays $left to $right in foreach loops foreach loops are supposed to iterate arrays $left to $right. E.g. `reg x[3:0]` should be iterated from 3 to 0 and `y[1:4]` from 1 to 4. The current implementation iterates them from $low to $high. Modify this to either count up or down depending on whether $left or $right is the larger of the two values. Note that the same applies for dynamic arrays. But since for dynamic arrays $left is always 0 and $right is always $high they always count up and we do not need to differentiate between two different cases. Signed-off-by: Lars-Peter Clausen --- elaborate.cc | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index bf285903c..27d2ea350 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -5276,7 +5276,7 @@ static void find_property_in_class(const LineInfo&loc, const NetScope*scope, per /* * The foreach statement can be written as a for statement like so: * - * for ( = $low() ; <= $high() ; += 1) + * for ( = $left() ; {<,>}= $right() ; {+,-}= 1) * * * The variable is already known to be in the containing named @@ -5386,6 +5386,9 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const NetESignal*idx_exp = new NetESignal(idx_sig); idx_exp->set_line(*this); + // This is a dynamic array or queue where $low is $left and $high is + // $right. It will always count up. + // Make an initialization expression for the index. NetESFunc*init_expr = new NetESFunc("$low", &netvector_t::atom2s32, 1); init_expr->set_line(*this); @@ -5458,36 +5461,33 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, // 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; - } + NetEConst*left_expr = make_const_val_s(idx_range.get_msb()); + NetEConst*right_expr = make_const_val_s(idx_range.get_lsb()); - hig_expr->set_line(*this); - low_expr->set_line(*this); + bool up = idx_range.get_msb() < idx_range.get_lsb(); + + left_expr->set_line(*this); + right_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) + // Make the condition expression {<,>}= $right(slice) NetESignal*idx_expr = new NetESignal(idx_sig); idx_expr->set_line(*this); - NetEBComp*cond_expr = new NetEBComp('L', idx_expr, hig_expr); + NetEBComp*cond_expr = new NetEBComp(up ? 'L' : 'G', idx_expr, right_expr); cond_expr->set_line(*this); - // Make the step statement: += 1 + // 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); + NetAssign*step = new NetAssign(idx_lv, up ? '+' : '-', step_val); step->set_line(*this); - stmt = new NetForLoop(idx_sig, low_expr, cond_expr, sub, step); + stmt = new NetForLoop(idx_sig, left_expr, cond_expr, sub, step); stmt->set_line(*this); sub = stmt;