Skip to content

Commit 20a9495

Browse files
committed
allow multiple ranges in dot notation
1 parent c14110b commit 20a9495

File tree

1 file changed

+51
-25
lines changed

1 file changed

+51
-25
lines changed

systemverilog-plugin/UhdmAst.cc

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -325,9 +325,12 @@ static size_t add_multirange_attribute(AST::AstNode *wire_node, const std::vecto
325325
}
326326
log_assert(ranges[i]->children[0]->type == AST::AST_CONSTANT);
327327
log_assert(ranges[i]->children[1]->type == AST::AST_CONSTANT);
328-
auto elem_size = max(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer) -
329-
min(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer) + 1;
330-
wire_node->multirange_dimensions.push_back(min(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer));
328+
329+
const auto low = min(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer);
330+
const auto high = max(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer);
331+
const auto elem_size = high - low + 1;
332+
333+
wire_node->multirange_dimensions.push_back(low);
331334
wire_node->multirange_dimensions.push_back(elem_size);
332335
wire_node->multirange_swapped.push_back(ranges[i]->range_swapped);
333336
size *= elem_size;
@@ -347,7 +350,8 @@ static AST::AstNode *convert_range(AST::AstNode *id, int packed_ranges_size, int
347350
std::vector<int> single_elem_size;
348351
single_elem_size.push_back(elem_size);
349352
for (size_t j = 0; (j + 1) < wire_node->multirange_dimensions.size(); j = j + 2) {
350-
elem_size *= wire_node->multirange_dimensions[j + 1] - wire_node->multirange_dimensions[j];
353+
// The ranges' widths are placed on odd indices of multirange_dimensions.
354+
elem_size *= wire_node->multirange_dimensions[j + 1];
351355
single_elem_size.push_back(elem_size);
352356
}
353357
std::reverse(single_elem_size.begin(), single_elem_size.end());
@@ -742,18 +746,22 @@ void UhdmAst::uhdmast_assert_log(const char *expr_str, const char *func, const c
742746

743747
static AST::AstNode *expand_dot(const AST::AstNode *current_struct, const AST::AstNode *search_node)
744748
{
745-
AST::AstNode *current_struct_elem = nullptr;
749+
const AST::AstNode *current_struct_elem;
746750
auto search_str = search_node->str.find("\\") == 0 ? search_node->str.substr(1) : search_node->str;
747751
auto struct_elem_it =
748752
std::find_if(current_struct->children.begin(), current_struct->children.end(), [&](AST::AstNode *node) { return node->str == search_str; });
749-
if (struct_elem_it == current_struct->children.end()) {
753+
if (struct_elem_it == current_struct->children.end() && current_struct->str == search_str) {
754+
// Couldn't find the elem, but the search string matches the current struct.
755+
current_struct_elem = current_struct;
756+
} else if (struct_elem_it == current_struct->children.end()) {
750757
current_struct->dumpAst(NULL, "struct >");
751758
log_error("Couldn't find search elem: %s in struct\n", search_str.c_str());
759+
} else {
760+
current_struct_elem = *struct_elem_it;
752761
}
753-
current_struct_elem = *struct_elem_it;
754762

755763
AST::AstNode *sub_dot = nullptr;
756-
AST::AstNode *struct_range = nullptr;
764+
std::vector<AST::AstNode *> struct_ranges;
757765

758766
for (auto c : search_node->children) {
759767
if (c->type == static_cast<int>(AST::Extended::AST_DOT)) {
@@ -762,12 +770,7 @@ static AST::AstNode *expand_dot(const AST::AstNode *current_struct, const AST::A
762770
sub_dot = expand_dot(current_struct_elem, c);
763771
}
764772
if (c->type == AST::AST_RANGE) {
765-
// Currently supporting only 1 range
766-
if (struct_range) {
767-
log_file_error(struct_range->filename, struct_range->location.first_line,
768-
"Currently support for dot-access is limited to single range\n");
769-
}
770-
struct_range = c;
773+
struct_ranges.push_back(c);
771774
}
772775
}
773776
AST::AstNode *left = nullptr, *right = nullptr;
@@ -783,7 +786,7 @@ static AST::AstNode *expand_dot(const AST::AstNode *current_struct, const AST::A
783786
// Currently support only special access to 2 dimensional packed element
784787
// when selecting single range
785788
log_assert(current_struct_elem->multirange_dimensions.size() % 2 == 0);
786-
if (struct_range && (current_struct_elem->multirange_dimensions.size() / 2) == 2) {
789+
if (!struct_ranges.empty() && (current_struct_elem->multirange_dimensions.size() / 2) == 2) {
787790
// get element size in number of bits
788791
const int single_elem_size = current_struct_elem->children.front()->range_left + 1;
789792
left = AST::AstNode::mkconst_int(single_elem_size * current_struct_elem->multirange_dimensions.back(), true);
@@ -809,29 +812,52 @@ static AST::AstNode *expand_dot(const AST::AstNode *current_struct, const AST::A
809812
std::swap(right, sub_dot->children[1]);
810813
delete sub_dot;
811814
}
812-
if (struct_range) {
815+
816+
for (size_t i = 0; i < struct_ranges.size(); i++) {
817+
const auto *struct_range = struct_ranges[i];
818+
auto const range_width_idx = i * 2 + 1;
819+
auto const range_offset_idx = i * 2;
820+
821+
int range_width = 0;
822+
if (current_struct_elem->multirange_dimensions.empty()) {
823+
range_width = 1;
824+
} else if (current_struct_elem->multirange_dimensions.size() > range_width_idx) {
825+
range_width = current_struct_elem->multirange_dimensions[range_width_idx];
826+
const auto range_offset = current_struct_elem->multirange_dimensions[range_offset_idx];
827+
if (range_offset != 0) {
828+
log_file_error(struct_range->filename, struct_range->location.first_line,
829+
"Accessing ranges that do not start from 0 is not supported.");
830+
}
831+
} else {
832+
struct_range->dumpAst(NULL, "range >");
833+
log_file_error(struct_range->filename, struct_range->location.first_line, "Couldn't find range width.");
834+
}
813835
// now we have correct element set,
814836
// but we still need to set correct struct
815837
log_assert(!struct_range->children.empty());
816838
if (current_struct_elem->type == AST::AST_STRUCT_ITEM) {
817839
// if we selecting range of struct item, just add this range
818840
// to our current select
841+
if (current_struct_elem->multirange_dimensions.size() > 2 && struct_range->children.size() == 2) {
842+
log_error("Selecting a range of positions from a multirange is not supported in the dot notation.\n");
843+
}
819844
if (struct_range->children.size() == 2) {
820845
auto range_size = new AST::AstNode(
821846
AST::AST_ADD, new AST::AstNode(AST::AST_SUB, struct_range->children[0]->clone(), struct_range->children[1]->clone()),
822847
AST::AstNode::mkconst_int(1, true));
823848
right = new AST::AstNode(AST::AST_ADD, right, struct_range->children[1]->clone());
824-
left = new AST::AstNode(
825-
AST::AST_ADD, left,
826-
new AST::AstNode(AST::AST_ADD, struct_range->children[1]->clone(), new AST::AstNode(AST::AST_SUB, range_size, elem_size->clone())));
849+
delete left;
850+
left = new AST::AstNode(AST::AST_ADD, right->clone(), new AST::AstNode(AST::AST_SUB, range_size, AST::AstNode::mkconst_int(1, true)));
851+
827852
} else if (struct_range->children.size() == 1) {
828-
if (!current_struct_elem->multirange_dimensions.empty()) {
829-
right = new AST::AstNode(AST::AST_ADD, right,
830-
new AST::AstNode(AST::AST_MUL, struct_range->children[0]->clone(),
831-
AST::AstNode::mkconst_int(current_struct_elem->multirange_dimensions.back(), true)));
853+
// Selected a single position, as in `foo.bar[i]`.
854+
if (range_width > 1 && current_struct_elem->multirange_dimensions.size() > range_width_idx + 2) {
855+
// if it's not the last dimension.
856+
right = new AST::AstNode(
857+
AST::AST_ADD, right,
858+
new AST::AstNode(AST::AST_MUL, struct_range->children[0]->clone(), AST::AstNode::mkconst_int(range_width, true)));
832859
delete left;
833-
left = new AST::AstNode(AST::AST_ADD, right->clone(),
834-
AST::AstNode::mkconst_int(current_struct_elem->multirange_dimensions.back() - 1, true));
860+
left = new AST::AstNode(AST::AST_ADD, right->clone(), AST::AstNode::mkconst_int(range_width - 1, true));
835861
} else {
836862
right = new AST::AstNode(AST::AST_ADD, right, struct_range->children[0]->clone());
837863
delete left;

0 commit comments

Comments
 (0)