@@ -295,6 +295,11 @@ static void add_multirange_wire(AST::AstNode *node, std::vector<AST::AstNode *>
295295
296296static 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
740747static 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