Skip non-synthesizable objects (#243)

* Skip non-synthesizable objects

Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>

* Add check for case node

Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>

* Add AST_BLOCK if not present in initial

Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>

* Add AST_BLOCK if stmt is missing in always

Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>

* Add AST_BLOCK if stmt is missing in initial

Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>

* Check if node is present in hier_path

Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>

* Check for node in if_else

Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>

* Rely on UHDM's SynthSubset to filter out non-synthesizables

Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>

Co-authored-by: Krzysztof Bieganski <kbieganski@antmicro.com>
diff --git a/systemverilog-plugin/UhdmAst.cc b/systemverilog-plugin/UhdmAst.cc
index 46a91f8..7f1d2b3 100644
--- a/systemverilog-plugin/UhdmAst.cc
+++ b/systemverilog-plugin/UhdmAst.cc
@@ -1376,7 +1376,12 @@
         if (initial_node_it != parent->children.end()) {
             AST::AstNode *initial_node = *initial_node_it;
 
-            log_assert(!(initial_node->children.empty()));
+            // simplify assumes that initial has a block under it
+            // In case we don't have one (there were no statements under the initial), let's add it
+            if (initial_node->children.empty()) {
+                initial_node->children.push_back(new AST::AstNode(AST::AST_BLOCK));
+            }
+
             log_assert(initial_node->children[0]->type == AST::AST_BLOCK);
             log_assert(!(child->children.empty()));
             log_assert(child->children[0]->type == AST::AST_BLOCK);
@@ -2471,13 +2476,18 @@
 {
     current_node = make_ast_node(AST::AST_ALWAYS);
     visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        AST::AstNode *block = nullptr;
-        if (node && node->type != AST::AST_BLOCK) {
-            block = new AST::AstNode(AST::AST_BLOCK, node);
+        if (node) {
+            AST::AstNode *block = nullptr;
+            if (node->type != AST::AST_BLOCK) {
+                block = new AST::AstNode(AST::AST_BLOCK, node);
+            } else {
+                block = node;
+            }
+            current_node->children.push_back(block);
         } else {
-            block = node;
+            // create empty block
+            current_node->children.push_back(new AST::AstNode(AST::AST_BLOCK));
         }
-        current_node->children.push_back(block);
     });
     switch (vpi_get(vpiAlwaysType, obj_h)) {
     case vpiAlwaysComb:
@@ -2525,6 +2535,8 @@
                 node = block_node;
             }
             current_node->children.push_back(node);
+        } else {
+            current_node->children.push_back(make_ast_node(AST::AST_BLOCK));
         }
     });
 }
@@ -3104,7 +3116,8 @@
     condition->children.push_back(constant);
     visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
         auto *statements = new AST::AstNode(AST::AST_BLOCK);
-        statements->children.push_back(node);
+        if (node)
+            statements->children.push_back(node);
         condition->children.push_back(statements);
     });
     current_node->children.push_back(condition);
@@ -3115,7 +3128,8 @@
         condition->children.push_back(elseBlock);
         visit_one_to_one({vpiElseStmt}, obj_h, [&](AST::AstNode *node) {
             auto *statements = new AST::AstNode(AST::AST_BLOCK);
-            statements->children.push_back(node);
+            if (node)
+                statements->children.push_back(node);
             condition->children.push_back(statements);
         });
         current_node->children.push_back(condition);
@@ -3224,12 +3238,14 @@
         current_node->children.push_back(new AST::AstNode(AST::AST_DEFAULT));
     }
     visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node->type != AST::AST_BLOCK) {
-            auto block_node = new AST::AstNode(AST::AST_BLOCK);
-            block_node->children.push_back(node);
-            node = block_node;
+        if (node) {
+            if (node->type != AST::AST_BLOCK) {
+                auto block_node = new AST::AstNode(AST::AST_BLOCK);
+                block_node->children.push_back(node);
+                node = block_node;
+            }
+            current_node->children.push_back(node);
         }
-        current_node->children.push_back(node);
     });
 }
 
@@ -3307,22 +3323,24 @@
     current_node->str = "\\";
     AST::AstNode *top_node = nullptr;
     visit_one_to_many({vpiActual}, obj_h, [&](AST::AstNode *node) {
-        if (node->str.find('[') != std::string::npos)
-            node->str = node->str.substr(0, node->str.find('['));
-        // for first node, just set correct string and move any children
-        if (!top_node) {
-            current_node->str += node->str.substr(1);
-            current_node->children = std::move(node->children);
-            top_node = current_node;
-            delete node;
-        } else {
-            if (node->str.empty()) {
-                log_assert(!node->children.empty());
-                top_node->children.push_back(node->children[0]);
+        if (node) {
+            if (node->str.find('[') != std::string::npos)
+                node->str = node->str.substr(0, node->str.find('['));
+            // for first node, just set correct string and move any children
+            if (!top_node) {
+                current_node->str += node->str.substr(1);
+                current_node->children = std::move(node->children);
+                top_node = current_node;
+                delete node;
             } else {
-                node->type = static_cast<AST::AstNodeType>(AST::AST_DOT);
-                top_node->children.push_back(node);
-                top_node = node;
+                if (node->str.empty()) {
+                    log_assert(!node->children.empty());
+                    top_node->children.push_back(node->children[0]);
+                } else {
+                    node->type = static_cast<AST::AstNodeType>(AST::AST_DOT);
+                    top_node->children.push_back(node);
+                    top_node = node;
+                }
             }
         }
     });
@@ -3435,20 +3453,6 @@
 {
     current_node = make_ast_node(AST::AST_FCALL);
 
-    // skip unsupported simulation functions
-    std::string to_skip[] = {
-      "\\$value$plusargs", "\\$test$plusargs", "\\$displayb", "\\$displayh",  "\\$displayo",  "\\$strobeb",  "\\$strobeh",       "\\$strobeo",
-      "\\$writeb",         "\\$writeh",        "\\$writeo",   "\\$dumplimit", "\\$dumpflush", "\\$fdisplay", "\\$fdisplayb",     "\\$fdisplayh",
-      "\\$fdisplayo",      "\\$fmonitor",      "\\$fstrobe",  "\\$fstrobeb",  "\\$fstrobeh",  "\\$fstrobeo", "\\$fwrite",        "\\$fwriteb",
-      "\\$fwriteh",        "\\$fwriteo",       "\\$ungetc",   "\\$fgetc",     "\\$fgets",     "\\$ftell",    "\\$printtimescale"};
-
-    if (std::find(std::begin(to_skip), std::end(to_skip), current_node->str) != std::end(to_skip)) {
-        log_warning("System function %s was skipped\n", current_node->str.substr(1).c_str());
-        delete current_node;
-        current_node = nullptr;
-        return;
-    }
-
     std::string task_calls[] = {"\\$display", "\\$monitor", "\\$write", "\\$time", "\\$readmemh", "\\$readmemb", "\\$finish", "\\$stop"};
 
     if (current_node->str == "\\$signed") {
@@ -3503,16 +3507,6 @@
     });
 }
 
-void UhdmAst::process_nonsynthesizable(const UHDM::BaseClass *object)
-{
-    log_warning("%s:%d: Non-synthesizable object of type '%s'\n", object->VpiFile().c_str(), object->VpiLineNo(), UHDM::VpiTypeName(obj_h).c_str());
-    current_node = make_ast_node(AST::AST_BLOCK);
-    visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node)
-            current_node->children.push_back(node);
-    });
-}
-
 void UhdmAst::process_logic_typespec()
 {
     current_node = make_ast_node(AST::AST_WIRE);
@@ -4040,6 +4034,13 @@
     const unsigned object_type = vpi_get(vpiType, obj_h);
     const uhdm_handle *const handle = (const uhdm_handle *)obj_h;
     const UHDM::BaseClass *const object = (const UHDM::BaseClass *)handle->object;
+    for (auto *obj : shared.nonSynthesizableObjects) {
+        if (!object->Compare(obj)) {
+            log_warning("%s:%d: Skipping non-synthesizable object of type '%s'\n", object->VpiFile().c_str(), object->VpiLineNo(),
+                        UHDM::VpiTypeName(obj_h).c_str());
+            return nullptr;
+        }
+    }
 
     if (shared.debug_flag) {
         std::cout << indent << "Object '" << object->VpiName() << "' of type '" << UHDM::VpiTypeName(obj_h) << '\'' << std::endl;
@@ -4236,9 +4237,6 @@
         break;
     case UHDM::uhdmimport_typespec:
         break;
-    case vpiDelayControl:
-        process_nonsynthesizable(object);
-        break;
     case vpiLogicTypespec:
         process_logic_typespec();
         break;
diff --git a/systemverilog-plugin/UhdmAst.h b/systemverilog-plugin/UhdmAst.h
index 8f6a368..b7877a6 100644
--- a/systemverilog-plugin/UhdmAst.h
+++ b/systemverilog-plugin/UhdmAst.h
@@ -148,7 +148,6 @@
     void process_gate();
     void process_primterm();
     void simplify_parameter(AST::AstNode *parameter, AST::AstNode *module_node = nullptr);
-    void process_nonsynthesizable(const UHDM::BaseClass *object);
     void process_unsupported_stmt(const UHDM::BaseClass *object);
 
     UhdmAst(UhdmAst *p, UhdmAstShared &s, const std::string &i) : parent(p), shared(s), indent(i)
diff --git a/systemverilog-plugin/uhdmastfrontend.cc b/systemverilog-plugin/uhdmastfrontend.cc
index 4874ee8..c09688c 100644
--- a/systemverilog-plugin/uhdmastfrontend.cc
+++ b/systemverilog-plugin/uhdmastfrontend.cc
@@ -44,6 +44,9 @@
         UHDM::Serializer serializer;
 
         std::vector<vpiHandle> restoredDesigns = serializer.Restore(filename);
+        UHDM::SynthSubset *synthSubset = new UHDM::SynthSubset(&serializer, this->shared.nonSynthesizableObjects, false);
+        synthSubset->listenDesigns(restoredDesigns);
+        delete synthSubset;
         if (this->shared.debug_flag || !this->report_directory.empty()) {
             for (auto design : restoredDesigns) {
                 std::stringstream strstr;
diff --git a/systemverilog-plugin/uhdmastshared.h b/systemverilog-plugin/uhdmastshared.h
index 9799055..2fa3e8b 100644
--- a/systemverilog-plugin/uhdmastshared.h
+++ b/systemverilog-plugin/uhdmastshared.h
@@ -52,6 +52,8 @@
     std::unordered_map<std::string, AST::AstNode *> param_types;
 
     AST::AstNode *current_top_node = nullptr;
+    // Set of non-synthesizable objects to skip in current design;
+    std::set<const UHDM::BaseClass *> nonSynthesizableObjects;
 };
 
 YOSYS_NAMESPACE_END
diff --git a/systemverilog-plugin/uhdmcommonfrontend.h b/systemverilog-plugin/uhdmcommonfrontend.h
index 6fcb0f9..3d5ff16 100644
--- a/systemverilog-plugin/uhdmcommonfrontend.h
+++ b/systemverilog-plugin/uhdmcommonfrontend.h
@@ -20,6 +20,8 @@
 #include "UhdmAst.h"
 #include "frontends/ast/ast.h"
 #include "kernel/yosys.h"
+#include "uhdm/SynthSubset.h"
+#include "uhdm/VpiListener.h"
 #include <string>
 #include <vector>
 
diff --git a/systemverilog-plugin/uhdmsurelogastfrontend.cc b/systemverilog-plugin/uhdmsurelogastfrontend.cc
index 39cc751..f2beaee 100644
--- a/systemverilog-plugin/uhdmsurelogastfrontend.cc
+++ b/systemverilog-plugin/uhdmsurelogastfrontend.cc
@@ -121,6 +121,11 @@
             }
         }
 
+        UHDM::Serializer serializer;
+        UHDM::SynthSubset *synthSubset = new UHDM::SynthSubset(&serializer, this->shared.nonSynthesizableObjects, false);
+        synthSubset->listenDesigns(uhdm_design);
+        delete synthSubset;
+
         SURELOG::shutdown_compiler(compiler);
         delete clp;
         delete symbolTable;