Merge branch 'master' into add_fifo_bram_macros
diff --git a/Makefile b/Makefile
index fc39ff4..70433f7 100644
--- a/Makefile
+++ b/Makefile
@@ -71,9 +71,9 @@
 CLANG_FORMAT ?= clang-format-8
 .PHONY: format
 format:
-	find . \( -name "*.h" -o -name "*.cc" \) -and -not -path './third_party/*' -print0 | xargs -0 -P $$(nproc) ${CLANG_FORMAT} -style=file -i
+	find . \( -name "*.h" -o -name "*.cc" \) -and -not -path '*/third_party/*' -print0 | xargs -0 -P $$(nproc) ${CLANG_FORMAT} -style=file -i
 
 VERIBLE_FORMAT ?= verible-verilog-format
 .PHONY: format-verilog
 format-verilog:
-	find */tests \( -name "*.v" -o -name "*.sv" \) -and -not -path './third_party/*' -print0 | xargs -0 $(VERIBLE_FORMAT) --inplace
+	find */tests \( -name "*.v" -o -name "*.sv" \) -and -not -path '*/third_party/*' -print0 | xargs -0 $(VERIBLE_FORMAT) --inplace
diff --git a/environment.yml b/environment.yml
index a4cf46c..dc51454 100644
--- a/environment.yml
+++ b/environment.yml
@@ -20,5 +20,5 @@
   - litex-hub
 dependencies:
   - litex-hub::yosys=0.17_7_g990c9b8e1=20220512_085338_py37
-  - litex-hub::surelog
+  - litex-hub::surelog=0.0_5519_g900fb2499=20221223_060448_py37
   - litex-hub::iverilog
diff --git a/ql-qlf-plugin/synth_quicklogic.cc b/ql-qlf-plugin/synth_quicklogic.cc
index fbbacb5..b6b475e 100644
--- a/ql-qlf-plugin/synth_quicklogic.cc
+++ b/ql-qlf-plugin/synth_quicklogic.cc
@@ -554,11 +554,7 @@
 
         if (check_label("blif")) {
             if (!blif_file.empty()) {
-                if (inferAdder) {
-                    run(stringf("write_blif -param %s", help_mode ? "<file-name>" : blif_file.c_str()));
-                } else {
-                    run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
-                }
+                run(stringf("write_blif -param %s", help_mode ? "<file-name>" : blif_file.c_str()));
             }
         }
 
diff --git a/systemverilog-plugin/Makefile b/systemverilog-plugin/Makefile
index a1d69e1..af5320d 100644
--- a/systemverilog-plugin/Makefile
+++ b/systemverilog-plugin/Makefile
@@ -18,11 +18,11 @@
 
 NAME = systemverilog
 SOURCES = UhdmAst.cc \
-          UhdmAstUpstream.cc \
           uhdmastfrontend.cc \
           uhdmcommonfrontend.cc \
           uhdmsurelogastfrontend.cc \
-          uhdmastreport.cc
+          uhdmastreport.cc \
+          third_party/yosys/const2ast.cc
 
 # Directory to search for Surelog and UHDM libraries
 UHDM_INSTALL_DIR ?= /usr/local
diff --git a/systemverilog-plugin/UhdmAst.cc b/systemverilog-plugin/UhdmAst.cc
index 20e68a0..00816d6 100644
--- a/systemverilog-plugin/UhdmAst.cc
+++ b/systemverilog-plugin/UhdmAst.cc
@@ -14,9 +14,33 @@
 #include <uhdm/uhdm.h>
 #include <uhdm/vpi_user.h>
 
-#include "UhdmAstUpstream.h"
+#include "third_party/yosys/const2ast.h"
 
 YOSYS_NAMESPACE_BEGIN
+namespace VERILOG_FRONTEND
+{
+extern bool sv_mode;
+}
+YOSYS_NAMESPACE_END
+
+namespace systemverilog_plugin
+{
+
+using namespace ::Yosys;
+
+namespace AST
+{
+using namespace ::Yosys::AST;
+
+namespace Extended
+{
+enum AstNodeTypeExtended {
+    AST_DOT = ::Yosys::AST::AST_BIND + 1, // here we always want to point to the last element of yosys' AstNodeType
+    AST_BREAK,
+    AST_CONTINUE
+};
+}
+} // namespace AST
 
 /*static*/ const IdString &UhdmAst::partial()
 {
@@ -96,6 +120,13 @@
     return objectName;
 }
 
+static AST::AstNode *mkconst_real(double d)
+{
+    AST::AstNode *node = new AST::AstNode(AST::AST_REALVALUE);
+    node->realvalue = d;
+    return node;
+}
+
 static AST::AstNode *make_range(int left, int right, bool is_signed = false)
 {
     // generate a pre-validated range node for a fixed signal range.
@@ -486,7 +517,7 @@
     AST::AstNode *struct_range = nullptr;
 
     for (auto c : search_node->children) {
-        if (c->type == static_cast<int>(AST::AST_DOT)) {
+        if (c->type == static_cast<int>(AST::Extended::AST_DOT)) {
             // There should be only 1 AST_DOT node children
             log_assert(!sub_dot);
             sub_dot = expand_dot(current_struct_elem, c);
@@ -851,8 +882,8 @@
 
 static void simplify(AST::AstNode *current_node, AST::AstNode *parent_node)
 {
-    auto dot_it =
-      std::find_if(current_node->children.begin(), current_node->children.end(), [](auto c) { return c->type == static_cast<int>(AST::AST_DOT); });
+    auto dot_it = std::find_if(current_node->children.begin(), current_node->children.end(),
+                               [](auto c) { return c->type == static_cast<int>(AST::Extended::AST_DOT); });
     AST::AstNode *dot = (dot_it != current_node->children.end()) ? *dot_it : nullptr;
 
     AST::AstNode *expanded = nullptr;
@@ -875,8 +906,8 @@
                     break;
                 } else {
                     current_node->str += "." + dot->str.substr(1);
-                    dot_it =
-                      std::find_if(dot->children.begin(), dot->children.end(), [](auto c) { return c->type == static_cast<int>(AST::AST_DOT); });
+                    dot_it = std::find_if(dot->children.begin(), dot->children.end(),
+                                          [](auto c) { return c->type == static_cast<int>(AST::Extended::AST_DOT); });
                     parent_node = dot;
                     dot = (dot_it != dot->children.end()) ? *dot_it : nullptr;
                 }
@@ -1155,7 +1186,7 @@
         }
         // handle vpiBinStrVal, vpiDecStrVal and vpiHexStrVal
         if (std::strchr(val.value.str, '\'')) {
-            return VERILOG_FRONTEND::const2ast(val.value.str, 0, false);
+            return ::systemverilog_plugin::const2ast(val.value.str, 0, false);
         } else {
             auto size = vpi_get(vpiSize, obj_h);
             if (size == 0) {
@@ -1163,7 +1194,7 @@
                 c->is_unsized = true;
                 return c;
             } else {
-                return VERILOG_FRONTEND::const2ast(std::to_string(size) + strValType + val.value.str, 0, false);
+                return ::systemverilog_plugin::const2ast(std::to_string(size) + strValType + val.value.str, 0, false);
             }
         }
     }
@@ -1233,15 +1264,15 @@
                 }
                 break;
             }
-            case AST::AST_BREAK:
-            case AST::AST_CONTINUE: {
+            case AST::Extended::AST_BREAK:
+            case AST::Extended::AST_CONTINUE: {
                 std::for_each(it, block->children.end(), [](auto *node) { delete node; });
                 block->children.erase(it, block->children.end());
                 if (!continue_wire)
                     continue_wire = make_cond_var("$continue");
                 auto *continue_id = make_identifier(continue_wire->str);
                 block->children.push_back(make_ast_node(AST::AST_ASSIGN_EQ, {continue_id, AST::AstNode::mkconst_int(1, false)}));
-                if (type == AST::AST_BREAK) {
+                if (type == AST::Extended::AST_BREAK) {
                     if (!break_wire)
                         break_wire = make_cond_var("$break");
                     auto *break_id = make_identifier(break_wire->str);
@@ -1998,42 +2029,67 @@
 
 void UhdmAst::process_enum_typespec()
 {
+    // BaseTypespec specifies underlying type of the enum.
+    // The BaseTypespec has at most one explicit packed dimension (range).
+    // When base type is not specified in SystemVerilog code, it is assumed to be an int.
+    // Type of enum items (constants) is the same as the enum type.
     current_node = make_ast_node(AST::AST_ENUM);
+    bool has_base_type = false;
+    visit_one_to_one({vpiBaseTypespec}, obj_h, [&](AST::AstNode *node) {
+        has_base_type = true;
+        current_node->children = std::move(node->children);
+        current_node->attributes = std::move(node->attributes);
+        current_node->is_signed = node->is_signed;
+        current_node->is_logic = node->is_logic;
+        delete node;
+    });
+    if (!has_base_type) {
+        // Base typespec is `int` by default
+        // TODO (mglb): This is almost the same code as in `process_int_typespec()`. Put common code in dedicated function.
+        std::vector<AST::AstNode *> packed_ranges;
+        packed_ranges.push_back(make_range(31, 0));
+        add_multirange_wire(current_node, std::move(packed_ranges), {});
+        current_node->is_signed = true;
+    }
+    // We have to restore node's range_* properties if there's no range.
+    const auto range_left = current_node->range_left;
+    const auto range_right = current_node->range_right;
+    const auto range_valid = current_node->range_valid;
+    // Create a range from the typespec just for the purpose of copying it to consts.
+    convert_packed_unpacked_range(current_node);
+    const auto range_it = std::find_if(current_node->children.cbegin(), current_node->children.cend(),
+                                       [](const AST::AstNode *n) { return n->type == AST::AST_RANGE || n->type == AST::AST_MULTIRANGE; });
+    const auto *const range = range_it != current_node->children.cend() ? *range_it : nullptr;
+    if (range) {
+        current_node->children.erase(range_it);
+    } else {
+        current_node->range_left = range_left;
+        current_node->range_right = range_right;
+        current_node->range_valid = range_valid;
+    }
+
     visit_one_to_one({vpiTypedefAlias}, obj_h, [&](AST::AstNode *node) {
         if (node) {
-            current_node->attributes["\\enum_base_type"] = node->clone();
+            current_node->attributes["\\enum_base_type"] = node;
         }
     });
-    visit_one_to_many({vpiEnumConst}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(node); });
-    vpiHandle typespec_h = vpi_handle(vpiBaseTypespec, obj_h);
-    if (typespec_h) {
-        int typespec_type = vpi_get(vpiType, typespec_h);
-        switch (typespec_type) {
-        case vpiLogicTypespec: {
-            current_node->is_logic = true;
-            shared.report.mark_handled(typespec_h);
-            break;
+    visit_one_to_many({vpiEnumConst}, obj_h, [&](AST::AstNode *node) {
+        // Enum const must have the same type and ranges as the enum.
+        node->is_logic = current_node->is_logic;
+        node->is_signed = current_node->is_signed;
+        if (range) {
+            node->children.push_back(range->clone());
+            node->range_valid = true;
+        } else {
+            node->range_left = range_left;
+            node->range_right = range_right;
+            node->range_valid = range_valid;
         }
-        case vpiByteTypespec:
-        case vpiIntTypespec:
-        case vpiIntegerTypespec: {
-            current_node->is_signed = vpi_get(vpiSigned, typespec_h);
-            shared.report.mark_handled(typespec_h);
-            break;
-        }
-        case vpiBitTypespec: {
-            shared.report.mark_handled(typespec_h);
-            break;
-        }
-        default: {
-            const uhdm_handle *const handle = (const uhdm_handle *)typespec_h;
-            const UHDM::BaseClass *const object = (const UHDM::BaseClass *)handle->object;
-            report_error("%s:%d: Encountered unhandled typespec in process_enum_typespec: '%s' of type '%s'\n", object->VpiFile().c_str(),
-                         object->VpiLineNo(), object->VpiName().c_str(), UHDM::VpiTypeName(typespec_h).c_str());
-            break;
-        }
-        }
-        vpi_release_handle(typespec_h);
+        // IMPORTANT: invalidates `range_it`!
+        current_node->children.push_back(node);
+    });
+    if (range) {
+        delete range;
     }
 }
 
@@ -2045,7 +2101,6 @@
         constant_node->filename = current_node->filename;
         constant_node->location = current_node->location;
         current_node->children.push_back(constant_node);
-        current_node->children.push_back(make_range(constant_node->range_left, constant_node->range_right, true));
     }
 }
 
@@ -3462,7 +3517,7 @@
                     log_assert(!node->children.empty());
                     top_node->children.push_back(node->children[0]);
                 } else {
-                    node->type = static_cast<AST::AstNodeType>(AST::AST_DOT);
+                    node->type = static_cast<AST::AstNodeType>(AST::Extended::AST_DOT);
                     top_node->children.push_back(node);
                     top_node = node;
                 }
@@ -3525,7 +3580,7 @@
     if (vpi_get(vpiType, typespec_h) == vpiStringTypespec) {
         std::string field_name = vpi_get_str(vpiName, typespec_h);
         if (field_name != "default") { // TODO: better support of the default keyword
-            auto field = new AST::AstNode(static_cast<AST::AstNodeType>(AST::AST_DOT));
+            auto field = new AST::AstNode(static_cast<AST::AstNodeType>(AST::Extended::AST_DOT));
             field->str = field_name;
             current_node->children[0]->children.push_back(field);
         }
@@ -4315,11 +4370,11 @@
         break;
     case vpiBreak:
         // Will be resolved later by loop processor
-        current_node = make_ast_node(static_cast<AST::AstNodeType>(AST::AST_BREAK));
+        current_node = make_ast_node(static_cast<AST::AstNodeType>(AST::Extended::AST_BREAK));
         break;
     case vpiContinue:
         // Will be resolved later by loop processor
-        current_node = make_ast_node(static_cast<AST::AstNodeType>(AST::AST_CONTINUE));
+        current_node = make_ast_node(static_cast<AST::AstNodeType>(AST::Extended::AST_CONTINUE));
         break;
     case vpiGenScopeArray:
         process_gen_scope_array();
@@ -4472,4 +4527,4 @@
     }
 }
 
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/UhdmAst.h b/systemverilog-plugin/UhdmAst.h
index 1e77c17..f3b1017 100644
--- a/systemverilog-plugin/UhdmAst.h
+++ b/systemverilog-plugin/UhdmAst.h
@@ -8,7 +8,8 @@
 #include "uhdmastshared.h"
 #include <uhdm/uhdm.h>
 
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
 
 class UhdmAst
 {
@@ -16,43 +17,44 @@
     // Walks through one-to-many relationships from given parent
     // node through the VPI interface, visiting child nodes belonging to
     // ChildrenNodeTypes that are present in the given object.
-    void visit_one_to_many(const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(AST::AstNode *)> &f);
+    void visit_one_to_many(const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(::Yosys::AST::AstNode *)> &f);
 
     // Walks through one-to-one relationships from given parent
     // node through the VPI interface, visiting child nodes belonging to
     // ChildrenNodeTypes that are present in the given object.
-    void visit_one_to_one(const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(AST::AstNode *)> &f);
+    void visit_one_to_one(const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(::Yosys::AST::AstNode *)> &f);
 
     // Visit children of type vpiRange that belong to the given parent node.
-    void visit_range(vpiHandle obj_h, const std::function<void(AST::AstNode *)> &f);
+    void visit_range(vpiHandle obj_h, const std::function<void(::Yosys::AST::AstNode *)> &f);
 
     // Visit the default expression assigned to a variable.
     void visit_default_expr(vpiHandle obj_h);
 
     // Create an AstNode of the specified type with metadata extracted from
     // the given vpiHandle.
-    AST::AstNode *make_ast_node(AST::AstNodeType type, std::vector<AST::AstNode *> children = {}, bool prefer_full_name = false);
+    ::Yosys::AST::AstNode *make_ast_node(::Yosys::AST::AstNodeType type, std::vector<::Yosys::AST::AstNode *> children = {},
+                                         bool prefer_full_name = false);
 
     // Create an identifier AstNode
-    AST::AstNode *make_identifier(const std::string &name);
+    ::Yosys::AST::AstNode *make_identifier(const std::string &name);
 
     // Makes the passed node a cell node of the specified type
-    void make_cell(vpiHandle obj_h, AST::AstNode *node, AST::AstNode *type);
+    void make_cell(vpiHandle obj_h, ::Yosys::AST::AstNode *node, ::Yosys::AST::AstNode *type);
 
     // Moves a type node to the specified node
-    void move_type_to_new_typedef(AST::AstNode *current_node, AST::AstNode *type_node);
+    void move_type_to_new_typedef(::Yosys::AST::AstNode *current_node, ::Yosys::AST::AstNode *type_node);
 
     // Go up the UhdmAst to find a parent node of the specified type
-    AST::AstNode *find_ancestor(const std::unordered_set<AST::AstNodeType> &types);
+    ::Yosys::AST::AstNode *find_ancestor(const std::unordered_set<::Yosys::AST::AstNodeType> &types);
 
     // Reports that something went wrong with reading the UHDM file
     void report_error(const char *format, ...) const;
 
     // Processes the value connected to the specified node
-    AST::AstNode *process_value(vpiHandle obj_h);
+    ::Yosys::AST::AstNode *process_value(vpiHandle obj_h);
 
     // Transforms break and continue nodes into structures accepted by the AST frontend
-    void transform_breaks_continues(AST::AstNode *loop, AST::AstNode *decl_block);
+    void transform_breaks_continues(::Yosys::AST::AstNode *loop, ::Yosys::AST::AstNode *decl_block);
 
     // The parent UhdmAst
     UhdmAst *parent;
@@ -64,7 +66,7 @@
     vpiHandle obj_h = 0;
 
     // The current Yosys AST node
-    AST::AstNode *current_node = nullptr;
+    ::Yosys::AST::AstNode *current_node = nullptr;
 
     // Indentation used for debug printing
     std::string indent;
@@ -128,7 +130,7 @@
     void process_logic_var();
     void process_sys_func_call();
     // use for task calls and function calls
-    void process_tf_call(AST::AstNodeType type);
+    void process_tf_call(::Yosys::AST::AstNodeType type);
     void process_immediate_assert();
     void process_hier_path();
     void process_logic_typespec();
@@ -148,7 +150,7 @@
     void process_while();
     void process_gate();
     void process_primterm();
-    void simplify_parameter(AST::AstNode *parameter, AST::AstNode *module_node = nullptr);
+    void simplify_parameter(::Yosys::AST::AstNode *parameter, ::Yosys::AST::AstNode *module_node = nullptr);
     void process_unsupported_stmt(const UHDM::BaseClass *object);
 
     UhdmAst(UhdmAst *p, UhdmAstShared &s, const std::string &i) : parent(p), shared(s), indent(i)
@@ -161,23 +163,19 @@
     UhdmAst(UhdmAstShared &s, const std::string &i = "") : UhdmAst(nullptr, s, i) {}
 
     // Visits single VPI object and creates proper AST node
-    AST::AstNode *process_object(vpiHandle obj_h);
+    ::Yosys::AST::AstNode *process_object(vpiHandle obj_h);
 
     // Visits all VPI design objects and returns created ASTs
-    AST::AstNode *visit_designs(const std::vector<vpiHandle> &designs);
+    ::Yosys::AST::AstNode *visit_designs(const std::vector<vpiHandle> &designs);
 
-    static const IdString &partial();
-    static const IdString &packed_ranges();
-    static const IdString &unpacked_ranges();
+    static const ::Yosys::IdString &partial();
+    static const ::Yosys::IdString &packed_ranges();
+    static const ::Yosys::IdString &unpacked_ranges();
     // set this attribute to force conversion of multirange wire to single range. It is useful to force-convert some memories.
-    static const IdString &force_convert();
-    static const IdString &is_imported();
+    static const ::Yosys::IdString &force_convert();
+    static const ::Yosys::IdString &is_imported();
 };
 
-namespace VERILOG_FRONTEND
-{
-extern bool sv_mode;
-}
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
 
 #endif
diff --git a/systemverilog-plugin/tests/Makefile b/systemverilog-plugin/tests/Makefile
index e078fa7..849a9f9 100644
--- a/systemverilog-plugin/tests/Makefile
+++ b/systemverilog-plugin/tests/Makefile
@@ -16,10 +16,18 @@
 
 TESTS = counter \
 		break_continue \
-		separate-compilation
+		separate-compilation \
+		debug-flag \
+		report-flag \
+		defines \
+		defaults
 
 include $(shell pwd)/../../Makefile_test.common
 
 counter_verify = true
 break_continue_verify = $(call diff_test,break_continue,out)
 separate-compilation_verify = true
+debug-flag_verify = true
+report-flag_verify = true
+defaults_verify = true
+defines_verify = true
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv b/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv
new file mode 100644
index 0000000..565946b
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv
@@ -0,0 +1,21 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+module BUF (
+  input I,
+  output O
+);
+  assign O = I;
+endmodule;
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag-pkg.sv b/systemverilog-plugin/tests/debug-flag/debug-flag-pkg.sv
new file mode 100644
index 0000000..b0362fc
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag-pkg.sv
@@ -0,0 +1,19 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+package pkg;
+  parameter BITS = 4;
+  parameter LOG2DELAY = 22;
+endpackage
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag.tcl b/systemverilog-plugin/tests/debug-flag/debug-flag.tcl
new file mode 100644
index 0000000..86cfee5
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag.tcl
@@ -0,0 +1,16 @@
+yosys -import
+if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
+yosys -import  ;# ingest plugin commands
+
+set TMP_DIR /tmp
+if { [info exists ::env(TMPDIR) ] } {
+  set TMP_DIR $::env(TMPDIR)
+}
+
+# Testing simple round-trip
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -defer $::env(DESIGN_TOP)-pkg.sv
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -defer $::env(DESIGN_TOP)-buf.sv
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -defer $::env(DESIGN_TOP).v
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -link
+hierarchy
+write_verilog
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag.v b/systemverilog-plugin/tests/debug-flag/debug-flag.v
new file mode 100644
index 0000000..5bd294a
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag.v
@@ -0,0 +1,31 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+module top (
+  input clk,
+  output [3:0] led
+);
+
+  wire bufg;
+  BUF bufgctrl (
+      .I(clk),
+      .O(bufg)
+  );
+  reg [pkg::BITS + pkg::LOG2DELAY-1 : 0] counter = 0;
+  always @(posedge bufg) begin
+    counter <= counter + 1;
+  end
+  assign led[3:0] = counter >> pkg::LOG2DELAY;
+endmodule
diff --git a/systemverilog-plugin/tests/defaults/defaults.tcl b/systemverilog-plugin/tests/defaults/defaults.tcl
new file mode 100644
index 0000000..a363895
--- /dev/null
+++ b/systemverilog-plugin/tests/defaults/defaults.tcl
@@ -0,0 +1,23 @@
+yosys -import
+if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
+yosys -import  ;# ingest plugin commands
+
+set TMP_DIR /tmp
+if { [info exists ::env(TMPDIR) ] } {
+  set TMP_DIR $::env(TMPDIR)
+}
+
+# Define forbidden value
+systemverilog_defaults -add -DPAKALA
+# Stash it
+systemverilog_defaults -push
+systemverilog_defaults -clear
+read_systemverilog $::env(DESIGN_TOP).v
+# Allow parsing the module again
+delete top
+systemverilog_defaults -pop
+# Skip check for forbidden value
+systemverilog_defaults -add -Pbypass=1
+read_systemverilog $::env(DESIGN_TOP).v
+hierarchy
+write_verilog
diff --git a/systemverilog-plugin/tests/defaults/defaults.v b/systemverilog-plugin/tests/defaults/defaults.v
new file mode 100644
index 0000000..f565a77
--- /dev/null
+++ b/systemverilog-plugin/tests/defaults/defaults.v
@@ -0,0 +1,28 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+module top #(
+  parameter bit bypass = 0
+)(
+  input clk,
+  output out
+);
+
+`ifdef PAKALA
+  initial if(!bypass) $stop("Defined forbidden value");
+`endif
+  assign out = clk;
+endmodule
diff --git a/systemverilog-plugin/tests/defines/defines.tcl b/systemverilog-plugin/tests/defines/defines.tcl
new file mode 100644
index 0000000..030c1ad
--- /dev/null
+++ b/systemverilog-plugin/tests/defines/defines.tcl
@@ -0,0 +1,15 @@
+yosys -import
+if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
+yosys -import  ;# ingest plugin commands
+
+set TMP_DIR /tmp
+if { [info exists ::env(TMPDIR) ] } {
+  set TMP_DIR $::env(TMPDIR)
+}
+
+systemverilog_defines -DPONA
+systemverilog_defines -DPAKALA
+systemverilog_defines -UPAKALA
+read_systemverilog $::env(DESIGN_TOP).v
+hierarchy
+write_verilog
diff --git a/systemverilog-plugin/tests/defines/defines.v b/systemverilog-plugin/tests/defines/defines.v
new file mode 100644
index 0000000..528e9f1
--- /dev/null
+++ b/systemverilog-plugin/tests/defines/defines.v
@@ -0,0 +1,29 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+module top (
+  input clk,
+  output out
+);
+
+`ifndef PONA
+  initial $stop("Define failed");
+`endif
+`ifdef PAKALA
+  initial $stop("Undefine failed");
+`endif
+  assign out = clk;
+endmodule
diff --git a/systemverilog-plugin/tests/report-flag/report-flag-buf.sv b/systemverilog-plugin/tests/report-flag/report-flag-buf.sv
new file mode 100644
index 0000000..565946b
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag-buf.sv
@@ -0,0 +1,21 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+module BUF (
+  input I,
+  output O
+);
+  assign O = I;
+endmodule;
diff --git a/systemverilog-plugin/tests/report-flag/report-flag-pkg.sv b/systemverilog-plugin/tests/report-flag/report-flag-pkg.sv
new file mode 100644
index 0000000..b0362fc
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag-pkg.sv
@@ -0,0 +1,19 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+package pkg;
+  parameter BITS = 4;
+  parameter LOG2DELAY = 22;
+endpackage
diff --git a/systemverilog-plugin/tests/report-flag/report-flag.tcl b/systemverilog-plugin/tests/report-flag/report-flag.tcl
new file mode 100644
index 0000000..3a3cc6d
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag.tcl
@@ -0,0 +1,16 @@
+yosys -import
+if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
+yosys -import  ;# ingest plugin commands
+
+set TMP_DIR /tmp
+if { [info exists ::env(TMPDIR) ] } {
+  set TMP_DIR $::env(TMPDIR)
+}
+
+# Testing simple round-trip
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -defer $::env(DESIGN_TOP)-pkg.sv
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -defer $::env(DESIGN_TOP)-buf.sv
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -defer $::env(DESIGN_TOP).v
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -link
+hierarchy
+write_verilog
diff --git a/systemverilog-plugin/tests/report-flag/report-flag.v b/systemverilog-plugin/tests/report-flag/report-flag.v
new file mode 100644
index 0000000..5bd294a
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag.v
@@ -0,0 +1,31 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+module top (
+  input clk,
+  output [3:0] led
+);
+
+  wire bufg;
+  BUF bufgctrl (
+      .I(clk),
+      .O(bufg)
+  );
+  reg [pkg::BITS + pkg::LOG2DELAY-1 : 0] counter = 0;
+  always @(posedge bufg) begin
+    counter <= counter + 1;
+  end
+  assign led[3:0] = counter >> pkg::LOG2DELAY;
+endmodule
diff --git a/systemverilog-plugin/third_party/yosys/README b/systemverilog-plugin/third_party/yosys/README
new file mode 100644
index 0000000..ceb62a9
--- /dev/null
+++ b/systemverilog-plugin/third_party/yosys/README
@@ -0,0 +1,17 @@
+Files in this directory were copied from Yosys sources and slightly adapted.
+Original sources and their license available at https://github.com/YosysHQ/yosys.
+
+Copied files, their sources, changes & notes:
+
+- const2ast.cc: yosys/frontends/verilog/const2ast.cc (rev. 72787f5)
+  - The file is a part of Yosys Verilog frontend, which is not publicly exposed
+    by Yosys. Copy has been made to avoid relying on internal details.
+  - Changes:
+    - C++ includes adapted to not rely on `verilog_frontend.h` file.
+    - Removed Yosys namespace; `const2ast()` has been placed inside
+      `systemverilog_plugin` namespace to avoid conflicts with the symbol from
+      Yosys when statically linking.
+
+Non-copied files placed here for interfacing purposes:
+
+- const2ast.h
diff --git a/systemverilog-plugin/third_party/yosys/const2ast.cc b/systemverilog-plugin/third_party/yosys/const2ast.cc
new file mode 100644
index 0000000..96ea6cc
--- /dev/null
+++ b/systemverilog-plugin/third_party/yosys/const2ast.cc
@@ -0,0 +1,252 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ *  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.
+ *
+ *  ---
+ *
+ *  The Verilog frontend.
+ *
+ *  This frontend is using the AST frontend library (see frontends/ast/).
+ *  Thus this frontend does not generate RTLIL code directly but creates an
+ *  AST directly from the Verilog parse tree and then passes this AST to
+ *  the AST frontend library.
+ *
+ *  ---
+ *
+ *  This file contains an ad-hoc parser for Verilog constants. The Verilog
+ *  lexer does only recognize a constant but does not actually split it to its
+ *  components. I.e. it just passes the Verilog code for the constant to the
+ *  bison parser. The parser then uses the function const2ast() from this file
+ *  to create an AST node for the constant.
+ *
+ *  ---
+ *
+ *  The file has been adapted for use in Yosys SystemVerilog Plugin.
+ *
+ */
+
+#include "const2ast.h"
+#include "frontends/ast/ast.h"
+#include "kernel/log.h"
+
+#include <string>
+#include <cmath>
+#include <vector>
+
+using namespace Yosys;
+using namespace Yosys::AST;
+
+// divide an arbitrary length decimal number by two and return the rest
+static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
+{
+	int carry = 0;
+	for (size_t i = 0; i < digits.size(); i++) {
+		if (digits[i] >= 10)
+			log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n");
+		digits[i] += carry * 10;
+		carry = digits[i] % 2;
+		digits[i] /= 2;
+	}
+	while (!digits.empty() && !digits.front())
+		digits.erase(digits.begin());
+	return carry;
+}
+
+// find the number of significant bits in a binary number (not including the sign bit)
+static int my_ilog2(int x)
+{
+	int ret = 0;
+	while (x != 0 && x != -1) {
+		x = x >> 1;
+		ret++;
+	}
+	return ret;
+}
+
+// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
+static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
+{
+	// all digits in string (MSB at index 0)
+	std::vector<uint8_t> digits;
+
+	while (*str) {
+		if ('0' <= *str && *str <= '9')
+			digits.push_back(*str - '0');
+		else if ('a' <= *str && *str <= 'f')
+			digits.push_back(10 + *str - 'a');
+		else if ('A' <= *str && *str <= 'F')
+			digits.push_back(10 + *str - 'A');
+		else if (*str == 'x' || *str == 'X')
+			digits.push_back(0xf0);
+		else if (*str == 'z' || *str == 'Z' || *str == '?')
+			digits.push_back(0xf1);
+		str++;
+	}
+
+	if (base == 10 && GetSize(digits) == 1 && digits.front() >= 0xf0)
+		base = 2;
+
+	data.clear();
+
+	if (base == 10) {
+		while (!digits.empty())
+			data.push_back(my_decimal_div_by_two(digits) ? State::S1 : State::S0);
+	} else {
+		int bits_per_digit = my_ilog2(base-1);
+		for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
+			if (*it > (base-1) && *it < 0xf0)
+				log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n",
+					       base-1, base);
+			for (int i = 0; i < bits_per_digit; i++) {
+				int bitmask = 1 << i;
+				if (*it == 0xf0)
+					data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx);
+				else if (*it == 0xf1)
+					data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz);
+				else
+					data.push_back((*it & bitmask) ? State::S1 : State::S0);
+			}
+		}
+	}
+
+	int len = GetSize(data);
+	RTLIL::State msb = data.empty() ? State::S0 : data.back();
+
+	if (len_in_bits < 0) {
+		if (len < 32)
+			data.resize(32, msb == State::S0 || msb == State::S1 ? RTLIL::S0 : msb);
+		return;
+	}
+
+	if (is_unsized && (len > len_in_bits))
+		log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len);
+
+	for (len = len - 1; len >= 0; len--)
+		if (data[len] == State::S1)
+			break;
+	if (msb == State::S0 || msb == State::S1) {
+		len += 1;
+		data.resize(len_in_bits, State::S0);
+	} else {
+		len += 2;
+		data.resize(len_in_bits, msb);
+	}
+
+	if (len_in_bits == 0)
+		log_file_error(current_filename, get_line_num(), "Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n");
+
+	if (len > len_in_bits)
+		log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n",
+			len_in_bits, len, current_filename.c_str(), get_line_num());
+}
+
+// convert the Verilog code for a constant to an AST node
+AstNode *systemverilog_plugin::const2ast(std::string code, char case_type, bool warn_z)
+{
+	if (warn_z) {
+		AstNode *ret = const2ast(code, case_type);
+		if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
+			log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
+				current_filename.c_str(), get_line_num());
+		return ret;
+	}
+
+	const char *str = code.c_str();
+
+	// Strings
+	if (*str == '"') {
+		int len = strlen(str) - 2;
+		std::vector<RTLIL::State> data;
+		data.reserve(len * 8);
+		for (int i = 0; i < len; i++) {
+			unsigned char ch = str[len - i];
+			for (int j = 0; j < 8; j++) {
+				data.push_back((ch & 1) ? State::S1 : State::S0);
+				ch = ch >> 1;
+			}
+		}
+		AstNode *ast = AstNode::mkconst_bits(data, false);
+		ast->str = code;
+		return ast;
+	}
+
+	for (size_t i = 0; i < code.size(); i++)
+		if (code[i] == '_' || code[i] == ' ' || code[i] == '\t' || code[i] == '\r' || code[i] == '\n')
+			code.erase(code.begin()+(i--));
+	str = code.c_str();
+
+	char *endptr;
+	long len_in_bits = strtol(str, &endptr, 10);
+
+	// Simple base-10 integer
+	if (*endptr == 0) {
+		std::vector<RTLIL::State> data;
+		my_strtobin(data, str, -1, 10, case_type, false);
+		if (data.back() == State::S1)
+			data.push_back(State::S0);
+		return AstNode::mkconst_bits(data, true);
+	}
+
+	// unsized constant
+	if (str == endptr)
+		len_in_bits = -1;
+
+	// The "<bits>'[sS]?[bodhBODH]<digits>" syntax
+	if (*endptr == '\'')
+	{
+		std::vector<RTLIL::State> data;
+		bool is_signed = false;
+		bool is_unsized = len_in_bits < 0;
+		if (*(endptr+1) == 's' || *(endptr+1) == 'S') {
+			is_signed = true;
+			endptr++;
+		}
+		switch (*(endptr+1))
+		{
+		case 'b':
+		case 'B':
+			my_strtobin(data, endptr+2, len_in_bits, 2, case_type, is_unsized);
+			break;
+		case 'o':
+		case 'O':
+			my_strtobin(data, endptr+2, len_in_bits, 8, case_type, is_unsized);
+			break;
+		case 'd':
+		case 'D':
+			my_strtobin(data, endptr+2, len_in_bits, 10, case_type, is_unsized);
+			break;
+		case 'h':
+		case 'H':
+			my_strtobin(data, endptr+2, len_in_bits, 16, case_type, is_unsized);
+			break;
+		default:
+			char next_char = char(tolower(*(endptr+1)));
+			if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') {
+				is_unsized = true;
+				my_strtobin(data, endptr+1, 1, 2, case_type, is_unsized);
+			} else {
+				return NULL;
+			}
+		}
+		if (len_in_bits < 0) {
+			if (is_signed && data.back() == State::S1)
+				data.push_back(State::S0);
+		}
+		return AstNode::mkconst_bits(data, is_signed, is_unsized);
+	}
+
+	return NULL;
+}
diff --git a/systemverilog-plugin/third_party/yosys/const2ast.h b/systemverilog-plugin/third_party/yosys/const2ast.h
new file mode 100644
index 0000000..f7130a2
--- /dev/null
+++ b/systemverilog-plugin/third_party/yosys/const2ast.h
@@ -0,0 +1,13 @@
+#ifndef SYSTEMVERILOG_PLUGIN_CONST2AST_H
+#define SYSTEMVERILOG_PLUGIN_CONST2AST_H
+
+#include "frontends/ast/ast.h"
+#include <string>
+
+namespace systemverilog_plugin
+{
+	// this function converts a Verilog constant to an AST_CONSTANT node
+	Yosys::AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
+}
+
+#endif // SYSTEMVERILOG_PLUGIN_CONST2AST_H
diff --git a/systemverilog-plugin/uhdmastfrontend.cc b/systemverilog-plugin/uhdmastfrontend.cc
index 0ee97c0..427fb37 100644
--- a/systemverilog-plugin/uhdmastfrontend.cc
+++ b/systemverilog-plugin/uhdmastfrontend.cc
@@ -25,7 +25,10 @@
                          bool shallowVisit = false);
 }
 
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
+
+using namespace ::Yosys;
 
 struct UhdmAstFrontend : public UhdmCommonFrontend {
     UhdmAstFrontend() : UhdmCommonFrontend("uhdm", "read UHDM file") {}
@@ -50,8 +53,8 @@
         delete synthSubset;
         if (this->shared.debug_flag || !this->report_directory.empty()) {
             for (auto design : restoredDesigns) {
-                std::stringstream strstr;
-                UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : strstr);
+                std::ofstream null_stream;
+                UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : null_stream);
             }
         }
         UhdmAst uhdm_ast(this->shared);
