Allow to omit dimensions in foreach loop

SystemVerilog allows to skip dimensions in a foreach loop by not specifying
an identifier name for the dimensions. E.g. the following will iterate over
the first and last dimensions, but skip the middle dimension.

```
int x[1][2][3];
foreach(x[a,,b]) ...
```

Add support for this to the parser as well as elaboration.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2022-10-02 21:01:31 +02:00
parent f8401095aa
commit e141aef828
3 changed files with 25 additions and 4 deletions

View File

@ -5379,8 +5379,6 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope,
<< "Handle as array with static dimensions." << endl;
}
ivl_assert(*this, index_vars_.size() > 0);
NetProc*sub;
if (statement_)
sub = statement_->elaborate(des, scope);
@ -5390,7 +5388,7 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope,
if (index_vars_.size() > dims.size()) {
delete sub;
cerr << get_fileline() << ": error: Number of foreach loop indices"
cerr << get_fileline() << ": error: Number of foreach loop variables"
<< "(" << index_vars_.size() << ") must not exceed number of "
<< "array dimensions (" << dims.size() << ")." << endl;
des->errors++;
@ -5400,6 +5398,11 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope,
for (int idx_idx = index_vars_.size()-1 ; idx_idx >= 0 ; idx_idx -= 1) {
const netrange_t&idx_range = dims[idx_idx];
// It is possible to skip dimensions by not providing a identifier
// name for it. E.g. `int x[1][2][3]; foreach(x[a,,b]) ...`
if (index_vars_[idx_idx].nil())
continue;
// Get the $high and $low constant values for this slice
// of the array.
NetEConst*hig_expr = make_const_val_s(idx_range.get_msb());
@ -5438,7 +5441,13 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope,
sub = stmt;
}
return stmt? stmt : sub;
// If there are no loop variables elide the whole block
if (!stmt) {
delete sub;
return new NetBlock(NetBlock::SEQU, 0);
}
return stmt;
}
/*

10
parse.y
View File

@ -1799,12 +1799,22 @@ loop_variables /* IEEE1800-2005: A.6.8 */
delete[]$3;
$$ = tmp;
}
| loop_variables ','
{ std::list<perm_string>*tmp = $1;
tmp->push_back(perm_string());
$$ = tmp;
}
| IDENTIFIER
{ std::list<perm_string>*tmp = new std::list<perm_string>;
tmp->push_back(lex_strings.make($1));
delete[]$1;
$$ = tmp;
}
|
{ std::list<perm_string>*tmp = new std::list<perm_string>;
tmp->push_back(perm_string());
$$ = tmp;
}
;
method_qualifier /* IEEE1800-2005: A.1.8 */

View File

@ -994,6 +994,8 @@ void pform_make_foreach_declarations(const struct vlltype&loc,
list<decl_assignment_t*>assign_list;
for (list<perm_string>::const_iterator cur = loop_vars->begin()
; cur != loop_vars->end() ; ++ cur) {
if (cur->nil())
continue;
decl_assignment_t*tmp_assign = new decl_assignment_t;
tmp_assign->name = lex_strings.make(*cur);
assign_list.push_back(tmp_assign);