Skip to content

Commit 4a05db9

Browse files
authored
Merge pull request #520 from antmicro/wsip/dotranges_multirange
systemverilog-plugin: allow multirange access in dot access
2 parents 38a8a5d + 20a9495 commit 4a05db9

File tree

1 file changed

+60
-31
lines changed

1 file changed

+60
-31
lines changed

systemverilog-plugin/UhdmAst.cc

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,11 @@ static void add_multirange_wire(AST::AstNode *node, std::vector<AST::AstNode *>
295295

296296
static size_t add_multirange_attribute(AST::AstNode *wire_node, const std::vector<AST::AstNode *> ranges)
297297
{
298+
// node->multirange_dimensions stores dimensions' offsets and widths.
299+
// It shall have even number of elements.
300+
// For a range of [A:B] it should be appended with {min(A,B)} and {max(A,B)-min(A,B)+1}
301+
// For a range of [A] it should be appended with {0} and {A}
302+
298303
size_t size = 1;
299304
for (size_t i = 0; i < ranges.size(); i++) {
300305
log_assert(AST_INTERNAL::current_ast_mod);
@@ -320,17 +325,18 @@ static size_t add_multirange_attribute(AST::AstNode *wire_node, const std::vecto
320325
}
321326
log_assert(ranges[i]->children[0]->type == AST::AST_CONSTANT);
322327
log_assert(ranges[i]->children[1]->type == AST::AST_CONSTANT);
323-
if (wire_node->type != AST::AST_STRUCT_ITEM) {
324-
wire_node->multirange_dimensions.push_back(min(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer));
325-
wire_node->multirange_swapped.push_back(ranges[i]->range_swapped);
326-
}
327-
auto elem_size = max(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer) -
328-
min(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer) + 1;
329-
if (wire_node->type != AST::AST_STRUCT_ITEM || (wire_node->type == AST::AST_STRUCT_ITEM && i == 0)) {
330-
wire_node->multirange_dimensions.push_back(elem_size);
331-
}
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);
334+
wire_node->multirange_dimensions.push_back(elem_size);
335+
wire_node->multirange_swapped.push_back(ranges[i]->range_swapped);
332336
size *= elem_size;
333337
}
338+
log_assert(wire_node->multirange_dimensions.size() % 2 == 0);
339+
334340
return size;
335341
}
336342

@@ -344,7 +350,8 @@ static AST::AstNode *convert_range(AST::AstNode *id, int packed_ranges_size, int
344350
std::vector<int> single_elem_size;
345351
single_elem_size.push_back(elem_size);
346352
for (size_t j = 0; (j + 1) < wire_node->multirange_dimensions.size(); j = j + 2) {
347-
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];
348355
single_elem_size.push_back(elem_size);
349356
}
350357
std::reverse(single_elem_size.begin(), single_elem_size.end());
@@ -739,18 +746,22 @@ void UhdmAst::uhdmast_assert_log(const char *expr_str, const char *func, const c
739746

740747
static AST::AstNode *expand_dot(const AST::AstNode *current_struct, const AST::AstNode *search_node)
741748
{
742-
AST::AstNode *current_struct_elem = nullptr;
749+
const AST::AstNode *current_struct_elem;
743750
auto search_str = search_node->str.find("\\") == 0 ? search_node->str.substr(1) : search_node->str;
744751
auto struct_elem_it =
745752
std::find_if(current_struct->children.begin(), current_struct->children.end(), [&](AST::AstNode *node) { return node->str == search_str; });
746-
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()) {
747757
current_struct->dumpAst(NULL, "struct >");
748758
log_error("Couldn't find search elem: %s in struct\n", search_str.c_str());
759+
} else {
760+
current_struct_elem = *struct_elem_it;
749761
}
750-
current_struct_elem = *struct_elem_it;
751762

752763
AST::AstNode *sub_dot = nullptr;
753-
AST::AstNode *struct_range = nullptr;
764+
std::vector<AST::AstNode *> struct_ranges;
754765

755766
for (auto c : search_node->children) {
756767
if (c->type == static_cast<int>(AST::Extended::AST_DOT)) {
@@ -759,12 +770,7 @@ static AST::AstNode *expand_dot(const AST::AstNode *current_struct, const AST::A
759770
sub_dot = expand_dot(current_struct_elem, c);
760771
}
761772
if (c->type == AST::AST_RANGE) {
762-
// Currently supporting only 1 range
763-
if (struct_range) {
764-
log_file_error(struct_range->filename, struct_range->location.first_line,
765-
"Currently support for dot-access is limited to single range\n");
766-
}
767-
struct_range = c;
773+
struct_ranges.push_back(c);
768774
}
769775
}
770776
AST::AstNode *left = nullptr, *right = nullptr;
@@ -780,7 +786,7 @@ static AST::AstNode *expand_dot(const AST::AstNode *current_struct, const AST::A
780786
// Currently support only special access to 2 dimensional packed element
781787
// when selecting single range
782788
log_assert(current_struct_elem->multirange_dimensions.size() % 2 == 0);
783-
if (struct_range && (current_struct_elem->multirange_dimensions.size() / 2) == 2) {
789+
if (!struct_ranges.empty() && (current_struct_elem->multirange_dimensions.size() / 2) == 2) {
784790
// get element size in number of bits
785791
const int single_elem_size = current_struct_elem->children.front()->range_left + 1;
786792
left = AST::AstNode::mkconst_int(single_elem_size * current_struct_elem->multirange_dimensions.back(), true);
@@ -806,29 +812,52 @@ static AST::AstNode *expand_dot(const AST::AstNode *current_struct, const AST::A
806812
std::swap(right, sub_dot->children[1]);
807813
delete sub_dot;
808814
}
809-
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+
}
810835
// now we have correct element set,
811836
// but we still need to set correct struct
812837
log_assert(!struct_range->children.empty());
813838
if (current_struct_elem->type == AST::AST_STRUCT_ITEM) {
814839
// if we selecting range of struct item, just add this range
815840
// 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+
}
816844
if (struct_range->children.size() == 2) {
817845
auto range_size = new AST::AstNode(
818846
AST::AST_ADD, new AST::AstNode(AST::AST_SUB, struct_range->children[0]->clone(), struct_range->children[1]->clone()),
819847
AST::AstNode::mkconst_int(1, true));
820848
right = new AST::AstNode(AST::AST_ADD, right, struct_range->children[1]->clone());
821-
left = new AST::AstNode(
822-
AST::AST_ADD, left,
823-
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+
824852
} else if (struct_range->children.size() == 1) {
825-
if (!current_struct_elem->multirange_dimensions.empty()) {
826-
right = new AST::AstNode(AST::AST_ADD, right,
827-
new AST::AstNode(AST::AST_MUL, struct_range->children[0]->clone(),
828-
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)));
829859
delete left;
830-
left = new AST::AstNode(AST::AST_ADD, right->clone(),
831-
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));
832861
} else {
833862
right = new AST::AstNode(AST::AST_ADD, right, struct_range->children[0]->clone());
834863
delete left;

0 commit comments

Comments
 (0)