@@ -68,4 +71,4 @@
     void call_log_header(RTLIL::Design *design) override { log_header(design, "Executing UHDM frontend.\n"); }
 } UhdmAstFrontend;
 
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmastreport.cc b/systemverilog-plugin/uhdmastreport.cc
index 9a2832f..1df94b3 100644
--- a/systemverilog-plugin/uhdmastreport.cc
+++ b/systemverilog-plugin/uhdmastreport.cc
@@ -5,7 +5,10 @@
 #include <uhdm/BaseClass.h>
 #include <unordered_set>
 
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
+
+using namespace ::Yosys;
 
 void UhdmAstReport::mark_handled(const UHDM::BaseClass *object)
 {
@@ -84,4 +87,4 @@
     index_file << "</body>\n</html>" << std::endl;
 }
 
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmastreport.h b/systemverilog-plugin/uhdmastreport.h
index ae16b95..e2403fc 100644
--- a/systemverilog-plugin/uhdmastreport.h
+++ b/systemverilog-plugin/uhdmastreport.h
@@ -8,7 +8,8 @@
 #undef cover
 #include <uhdm/uhdm.h>
 
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
 
 class UhdmAstReport
 {
@@ -30,6 +31,6 @@
     void write(const std::string &directory);
 };
 
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
 
 #endif
