systemverilog-plugin: add support for custom type with multiranges inside struct/union Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>
diff --git a/systemverilog-plugin/UhdmAst.cc b/systemverilog-plugin/UhdmAst.cc index ca8f32d..e456857 100644 --- a/systemverilog-plugin/UhdmAst.cc +++ b/systemverilog-plugin/UhdmAst.cc
@@ -350,7 +350,8 @@ // needs to have access to all already defined ids while (wire_node->simplify(true, false, false, 1, -1, false, false)) { } - if (wiretype_ast->children[0]->type == AST::AST_STRUCT && wire_node->type == AST::AST_WIRE) { + if ((wiretype_ast->children[0]->type == AST::AST_STRUCT || wiretype_ast->children[0]->type == AST::AST_UNION) && + wire_node->type == AST::AST_WIRE) { auto struct_width = get_max_offset_struct(wiretype_ast->children[0]); wire_node->range_left = struct_width; wire_node->children[0]->range_left = struct_width; @@ -606,22 +607,18 @@ current_struct_elem = *struct_elem_it; AST::AstNode *left = nullptr, *right = nullptr; - if (current_struct_elem->type == AST::AST_STRUCT_ITEM) { + switch (current_struct_elem->type) { + case AST::AST_STRUCT_ITEM: + case AST::AST_STRUCT: + case AST::AST_UNION: left = AST::AstNode::mkconst_int(current_struct_elem->range_left, true); right = AST::AstNode::mkconst_int(current_struct_elem->range_right, true); - } else if (current_struct_elem->type == AST::AST_STRUCT) { - // Struct can have multiple range, so to get size of 1 struct, - // we get left range for first children, and right range for last children - left = AST::AstNode::mkconst_int(current_struct_elem->children.front()->range_left, true); - right = AST::AstNode::mkconst_int(current_struct_elem->children.back()->range_right, true); - } else if (current_struct_elem->type == AST::AST_UNION) { - left = AST::AstNode::mkconst_int(current_struct_elem->range_left, true); - right = AST::AstNode::mkconst_int(current_struct_elem->range_right, true); - } else { + break; + default: // Structs currently can only have AST_STRUCT, AST_STRUCT_ITEM, or AST_UNION. log_file_error(current_struct_elem->filename, current_struct_elem->location.first_line, "Accessing struct member of type %s is unsupported.\n", type2str(current_struct_elem->type).c_str()); - } + }; auto elem_size = new AST::AstNode(AST::AST_ADD, new AST::AstNode(AST::AST_SUB, left->clone(), right->clone()), AST::AstNode::mkconst_int(1, true)); @@ -636,7 +633,9 @@ } if (c->type == AST::AST_RANGE) { // Currently supporting only 1 range - log_assert(!struct_range); + if (struct_range) { + log_error("Currently support for dot-access is limited to single range\n"); + } struct_range = c; } } @@ -817,10 +816,6 @@ std::vector<AST::AstNode *> ranges(it, snode->children.end()); snode->children.erase(it, snode->children.end()); if (!ranges.empty()) { - if (ranges.size() > 1) { - log_file_error(ranges[1]->filename, ranges[1]->location.first_line, - "Currently support for custom-type with range is limited to single range\n"); - } for (auto range : ranges) { snode->multirange_dimensions.push_back(min(range->range_left, range->range_right)); snode->multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1); @@ -835,9 +830,10 @@ // embedded struct or union width = simplify_struct(node, base_offset + offset, parent_node); if (!node->multirange_dimensions.empty()) { - int number_of_structs = 1; - number_of_structs = node->multirange_dimensions.back(); - width *= number_of_structs; + // reverse-iterate over multiranges, skip right_range + for (auto rit = node->multirange_dimensions.rbegin(); rit != node->multirange_dimensions.rend(); rit += 2) { + width *= *rit; + } } // set range of struct node->range_right = base_offset + offset;