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) * - index variable (name1_) (optional)
* - initial value (expr1_) (only if name1_ is present) * - initial value (expr1_) (only if name1_ is present)
* - condition expression (cond_) * - condition expression (cond_) (optional)
* - step statement (step_) (optional) * - step statement (step_) (optional)
* - sub-statement (statement_) * - sub-statement (statement_)
* *
@ -5693,12 +5693,15 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
// Elaborate the condition expression. Try to evaluate it too, // Elaborate the condition expression. Try to evaluate it too,
// in case it is a constant. This is an interesting case // in case it is a constant. This is an interesting case
// worthy of a warning. // worthy of a warning.
NetExpr*ce = elab_and_eval(des, scope, cond_, -1); NetExpr*ce = nullptr;
if (!ce) if (cond_) {
error_flag = true; ce = elab_and_eval(des, scope, cond_, -1);
if (dynamic_cast<NetEConst*>(ce)) { if (!ce)
cerr << get_fileline() << ": warning: condition expression " error_flag = true;
"of for-loop is constant." << endl; 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 // 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_notifier timeskew_fullskew_opt_event_based_flag
%type <spec_optional_args> timeskew_fullskew_opt_remain_active_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> expr_primary_or_typename expr_primary
%type <expr> class_new dynamic_array_new %type <expr> class_new dynamic_array_new
%type <expr> var_decl_initializer_opt initializer_opt %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 statements are kinds of statements. */
loop_statement /* IEEE1800-2005: A.6.8 */ 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 statement_or_null
{ PForStatement*tmp = new PForStatement($3, $5, $7, $9, $11); { PForStatement*tmp = new PForStatement($3, $5, $7, $9, $11);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
@ -1762,7 +1762,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */
} }
// The initialization statement is optional. // The initialization statement is optional.
| K_for '(' ';' expression ';' for_step_opt ')' | K_for '(' ';' expression_opt ';' for_step_opt ')'
statement_or_null statement_or_null
{ PForStatement*tmp = new PForStatement(nullptr, nullptr, $4, $6, $8); { PForStatement*tmp = new PForStatement(nullptr, nullptr, $4, $6, $8);
FILE_NAME(tmp, @1); 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 // statement in a synthetic named block. We can name the block
// after the variable that we are creating, that identifier is // after the variable that we are creating, that identifier is
// safe in the controlling scope. // 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; { static unsigned for_counter = 0;
char for_block_name [64]; char for_block_name [64];
snprintf(for_block_name, sizeof for_block_name, "$ivl_for_loop%u", for_counter); 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. */ /* Error forms for loop statements. */
| K_for '(' lpvalue '=' expression ';' expression ';' error ')' | K_for '(' lpvalue '=' expression ';' expression_opt ';' error ')'
statement_or_null statement_or_null
{ $$ = 0; { $$ = 0;
yyerror(@1, "error: Error in for loop step assignment."); yyerror(@1, "error: Error in for loop step assignment.");
@ -3682,6 +3682,11 @@ expression
} }
; ;
expression_opt
: expression { $$ = $1; }
| { $$ = nullptr; }
;
expr_mintypmax expr_mintypmax
: expression : expression
{ $$ = $1; } { $$ = $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 CERN 2013 / Stephen Williams (steve@icarus.com)
* Copyright (c) 2016 CERN Michele Castellana (michele.castellana@cern.ch) * 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_; return net->u_.while_.cond_;
case IVL_ST_FORLOOP: case IVL_ST_FORLOOP:
assert(net->u_.forloop_.condition); // XXXX
return net->u_.forloop_.condition; return net->u_.forloop_.condition;
default: 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. */ /* Top of the loop, draw the condition test. */
fprintf(vvp_out, "T_%u.%u ; Top of for-loop\n", thread_count, top_label); 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)); if (ivl_stmt_cond_expr(net)) {
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, %d;\n", int use_flag = draw_eval_condition(ivl_stmt_cond_expr(net));
thread_count, out_label, use_flag); fprintf(vvp_out, " %%jmp/0xz T_%u.%u, %d;\n",
clr_flag(use_flag); thread_count, out_label, use_flag);
clr_flag(use_flag);
}
/* Draw the body of the loop. */ /* Draw the body of the loop. */
rc += show_statement(ivl_stmt_sub_stmt(net), scope); rc += show_statement(ivl_stmt_sub_stmt(net), scope);