@@ -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
743747static 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