diff --git a/systemverilog-plugin/uhdmastshared.h b/systemverilog-plugin/uhdmastshared.h
index a1ad1c6..b185975 100644
--- a/systemverilog-plugin/uhdmastshared.h
+++ b/systemverilog-plugin/uhdmastshared.h
@@ -5,7 +5,8 @@
 #include <string>
 #include <unordered_map>
 
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
 
 class UhdmAstShared
 {
@@ -51,19 +52,19 @@
     bool link = false;
 
     // Top nodes of the design (modules, interfaces)
-    std::unordered_map<std::string, AST::AstNode *> top_nodes;
+    std::unordered_map<std::string, ::Yosys::AST::AstNode *> top_nodes;
 
     // UHDM node coverage report
     UhdmAstReport report;
 
     // Map from AST param nodes to their types (used for params with struct types)
-    std::unordered_map<std::string, AST::AstNode *> param_types;
+    std::unordered_map<std::string, ::Yosys::AST::AstNode *> param_types;
 
-    AST::AstNode *current_top_node = nullptr;
+    ::Yosys::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
+} // namespace systemverilog_plugin
 
 #endif
diff --git a/systemverilog-plugin/uhdmcommonfrontend.cc b/systemverilog-plugin/uhdmcommonfrontend.cc
index 651552a..167259c 100644
--- a/systemverilog-plugin/uhdmcommonfrontend.cc
+++ b/systemverilog-plugin/uhdmcommonfrontend.cc
@@ -19,7 +19,10 @@
 
 #include "uhdmcommonfrontend.h"
 
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
+
+using namespace ::Yosys;
 
 /* Stub for AST::process */
 static void set_line_num(int) {}
@@ -147,4 +150,4 @@
     }
 }
 
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmcommonfrontend.h b/systemverilog-plugin/uhdmcommonfrontend.h
index e8b59f9..4c10d10 100644
--- a/systemverilog-plugin/uhdmcommonfrontend.h
+++ b/systemverilog-plugin/uhdmcommonfrontend.h
@@ -26,7 +26,8 @@
 #include <type_traits>
 #include <vector>
 
-YOSYS_NAMESPACE_BEGIN
+namespace systemverilog_plugin
+{
 
 // FIXME (mglb): temporary fix to support UHDM both before and after the following change:
 // https://github.com/chipsalliance/UHDM/commit/d78d094448bd94926644e48adea4df293b82f101
@@ -45,16 +46,16 @@
     return new ObjT(std::forward<ArgN>(arg_n)..., true);
 }
 
-struct UhdmCommonFrontend : public Frontend {
+struct UhdmCommonFrontend : public ::Yosys::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);
+    virtual ::Yosys::AST::AstNode *parse(std::string filename) = 0;
+    virtual void call_log_header(::Yosys::RTLIL::Design *design) = 0;
+    void execute(std::istream *&f, std::string filename, std::vector<std::string> args, ::Yosys::RTLIL::Design *design);
 };
 
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmsurelogastfrontend.cc b/systemverilog-plugin/uhdmsurelogastfrontend.cc
index 4f664c7..a72b405 100644
--- a/systemverilog-plugin/uhdmsurelogastfrontend.cc
+++ b/systemverilog-plugin/uhdmsurelogastfrontend.cc
@@ -29,6 +29,9 @@
 #include <sys/param.h>
 #include <unistd.h>
 #endif
+#include <memory>
+
+#include <list>
 
 #include "Surelog/ErrorReporting/Report.h"
 #include "Surelog/surelog.h"
@@ -39,44 +42,78 @@
                          bool shallowVisit = false);
 }
 
-YOSYS_NAMESPACE_BEGIN
-
-std::vector<vpiHandle> executeCompilation(SURELOG::SymbolTable *symbolTable, SURELOG::ErrorContainer *errors, SURELOG::CommandLineParser *clp,
-                                          SURELOG::scompiler *compiler)
+namespace systemverilog_plugin
 {
-    bool success = true;
-    bool noFatalErrors = true;
-    unsigned int codedReturn = 0;
-    clp->setWriteUhdm(false);
-    errors->printMessages(clp->muteStdout());
-    std::vector<vpiHandle> the_design;
-    if (success && (!clp->help())) {
-        compiler = SURELOG::start_compiler(clp);
-        if (!compiler)
+
+using namespace ::Yosys;
+
+// Store systemverilog defaults to be passed for every invocation of read_systemverilog
+static std::vector<std::string> systemverilog_defaults;
+static std::list<std::vector<std::string>> systemverilog_defaults_stack;
+
+// Store global definitions for top-level defines
+static std::vector<std::string> systemverilog_defines;
+
+// SURELOG::scompiler wrapper.
+// Owns UHDM/VPI resources used by designs returned from `execute`
+class Compiler
+{
+  public:
+    Compiler() = default;
+    ~Compiler()
+    {
+        if (this->scompiler) {
+            SURELOG::shutdown_compiler(this->scompiler);
+        }
+    }
+
+    const std::vector<vpiHandle> &execute(std::unique_ptr<SURELOG::ErrorContainer> errors, std::unique_ptr<SURELOG::CommandLineParser> clp)
+    {
+        log_assert(!this->errors && !this->clp && !this->scompiler);
+
+        bool success = true;
+        bool noFatalErrors = true;
+        unsigned int codedReturn = 0;
+        clp->setWriteUhdm(false);
+        errors->printMessages(clp->muteStdout());
+        if (success && (!clp->help())) {
+            this->scompiler = SURELOG::start_compiler(clp.get());
+            if (!this->scompiler)
+                codedReturn |= 1;
+            this->designs.push_back(SURELOG::get_uhdm_design(this->scompiler));
+        }
+        SURELOG::ErrorContainer::Stats stats;
+        if (!clp->help()) {
+            stats = errors->getErrorStats();
+            if (stats.nbFatal)
+                codedReturn |= 1;
+            if (stats.nbSyntax)
+                codedReturn |= 2;
+        }
+        bool noFErrors = true;
+        if (!clp->help())
+            noFErrors = errors->printStats(stats, clp->muteStdout());
+        if (noFErrors == false) {
+            noFatalErrors = false;
+        }
+        if ((!noFatalErrors) || (!success) || (errors->getErrorStats().nbError))
             codedReturn |= 1;
-        the_design.push_back(SURELOG::get_uhdm_design(compiler));
+        if (codedReturn) {
+            log_error("Error when parsing design. Aborting!\n");
+        }
+
+        this->clp = std::move(clp);
+        this->errors = std::move(errors);
+
+        return this->designs;
     }
-    SURELOG::ErrorContainer::Stats stats;
-    if (!clp->help()) {
-        stats = errors->getErrorStats();
-        if (stats.nbFatal)
-            codedReturn |= 1;
-        if (stats.nbSyntax)
-            codedReturn |= 2;
-    }
-    bool noFErrors = true;
-    if (!clp->help())
-        noFErrors = errors->printStats(stats, clp->muteStdout());
-    if (noFErrors == false) {
-        noFatalErrors = false;
-    }
-    if ((!noFatalErrors) || (!success) || (errors->getErrorStats().nbError))
-        codedReturn |= 1;
-    if (codedReturn) {
-        log_error("Error when parsing design. Aborting!\n");
-    }
-    return the_design;
-}
+
+  private:
+    std::unique_ptr<SURELOG::ErrorContainer> errors = nullptr;
+    std::unique_ptr<SURELOG::CommandLineParser> clp = nullptr;
+    SURELOG::scompiler *scompiler = nullptr;
+    std::vector<vpiHandle> designs = {};
+};
 
 struct UhdmSurelogAstFrontend : public UhdmCommonFrontend {
     UhdmSurelogAstFrontend(std::string name, std::string short_help) : UhdmCommonFrontend(name, short_help) {}
@@ -94,13 +131,33 @@
     AST::AstNode *parse(std::string filename) override
     {
         std::vector<const char *> cstrings;
-        cstrings.reserve(this->args.size());
-        for (size_t i = 0; i < this->args.size(); ++i)
+        bool link = false;
+        cstrings.reserve(this->args.size() + systemverilog_defaults.size() + systemverilog_defines.size());
+        for (size_t i = 0; i < this->args.size(); ++i) {
             cstrings.push_back(const_cast<char *>(this->args[i].c_str()));
+            if (this->args[i] == "-link")
+                link = true;
+        }
 
-        SURELOG::SymbolTable *symbolTable = new SURELOG::SymbolTable();
-        SURELOG::ErrorContainer *errors = new SURELOG::ErrorContainer(symbolTable);
-        SURELOG::CommandLineParser *clp = new SURELOG::CommandLineParser(errors, symbolTable, false, false);
+        if (!link) {
+            // Add systemverilog defaults args
+            for (size_t i = 0; i < systemverilog_defaults.size(); ++i) {
+                // Convert args to surelog compatible
+                if (systemverilog_defaults[i] == "-defer")
+                    this->shared.defer = true;
+                // Pass any remainings args directly to surelog
+                else
+                    cstrings.push_back(const_cast<char *>(systemverilog_defaults[i].c_str()));
+            }
+
+            // Add systemverilog defines args
+            for (size_t i = 0; i < systemverilog_defines.size(); ++i)
+                cstrings.push_back(const_cast<char *>(systemverilog_defines[i].c_str()));
+        }
+
+        auto symbolTable = std::make_unique<SURELOG::SymbolTable>();
+        auto errors = std::make_unique<SURELOG::ErrorContainer>(symbolTable.get());
+        auto clp = std::make_unique<SURELOG::CommandLineParser>(errors.get(), symbolTable.get(), false, false);
         bool success = clp->parseCommandLine(cstrings.size(), &cstrings[0]);
         if (!success) {
             log_error("Error parsing Surelog arguments!\n");
@@ -122,25 +179,21 @@
             clp->setLink(true);
         }
 
-        SURELOG::scompiler *compiler = nullptr;
-        const std::vector<vpiHandle> uhdm_design = executeCompilation(symbolTable, errors, clp, compiler);
+        Compiler compiler;
+        const auto &uhdm_designs = compiler.execute(std::move(errors), std::move(clp));
+
         if (this->shared.debug_flag || !this->report_directory.empty()) {
-            for (auto design : uhdm_design) {
-                std::stringstream strstr;
-                UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : strstr);
+            for (auto design : uhdm_designs) {
+                std::ofstream null_stream;
+                UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : null_stream);
             }
         }
 
-        SURELOG::shutdown_compiler(compiler);
-        delete clp;
-        delete symbolTable;
-        delete errors;
         // on parse_only mode, don't try to load design
         // into yosys
         if (this->shared.parse_only)
             return nullptr;
 
-        UhdmAst uhdm_ast(this->shared);
         if (this->shared.defer && !this->shared.link)
             return nullptr;
 
@@ -151,15 +204,19 @@
             UHDM::Serializer serializer;
             UHDM::SynthSubset *synthSubset =
               make_new_object_with_optional_extra_true_arg<UHDM::SynthSubset>(&serializer, this->shared.nonSynthesizableObjects, false);
-            synthSubset->listenDesigns(uhdm_design);
+            synthSubset->listenDesigns(uhdm_designs);
             delete synthSubset;
         }
 
-        AST::AstNode *current_ast = uhdm_ast.visit_designs(uhdm_design);
+        UhdmAst uhdm_ast(this->shared);
+        AST::AstNode *current_ast = uhdm_ast.visit_designs(uhdm_designs);
         if (!this->report_directory.empty()) {
             this->shared.report.write(this->report_directory);
         }
 
+        // FIXME: Check and reset remaining shared data
+        this->shared.top_nodes.clear();
+        this->shared.nonSynthesizableObjects.clear();
         return current_ast;
     }
     void call_log_header(RTLIL::Design *design) override { log_header(design, "Executing Verilog with UHDM frontend.\n"); }
@@ -176,7 +233,164 @@
         log("Read SystemVerilog files using Surelog into the current design\n");
         log("\n");
         this->print_read_options();
+        log("    -Ipath\n");
+        log("        add include path.\n");
+        log("\n");
+        log("    -Pparameter=value\n");
+        log("        define parameter as value.\n");
+        log("\n");
     }
 } UhdmSystemVerilogFrontend;
 
-YOSYS_NAMESPACE_END
+struct SystemVerilogDefaults : public Pass {
+    SystemVerilogDefaults() : Pass("systemverilog_defaults", "set default options for read_systemverilog") {}
+    void help() override
+    {
+        //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+        log("\n");
+        log("    systemverilog_defaults -add [options]\n");
+        log("\n");
+        log("Add the specified options to the list of default options to read_systemverilog.\n");
+        log("\n");
+        log("\n");
+        log("    systemverilog_defaults -clear\n");
+        log("\n");
+        log("Clear the list of Systemverilog default options.\n");
+        log("\n");
+        log("\n");
+        log("    systemverilog_defaults -push\n");
+        log("    systemverilog_defaults -pop\n");
+        log("\n");
+        log("Push or pop the list of default options to a stack. Note that -push does\n");
+        log("not imply -clear.\n");
+        log("\n");
+    }
+    void execute(std::vector<std::string> args, RTLIL::Design *) override
+    {
+        if (args.size() < 2)
+            cmd_error(args, 1, "Missing argument.");
+
+        if (args[1] == "-add") {
+            systemverilog_defaults.insert(systemverilog_defaults.end(), args.begin() + 2, args.end());
+            return;
+        }
+
+        if (args.size() != 2)
+            cmd_error(args, 2, "Extra argument.");
+
+        if (args[1] == "-clear") {
+            systemverilog_defaults.clear();
+            return;
+        }
+
+        if (args[1] == "-push") {
+            systemverilog_defaults_stack.push_back(systemverilog_defaults);
+            return;
+        }
+
+        if (args[1] == "-pop") {
+            if (systemverilog_defaults_stack.empty()) {
+                systemverilog_defaults.clear();
+            } else {
+                systemverilog_defaults.swap(systemverilog_defaults_stack.back());
+                systemverilog_defaults_stack.pop_back();
+            }
+            return;
+        }
+    }
+} SystemVerilogDefaults;
+
+struct SystemVerilogDefines : public Pass {
+    SystemVerilogDefines() : Pass("systemverilog_defines", "define and undefine systemverilog defines")
+    {
+        systemverilog_defines.push_back("-DYOSYS=1");
+    }
+    void help() override
+    {
+        //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+        log("\n");
+        log("    systemverilog_defines [options]\n");
+        log("\n");
+        log("Define and undefine systemverilog preprocessor macros.\n");
+        log("\n");
+        log("    -Dname[=definition]\n");
+        log("        define the preprocessor symbol 'name' and set its optional value\n");
+        log("        'definition'\n");
+        log("\n");
+        log("    -Uname[=definition]\n");
+        log("        undefine the preprocessor symbol 'name'\n");
+        log("\n");
+        log("    -reset\n");
+        log("        clear list of defined preprocessor symbols\n");
+        log("\n");
+        log("    -list\n");
+        log("        list currently defined preprocessor symbols\n");
+        log("\n");
+    }
+    void remove(const std::string name)
+    {
+        auto it = systemverilog_defines.begin();
+        while (it != systemverilog_defines.end()) {
+            std::string nm;
+            size_t equal = (*it).find('=', 2);
+            if (equal == std::string::npos)
+                nm = (*it).substr(2, std::string::npos);
+            else
+                nm = (*it).substr(2, equal - 2);
+            if (name == nm)
+                systemverilog_defines.erase(it);
+            else
+                it++;
+        }
+    }
+    void dump(void)
+    {
+        for (size_t i = 0; i < systemverilog_defines.size(); ++i) {
+            std::string name, value = "";
+            size_t equal = systemverilog_defines[i].find('=', 2);
+            name = systemverilog_defines[i].substr(2, equal - 2);
+            if (equal != std::string::npos)
+                value = systemverilog_defines[i].substr(equal + 1, std::string::npos);
+            Yosys::log("`define %s %s\n", name.c_str(), value.c_str());
+        }
+    }
+    void execute(std::vector<std::string> args, RTLIL::Design *design) override
+    {
+        size_t argidx;
+        for (argidx = 1; argidx < args.size(); argidx++) {
+            std::string arg = args[argidx];
+            if (arg == "-D" && argidx + 1 < args.size()) {
+                systemverilog_defines.push_back("-D" + args[++argidx]);
+                continue;
+            }
+            if (arg.compare(0, 2, "-D") == 0) {
+                systemverilog_defines.push_back(arg);
+                continue;
+            }
+            if (arg == "-U" && argidx + 1 < args.size()) {
+                std::string name = args[++argidx];
+                this->remove(name);
+                continue;
+            }
+            if (arg.compare(0, 2, "-U") == 0) {
+                std::string name = arg.substr(2);
+                this->remove(name);
+                continue;
+            }
+            if (arg == "-reset") {
+                systemverilog_defines.erase(systemverilog_defines.begin() + 1, systemverilog_defines.end());
+                continue;
+            }
+            if (arg == "-list") {
+                this->dump();
+                continue;
+            }
+            break;
+        }
+
+        if (args.size() != argidx)
+            cmd_error(args, argidx, "Extra argument.");
+    }
+} SystemVerilogDefines;
+
+} // namespace systemverilog_plugin