mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-03 21:09:12 +00:00 
			
		
		
		
	Merge pull request #2317 from zachjs/expand-genblock
Fix generate scoping issues
This commit is contained in:
		
						commit
						a9681f4e06
					
				
					 3 changed files with 168 additions and 42 deletions
				
			
		| 
						 | 
				
			
			@ -250,7 +250,7 @@ namespace AST
 | 
			
		|||
		// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
 | 
			
		||||
		bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);
 | 
			
		||||
		AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
 | 
			
		||||
		void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
 | 
			
		||||
		void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map, bool original_scope = true);
 | 
			
		||||
		void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);
 | 
			
		||||
		void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
 | 
			
		||||
				dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3711,8 +3711,11 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// annotate the names of all wires and other named objects in a generate block
 | 
			
		||||
void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map)
 | 
			
		||||
void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map, bool original_scope)
 | 
			
		||||
{
 | 
			
		||||
	// `original_scope` defaults to false, and is used to prevent the premature
 | 
			
		||||
	// prefixing of items in named sub-blocks
 | 
			
		||||
 | 
			
		||||
	if (!index_var.empty() && type == AST_IDENTIFIER && str == index_var) {
 | 
			
		||||
		if (children.empty()) {
 | 
			
		||||
			current_scope[index_var]->children[0]->cloneInto(this);
 | 
			
		||||
| 
						 | 
				
			
			@ -3725,53 +3728,85 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL || type == AST_WIRETYPE) && name_map.count(str) > 0)
 | 
			
		||||
		str = name_map[str];
 | 
			
		||||
	if (type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL || type == AST_WIRETYPE) {
 | 
			
		||||
		if (name_map.count(str) > 0) {
 | 
			
		||||
			str = name_map[str];
 | 
			
		||||
		} else {
 | 
			
		||||
			// remap the prefix of this ident if it is a local generate scope
 | 
			
		||||
			size_t pos = str.rfind('.');
 | 
			
		||||
			if (pos != std::string::npos) {
 | 
			
		||||
				std::string existing_prefix = str.substr(0, pos);
 | 
			
		||||
				if (name_map.count(existing_prefix) > 0) {
 | 
			
		||||
					str = name_map[existing_prefix] + str.substr(pos);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::map<std::string, std::string> backup_name_map;
 | 
			
		||||
 | 
			
		||||
	auto prefix_node = [&](AstNode* child) {
 | 
			
		||||
		if (backup_name_map.size() == 0)
 | 
			
		||||
			backup_name_map = name_map;
 | 
			
		||||
 | 
			
		||||
		// if within a nested scope
 | 
			
		||||
		if (!original_scope) {
 | 
			
		||||
			// this declaration shadows anything in the parent scope(s)
 | 
			
		||||
			name_map[child->str] = child->str;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix;
 | 
			
		||||
		size_t pos = child->str.rfind('.');
 | 
			
		||||
		if (pos == std::string::npos)
 | 
			
		||||
			pos = child->str[0] == '\\' && prefix[0] == '\\' ? 1 : 0;
 | 
			
		||||
		else
 | 
			
		||||
			pos = pos + 1;
 | 
			
		||||
		new_name = child->str.substr(0, pos) + new_name + child->str.substr(pos);
 | 
			
		||||
		if (new_name[0] != '$' && new_name[0] != '\\')
 | 
			
		||||
			new_name = prefix[0] + new_name;
 | 
			
		||||
 | 
			
		||||
		name_map[child->str] = new_name;
 | 
			
		||||
		if (child->type == AST_FUNCTION)
 | 
			
		||||
			replace_result_wire_name_in_function(child, child->str, new_name);
 | 
			
		||||
		else
 | 
			
		||||
			child->str = new_name;
 | 
			
		||||
		current_scope[new_name] = child;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < children.size(); i++) {
 | 
			
		||||
		AstNode *child = children[i];
 | 
			
		||||
		if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM ||
 | 
			
		||||
				child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL || child->type == AST_TYPEDEF || child->type == AST_ENUM_ITEM) {
 | 
			
		||||
			if (backup_name_map.size() == 0)
 | 
			
		||||
				backup_name_map = name_map;
 | 
			
		||||
			std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix;
 | 
			
		||||
			size_t pos = child->str.rfind('.');
 | 
			
		||||
			if (pos == std::string::npos)
 | 
			
		||||
				pos = child->str[0] == '\\' && prefix[0] == '\\' ? 1 : 0;
 | 
			
		||||
			else
 | 
			
		||||
				pos = pos + 1;
 | 
			
		||||
			new_name = child->str.substr(0, pos) + new_name + child->str.substr(pos);
 | 
			
		||||
			if (new_name[0] != '$' && new_name[0] != '\\')
 | 
			
		||||
				new_name = prefix[0] + new_name;
 | 
			
		||||
			name_map[child->str] = new_name;
 | 
			
		||||
			if (child->type == AST_FUNCTION)
 | 
			
		||||
				replace_result_wire_name_in_function(child, child->str, new_name);
 | 
			
		||||
			else
 | 
			
		||||
				child->str = new_name;
 | 
			
		||||
			current_scope[new_name] = child;
 | 
			
		||||
		}
 | 
			
		||||
		if (child->type == AST_ENUM){
 | 
			
		||||
 | 
			
		||||
		switch (child->type) {
 | 
			
		||||
		case AST_WIRE:
 | 
			
		||||
		case AST_MEMORY:
 | 
			
		||||
		case AST_PARAMETER:
 | 
			
		||||
		case AST_LOCALPARAM:
 | 
			
		||||
		case AST_FUNCTION:
 | 
			
		||||
		case AST_TASK:
 | 
			
		||||
		case AST_CELL:
 | 
			
		||||
		case AST_TYPEDEF:
 | 
			
		||||
		case AST_ENUM_ITEM:
 | 
			
		||||
		case AST_GENVAR:
 | 
			
		||||
			prefix_node(child);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case AST_BLOCK:
 | 
			
		||||
		case AST_GENBLOCK:
 | 
			
		||||
			if (!child->str.empty())
 | 
			
		||||
				prefix_node(child);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case AST_ENUM:
 | 
			
		||||
			current_scope[child->str] = child;
 | 
			
		||||
			for (auto enode : child->children){
 | 
			
		||||
				log_assert(enode->type == AST_ENUM_ITEM);
 | 
			
		||||
				if (backup_name_map.size() == 0)
 | 
			
		||||
					backup_name_map = name_map;
 | 
			
		||||
				std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix;
 | 
			
		||||
				size_t pos = enode->str.rfind('.');
 | 
			
		||||
				if (pos == std::string::npos)
 | 
			
		||||
					pos = enode->str[0] == '\\' && prefix[0] == '\\' ? 1 : 0;
 | 
			
		||||
				else
 | 
			
		||||
					pos = pos + 1;
 | 
			
		||||
				new_name = enode->str.substr(0, pos) + new_name + enode->str.substr(pos);
 | 
			
		||||
				if (new_name[0] != '$' && new_name[0] != '\\')
 | 
			
		||||
					new_name = prefix[0] + new_name;
 | 
			
		||||
				name_map[enode->str] = new_name;
 | 
			
		||||
 | 
			
		||||
				enode->str = new_name;
 | 
			
		||||
				current_scope[new_name] = enode;
 | 
			
		||||
				prefix_node(enode);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3781,8 +3816,14 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
 | 
			
		|||
		// still needs to recursed-into
 | 
			
		||||
		if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (child->type != AST_FUNCTION && child->type != AST_TASK)
 | 
			
		||||
			child->expand_genblock(index_var, prefix, name_map);
 | 
			
		||||
		// functions/tasks may reference wires, constants, etc. in this scope
 | 
			
		||||
		if (child->type == AST_FUNCTION || child->type == AST_TASK)
 | 
			
		||||
			child->expand_genblock(index_var, prefix, name_map, false);
 | 
			
		||||
		// continue prefixing if this child block is anonymous
 | 
			
		||||
		else if (child->type == AST_GENBLOCK || child->type == AST_BLOCK)
 | 
			
		||||
			child->expand_genblock(index_var, prefix, name_map, original_scope && child->str.empty());
 | 
			
		||||
		else
 | 
			
		||||
			child->expand_genblock(index_var, prefix, name_map, original_scope);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -159,3 +159,88 @@ generate
 | 
			
		|||
    end
 | 
			
		||||
endgenerate
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------
 | 
			
		||||
 | 
			
		||||
module gen_test7;
 | 
			
		||||
	reg [2:0] out1;
 | 
			
		||||
	reg [2:0] out2;
 | 
			
		||||
	wire [2:0] out3;
 | 
			
		||||
	generate
 | 
			
		||||
		begin : cond
 | 
			
		||||
			reg [2:0] sub_out1;
 | 
			
		||||
			reg [2:0] sub_out2;
 | 
			
		||||
			wire [2:0] sub_out3;
 | 
			
		||||
			initial begin : init
 | 
			
		||||
				reg signed [31:0] x;
 | 
			
		||||
				x = 2 ** 2;
 | 
			
		||||
				out1 = x;
 | 
			
		||||
				sub_out1 = x;
 | 
			
		||||
			end
 | 
			
		||||
			always @* begin : proc
 | 
			
		||||
				reg signed [31:0] x;
 | 
			
		||||
				x = 2 ** 1;
 | 
			
		||||
				out2 = x;
 | 
			
		||||
				sub_out2 = x;
 | 
			
		||||
			end
 | 
			
		||||
			genvar x;
 | 
			
		||||
			for (x = 0; x < 3; x = x + 1) begin
 | 
			
		||||
				assign out3[x] = 1;
 | 
			
		||||
				assign sub_out3[x] = 1;
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	endgenerate
 | 
			
		||||
 | 
			
		||||
// `define VERIFY
 | 
			
		||||
`ifdef VERIFY
 | 
			
		||||
	assert property (out1 == 4);
 | 
			
		||||
	assert property (out2 == 2);
 | 
			
		||||
	assert property (out3 == 7);
 | 
			
		||||
	assert property (cond.sub_out1 == 4);
 | 
			
		||||
	assert property (cond.sub_out2 == 2);
 | 
			
		||||
	assert property (cond.sub_out3 == 7);
 | 
			
		||||
`endif
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------
 | 
			
		||||
 | 
			
		||||
module gen_test8;
 | 
			
		||||
 | 
			
		||||
// `define VERIFY
 | 
			
		||||
`ifdef VERIFY
 | 
			
		||||
	`define ASSERT(expr) assert property (expr);
 | 
			
		||||
`else
 | 
			
		||||
	`define ASSERT(expr)
 | 
			
		||||
`endif
 | 
			
		||||
 | 
			
		||||
	wire [1:0] x = 2'b11;
 | 
			
		||||
	generate
 | 
			
		||||
		begin : A
 | 
			
		||||
			wire [1:0] x;
 | 
			
		||||
			begin : B
 | 
			
		||||
				wire [1:0] x = 2'b00;
 | 
			
		||||
				`ASSERT(x == 0)
 | 
			
		||||
				`ASSERT(A.x == 2)
 | 
			
		||||
				`ASSERT(A.C.x == 1)
 | 
			
		||||
				`ASSERT(A.B.x == 0)
 | 
			
		||||
			end
 | 
			
		||||
			begin : C
 | 
			
		||||
				wire [1:0] x = 2'b01;
 | 
			
		||||
				`ASSERT(x == 1)
 | 
			
		||||
				`ASSERT(A.x == 2)
 | 
			
		||||
				`ASSERT(A.C.x == 1)
 | 
			
		||||
				`ASSERT(A.B.x == 0)
 | 
			
		||||
			end
 | 
			
		||||
			assign x = B.x ^ 2'b11 ^ C.x;
 | 
			
		||||
			`ASSERT(x == 2)
 | 
			
		||||
			`ASSERT(A.x == 2)
 | 
			
		||||
			`ASSERT(A.C.x == 1)
 | 
			
		||||
			`ASSERT(A.B.x == 0)
 | 
			
		||||
		end
 | 
			
		||||
	endgenerate
 | 
			
		||||
 | 
			
		||||
	`ASSERT(x == 3)
 | 
			
		||||
	`ASSERT(A.x == 2)
 | 
			
		||||
	`ASSERT(A.C.x == 1)
 | 
			
		||||
	`ASSERT(A.B.x == 0)
 | 
			
		||||
endmodule
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue