yosys-systemverilog: fix multirange with dot usage Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>
diff --git a/systemverilog-plugin/UhdmAst.cc b/systemverilog-plugin/UhdmAst.cc index 06a50e3..64b2203 100644 --- a/systemverilog-plugin/UhdmAst.cc +++ b/systemverilog-plugin/UhdmAst.cc
@@ -962,29 +962,47 @@ } log_assert(struct_node); auto expanded = expand_dot(struct_node, dot); - if (node->children[0]->type == AST::AST_RANGE) { - int struct_size_int = get_max_offset_struct(struct_node) + 1; - log_assert(!wire_node->multirange_dimensions.empty()); - int range = wire_node->multirange_dimensions.back() - 1; - if (!wire_node->attributes[UhdmAst::unpacked_ranges()]->children.empty() && - wire_node->attributes[UhdmAst::unpacked_ranges()]->children.back()->range_left == range) { - expanded->children[1] = new AST::AstNode( - AST::AST_ADD, expanded->children[1], - new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), - new AST::AstNode(AST::AST_SUB, AST::AstNode::mkconst_int(range, true, 32), node->children[0]->children[0]->clone()))); - expanded->children[0] = new AST::AstNode( - AST::AST_ADD, expanded->children[0], - new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), - new AST::AstNode(AST::AST_SUB, AST::AstNode::mkconst_int(range, true, 32), node->children[0]->children[0]->clone()))); - } else { - expanded->children[1] = new AST::AstNode( - AST::AST_ADD, expanded->children[1], - new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), node->children[0]->children[0]->clone())); - expanded->children[0] = new AST::AstNode( - AST::AST_ADD, expanded->children[0], - new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), node->children[0]->children[0]->clone())); + std::vector<AST::AstNode *> struct_ranges; + for (auto c : node->children) { + if (c->type == AST::AST_RANGE) { + struct_ranges.push_back(c); } } + const auto wire_node_unpacked_ranges_size = wire_node->attributes[UhdmAst::unpacked_ranges()]->children.size(); + // 'dot' notation can only be used on specific struct element + // '1' packed range is from wiretype and it is already expanded in 'expand_dot' + // TODO(krak): wire ranges are sometimes under wiretype node (e.g. in case of typedef) + // but wiretype ranges contains also struct range that is already expanded in 'expand_dot' + // we need to find a way to calculate size of wire ranges without struct range here to enable this assert + // const auto wire_node_packed_ranges_size = wire_node->attributes[UhdmAst::packed_ranges()]->children.size(); + // const auto wire_node_ranges_size = wire_node_packed_ranges_size + wire_node_unpacked_ranges_size; + // log_assert(struct_ranges.size() == (wire_node_ranges_size - 1)); + + // Get size of single structure + int struct_size_int = get_max_offset_struct(struct_node) + 1; + // Get reverse iterator of wire dimensions + auto dimensions_it = wire_node->multirange_dimensions.rbegin(); + unsigned long range_id = 0; + for (auto it = struct_ranges.rbegin(); it != struct_ranges.rend(); it++) { + // in 'dot' context, we need to select specific struct + // element, so assert that there is only 1 child (range with single const) in struct + log_assert((*it)->children.size() == 1); + bool is_unpacked_range = range_id < wire_node_unpacked_ranges_size; + // if unpacked range, select from back; + auto elem = is_unpacked_range + ? new AST::AstNode(AST::AST_SUB, AST::AstNode::mkconst_int(*dimensions_it - 1, true, 32), (*it)->children[0]->clone()) + : (*it)->children[0]->clone(); + // calculate which struct we selected + auto move_offset = new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), elem); + // move our expanded dot to currently selected struct + expanded->children[0] = new AST::AstNode(AST::AST_ADD, move_offset->clone(), expanded->children[0]); + expanded->children[1] = new AST::AstNode(AST::AST_ADD, move_offset, expanded->children[1]); + // next range, multiply struct_size_int by whole dimension size + struct_size_int *= *dimensions_it; + // move iterator to next dimension width + dimensions_it += 2; + range_id++; + } return expanded; }