diff options
author | Zachary Snow <zach@zachjs.com> | 2021-08-31 11:45:02 -0600 |
---|---|---|
committer | Zachary Snow <zachary.j.snow@gmail.com> | 2021-08-31 12:34:55 -0600 |
commit | b2e9717419e9a852f4e64f12891b8e9742900917 (patch) | |
tree | 3a989a50c1f9beef9068b423f202d4918dcf3d6a | |
parent | b20bb653ce0bfe452f8a1ff4a7a9b64262acced3 (diff) | |
download | yosys-b2e9717419e9a852f4e64f12891b8e9742900917.tar.gz yosys-b2e9717419e9a852f4e64f12891b8e9742900917.tar.bz2 yosys-b2e9717419e9a852f4e64f12891b8e9742900917.zip |
sv: support declaration in generate for initialization
This is accomplished by generating a unique name for the genvar,
renaming references to the genvar only in the loop's initialization,
guard, and incrementation, and finally adding a localparam inside the
loop body with the original name so that the genvar can be shadowed as
expected.
-rw-r--r-- | frontends/verilog/verilog_parser.y | 96 | ||||
-rw-r--r-- | tests/verilog/genfor_decl_no_init.ys | 7 | ||||
-rw-r--r-- | tests/verilog/genfor_decl_no_sv.ys | 7 | ||||
-rw-r--r-- | tests/verilog/genvar_loop_decl_1.sv | 18 | ||||
-rw-r--r-- | tests/verilog/genvar_loop_decl_1.ys | 14 | ||||
-rw-r--r-- | tests/verilog/genvar_loop_decl_2.sv | 30 | ||||
-rw-r--r-- | tests/verilog/genvar_loop_decl_2.ys | 5 | ||||
-rw-r--r-- | tests/verilog/genvar_loop_decl_3.sv | 28 | ||||
-rw-r--r-- | tests/verilog/genvar_loop_decl_3.ys | 5 |
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 |