Skip to content

Commit a2ffbc3

Browse files
committed
Validate the generate "loop" expressions
1 parent adcb9f4 commit a2ffbc3

File tree

9 files changed

+137
-11
lines changed

9 files changed

+137
-11
lines changed

elab_scope.cc

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2000-2024 Stephen Williams ([email protected])
2+
* Copyright (c) 2000-2025 Stephen Williams ([email protected])
33
* Copyright CERN 2013 / Stephen Williams ([email protected])
44
*
55
* This source code is free software; you can redistribute it
@@ -942,7 +942,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
942942
while (cscope && !cscope->find_genvar(loop_index)) {
943943
if (cscope->symbol_exists(loop_index)) {
944944
cerr << get_fileline() << ": error: "
945-
<< "generate loop variable '" << loop_index
945+
<< "generate \"loop\" variable '" << loop_index
946946
<< "' is not a genvar in this scope." << endl;
947947
des->errors += 1;
948948
return false;
@@ -967,8 +967,16 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
967967
NetExpr*init_ex = elab_and_eval(des, container, loop_init, -1, true);
968968
NetEConst*init = dynamic_cast<NetEConst*> (init_ex);
969969
if (init == 0) {
970-
cerr << get_fileline() << ": error: Cannot evaluate genvar"
971-
<< " init expression: " << *loop_init << endl;
970+
cerr << get_fileline() << ": error: "
971+
"Cannot evaluate generate \"loop\" initialization "
972+
"expression: " << *loop_init << endl;
973+
des->errors += 1;
974+
return false;
975+
}
976+
if (! init->value().is_defined()) {
977+
cerr << get_fileline() << ": error: "
978+
<< "Generate \"loop\" initialization expression cannot have "
979+
"undefined bits. given (" << *loop_init << ")." << endl;
972980
des->errors += 1;
973981
return false;
974982
}
@@ -979,27 +987,43 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
979987

980988
if (debug_scopes)
981989
cerr << get_fileline() << ": debug: genvar init = " << genvar << endl;
990+
982991
container->genvar_tmp = loop_index;
983992
container->genvar_tmp_val = genvar;
984993
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1, true);
985994
NetEConst*test = dynamic_cast<NetEConst*>(test_ex);
986995
if (test == 0) {
987-
cerr << get_fileline() << ": error: Cannot evaluate genvar"
988-
<< " conditional expression: " << *loop_test << endl;
996+
cerr << get_fileline() << ": error: Cannot evaluate generate \"loop\" "
997+
"conditional expression: " << *loop_test << endl;
989998
des->errors += 1;
990999
return false;
9911000
}
1001+
if (! test->value().is_defined()) {
1002+
cerr << get_fileline() << ": error: "
1003+
"Generate \"loop\" conditional expression cannot have "
1004+
"undefined bits. given (" << *loop_test << ")." << endl;
1005+
des->errors += 1;
1006+
return false;
1007+
}
1008+
unsigned long loop_count = 1;
9921009
while (test->value().as_long()) {
9931010

9941011
// The actual name of the scope includes the genvar so
9951012
// that each instance has a unique name in the
9961013
// container. The format of using [] is part of the
9971014
// Verilog standard.
9981015
hname_t use_name (scope_name, genvar);
1016+
if (container->child(use_name)) {
1017+
cerr << get_fileline() << ": error: "
1018+
"Trying to create a duplicate generate scope named \""
1019+
<< use_name << "\"." << endl;
1020+
des->errors += 1;
1021+
return false;
1022+
}
9991023

10001024
if (debug_scopes)
10011025
cerr << get_fileline() << ": debug: "
1002-
<< "Create generated scope " << use_name << endl;
1026+
"Create generated scope " << use_name << endl;
10031027

10041028
NetScope*scope = new NetScope(container, use_name,
10051029
NetScope::GENBLOCK);
@@ -1025,7 +1049,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
10251049
scope->set_parameter(loop_index, gp, *this);
10261050
if (debug_scopes)
10271051
cerr << get_fileline() << ": debug: "
1028-
<< "Create implicit localparam "
1052+
"Create implicit localparam "
10291053
<< loop_index << " = " << genvar_verinum << endl;
10301054
}
10311055

@@ -1035,23 +1059,58 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
10351059
NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1, true);
10361060
NetEConst*step = dynamic_cast<NetEConst*>(step_ex);
10371061
if (step == 0) {
1038-
cerr << get_fileline() << ": error: Cannot evaluate genvar"
1039-
<< " step expression: " << *loop_step << endl;
1062+
cerr << get_fileline() << ": error: Cannot evaluate generate "
1063+
"\"loop\" increment expression: " << *loop_step << endl;
10401064
des->errors += 1;
10411065
return false;
10421066
}
10431067
if (debug_scopes)
10441068
cerr << get_fileline() << ": debug: genvar step from "
10451069
<< genvar << " to " << step->value().as_long() << endl;
10461070

1047-
genvar = step->value().as_long();
1071+
if (! step->value().is_defined()) {
1072+
cerr << get_fileline() << ": error: "
1073+
"Generate \"loop\" increment expression cannot have "
1074+
"undefined bits, given (" << *loop_step << ")." << endl;
1075+
des->errors += 1;
1076+
return false;
1077+
}
1078+
long next_genvar;
1079+
next_genvar = step->value().as_long();
1080+
if (next_genvar == genvar) {
1081+
cerr << get_fileline() << ": error: "
1082+
<< "The generate \"loop\" is not incrementing. The "
1083+
"previous and next genvar values are ("
1084+
<< genvar << ")." << endl;
1085+
des->errors += 1;
1086+
return false;
1087+
}
1088+
genvar = next_genvar;
10481089
check_for_valid_genvar_value_(genvar);
10491090
container->genvar_tmp_val = genvar;
10501091
delete step;
10511092
delete test_ex;
10521093
test_ex = elab_and_eval(des, container, loop_test, -1, true);
10531094
test = dynamic_cast<NetEConst*>(test_ex);
10541095
ivl_assert(*this, test);
1096+
if (! test->value().is_defined()) {
1097+
cerr << get_fileline() << ": error: "
1098+
"The generate \"loop\" conditional expression cannot have "
1099+
"undefined bits. given (" << *loop_test << ")." << endl;
1100+
des->errors += 1;
1101+
return false;
1102+
}
1103+
1104+
// If there are half a million iterations this is likely an infinite loop!
1105+
if (loop_count > 500000) {
1106+
cerr << get_fileline() << ": error: "
1107+
<< "Probable infinite loop detected in generate \"loop\". "
1108+
"It has run for " << loop_count
1109+
<< " iterations." << endl;
1110+
des->errors += 1;
1111+
return false;
1112+
}
1113+
++loop_count;
10551114
}
10561115

10571116
// Clear the genvar_tmp field in the scope to reflect that the

ivtest/gold/br_gh1225a.gold

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
./ivltests/br_gh1225a.v:5: error: A generate "loop" requires the initialization genvar (gv2) to match the iteration genvar (gv1).

ivtest/gold/br_gh1225b.gold

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
./ivltests/br_gh1225b.v:5: error: 'named' has already been declared in this scope.
2+
./ivltests/br_gh1225b.v:3: : It was declared here as a variable.
3+
./ivltests/br_gh1225b.v:9: error: 'match' has already been declared in this scope.
4+
./ivltests/br_gh1225b.v:8: : It was declared here as a generate block.

ivtest/gold/br_gh1225c.gold

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
./ivltests/br_gh1225c.v:3: error: The generate "loop" is not incrementing. The previous and next genvar values are (-1).
2+
./ivltests/br_gh1225c.v:6: error: Trying to create a duplicate generate scope named "$gen2[0]".
3+
./ivltests/br_gh1225c.v:9: error: Generate "loop" initialization expression cannot have undefined bits. given (1'bx).
4+
./ivltests/br_gh1225c.v:12: error: Generate "loop" increment expression cannot have undefined bits, given ((gv4)+(1'bx)).
5+
./ivltests/br_gh1225c.v:15: error: Generate "loop" conditional expression cannot have undefined bits. given (1'bx).
6+
./ivltests/br_gh1225c.v:18: error: Unable to bind parameter `gv6' in `test'
7+
./ivltests/br_gh1225c.v:18: error: Cannot evaluate generate "loop" initialization expression: (gv6)+('sd1)
8+
./ivltests/br_gh1225c.v:21: error: Probable infinite loop detected in generate "loop". It has run for 500001 iterations.
9+
./ivltests/br_gh1225c.v:24: error: Probable infinite loop detected in generate "loop". It has run for 500001 iterations.
10+
9 error(s) during elaboration.

ivtest/ivltests/br_gh1225a.v

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module test;
2+
genvar gv1;
3+
4+
// initialization and increment genvars do not match
5+
for (genvar gv2 = -1; -1; gv1 = -1);
6+
endmodule

ivtest/ivltests/br_gh1225b.v

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module test;
2+
// This should conflict with the generate loops below.
3+
reg named;
4+
// scope name matches a register
5+
for (genvar gv = 0; gv < 1; gv = gv + 1) begin:named; end;
6+
7+
// You cannot have generate blocks with the same name.
8+
for (genvar gv = 0; gv < 1; gv = gv + 1) begin:match; end;
9+
for (genvar gv = 0; gv < 1; gv = gv + 1) begin:match; end;
10+
endmodule

ivtest/ivltests/br_gh1225c.v

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
module test;
2+
// genvar does not increment.
3+
for (genvar gv1 = -1; gv1 <= 2; gv1 = -1);
4+
5+
// genvar duplicates.
6+
for (genvar gv2 = 0; gv2 >= 0; gv2 = gv2 + 64'h80000000);
7+
8+
// undefined value in initialization
9+
for (genvar gv3 = 1'bx; gv3 <= 1; gv3 = gv3 + 1);
10+
11+
// undefined value in increment
12+
for (genvar gv4 = 0; gv4 <= 1; gv4 = gv4 + 1'bx);
13+
14+
// undefined value in test condition
15+
for (genvar gv5 = 0; 1'bx; gv5 = gv5 + 1);
16+
17+
// genvar used in RHS of initialization
18+
for (genvar gv6 = gv6 + 1; gv <= 1; gv6 = gv6 + 1);
19+
20+
// loop forever
21+
for (genvar gv7 = 0; 1'b1; gv7 = gv7 + 1);
22+
23+
// Almost forever
24+
for (genvar gv8 = 0; gv8 >= 0; gv8 = gv8 + 1);
25+
endmodule

ivtest/regress-vlg.list

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,9 @@ br_gh1182 CE ivltests gold=br_gh1182.gold
367367
br_gh1223a normal,-g2009 ivltests
368368
br_gh1223b normal,-g2009 ivltests
369369
br_gh1223c normal,-g2009 ivltests
370+
br_gh1225a CE ivltests gold=br_gh1225a.gold
371+
br_gh1225b CE ivltests gold=br_gh1225b.gold
372+
br_gh1225c CE ivltests gold=br_gh1225c.gold
370373
br_ml20150315 normal ivltests gold=br_ml_20150315.gold
371374
br_ml20150321 CE ivltests
372375
br_mw20171108 normal ivltests

pform.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,14 @@ void pform_start_generate_for(const struct vlltype&li,
15371537
pform_cur_generate->loop_test = test;
15381538
pform_cur_generate->loop_step = next;
15391539

1540+
if (strcmp(ident1, ident2)) {
1541+
cerr << li << ": error: "
1542+
<< "A generate \"loop\" requires the initialization genvar ("
1543+
<< ident1 << ") to match the iteration genvar ("
1544+
<< ident2 << ")." << endl;
1545+
error_count += 1;
1546+
}
1547+
15401548
delete[]ident1;
15411549
delete[]ident2;
15421550
}

0 commit comments

Comments
 (0)