mirror of https://github.com/YosysHQ/yosys.git
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.
This commit is contained in:
parent
b20bb653ce
commit
b2e9717419
|
@ -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 ')' {
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
read_verilog -sv genvar_loop_decl_2.sv
|
||||
proc
|
||||
equiv_make gold gate equiv
|
||||
equiv_simple
|
||||
equiv_status -assert
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
read_verilog -sv genvar_loop_decl_3.sv
|
||||
proc
|
||||
equiv_make gold gate equiv
|
||||
equiv_simple
|
||||
equiv_status -assert
|
Loading…
Reference in New Issue