Merge pull request #221 from antmicro/dsp-ff-plugin

A plugin for inference of DSP registers
diff --git a/ql-qlf-plugin/synth_quicklogic.cc b/ql-qlf-plugin/synth_quicklogic.cc
index d26f53a..33433fd 100644
--- a/ql-qlf-plugin/synth_quicklogic.cc
+++ b/ql-qlf-plugin/synth_quicklogic.cc
@@ -221,6 +221,8 @@
         std::string noDFFArgs;
         if (family == "qlf_k4n8") {
             noDFFArgs = " -nodffe -nosdff";
+        } else if (family == "qlf_k6n10f") {
+            noDFFArgs = " -nosdff";
         }
 
         if (check_label("coarse")) {
diff --git a/uhdm-plugin/Makefile b/uhdm-plugin/Makefile
index 0ad9ee0..223a126 100644
--- a/uhdm-plugin/Makefile
+++ b/uhdm-plugin/Makefile
@@ -9,6 +9,7 @@
 NAME = uhdm
 SOURCES = UhdmAst.cc \
 	  uhdmastfrontend.cc \
+	  uhdmcommonfrontend.cc \
 	  uhdmsurelogastfrontend.cc \
 	  uhdmastreport.cc
 
@@ -16,7 +17,7 @@
 
 CPPFLAGS += -std=c++17 -Wall -W -Wextra -Werror \
               -I${UHDM_INSTALL_DIR}/include \
-	      -I${UHDM_INSTALL_DIR}/include/surelog
+	      -I${UHDM_INSTALL_DIR}/include/Surelog
 
 CXXFLAGS += -Wno-unused-parameter
 LDFLAGS += -L${UHDM_INSTALL_DIR}/lib/uhdm -L${UHDM_INSTALL_DIR}/lib/surelog -L${UHDM_INSTALL_DIR}/lib -L${UHDM_INSTALL_DIR}/lib64/uhdm -L${UHDM_INSTALL_DIR}/lib64/surelog -L${UHDM_INSTALL_DIR}/lib64
diff --git a/uhdm-plugin/Makefile.inc b/uhdm-plugin/Makefile.inc
deleted file mode 100644
index ddd8e8f..0000000
--- a/uhdm-plugin/Makefile.inc
+++ /dev/null
@@ -1,15 +0,0 @@
-
-OBJS += frontends/uhdm/UhdmAst.o
-OBJS += frontends/uhdm/uhdmastreport.o
-OBJS += frontends/uhdm/uhdmastfrontend.o
-OBJS += frontends/uhdm/vpivisitor.o
-
-UHDM_INSTALL_DIR ?= $(PREFIX)
-
-#*** UHDM ***
-CPPFLAGS += -std=c++14 -I${UHDM_INSTALL_DIR}/include/uhdm \
-			-I${UHDM_INSTALL_DIR}/include/uhdm/include \
-			-I${UHDM_INSTALL_DIR}/include/uhdm/headers
-CXXFLAGS += -Wno-inconsistent-missing-override
-LDFLAGS += -L${UHDM_INSTALL_DIR}/lib/uhdm -L${UHDM_INSTALL_DIR}/lib
-LDLIBS += -luhdm -lcapnp -lkj -ldl -lutil -lm -lrt -lpthread
diff --git a/uhdm-plugin/UhdmAst.cc b/uhdm-plugin/UhdmAst.cc
index b6b541b..6b6f142 100644
--- a/uhdm-plugin/UhdmAst.cc
+++ b/uhdm-plugin/UhdmAst.cc
@@ -1,6 +1,7 @@
 #include <algorithm>
 #include <cstring>
 #include <functional>
+#include <regex>
 #include <string>
 #include <vector>
 
@@ -105,6 +106,24 @@
     return range;
 }
 
