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 /frontends/verilog/verilog_parser.y | |
| 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.
Diffstat (limited to 'frontends/verilog/verilog_parser.y')
| -rw-r--r-- | frontends/verilog/verilog_parser.y | 96 | 
1 files changed, 95 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 ')' { | 
