Merge pull request #452 from antmicro/kr/add_list_op

systemverilog-plugin: move handle of list op to process_case_item
diff --git a/systemverilog-plugin/UhdmAst.cc b/systemverilog-plugin/UhdmAst.cc
index 7bc9298..41ff2aa 100644
--- a/systemverilog-plugin/UhdmAst.cc
+++ b/systemverilog-plugin/UhdmAst.cc
@@ -73,6 +73,12 @@
     return id;
 }
 
+/*static*/ const IdString &UhdmAst::low_high_bound()
+{
+    static const IdString id("\\low_high_bound");
+    return id;
+}
+
 static void sanitize_symbol_name(std::string &name)
 {
     if (!name.empty()) {
@@ -1028,6 +1034,42 @@
         if (current_node->str == "$display" || current_node->str == "$write")
             simplify_format_string(current_node);
         break;
+    case AST::AST_COND:
+    case AST::AST_CONDX:
+    case AST::AST_CONDZ:
+        // handle custom low high bound
+        if (current_node->attributes.count(UhdmAst::low_high_bound())) {
+            log_assert(!current_node->children.empty());
+            log_assert(current_node->children[0]->type == AST::AST_BLOCK);
+            log_assert(current_node->children[0]->children.size() == 2);
+            auto low_high_bound = current_node->children[0];
+            // this is executed when condition is met
+            // save pointer that will be added later again
+            // as conditions needs to go before this block
+            auto result = current_node->children[1];
+            current_node->children.clear();
+            while (low_high_bound->children[0]->simplify(true, false, false, 1, -1, false, false)) {
+            };
+            while (low_high_bound->children[1]->simplify(true, false, false, 1, -1, false, false)) {
+            };
+            log_assert(low_high_bound->children[0]->type == AST::AST_CONSTANT);
+            log_assert(low_high_bound->children[1]->type == AST::AST_CONSTANT);
+            const int low = low_high_bound->children[0]->integer;
+            const int high = low_high_bound->children[1]->integer;
+            const int range = low_high_bound->children[1]->range_valid
+                                ? low_high_bound->children[1]->range_left
+                                : low_high_bound->children[0]->range_valid ? low_high_bound->children[0]->range_left : 32;
+            delete low_high_bound;
+            // According to standard:
+            // If the bound to the left of the colon is greater than the
+            // bound to the right, the range is empty and contains no values.
+            for (int i = low; i >= low && i <= high; i++) {
+                current_node->children.push_back(AST::AstNode::mkconst_int(i, false, range));
+            }
+            current_node->children.push_back(result);
+            current_node->attributes.erase(UhdmAst::low_high_bound());
+        }
+        break;
     default:
         break;
     }
@@ -3190,35 +3232,12 @@
 {
     // Add all operands as children of process node
     if (auto parent_node = find_ancestor({AST::AST_ALWAYS, AST::AST_COND})) {
-        std::vector<AST::AstNode *> nodes;
-        // vpiListOp is returned in 2 cases:
-        // a, b, c ... -> multiple vpiListOp with single item
-        // [a : b] -> single vpiListOp with 2 items
         visit_one_to_many({vpiOperand}, obj_h, [&](AST::AstNode *node) {
+            // add directly to process/cond node
             if (node) {
-                nodes.push_back(node);
+                parent_node->children.push_back(node);
             }
         });
-        if (nodes.size() == 1) {
-            parent_node->children.push_back(nodes[0]);
-        } else {
-            log_assert(nodes.size() == 2);
-            // TODO(krak): we should actually simplify this nodes first,
-            // but that would require to delay this to later.
-            // For now check that they are constants.
-            log_assert(nodes[0]->type == AST::AST_CONSTANT);
-            log_assert(nodes[1]->type == AST::AST_CONSTANT);
-            const int low = nodes[0]->integer;
-            const int high = nodes[1]->integer;
-            // According to standard:
-            // If the bound to the left of the colon is greater than the
-            // bound to the right, the range is empty and contains no values.
-            for (int i = low; i >= low && i <= high; i++) {
-                // TODO(krak): get proper width of constant
-                log_assert(nodes[0]->range_left == 31);
-                parent_node->children.push_back(AST::AstNode::mkconst_int(i, false, 32));
-            }
-        }
     } else {
         log_error("Unhandled list op, couldn't find parent node.");
     }
@@ -3510,13 +3529,27 @@
     while (vpiHandle expr_h = vpi_scan(itr)) {
         // case ... inside statement, the operation is stored in UHDM inside case items
         // Retrieve just the InsideOp arguments here, we don't add any special handling
-        // TODO: handle inside range (list operations) properly here
         if (vpi_get(vpiType, expr_h) == vpiOperation && vpi_get(vpiOpType, expr_h) == vpiInsideOp) {
             visit_one_to_many({vpiOperand}, expr_h, [&](AST::AstNode *node) {
-                if (node) {
-                    current_node->children.push_back(node);
-                }
+                // Currently we are adding nodes directly to ancestor
+                // inside process_list_op, so after this function, we have
+                // nodes already in `current_node`.
+                // We should probably refactor this to return node instead.
+                // For now, make sure this function doesn't return any nodes.
+                log_assert(node == nullptr);
             });
+            // vpiListOp is returned in 2 cases:
+            // a, b, c ... -> multiple vpiListOp with single item
+            // [a : b] -> single vpiListOp with 2 items
+            // single item is handled by default,
+            // here handle 2 items with custom low_high_bound attribute
+            if (current_node->children.size() == 2) {
+                auto block = make_ast_node(AST::AST_BLOCK);
+                block->children = std::move(current_node->children);
+                current_node->children.clear();
+                current_node->children.push_back(block);
+                current_node->attributes[UhdmAst::low_high_bound()] = AST::AstNode::mkconst_int(1, false, 1);
+            }
         } else {
             UhdmAst uhdm_ast(this, shared, indent + "  ");
             auto *node = uhdm_ast.process_object(expr_h);
diff --git a/systemverilog-plugin/UhdmAst.h b/systemverilog-plugin/UhdmAst.h
index bbd0460..81679e3 100644
--- a/systemverilog-plugin/UhdmAst.h
+++ b/systemverilog-plugin/UhdmAst.h
@@ -175,6 +175,7 @@
     static const ::Yosys::IdString &force_convert();
     static const ::Yosys::IdString &is_imported();
     static const ::Yosys::IdString &is_simplified_wire();
+    static const ::Yosys::IdString &low_high_bound();
 };
 
 } // namespace systemverilog_plugin