+static void copy_packed_unpacked_attribute(AST::AstNode *from, AST::AstNode *to)
+{
+    if (!to->attributes.count(UhdmAst::packed_ranges()))
+        to->attributes[UhdmAst::packed_ranges()] = AST::AstNode::mkconst_int(1, false, 1);
+    if (!to->attributes.count(UhdmAst::unpacked_ranges()))
+        to->attributes[UhdmAst::unpacked_ranges()] = AST::AstNode::mkconst_int(1, false, 1);
+    if (from->attributes.count(UhdmAst::packed_ranges())) {
+        for (auto r : from->attributes[UhdmAst::packed_ranges()]->children) {
+            to->attributes[UhdmAst::packed_ranges()]->children.push_back(r->clone());
+        }
+    }
+    if (from->attributes.count(UhdmAst::unpacked_ranges())) {
+        for (auto r : from->attributes[UhdmAst::unpacked_ranges()]->children) {
+            to->attributes[UhdmAst::unpacked_ranges()]->children.push_back(r->clone());
+        }
+    }
+}
+
 #include "UhdmAstUpstream.cc"
 
 static int get_max_offset_struct(AST::AstNode *node)
@@ -554,10 +573,10 @@
         } else {
             expanded->children[1] = new AST::AstNode(
               AST::AST_ADD, expanded->children[1],
-              new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), AST::AstNode::mkconst_int(range, true, 32)));
+              new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), node->children[0]->children[0]->clone()));
             expanded->children[0] = new AST::AstNode(
               AST::AST_ADD, expanded->children[0],
-              new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), AST::AstNode::mkconst_int(range, true, 32)));
+              new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), node->children[0]->children[0]->clone()));
         }
     }
     return expanded;
@@ -765,7 +784,8 @@
     wnode->is_signed = template_node->is_signed;
     int offset = get_max_offset_struct(template_node);
     auto range = make_range(offset, 0);
-    wnode->children.push_back(range);
+    copy_packed_unpacked_attribute(template_node, wnode);
+    wnode->attributes[UhdmAst::packed_ranges()]->children.insert(wnode->attributes[UhdmAst::packed_ranges()]->children.begin(), range);
     // make sure this node is the one in scope for this name
     AST_INTERNAL::current_scope[name] = wnode;
     // add all the struct members to scope under the wire's name
@@ -773,6 +793,40 @@
     return wnode;
 }
 
+static void simplify_format_string(AST::AstNode *current_node)
+{
+    std::string sformat = current_node->children[0]->str;
+    std::string preformatted_string = "";
+    int next_arg = 1;
+    for (size_t i = 0; i < sformat.length(); i++) {
+        if (sformat[i] == '%') {
+            AST::AstNode *node_arg = current_node->children[next_arg];
+            char cformat = sformat[++i];
+            if (cformat == 'b' or cformat == 'B') {
+                node_arg->simplify(true, false, false, 1, -1, false, false);
+                if (node_arg->type != AST::AST_CONSTANT)
+                    log_file_error(current_node->filename, current_node->location.first_line,
+                                   "Failed to evaluate system task `%s' with non-constant argument.\n", current_node->str.c_str());
+
+                RTLIL::Const val = node_arg->bitsAsConst();
+                for (int j = val.size() - 1; j >= 0; j--) {
+                    // We add ACII value of 0 to convert number to character
+                    preformatted_string += ('0' + val[j]);
+                }
+                delete current_node->children[next_arg];
+                current_node->children.erase(current_node->children.begin() + next_arg);
+            } else {
+                next_arg++;
+                preformatted_string += std::string("%") + cformat;
+            }
+        } else {
+            preformatted_string += sformat[i];
+        }
+    }
+    delete current_node->children[0];
+    current_node->children[0] = AST::AstNode::mkconst_str(preformatted_string);
+}
+
 static void simplify(AST::AstNode *current_node, AST::AstNode *parent_node)
 {
     AST::AstNode *expanded = nullptr;
@@ -862,6 +916,7 @@
         if (!current_node->str.empty() && current_node->str[0] == '\\') {
             // instance so add a wire for the packed structure
             auto wnode = make_packed_struct_local(current_node, current_node->str);
+            convert_packed_unpacked_range(wnode);
             log_assert(AST_INTERNAL::current_ast_mod);
             AST_INTERNAL::current_ast_mod->children.push_back(wnode);
             AST_INTERNAL::current_scope[wnode->str]->attributes[ID::wiretype] = AST::AstNode::mkconst_str(current_node->str);
@@ -876,6 +931,10 @@
         while (current_node->simplify(true, false, false, 1, -1, false, false)) {
         };
         break;
+    case AST::AST_TCALL:
+        if (current_node->str == "$display" || current_node->str == "$write")
+            simplify_format_string(current_node);
+        break;
     default:
         break;
     }
@@ -1023,8 +1082,8 @@
             if (size == 64) {
                 size = 32;
             }
-            auto c = AST::AstNode::mkconst_int(val.value.integer, true, size ? size : 32);
-            if (size == 0)
+            auto c = AST::AstNode::mkconst_int(val.value.integer, true, size > 0 ? size : 32);
+            if (size == 0 || size == -1)
                 c->is_unsized = true;
             return c;
         }
