From f09ea16bd18e8ca34170becd4b9f91c495e8753a Mon Sep 17 00:00:00 2001 From: Dag Lem Date: Fri, 5 Jan 2024 19:29:06 +0100 Subject: [PATCH] Resolve struct member multiple dimensions defined in stages with typedef --- frontends/ast/simplify.cc | 60 +++++------------------------- frontends/verilog/verilog_parser.y | 12 +++--- tests/svtypes/struct_array.sv | 45 ++++++++++++++++++++++ 3 files changed, 62 insertions(+), 55 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index d0e94a25b..96296aeb8 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -384,8 +384,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; } @@ -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(); diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index c4b569c5a..15a04eb28 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -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 { @@ -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 diff --git a/tests/svtypes/struct_array.sv b/tests/svtypes/struct_array.sv index bedc05b6f..e07c9b232 100644 --- a/tests/svtypes/struct_array.sv +++ b/tests/svtypes/struct_array.sv @@ -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