3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-13 04:28:18 +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:
Jannis Harder 2023-02-15 11:21:56 +01:00 committed by GitHub
commit 53bda9de54
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 22 deletions

View file

@ -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);

View file

@ -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.