mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 13:29:12 +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];
 | 
				
			||||||
						// C-style array size, e.g. bit [63:0] a [4]
 | 
											if (rnode->children.size() == 1) {
 | 
				
			||||||
						bool c_type = rnode->children.size() == 1;
 | 
												// C-style array size, e.g. bit [63:0] a [4]
 | 
				
			||||||
						int array_count = c_type ? rnode->range_left : range_width(node, rnode);
 | 
												node->multirange_dimensions.push_back(0);
 | 
				
			||||||
						save_struct_array_width(node, array_count);
 | 
												node->multirange_dimensions.push_back(rnode->range_left);
 | 
				
			||||||
						save_struct_range_swapped(node, rnode->range_swapped || c_type);
 | 
												node->multirange_swapped.push_back(true);
 | 
				
			||||||
						save_struct_array_width(node, width);
 | 
												width *= rnode->range_left;
 | 
				
			||||||
						save_struct_range_swapped(node, node->children[0]->range_swapped);
 | 
											} else {
 | 
				
			||||||
						width *= array_count;
 | 
												save_struct_range_dimensions(node, rnode);
 | 
				
			||||||
 | 
												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