Support for loops with no loop condition.

SystemVerilog makes all of the initialisation, condition, and step
components of a for loop optional. We already support this for the
initialisation and step components.
This commit is contained in:
Martin Whitaker 2024-07-09 21:58:15 +01:00
parent 5cbdff202e
commit a204af04a5
4 changed files with 27 additions and 18 deletions

View File

@ -5613,7 +5613,7 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope,
*
* - index variable (name1_) (optional)
* - initial value (expr1_) (only if name1_ is present)
* - condition expression (cond_)
* - condition expression (cond_) (optional)
* - step statement (step_) (optional)
* - sub-statement (statement_)
*
@ -5693,12 +5693,15 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
// Elaborate the condition expression. Try to evaluate it too,
// in case it is a constant. This is an interesting case
// worthy of a warning.
NetExpr*ce = elab_and_eval(des, scope, cond_, -1);
if (!ce)
error_flag = true;
if (dynamic_cast<NetEConst*>(ce)) {
cerr << get_fileline() << ": warning: condition expression "
"of for-loop is constant." << endl;
NetExpr*ce = nullptr;
if (cond_) {
ce = elab_and_eval(des, scope, cond_, -1);
if (!ce)
error_flag = true;
if (dynamic_cast<NetEConst*>(ce)) {
cerr << get_fileline() << ": warning: condition expression "
"of for-loop is constant." << endl;
}
}
// Error recovery - if we failed to elaborate any of the loop

15
parse.y
View File

@ -728,7 +728,7 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
%type <spec_optional_args> timeskew_fullskew_opt_notifier timeskew_fullskew_opt_event_based_flag
%type <spec_optional_args> timeskew_fullskew_opt_remain_active_flag
%type <expr> assignment_pattern expression expr_mintypmax
%type <expr> assignment_pattern expression expression_opt expr_mintypmax
%type <expr> expr_primary_or_typename expr_primary
%type <expr> class_new dynamic_array_new
%type <expr> var_decl_initializer_opt initializer_opt
@ -1754,7 +1754,7 @@ lifetime_opt /* IEEE1800-2005: A.2.1.3 */
/* Loop statements are kinds of statements. */
loop_statement /* IEEE1800-2005: A.6.8 */
: K_for '(' lpvalue '=' expression ';' expression ';' for_step_opt ')'
: K_for '(' lpvalue '=' expression ';' expression_opt ';' for_step_opt ')'
statement_or_null
{ PForStatement*tmp = new PForStatement($3, $5, $7, $9, $11);
FILE_NAME(tmp, @1);
@ -1762,7 +1762,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */
}
// The initialization statement is optional.
| K_for '(' ';' expression ';' for_step_opt ')'
| K_for '(' ';' expression_opt ';' for_step_opt ')'
statement_or_null
{ PForStatement*tmp = new PForStatement(nullptr, nullptr, $4, $6, $8);
FILE_NAME(tmp, @1);
@ -1773,7 +1773,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */
// statement in a synthetic named block. We can name the block
// after the variable that we are creating, that identifier is
// safe in the controlling scope.
| K_for '(' K_var_opt data_type IDENTIFIER '=' expression ';' expression ';' for_step_opt ')'
| K_for '(' K_var_opt data_type IDENTIFIER '=' expression ';' expression_opt ';' for_step_opt ')'
{ static unsigned for_counter = 0;
char for_block_name [64];
snprintf(for_block_name, sizeof for_block_name, "$ivl_for_loop%u", for_counter);
@ -1858,7 +1858,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */
/* Error forms for loop statements. */
| K_for '(' lpvalue '=' expression ';' expression ';' error ')'
| K_for '(' lpvalue '=' expression ';' expression_opt ';' error ')'
statement_or_null
{ $$ = 0;
yyerror(@1, "error: Error in for loop step assignment.");
@ -3682,6 +3682,11 @@ expression
}
;
expression_opt
: expression { $$ = $1; }
| { $$ = nullptr; }
;
expr_mintypmax
: expression
{ $$ = $1; }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2021 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2024 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
* Copyright (c) 2016 CERN Michele Castellana (michele.castellana@cern.ch)
*
@ -2822,7 +2822,6 @@ extern "C" ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net)
return net->u_.while_.cond_;
case IVL_ST_FORLOOP:
assert(net->u_.forloop_.condition); // XXXX
return net->u_.forloop_.condition;
default:

View File

@ -121,10 +121,12 @@ int show_stmt_forloop(ivl_statement_t net, ivl_scope_t scope)
/* Top of the loop, draw the condition test. */
fprintf(vvp_out, "T_%u.%u ; Top of for-loop\n", thread_count, top_label);
int use_flag = draw_eval_condition(ivl_stmt_cond_expr(net));
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, %d;\n",
thread_count, out_label, use_flag);
clr_flag(use_flag);
if (ivl_stmt_cond_expr(net)) {
int use_flag = draw_eval_condition(ivl_stmt_cond_expr(net));
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, %d;\n",
thread_count, out_label, use_flag);
clr_flag(use_flag);
}
/* Draw the body of the loop. */
rc += show_statement(ivl_stmt_sub_stmt(net), scope);