mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	Merge pull request #3661 from daglem/struct-array-range-offset
Handle range offsets in packed arrays within packed structs
This commit is contained in:
		
						commit
						53bda9de54
					
				
					 2 changed files with 51 additions and 22 deletions
				
			
		|  | @ -278,17 +278,21 @@ static int range_width(AstNode *node, AstNode *rnode) | ||||||
| 	log_file_error(node->filename, node->location.first_line, "Unpacked array in packed struct/union member %s\n", node->str.c_str()); | 	log_file_error(node->filename, node->location.first_line, "Unpacked array in packed struct/union member %s\n", node->str.c_str()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void save_struct_array_width(AstNode *node, int width) | static void save_struct_range_dimensions(AstNode *node, AstNode *rnode) | ||||||
| { | { | ||||||
| 	// stash the stride for the array
 | 	node->multirange_dimensions.push_back(rnode->range_right); | ||||||
| 	node->multirange_dimensions.push_back(width); | 	node->multirange_dimensions.push_back(range_width(node, rnode)); | ||||||
| 
 | 	node->multirange_swapped.push_back(rnode->range_swapped); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void save_struct_range_swapped(AstNode *node, bool range_swapped) | static int get_struct_range_offset(AstNode *node, int dimension) | ||||||
| { | { | ||||||
| 	node->multirange_swapped.push_back(range_swapped); | 	return node->multirange_dimensions[2*dimension]; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | static int get_struct_range_width(AstNode *node, int dimension) | ||||||
|  | { | ||||||
|  | 	return node->multirange_dimensions[2*dimension + 1]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int size_packed_struct(AstNode *snode, int base_offset) | static int size_packed_struct(AstNode *snode, int base_offset) | ||||||
|  | @ -322,14 +326,17 @@ static int size_packed_struct(AstNode *snode, int base_offset) | ||||||
| 					if (node->children[1]->type == AST_RANGE) { | 					if (node->children[1]->type == AST_RANGE) { | ||||||
| 						// Unpacked array, e.g. bit [63:0] a [0:3]
 | 						// Unpacked array, e.g. bit [63:0] a [0:3]
 | ||||||
| 						auto rnode = node->children[1]; | 						auto rnode = node->children[1]; | ||||||
|  | 						if (rnode->children.size() == 1) { | ||||||
| 							// C-style array size, e.g. bit [63:0] a [4]
 | 							// C-style array size, e.g. bit [63:0] a [4]
 | ||||||
| 						bool c_type = rnode->children.size() == 1; | 							node->multirange_dimensions.push_back(0); | ||||||
| 						int array_count = c_type ? rnode->range_left : range_width(node, rnode); | 							node->multirange_dimensions.push_back(rnode->range_left); | ||||||
| 						save_struct_array_width(node, array_count); | 							node->multirange_swapped.push_back(true); | ||||||
| 						save_struct_range_swapped(node, rnode->range_swapped || c_type); | 							width *= rnode->range_left; | ||||||
| 						save_struct_array_width(node, width); | 						} else { | ||||||
| 						save_struct_range_swapped(node, node->children[0]->range_swapped); | 							save_struct_range_dimensions(node, rnode); | ||||||
| 						width *= array_count; | 							width *= range_width(node, rnode); | ||||||
|  | 						} | ||||||
|  | 						save_struct_range_dimensions(node, node->children[0]); | ||||||
| 					} | 					} | ||||||
| 					else { | 					else { | ||||||
| 						// The Yosys extension for unpacked arrays in packed structs / unions
 | 						// The Yosys extension for unpacked arrays in packed structs / unions
 | ||||||
|  | @ -338,8 +345,7 @@ static int size_packed_struct(AstNode *snode, int base_offset) | ||||||
| 					} | 					} | ||||||
| 				} else { | 				} else { | ||||||
| 					// Vector
 | 					// Vector
 | ||||||
| 					save_struct_array_width(node, width); | 					save_struct_range_dimensions(node, node->children[0]); | ||||||
| 					save_struct_range_swapped(node, node->children[0]->range_swapped); |  | ||||||
| 				} | 				} | ||||||
| 				// range nodes are now redundant
 | 				// range nodes are now redundant
 | ||||||
| 				for (AstNode *child : node->children) | 				for (AstNode *child : node->children) | ||||||
|  | @ -355,10 +361,8 @@ static int size_packed_struct(AstNode *snode, int base_offset) | ||||||
| 				} | 				} | ||||||
| 				width = 1; | 				width = 1; | ||||||
| 				for (auto rnode : node->children[0]->children) { | 				for (auto rnode : node->children[0]->children) { | ||||||
| 					int rwidth = range_width(node, rnode); | 					save_struct_range_dimensions(node, rnode); | ||||||
| 					save_struct_array_width(node, rwidth); | 					width *= range_width(node, rnode); | ||||||
| 					save_struct_range_swapped(node, rnode->range_swapped); |  | ||||||
| 					width *= rwidth; |  | ||||||
| 				} | 				} | ||||||
| 				// range nodes are now redundant
 | 				// range nodes are now redundant
 | ||||||
| 				for (AstNode *child : node->children) | 				for (AstNode *child : node->children) | ||||||
|  | @ -422,9 +426,14 @@ static AstNode *normalize_struct_index(AstNode *expr, AstNode *member_node, int | ||||||
| { | { | ||||||
| 	expr = expr->clone(); | 	expr = expr->clone(); | ||||||
| 
 | 
 | ||||||
|  | 	int offset = get_struct_range_offset(member_node, dimension); | ||||||
|  | 	if (offset) { | ||||||
|  | 		expr = new AstNode(AST_SUB, expr, node_int(offset)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (member_node->multirange_swapped[dimension]) { | 	if (member_node->multirange_swapped[dimension]) { | ||||||
| 		// The dimension has swapped range; swap index into the struct accordingly.
 | 		// The dimension has swapped range; swap index into the struct accordingly.
 | ||||||
| 		int msb = member_node->multirange_dimensions[dimension] - 1; | 		int msb = get_struct_range_width(member_node, dimension) - 1; | ||||||
| 		expr = new AstNode(AST_SUB, node_int(msb), expr); | 		expr = new AstNode(AST_SUB, node_int(msb), expr); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -433,7 +442,7 @@ static AstNode *normalize_struct_index(AstNode *expr, AstNode *member_node, int | ||||||
| 
 | 
 | ||||||
| static AstNode *struct_index_lsb_offset(AstNode *lsb_offset, AstNode *rnode, AstNode *member_node, int dimension, int &stride) | static AstNode *struct_index_lsb_offset(AstNode *lsb_offset, AstNode *rnode, AstNode *member_node, int dimension, int &stride) | ||||||
| { | { | ||||||
| 	stride /= member_node->multirange_dimensions[dimension]; | 	stride /= get_struct_range_width(member_node, dimension); | ||||||
| 	auto right = normalize_struct_index(rnode->children.back(), member_node, dimension); | 	auto right = normalize_struct_index(rnode->children.back(), member_node, dimension); | ||||||
| 	auto offset = stride > 1 ? multiply_by_const(right, stride) : right; | 	auto offset = stride > 1 ? multiply_by_const(right, stride) : right; | ||||||
| 	return new AstNode(AST_ADD, lsb_offset, offset); | 	return new AstNode(AST_ADD, lsb_offset, offset); | ||||||
|  |  | ||||||
|  | @ -141,6 +141,26 @@ module top; | ||||||
| 
 | 
 | ||||||
| 	always_comb assert(s3_llb==80'hFC00_4200_0012_3400_FFFC); | 	always_comb assert(s3_llb==80'hFC00_4200_0012_3400_FFFC); | ||||||
| 
 | 
 | ||||||
|  | 	struct packed { | ||||||
|  | 		bit [-10:-3] [-2:-1] [5:2] a; | ||||||
|  | 		bit [0:15] b;		// filler for non-zero offset
 | ||||||
|  | 	} s3_off; | ||||||
|  | 
 | ||||||
|  | 	initial begin | ||||||
|  | 		s3_off = '0; | ||||||
|  | 
 | ||||||
|  | 		s3_off.a[-5:-4] = 16'h1234; | ||||||
|  | 		s3_off.a[-8] = 8'h42; | ||||||
|  | 
 | ||||||
|  | 		s3_off.a[-10] = '1; | ||||||
|  | 		s3_off.a[-10][-1][3:0] = '0; | ||||||
|  | 
 | ||||||
|  | 		s3_off.b = '1; | ||||||
|  | 		s3_off.b[14:15] = '0; | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	always_comb assert(s3_off==80'hFC00_4200_0012_3400_FFFC); | ||||||
|  | 
 | ||||||
| `ifndef VERIFIC | `ifndef VERIFIC | ||||||
| 	// Note that the tests below for unpacked arrays in structs rely on the
 | 	// Note that the tests below for unpacked arrays in structs rely on the
 | ||||||
| 	// fact that they are actually packed in Yosys.
 | 	// fact that they are actually packed in Yosys.
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue