Skip to content

Commit 6689e20

Browse files
authored
Merge pull request chipsalliance#529 from antmicro/kr/fix_multirange_with_dot
yosys-systemverilog: fix multirange with dot usage
2 parents 188555f + c12a4b8 commit 6689e20

File tree

1 file changed

+41
-21
lines changed

1 file changed

+41
-21
lines changed

systemverilog-plugin/UhdmAst.cc

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -958,29 +958,49 @@ static AST::AstNode *convert_dot(AST::AstNode *wire_node, AST::AstNode *node, AS
958958
}
959959
log_assert(struct_node);
960960
auto expanded = expand_dot(struct_node, dot);
961-
if (node->children[0]->type == AST::AST_RANGE) {
962-
int struct_size_int = get_max_offset_struct(struct_node) + 1;
963-
log_assert(!wire_node->multirange_dimensions.empty());
964-
int range = wire_node->multirange_dimensions.back() - 1;
965-
if (!wire_node->attributes[UhdmAst::unpacked_ranges()]->children.empty() &&
966-
wire_node->attributes[UhdmAst::unpacked_ranges()]->children.back()->range_left == range) {
967-
expanded->children[1] = new AST::AstNode(
968-
AST::AST_ADD, expanded->children[1],
969-
new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32),
970-
new AST::AstNode(AST::AST_SUB, AST::AstNode::mkconst_int(range, true, 32), node->children[0]->children[0]->clone())));
971-
expanded->children[0] = new AST::AstNode(
972-
AST::AST_ADD, expanded->children[0],
973-
new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32),
974-
new AST::AstNode(AST::AST_SUB, AST::AstNode::mkconst_int(range, true, 32), node->children[0]->children[0]->clone())));
975-
} else {
976-
expanded->children[1] = new AST::AstNode(
977-
AST::AST_ADD, expanded->children[1],
978-
new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), node->children[0]->children[0]->clone()));
979-
expanded->children[0] = new AST::AstNode(
980-
AST::AST_ADD, expanded->children[0],
981-
new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), node->children[0]->children[0]->clone()));
961+
// Now expand ranges that are at instance part of dotted reference
962+
// `expand_dot` returns AST_RANGE with 2 children that selects member pointed by dotted reference
963+
// now we need to move this range to select correct struct
964+
std::vector<AST::AstNode *> struct_ranges;
965+
for (auto c : node->children) {
966+
if (c->type == AST::AST_RANGE) {
967+
struct_ranges.push_back(c);
982968
}
983969
}
970+
log_assert(wire_node->attributes.count(UhdmAst::unpacked_ranges()));
971+
log_assert(wire_node->attributes.count(UhdmAst::packed_ranges()));
972+
log_assert(struct_ranges.size() <= (wire_node->multirange_dimensions.size() / 2));
973+
const auto wire_node_unpacked_ranges_size = wire_node->attributes[UhdmAst::unpacked_ranges()]->children.size();
974+
// TODO(krak): wire ranges are sometimes under wiretype node (e.g. in case of typedef)
975+
// but wiretype ranges contains also struct range that is already expanded in 'expand_dot'
976+
// we need to find a way to calculate size of wire ranges without struct range here to enable this assert
977+
// const auto wire_node_packed_ranges_size = wire_node->attributes[UhdmAst::packed_ranges()]->children.size();
978+
// const auto wire_node_ranges_size = wire_node_packed_ranges_size + wire_node_unpacked_ranges_size;
979+
// log_assert(struct_ranges.size() == (wire_node_ranges_size - 1));
980+
981+
// Get size of single structure
982+
int struct_size_int = get_max_offset_struct(struct_node) + 1;
983+
auto wire_dimension_size_it = wire_node->multirange_dimensions.rbegin();
984+
unsigned long range_id = 0;
985+
for (auto it = struct_ranges.rbegin(); it != struct_ranges.rend(); it++) {
986+
// in 'dot' context, we need to select specific struct element,
987+
// so assert that there is only 1 child in struct range (range with single child)
988+
log_assert((*it)->children.size() == 1);
989+
bool is_unpacked_range = range_id < wire_node_unpacked_ranges_size;
990+
// if unpacked range, select from back
991+
auto elem = is_unpacked_range
992+
? new AST::AstNode(AST::AST_SUB, AST::AstNode::mkconst_int(*wire_dimension_size_it - 1, true, 32), (*it)->children[0]->clone())
993+
: (*it)->children[0]->clone();
994+
// calculate which struct we selected
995+
auto move_offset = new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), elem);
996+
// move our expanded dot to currently selected struct
997+
expanded->children[0] = new AST::AstNode(AST::AST_ADD, move_offset->clone(), expanded->children[0]);
998+
expanded->children[1] = new AST::AstNode(AST::AST_ADD, move_offset, expanded->children[1]);
999+
struct_size_int *= *wire_dimension_size_it;
1000+
// wire_dimension_size stores interleaved offset and size. Move to next dimension's size
1001+
wire_dimension_size_it += 2;
1002+
range_id++;
1003+
}
9841004
return expanded;
9851005
}
9861006

0 commit comments

Comments
 (0)