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);
|
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}
|
%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 <al> attr case_attr
|
||||||
%type <ast> struct_union
|
%type <ast> struct_union
|
||||||
%type <ast_node_type> asgn_binop
|
%type <ast_node_type> asgn_binop
|
||||||
|
%type <ast> genvar_identifier
|
||||||
|
|
||||||
%type <specify_target_ptr> specify_target
|
%type <specify_target_ptr> specify_target
|
||||||
%type <specify_triple_ptr> specify_triple specify_opt_triple
|
%type <specify_triple_ptr> specify_triple specify_opt_triple
|
||||||
|
@ -2978,16 +3038,50 @@ gen_stmt_or_module_body_stmt:
|
||||||
free_attr($1);
|
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
|
// this production creates the obligatory if-else shift/reduce conflict
|
||||||
gen_stmt:
|
gen_stmt:
|
||||||
TOK_FOR '(' {
|
TOK_FOR '(' {
|
||||||
AstNode *node = new AstNode(AST_GENFOR);
|
AstNode *node = new AstNode(AST_GENFOR);
|
||||||
ast_stack.back()->children.push_back(node);
|
ast_stack.back()->children.push_back(node);
|
||||||
ast_stack.push_back(node);
|
ast_stack.push_back(node);
|
||||||
} simple_behavioral_stmt ';' expr {
|
} genvar_initialization ';' expr {
|
||||||
ast_stack.back()->children.push_back($6);
|
ast_stack.back()->children.push_back($6);
|
||||||
} ';' simple_behavioral_stmt ')' gen_stmt_block {
|
} ';' simple_behavioral_stmt ')' gen_stmt_block {
|
||||||
SET_AST_NODE_LOC(ast_stack.back(), @1, @11);
|
SET_AST_NODE_LOC(ast_stack.back(), @1, @11);
|
||||||
|
rewriteGenForDeclInit(ast_stack.back());
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
} |
|
} |
|
||||||
TOK_IF '(' expr ')' {
|
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