mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-30 19:22:31 +00:00 
			
		
		
		
	Resolve struct member multiple dimensions defined in stages with typedef
This commit is contained in:
		
							parent
							
								
									fab326d3e8
								
							
						
					
					
						commit
						f09ea16bd1
					
				
					 3 changed files with 62 additions and 55 deletions
				
			
		|  | @ -384,7 +384,6 @@ static int size_packed_struct(AstNode *snode, int base_offset) | |||
| 	snode->range_right = base_offset; | ||||
| 	snode->range_left = base_offset + width - 1; | ||||
| 	snode->range_valid = true; | ||||
| 	if (snode->dimensions.empty()) | ||||
| 	snode->dimensions.push_back({ 0, width, false }); | ||||
| 
 | ||||
| 	return width; | ||||
|  | @ -1439,57 +1438,16 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin | |||
| 
 | ||||
| 	case AST_STRUCT_ITEM: | ||||
| 		if (is_custom_type) { | ||||
| 			log_assert(children.size() == 1); | ||||
| 			log_assert(children.size() >= 1); | ||||
| 			log_assert(children[0]->type == AST_WIRETYPE); | ||||
| 			auto type_name = children[0]->str; | ||||
| 			if (!current_scope.count(type_name)) { | ||||
| 				log_file_error(filename, location.first_line, "Unknown identifier `%s' used as type name\n", type_name.c_str()); | ||||
| 			} | ||||
| 			AstNode *resolved_type_node = current_scope.at(type_name); | ||||
| 			if (resolved_type_node->type != AST_TYPEDEF) | ||||
| 				log_file_error(filename, location.first_line, "`%s' does not name a type\n", type_name.c_str()); | ||||
| 			log_assert(resolved_type_node->children.size() == 1); | ||||
| 			AstNode *template_node = resolved_type_node->children[0]; | ||||
| 
 | ||||
| 			// Ensure typedef itself is fully simplified
 | ||||
| 			while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; | ||||
| 
 | ||||
| 			// Remove type reference
 | ||||
| 			delete children[0]; | ||||
| 			children.pop_back(); | ||||
| 
 | ||||
| 			switch (template_node->type) { | ||||
| 			case AST_WIRE: | ||||
| 			// Pretend it's just a wire in order to resolve the type.
 | ||||
| 			type = AST_WIRE; | ||||
| 			while (is_custom_type && simplify(const_fold, stage, width_hint, sign_hint)) {}; | ||||
| 			if (type == AST_WIRE) | ||||
| 				type = AST_STRUCT_ITEM; | ||||
| 				break; | ||||
| 			case AST_STRUCT: | ||||
| 			case AST_UNION: | ||||
| 				type = template_node->type; | ||||
| 				break; | ||||
| 			default: | ||||
| 				log_file_error(filename, location.first_line, "Invalid type for struct member: %s", type2str(template_node->type).c_str()); | ||||
| 			} | ||||
| 
 | ||||
| 			is_reg = template_node->is_reg; | ||||
| 			is_logic = template_node->is_logic; | ||||
| 			is_signed = template_node->is_signed; | ||||
| 			is_string = template_node->is_string; | ||||
| 			is_custom_type = template_node->is_custom_type; | ||||
| 
 | ||||
| 			range_valid = template_node->range_valid; | ||||
| 			range_swapped = template_node->range_swapped; | ||||
| 			range_left = template_node->range_left; | ||||
| 			range_right = template_node->range_right; | ||||
| 
 | ||||
| 			set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); | ||||
| 
 | ||||
| 			// Copy clones of children from template
 | ||||
| 			for (auto template_child : template_node->children) { | ||||
| 				children.push_back(template_child->clone()); | ||||
| 			} | ||||
| 
 | ||||
| 			did_something = true; | ||||
| 
 | ||||
| 		} | ||||
| 		log_assert(!is_custom_type); | ||||
| 		break; | ||||
|  | @ -1963,14 +1921,16 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin | |||
| 		if (is_custom_type) { | ||||
| 			log_assert(children.size() >= 2); | ||||
| 			log_assert(children[1]->type == AST_WIRETYPE); | ||||
| 			// Pretend it's a wire in order to resolve the type in the code block above.
 | ||||
| 
 | ||||
| 			// Pretend it's just a wire in order to resolve the type in the code block above.
 | ||||
| 			AstNodeType param_type = type; | ||||
| 			type = AST_WIRE; | ||||
| 			AstNode *expr = children[0]; | ||||
| 			children.erase(children.begin()); | ||||
| 			while (simplify(const_fold, stage, width_hint, sign_hint)) {}; | ||||
| 			while (is_custom_type && simplify(const_fold, stage, width_hint, sign_hint)) {}; | ||||
| 			type = param_type; | ||||
| 			children.insert(children.begin(), expr); | ||||
| 
 | ||||
| 			if (children[1]->type == AST_MEMORY) | ||||
| 				input_error("unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str()); | ||||
| 			fixup_hierarchy_flags(); | ||||
|  |  | |||
|  | @ -1900,9 +1900,10 @@ struct_member_type: { astbuf1 = new AstNode(AST_STRUCT_ITEM); } member_type_toke | |||
| 	; | ||||
| 
 | ||||
| member_type_token: | ||||
| 	  member_type | ||||
| 	| hierarchical_type_id { | ||||
| 			addWiretypeNode($1, astbuf1); | ||||
| 	member_type range_or_multirange { | ||||
| 		AstNode *range = checkRange(astbuf1, $2); | ||||
| 		if (range) | ||||
| 			astbuf1->children.push_back(range); | ||||
| 	} | ||||
| 	| { | ||||
| 		delete astbuf1; | ||||
|  | @ -1919,7 +1920,8 @@ member_type_token: | |||
| 	; | ||||
| 
 | ||||
| member_type: type_atom type_signing | ||||
| 	| type_vec type_signing range_or_multirange	{ if ($3) astbuf1->children.push_back($3); } | ||||
| 	| type_vec type_signing | ||||
| 	| hierarchical_type_id { addWiretypeNode($1, astbuf1); } | ||||
| 	; | ||||
| 
 | ||||
| struct_var_list: struct_var | ||||
|  |  | |||
|  | @ -23,6 +23,29 @@ module top; | |||
| 	always_comb assert(s.b[23:16]===8'hxx); | ||||
| 	always_comb assert(s.b[19:12]===8'hxf); | ||||
| 
 | ||||
| 	// Same as s, but defining dimensions in stages with typedef
 | ||||
| 	typedef bit [7:0] bit8_t; | ||||
| 	struct packed { | ||||
| 		bit8_t [5:0] a;		// 6 element packed array of bytes
 | ||||
| 		bit [15:0] b;		// filler for non-zero offset
 | ||||
| 	} s_s; | ||||
| 
 | ||||
| 	initial begin | ||||
| 		s_s = '0; | ||||
| 
 | ||||
| 		s_s.a[2:1] = 16'h1234; | ||||
| 		s_s.a[5] = 8'h42; | ||||
| 		s_s.a[-1] = '0; | ||||
| 
 | ||||
| 		s_s.b = '1; | ||||
| 		s_s.b[1:0] = '0; | ||||
| 	end | ||||
| 
 | ||||
| 	always_comb assert(s_s==64'h4200_0012_3400_FFFC); | ||||
| 	always_comb assert(s_s.a[0][3:-4]===8'h0x); | ||||
| 	always_comb assert(s_s.b[23:16]===8'hxx); | ||||
| 	always_comb assert(s_s.b[19:12]===8'hxf); | ||||
| 
 | ||||
| 	struct packed { | ||||
| 		bit [7:0] [7:0] a;	// 8 element packed array of bytes
 | ||||
| 		bit [15:0] b;		// filler for non-zero offset
 | ||||
|  | @ -125,6 +148,28 @@ module top; | |||
| 
 | ||||
| 	always_comb assert(s3_lbl==80'hFC00_4200_0012_3400_FFFC); | ||||
| 
 | ||||
| 	// Same as s3_lbl, but defining dimensions in stages with typedef
 | ||||
| 	typedef bit [0:3] bit3l_t; | ||||
| 	struct packed { | ||||
| 		bit3l_t [0:7] [1:0] a; | ||||
| 		bit [0:15] b;		// filler for non-zero offset
 | ||||
| 	} s3_lbl_s; | ||||
| 
 | ||||
| 	initial begin | ||||
| 		s3_lbl_s = '0; | ||||
| 
 | ||||
| 		s3_lbl_s.a[5:6] = 16'h1234; | ||||
| 		s3_lbl_s.a[2] = 8'h42; | ||||
| 
 | ||||
| 		s3_lbl_s.a[0] = '1; | ||||
| 		s3_lbl_s.a[0][0][2:3] = '0; | ||||
| 
 | ||||
| 		s3_lbl_s.b = '1; | ||||
| 		s3_lbl_s.b[14:15] = '0; | ||||
| 	end | ||||
| 
 | ||||
| 	always_comb assert(s3_lbl_s==80'hFC00_4200_0012_3400_FFFC); | ||||
| 
 | ||||
| 	struct packed { | ||||
| 		bit [0:7] [0:1] [3:0] a; | ||||
| 		bit [0:15] b;		// filler for non-zero offset
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue