aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--frontends/verilog/verilog_parser.y96
-rw-r--r--tests/verilog/genfor_decl_no_init.ys7
-rw-r--r--tests/verilog/genfor_decl_no_sv.ys7
-rw-r--r--tests/verilog/genvar_loop_decl_1.sv18
-rw-r--r--tests/verilog/genvar_loop_decl_1.ys14
-rw-r--r--tests/verilog/genvar_loop_decl_2.sv30
-rw-r--r--tests/verilog/genvar_loop_decl_2.ys5
-rw-r--r--tests/verilog/genvar_loop_decl_3.sv28
-rw-r--r--tests/verilog/genvar_loop_decl_3.ys5
9 files changed, 209 insertions, 1 deletions
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 23404f844..8d0ba4cf6 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -254,6 +254,65 @@ static void checkLabelsMatch(const char *element, const std::string *before, con
element, before->c_str() + 1, after->c_str() + 1);
}
+// This transforms a loop like
+// for (genvar i = 0; i < 10; i++) begin : blk
+// to
+// genvar _i;
+// for (_i = 0; _i < 10; _i++) begin : blk
+// localparam i = _i;
+// where `_i` is actually some auto-generated name.
+static void rewriteGenForDeclInit(AstNode *loop)
+{
+ // check if this generate for loop contains an inline declaration
+ log_assert(loop->type == AST_GENFOR);
+ AstNode *decl = loop->children[0];
+ if (decl->type == AST_ASSIGN_EQ)
+ return;
+ log_assert(decl->type == AST_GENVAR);
+ log_assert(loop->children.size() == 5);
+
+ // identify each component of the loop
+ AstNode *init = loop->children[1];
+ AstNode *cond = loop->children[2];
+ AstNode *incr = loop->children[3];
+ AstNode *body = loop->children[4];
+ log_assert(init->type == AST_ASSIGN_EQ);
+ log_assert(incr->type == AST_ASSIGN_EQ);
+ log_assert(body->type == AST_GENBLOCK);
+
+ // create a unique name for the genvar
+ std::string old_str = decl->str;
+ std::string new_str = stringf("$genfordecl$%d$%s", autoidx++, old_str.c_str());
+
+ // rename and move the genvar declaration to the containing description
+ decl->str = new_str;
+ loop->children.erase(loop->children.begin());
+ log_assert(current_ast_mod != nullptr);
+ current_ast_mod->children.push_back(decl);
+
+ // create a new localparam with old name so that the items in the loop
+ // can simply use the old name and shadow it as necessary
+ AstNode *indirect = new AstNode(AST_LOCALPARAM);
+ indirect->str = old_str;
+ AstNode *ident = new AstNode(AST_IDENTIFIER);
+ ident->str = new_str;
+ indirect->children.push_back(ident);
+
+ body->children.insert(body->children.begin(), indirect);
+
+ // only perform the renaming for the initialization, guard, and
+ // incrementation to enable proper shadowing of the synthetic localparam
+ std::function<void(AstNode*)> substitute = [&](AstNode *node) {
+ if (node->type == AST_IDENTIFIER && node->str == old_str)
+ node->str = new_str;
+ for (AstNode *child : node->children)
+ substitute(child);
+ };
+ substitute(init);
+ substitute(cond);
+ substitute(incr);
+}
+
%}
%define api.prefix {frontend_verilog_yy}
@@ -321,6 +380,7 @@ static void checkLabelsMatch(const char *element, const std::string *before, con
%type <al> attr case_attr
%type <ast> struct_union
%type <ast_node_type> asgn_binop
+%type <ast> genvar_identifier
%type <specify_target_ptr> specify_target
%type <specify_triple_ptr> specify_triple specify_opt_triple
@@ -2978,16 +3038,50 @@ gen_stmt_or_module_body_stmt:
free_attr($1);
};
+genvar_identifier:
+ TOK_ID {
+ $$ = new AstNode(AST_IDENTIFIER);
+ $$->str = *$1;
+ delete $1;
+ };
+
+genvar_initialization:
+ TOK_GENVAR genvar_identifier {
+ frontend_verilog_yyerror("Generate for loop variable declaration is missing initialization!");
+ } |
+ TOK_GENVAR genvar_identifier '=' expr {
+ if (!sv_mode)
+ frontend_verilog_yyerror("Generate for loop inline variable declaration is only supported in SystemVerilog mode!");
+ AstNode *node = new AstNode(AST_GENVAR);
+ node->is_reg = true;
+ node->is_signed = true;
+ node->range_left = 31;
+ node->range_right = 0;
+ node->str = $2->str;
+ node->children.push_back(checkRange(node, nullptr));
+ ast_stack.back()->children.push_back(node);
+ SET_AST_NODE_LOC(node, @1, @4);
+ node = new AstNode(AST_ASSIGN_EQ, $2, $4);
+ ast_stack.back()->children.push_back(node);
+ SET_AST_NODE_LOC(node, @1, @4);
+ } |
+ genvar_identifier '=' expr {
+ AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3);
+ ast_stack.back()->children.push_back(node);
+ SET_AST_NODE_LOC(node, @1, @3);
+ };
+
// this production creates the obligatory if-else shift/reduce conflict
gen_stmt:
TOK_FOR '(' {
AstNode *node = new AstNode(AST_GENFOR);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
- } simple_behavioral_stmt ';' expr {
+ } genvar_initialization ';' expr {
ast_stack.back()->children.push_back($6);
} ';' simple_behavioral_stmt ')' gen_stmt_block {
SET_AST_NODE_LOC(ast_stack.back(), @1, @11);
+ rewriteGenForDeclInit(ast_stack.back());
ast_stack.pop_back();
} |
TOK_IF '(' expr ')' {
diff --git a/tests/verilog/genfor_decl_no_init.ys b/tests/verilog/genfor_decl_no_init.ys
new file mode 100644
index 000000000..348899195
--- /dev/null
+++ b/tests/verilog/genfor_decl_no_init.ys
@@ -0,0 +1,7 @@
+logger -expect error "Generate for loop variable declaration is missing initialization!" 1
+read_verilog -sv <<EOT
+module top;
+ for (genvar i; i < 10; i = i + 1)
+ wire x;
+endmodule
+EOT
diff --git a/tests/verilog/genfor_decl_no_sv.ys b/tests/verilog/genfor_decl_no_sv.ys
new file mode 100644
index 000000000..124a27c28
--- /dev/null
+++ b/tests/verilog/genfor_decl_no_sv.ys
@@ -0,0 +1,7 @@
+logger -expect error "Generate for loop inline variable declaration is only supported in SystemVerilog mode!" 1
+read_verilog <<EOT
+module top;
+ for (genvar i = 1; i < 10; i = i + 1)
+ wire x;
+endmodule
+EOT
diff --git a/tests/verilog/genvar_loop_decl_1.sv b/tests/verilog/genvar_loop_decl_1.sv
new file mode 100644
index 000000000..b503f75da
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_1.sv
@@ -0,0 +1,18 @@
+`default_nettype none
+
+module gate(a);
+ for (genvar i = 0; i < 2; i++)
+ wire [i:0] x = '1;
+
+ output wire [32:0] a;
+ assign a = {1'b0, genblk1[0].x, 1'b0, genblk1[1].x, 1'b0};
+endmodule
+
+module gold(a);
+ genvar i;
+ for (i = 0; i < 2; i++)
+ wire [i:0] x = '1;
+
+ output wire [32:0] a;
+ assign a = {1'b0, genblk1[0].x, 1'b0, genblk1[1].x, 1'b0};
+endmodule
diff --git a/tests/verilog/genvar_loop_decl_1.ys b/tests/verilog/genvar_loop_decl_1.ys
new file mode 100644
index 000000000..ded486248
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_1.ys
@@ -0,0 +1,14 @@
+read_verilog -sv genvar_loop_decl_1.sv
+
+select -assert-count 1 gate/genblk1[0].x
+select -assert-count 1 gate/genblk1[1].x
+select -assert-count 0 gate/genblk1[2].x
+
+select -assert-count 1 gold/genblk1[0].x
+select -assert-count 1 gold/genblk1[1].x
+select -assert-count 0 gold/genblk1[2].x
+
+proc
+equiv_make gold gate equiv
+equiv_simple
+equiv_status -assert
diff --git a/tests/verilog/genvar_loop_decl_2.sv b/tests/verilog/genvar_loop_decl_2.sv
new file mode 100644
index 000000000..c5a85ef11
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_2.sv
@@ -0,0 +1,30 @@
+`default_nettype none
+
+module gate(out);
+ wire [3:0] x;
+ for (genvar x = 0; x < 2; x++) begin : blk
+ localparam w = x;
+ if (x == 0) begin : sub
+ wire [w:0] x;
+ end
+ end
+ assign x = 2;
+ assign blk[0].sub.x = '1;
+ output wire [9:0] out;
+ assign out = {1'bx, x, blk[0].sub.x};
+endmodule
+
+module gold(out);
+ wire [3:0] x;
+ genvar z;
+ for (z = 0; z < 2; z++) begin : blk
+ localparam w = z;
+ if (z == 0) begin : sub
+ wire [w:0] x;
+ end
+ end
+ assign x = 2;
+ assign blk[0].sub.x = '1;
+ output wire [9:0] out;
+ assign out = {1'bx, x, blk[0].sub.x};
+endmodule
diff --git a/tests/verilog/genvar_loop_decl_2.ys b/tests/verilog/genvar_loop_decl_2.ys
new file mode 100644
index 000000000..52fdeb49c
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_2.ys
@@ -0,0 +1,5 @@
+read_verilog -sv genvar_loop_decl_2.sv
+proc
+equiv_make gold gate equiv
+equiv_simple
+equiv_status -assert
diff --git a/tests/verilog/genvar_loop_decl_3.sv b/tests/verilog/genvar_loop_decl_3.sv
new file mode 100644
index 000000000..4d6d2366d
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_3.sv
@@ -0,0 +1,28 @@
+`default_nettype none
+
+module gate(x, y);
+ output reg [15:0] x, y;
+ if (1) begin : gen
+ integer x, y;
+ for (genvar x = 0; x < 2; x++)
+ if (x == 0)
+ initial gen.x = 10;
+ assign y = x + 1;
+ end
+ initial x = gen.x;
+ assign y = gen.y;
+endmodule
+
+module gold(x, y);
+ output reg [15:0] x, y;
+ if (1) begin : gen
+ integer x, y;
+ genvar z;
+ for (z = 0; z < 2; z++)
+ if (z == 0)
+ initial x = 10;
+ assign y = x + 1;
+ end
+ initial x = gen.x;
+ assign y = gen.y;
+endmodule
diff --git a/tests/verilog/genvar_loop_decl_3.ys b/tests/verilog/genvar_loop_decl_3.ys
new file mode 100644
index 000000000..19f754124
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_3.ys
@@ -0,0 +1,5 @@
+read_verilog -sv genvar_loop_decl_3.sv
+proc
+equiv_make gold gate equiv
+equiv_simple
+equiv_status -assert