Skip to content

Commit

Permalink
Resolve struct member multiple dimensions defined in stages with typedef
Browse files Browse the repository at this point in the history
  • Loading branch information
daglem committed Jan 29, 2024
1 parent 3700d47 commit f57abd4
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 55 deletions.
60 changes: 10 additions & 50 deletions frontends/ast/simplify.cc
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,7 @@ 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 });
snode->dimensions.push_back({ 0, width, false });

return width;
}
Expand Down Expand Up @@ -1435,57 +1434,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;
Expand Down Expand Up @@ -1959,14 +1917,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();
Expand Down
12 changes: 7 additions & 5 deletions frontends/verilog/verilog_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -1900,10 +1900,11 @@ 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;
} struct_union {
Expand All @@ -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
Expand Down
45 changes: 45 additions & 0 deletions tests/svtypes/struct_array.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit f57abd4

Please sign in to comment.