@@ -1761,6 +1820,7 @@
         if (node->str.empty()) {
             // anonymous typespec, move the children to variable
             current_node->type = node->type;
+            copy_packed_unpacked_attribute(node, current_node);
             current_node->children = std::move(node->children);
         } else {
             auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
@@ -2070,7 +2130,7 @@
         if (net_type == vpiLogicNet) {
             current_node->is_logic = true;
             current_node->is_signed = vpi_get(vpiSigned, net_h);
-            visit_range(net_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
+            visit_one_to_many({vpiRange}, net_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
             shared.report.mark_handled(net_h);
         } else if (net_type == vpiStructNet) {
             visit_one_to_one({vpiTypespec}, net_h, [&](AST::AstNode *node) {
@@ -2173,7 +2233,7 @@
     visit_one_to_one({vpiExpr}, obj_h, [&](AST::AstNode *node) { current_node = node; });
     if (current_node == nullptr) {
         current_node = make_ast_node(AST::AST_MODPORTMEMBER);
-        visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
+        visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { unpacked_ranges.push_back(node); });
     }
     visit_one_to_one({vpiTypedef}, obj_h, [&](AST::AstNode *node) {
         if (node) {
@@ -3134,14 +3194,13 @@
         return;
     }
 
+    std::string task_calls[] = {"\\$display", "\\$monitor", "\\$write", "\\$time", "\\$readmemh", "\\$readmemb", "\\$finish", "\\$stop"};
+
     if (current_node->str == "\\$signed") {
         current_node->type = AST::AST_TO_SIGNED;
     } else if (current_node->str == "\\$unsigned") {
         current_node->type = AST::AST_TO_UNSIGNED;
-    } else if (current_node->str == "\\$display" || current_node->str == "\\$time" || current_node->str == "\\$monitor") {
-        current_node->type = AST::AST_TCALL;
-        current_node->str = current_node->str.substr(1);
-    } else if (current_node->str == "\\$readmemh") {
+    } else if (std::find(std::begin(task_calls), std::end(task_calls), current_node->str) != std::end(task_calls)) {
         current_node->type = AST::AST_TCALL;
     }
 
@@ -3150,6 +3209,19 @@
             current_node->children.push_back(node);
         }
     });
+
+    if (current_node->str == "\\$display" || current_node->str == "\\$write") {
+        // According to standard, %h and %x mean the same, but %h is currently unsupported by mainline yosys
+        std::string replaced_string = std::regex_replace(current_node->children[0]->str, std::regex("%[h|H]"), "%x");
+        delete current_node->children[0];
+        current_node->children[0] = AST::AstNode::mkconst_str(replaced_string);
+    }
+
+    std::string remove_backslash[] = {"\\$display", "\\$strobe",   "\\$write",    "\\$monitor", "\\$time",    "\\$finish",
+                                      "\\$stop",    "\\$dumpfile", "\\$dumpvars", "\\$dumpon",  "\\$dumpoff", "\\$dumpall"};
+
+    if (std::find(std::begin(remove_backslash), std::end(remove_backslash), current_node->str) != std::end(remove_backslash))
+        current_node->str = current_node->str.substr(1);
 }
 
 void UhdmAst::process_func_call()
diff --git a/uhdm-plugin/uhdmastfrontend.cc b/uhdm-plugin/uhdmastfrontend.cc
index c857076..9a22339 100644
--- a/uhdm-plugin/uhdmastfrontend.cc
+++ b/uhdm-plugin/uhdmastfrontend.cc
@@ -19,9 +19,7 @@
  *
  */
 
-#include "UhdmAst.h"
-#include "frontends/ast/ast.h"
-#include "kernel/yosys.h"
+#include "uhdmcommonfrontend.h"
 
 namespace UHDM
 {
@@ -31,15 +29,9 @@
 
 YOSYS_NAMESPACE_BEGIN
 
-/* Stub for AST::process */
-static void set_line_num(int) {}
-
-/* Stub for AST::process */
-static int get_line_num(void) { return 1; }
-
-struct UhdmAstFrontend : public Frontend {
-    UhdmAstFrontend() : Frontend("uhdm", "read UHDM file") {}
-    void help()
+struct UhdmAstFrontend : public UhdmCommonFrontend {
+    UhdmAstFrontend() : UhdmCommonFrontend("uhdm", "read UHDM file") {}
+    void help() override
     {
         //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
         log("\n");
@@ -47,70 +39,27 @@
         log("\n");
         log("Load design from a UHDM file into the current design\n");
         log("\n");
-        log("    -noassert\n");
-        log("        ignore assert() statements");
-        log("\n");
-        log("    -debug\n");
-        log("        print debug info to stdout");
-        log("\n");
-        log("    -report [directory]\n");
-        log("        write a coverage report for the UHDM file\n");
-        log("\n");
-        log("    -defer\n");
-        log("        only read the abstract syntax tree and defer actual compilation\n");
-        log("        to a later 'hierarchy' command. Useful in cases where the default\n");
-        log("        parameters of modules yield invalid or not synthesizable code.\n");
-        log("\n");
+        this->print_read_options();
     }
-    void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+    AST::AstNode *parse(std::string filename) override
     {
-        log_header(design, "Executing UHDM frontend.\n");
-
-        UhdmAstShared shared;
-        UhdmAst uhdm_ast(shared);
-        bool defer = false;
-
-        std::string report_directory;
-        for (size_t i = 1; i < args.size(); i++) {
-            if (args[i] == "-debug") {
-                shared.debug_flag = true;
-            } else if (args[i] == "-report" && ++i < args.size()) {
-                report_directory = args[i];
-                shared.stop_on_error = false;
-            } else if (args[i] == "-noassert") {
-                shared.no_assert = true;
-            } else if (args[i] == "-defer") {
-                defer = true;
-            }
-        }
-        extra_args(f, filename, args, args.size() - 1);
-
-        AST::current_filename = filename;
-        AST::set_line_num = &set_line_num;
-        AST::get_line_num = &get_line_num;
-        struct AST::AstNode *current_ast;
-
         UHDM::Serializer serializer;
 
         std::vector<vpiHandle> restoredDesigns = serializer.Restore(filename);
         for (auto design : restoredDesigns) {
             std::stringstream strstr;
-            UHDM::visit_object(design, 1, "", &shared.report.unhandled, shared.debug_flag ? std::cout : strstr);
+            UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : strstr);
         }
-        current_ast = uhdm_ast.visit_designs(restoredDesigns);
-        if (!report_directory.empty()) {
-            shared.report.write(report_directory);
+        UhdmAst uhdm_ast(this->shared);
+        AST::AstNode *current_ast = uhdm_ast.visit_designs(restoredDesigns);
+        if (!this->report_directory.empty()) {
+            this->shared.report.write(this->report_directory);
         }
         for (auto design : restoredDesigns)
             vpi_release_handle(design);
-        bool dump_ast1 = shared.debug_flag;
-        bool dump_ast2 = shared.debug_flag;
-        bool dont_redefine = false;
-        bool default_nettype_wire = true;
-        AST::process(design, current_ast, dump_ast1, dump_ast2, false, false, false, false, false, false, false, false, false, false, false, false,
-                     false, false, dont_redefine, false, defer, default_nettype_wire);
-        delete current_ast;
+        return current_ast;
     }
+    void call_log_header(RTLIL::Design *design) override { log_header(design, "Executing UHDM frontend.\n"); }
 } UhdmAstFrontend;
 
 YOSYS_NAMESPACE_END
diff --git a/uhdm-plugin/uhdmcommonfrontend.cc b/uhdm-plugin/uhdmcommonfrontend.cc
new file mode 100644
index 0000000..b340797
--- /dev/null
+++ b/uhdm-plugin/uhdmcommonfrontend.cc
@@ -0,0 +1,86 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2020 Antmicro
+
+ *  Based on frontends/json/jsonparse.cc
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "uhdmcommonfrontend.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+/* Stub for AST::process */
+static void set_line_num(int) {}
+
+/* Stub for AST::process */
+static int get_line_num(void) { return 1; }
+
+void UhdmCommonFrontend::print_read_options()
+{
+    log("    -noassert\n");
+    log("        ignore assert() statements");
+    log("\n");
+    log("    -debug\n");
+    log("        print debug info to stdout");
+    log("\n");
+    log("    -report [directory]\n");
+    log("        write a coverage report for the UHDM file\n");
+    log("\n");
+    log("    -defer\n");
+    log("        only read the abstract syntax tree and defer actual compilation\n");
+    log("        to a later 'hierarchy' command. Useful in cases where the default\n");
+    log("        parameters of modules yield invalid or not synthesizable code.\n");
+    log("\n");
+}
+
+void UhdmCommonFrontend::execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+{
+    this->call_log_header(design);
+    this->args = args;
+
+    bool defer = false;
+    for (size_t i = 1; i < args.size(); i++) {
+        if (args[i] == "-debug") {
+            this->shared.debug_flag = true;
+        } else if (args[i] == "-report" && ++i < args.size()) {
+            this->report_directory = args[i];
+            this->shared.stop_on_error = false;
+        } else if (args[i] == "-noassert") {
+            this->shared.no_assert = true;
+        } else if (args[i] == "-defer") {
+            defer = true;
+        }
+    }
+    extra_args(f, filename, args, args.size() - 1);
+
+    AST::current_filename = filename;
+    AST::set_line_num = &set_line_num;
+    AST::get_line_num = &get_line_num;
+
+    bool dump_ast1 = this->shared.debug_flag;
+    bool dump_ast2 = this->shared.debug_flag;
+    bool dont_redefine = false;
+    bool default_nettype_wire = true;
+
+    AST::AstNode *current_ast = parse(filename);
+
+    AST::process(design, current_ast, dump_ast1, dump_ast2, false, false, false, false, false, false, false, false, false, false, false, false, false,
+                 false, dont_redefine, false, defer, default_nettype_wire);
+    delete current_ast;
+}
+
+YOSYS_NAMESPACE_END
diff --git a/uhdm-plugin/uhdmcommonfrontend.h b/uhdm-plugin/uhdmcommonfrontend.h
new file mode 100644
index 0000000..f2d12a8
--- /dev/null
+++ b/uhdm-plugin/uhdmcommonfrontend.h
@@ -0,0 +1,42 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2020 Antmicro
+
+ *  Based on frontends/json/jsonparse.cc
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "UhdmAst.h"
+#include "frontends/ast/ast.h"
+#include "kernel/yosys.h"
+#include <string>
+#include <vector>
+
+YOSYS_NAMESPACE_BEGIN
+
+struct UhdmCommonFrontend : public Frontend {
+    UhdmAstShared shared;
+    std::string report_directory;
+    std::vector<std::string> args;
+    UhdmCommonFrontend(std::string name, std::string short_help) : Frontend(name, short_help) {}
+    virtual void print_read_options();
+    virtual void help() = 0;
+    virtual AST::AstNode *parse(std::string filename) = 0;
+    virtual void call_log_header(RTLIL::Design *design) = 0;
+    void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design);
+};
+
+YOSYS_NAMESPACE_END
diff --git a/uhdm-plugin/uhdmsurelogastfrontend.cc b/uhdm-plugin/uhdmsurelogastfrontend.cc
index 7bfd53d..ce79772 100644
--- a/uhdm-plugin/uhdmsurelogastfrontend.cc
+++ b/uhdm-plugin/uhdmsurelogastfrontend.cc
@@ -22,6 +22,7 @@
 #include "UhdmAst.h"
 #include "frontends/ast/ast.h"
 #include "kernel/yosys.h"
+#include "uhdmcommonfrontend.h"
 
 #if defined(_MSC_VER)
 #include <direct.h>
@@ -31,8 +32,8 @@
 #include <unistd.h>
 #endif
 
-#include "surelog/ErrorReporting/Report.h"
-#include "surelog/surelog.h"
+#include "ErrorReporting/Report.h"
+#include "surelog.h"
 
 namespace UHDM
 {
@@ -76,9 +77,16 @@
     return the_design;
 }
 
-struct UhdmSurelogAstFrontend : public Frontend {
-    UhdmSurelogAstFrontend() : Frontend("verilog_with_uhdm", "generate/read UHDM file") {}
-    void help()
+struct UhdmSurelogAstFrontend : public UhdmCommonFrontend {
+    UhdmSurelogAstFrontend() : UhdmCommonFrontend("verilog_with_uhdm", "generate/read UHDM file") {}
+    void print_read_options() override
+    {
+        log("    -process\n");
+        log("        loads design from given UHDM file\n");
+        log("\n");
+        UhdmCommonFrontend::print_read_options();
+    }
+    void help() override
     {
         //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
         log("\n");
@@ -86,56 +94,14 @@
         log("\n");
         log("Generate or load design from a UHDM file into the current design\n");
         log("\n");
-        log("    -process\n");
-        log("        loads design from given UHDM file\n");
-        log("\n");
-        log("    -noassert\n");
-        log("        ignore assert() statements");
-        log("\n");
-        log("    -debug\n");
-        log("        print debug info to stdout");
-        log("\n");
-        log("    -report [directory]\n");
-        log("        write a coverage report for the UHDM file\n");
-        log("\n");
-        log("    -defer\n");
-        log("        only read the abstract syntax tree and defer actual compilation\n");
-        log("        to a later 'hierarchy' command. Useful in cases where the default\n");
-        log("        parameters of modules yield invalid or not synthesizable code.\n");
-        log("\n");
+        this->print_read_options();
     }
-    void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+    AST::AstNode *parse(std::string filename) override
     {
-        log_header(design, "Executing Verilog with UHDM frontend.\n");
-
-        UhdmAstShared shared;
-        UhdmAst uhdm_ast(shared);
-        bool defer = false;
-
-        std::string report_directory;
-        auto it = args.begin();
-        while (it != args.end()) {
-            if (*it == "-debug") {
-                shared.debug_flag = true;
-                it = args.erase(it);
-            } else if (*it == "-report" && (it = args.erase(it)) < args.end()) {
-                report_directory = *it;
-                shared.stop_on_error = false;
-                it = args.erase(it);
-            } else if (*it == "-noassert") {
-                shared.no_assert = true;
-                it = args.erase(it);
-            } else if (*it == "-defer") {
-                defer = true;
-                it = args.erase(it);
-            } else {
-                ++it;
-            }
-        }
         std::vector<const char *> cstrings;
-        cstrings.reserve(args.size());
-        for (size_t i = 0; i < args.size(); ++i)
-            cstrings.push_back(const_cast<char *>(args[i].c_str()));
+        cstrings.reserve(this->args.size());
+        for (size_t i = 0; i < this->args.size(); ++i)
+            cstrings.push_back(const_cast<char *>(this->args[i].c_str()));
 
         SURELOG::SymbolTable *symbolTable = new SURELOG::SymbolTable();
         SURELOG::ErrorContainer *errors = new SURELOG::ErrorContainer(symbolTable);
@@ -146,22 +112,21 @@
         }
         SURELOG::scompiler *compiler = nullptr;
         const std::vector<vpiHandle> uhdm_design = executeCompilation(symbolTable, errors, clp, compiler);
-        struct AST::AstNode *current_ast = uhdm_ast.visit_designs(uhdm_design);
-        if (report_directory != "") {
-            shared.report.write(report_directory);
-        }
-        bool dump_ast1 = shared.debug_flag;
-        bool dump_ast2 = shared.debug_flag;
-        bool dont_redefine = false;
-        bool default_nettype_wire = true;
-        AST::process(design, current_ast, dump_ast1, dump_ast2, false, false, false, false, false, false, false, false, false, false, false, false,
-                     false, false, dont_redefine, false, defer, default_nettype_wire);
-        delete current_ast;
+
         SURELOG::shutdown_compiler(compiler);
         delete clp;
         delete symbolTable;
         delete errors;
+
+        UhdmAst uhdm_ast(this->shared);
+        AST::AstNode *current_ast = uhdm_ast.visit_designs(uhdm_design);
+        if (report_directory != "") {
+            shared.report.write(report_directory);
+        }
+
+        return current_ast;
     }
+    void call_log_header(RTLIL::Design *design) override { log_header(design, "Executing Verilog with UHDM frontend.\n"); }
 } UhdmSurelogAstFrontend;
 
 YOSYS_NAMESPACE_END