Remove the SV plugin

Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
diff --git a/.github/workflows/build-and-test.sh b/.github/workflows/build-and-test.sh
index 69fd8a7..efab5db 100755
--- a/.github/workflows/build-and-test.sh
+++ b/.github/workflows/build-and-test.sh
@@ -28,13 +28,13 @@
 
 start_section Building
 
-if [ "$PLUGIN_NAME" == "xdc" ] || [ "$PLUGIN_NAME" == "sdc" ]; then 
+if [ "$PLUGIN_NAME" == "xdc" ] || [ "$PLUGIN_NAME" == "sdc" ]; then
     make design_introspection.so -j`nproc`
 	make install_design_introspection -j`nproc`
-fi 
+fi
 
 export CXXFLAGS=-Werror
-make UHDM_INSTALL_DIR=`pwd`/env/conda/envs/yosys-plugins/ ${PLUGIN_NAME}.so -j`nproc`
+make ${PLUGIN_NAME}.so -j`nproc`
 unset CXXFLAGS
 
 end_section
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 95737de..f2fae72 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -35,8 +35,6 @@
           - design_introspection
           - integrateinv
           - ql-qlf
-          - systemverilog
-          - uhdm
           - dsp-ff
 
     steps:
diff --git a/.github/workflows/setup.sh b/.github/workflows/setup.sh
index 38bcf3f..1111aa3 100644
--- a/.github/workflows/setup.sh
+++ b/.github/workflows/setup.sh
@@ -47,9 +47,9 @@
 #Install yosys
 start_section Install-Yosys
 (
-    echo '================================='
-    echo 'Making env with Yosys and Surelog'
-    echo '================================='
+    echo '====================='
+    echo 'Making env with Yosys'
+    echo '====================='
     make env
     source env/conda/bin/activate yosys-plugins
     conda list
diff --git a/Makefile b/Makefile
index 5051171..11721f9 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@
 # TODO: pass as -D to gcc so that modules can provide e.g. --version flags.
 PLUGIN_VERSION = 1.20230906
 
-PLUGIN_LIST := fasm xdc params sdc ql-iob design_introspection integrateinv ql-qlf systemverilog uhdm dsp-ff
+PLUGIN_LIST := fasm xdc params sdc ql-iob design_introspection integrateinv ql-qlf dsp-ff
 PLUGINS := $(foreach plugin,$(PLUGIN_LIST),$(plugin).so)
 PLUGINS_INSTALL := $(foreach plugin,$(PLUGIN_LIST),install_$(plugin))
 PLUGINS_CLEAN := $(foreach plugin,$(PLUGIN_LIST),clean_$(plugin))
@@ -87,3 +87,17 @@
 .PHONY: format-verilog
 format-verilog:
 	find */tests \( -name "*.v" -o -name "*.sv" \) -and -not -path '*/third_party/*' -print0 | xargs -0 $(VERIBLE_FORMAT) --inplace
+
+# Notify that the SystemVerilog plugin has been moved
+.PHONY: systemverilog.so
+systemverilog.so:
+	$(error The SystemVerilog plugin has been moved to https://github.com/chipsalliance/systemverilog-plugin.)
+
+.PHONY: install_systemverilog
+install_systemverilog: systemverilog.so
+
+.PHONY: clean_systemverilog
+clean_systemverilog: systemverilog.so
+
+.PHONY: test_systemverilog
+test_systemverilog: systemverilog.so
diff --git a/README.md b/README.md
index 53d80e5..d440eae 100644
--- a/README.md
+++ b/README.md
@@ -99,15 +99,7 @@
 
 ## SystemVerilog plugin
 
-Reads SystemVerilog and UHDM files and processes them into yosys AST.
-
-The plugin adds the following commands:
-
-* read_systemverilog
-* read_uhdm
-
-Detailed help on the supported command(s) can be obtained by running `help <command_name>` in Yosys.
-
+The SystemVerilog plugin has been moved to [chipsalliance/systemverilog-plugin](https://github.com/chipsalliance/systemverilog-plugin).
 
 ## Clock Gating plugin
 
diff --git a/environment.yml b/environment.yml
index a4cf46c..5e5062b 100644
--- a/environment.yml
+++ b/environment.yml
@@ -20,5 +20,4 @@
   - litex-hub
 dependencies:
   - litex-hub::yosys=0.17_7_g990c9b8e1=20220512_085338_py37
-  - litex-hub::surelog
   - litex-hub::iverilog
diff --git a/systemverilog-plugin/Makefile b/systemverilog-plugin/Makefile
deleted file mode 100644
index 525d43a..0000000
--- a/systemverilog-plugin/Makefile
+++ /dev/null
@@ -1,54 +0,0 @@
-# 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
-
-PLUGIN_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
-
-NAME = systemverilog
-SOURCES = UhdmAst.cc \
-          uhdmastfrontend.cc \
-          uhdmcommonfrontend.cc \
-          uhdmsurelogastfrontend.cc \
-          third_party/yosys/const2ast.cc \
-          third_party/yosys/simplify.cc
-
-# Directory to search for Surelog and UHDM libraries
-UHDM_INSTALL_DIR ?= /usr/local
-
-# Tell pkg-config to look in the provided install path first.
-# PKG_CONFIG_PATH and PKG_CONFIG_PATH_FOR_TARGET are search paths it looks in
-# so set the environment variables and prefix with our local install first
-PKG_CONFIG_INVOKE = \
-   PKG_CONFIG_PATH=$(UHDM_INSTALL_DIR)/lib/pkgconfig:${PKG_CONFIG_PATH} \
-   PKG_CONFIG_PATH_FOR_TARGET=$(UHDM_INSTALL_DIR)/lib/pkgconfig:${PKG_CONFIG_PATH_FOR_TARGET} \
-   pkg-config
-
-include ../Makefile_plugin.common
-
-# A litmus-test: make compilation fail if pkg-config fails
-.SECONDARY: $(BUILD_DIR)/.$(NAME)-deps-test
-$(BUILD_DIR)/.$(NAME)-deps-test:
-	$(PKG_CONFIG_INVOKE) --cflags Surelog
-
-${SO_LIB}: | $(BUILD_DIR)/.$(NAME)-deps-test
-
-CXXFLAGS += -std=c++17 -Wall -W -Wextra \
-            -Wno-deprecated-declarations \
-            -Wno-unused-parameter \
-            $(shell $(PKG_CONFIG_INVOKE) --cflags Surelog)
-
-LDFLAGS += $(shell $(PKG_CONFIG_INVOKE) --libs-only-L Surelog)
-
-LDLIBS += $(shell $(PKG_CONFIG_INVOKE) --libs-only-l --libs-only-other Surelog)
diff --git a/systemverilog-plugin/README.md b/systemverilog-plugin/README.md
index cdd2edd..c67fd2e 100644
--- a/systemverilog-plugin/README.md
+++ b/systemverilog-plugin/README.md
@@ -1,117 +1,3 @@
 # SystemVerilog Plugin
 
-Reads SystemVerilog and UHDM files and processes them into Yosys AST.
-
-The plugin adds the following commands:
-
-* `read_systemverilog`
-* `read_uhdm`
-
-A more detailed help on the supported commands can be obtained by running `help <command_name>` in Yosys.
-
-Please see the dedicated [integration repository](https://github.com/antmicro/yosys-uhdm-plugin-integration) which contains more information about installation and usage of this plugin.
-This repository also runs dedicated CI pipelines that perform extensive testing of this plugin.
-
-## Installation
-
-A pre-built binary can be downloaded from the [release page](https://github.com/antmicro/yosys-uhdm-plugin-integration/releases).
-The release archive contains an installation script that detects Yosys installation and installs the plugin.
-
-To build from sources please refer to the [integration repository](https://github.com/antmicro/yosys-uhdm-plugin-integration).
-
-## Usage
-
-Usage of the plugin is very simple.
-
-This paragraph describes the synthesis process given the following `counter.sv` file:
-
-```
-module top (
-  input clk,
-  output [3:0] led
-);
-  localparam BITS = 4;
-  localparam LOG2DELAY = 22;
-
-  wire bufg;
-  BUFG bufgctrl (
-      .I(clk),
-      .O(bufg)
-  );
-  reg [BITS+LOG2DELAY-1:0] counter = 0;
-  always @(posedge bufg) begin
-    counter <= counter + 1;
-  end
-  assign led[3:0] = counter >> LOG2DELAY;
-endmodule
-```
-
-To load the plugin, execute `plugin -i systemverilog`.
-Then to load SystemVerilog sources, execute `read_systemverilog`.
-The rest of the flow is exactly the same as without the plugin.
-
-To synthesize the `counter.sv` file:
-
-```
-yosys> plugin -i systemverilog
-yosys> read_systemverilog  counter.v
-1. Executing Verilog with UHDM frontend.
-[INF:CM0023] Creating log file ./slpp_all/surelog.log.
-[WRN:PA0205] counter.v:1: No timescale set for "top".
-[INF:CP0300] Compilation...
-[INF:CP0303] counter.v:1: Compile module "work@top".
-(...)
-Generating RTLIL representation for module `\top'.
-
-yosys> synth_xilinx
-
-2. Executing SYNTH_XILINX pass.
-
-(...)
-
-3.50. Printing statistics.
-
-=== top ===
-
-   Number of wires:                 10
-   Number of wire bits:            167
-   Number of public wires:           4
-   Number of public wire bits:      32
-   Number of memories:               0
-   Number of memory bits:            0
-   Number of processes:              0
-   Number of cells:                 40
-     BUFG                            1
-     CARRY4                          7
-     FDRE                           26
-     IBUF                            1
-     INV                             1
-     OBUF                            4
-
-   Estimated number of LCs:          0
-
-3.51. Executing CHECK pass (checking for obvious problems).
-Checking module top...
-Found and reported 0 problems.
-
-yosys> write_edif counter.edif
-
-4. Executing EDIF backend.
-
-```
-As a result we get a `counter.edif` file that can be further processed to get the bitstream.
-
-### Parsing multiple files
-When parsing multiple files you can either pass them together to the `read_systemverilog` command
-or read them one by one using `-defer` flag. In the latter case, you will need to call 
-`readsystemverilog -link` after processing all files to elaborate them. An example flow would
-look like below:
-```
-plugin -i systemverilog
-# Read each file separately
-read_systemverilog -defer dut.sv
-read_systemverilog -defer top.sv
-# Finish reading files, elaborate the design
-read_systemverilog -link
-# Continue Yosys flow...
-```
+The SystemVerilog plugin has been moved to [chipsalliance/systemverilog-plugin](https://github.com/chipsalliance/systemverilog-plugin).
diff --git a/systemverilog-plugin/UhdmAst.cc b/systemverilog-plugin/UhdmAst.cc
deleted file mode 100644
index 45240c2..0000000
--- a/systemverilog-plugin/UhdmAst.cc
+++ /dev/null
@@ -1,5373 +0,0 @@
-#include <algorithm>
-#include <cstdlib>
-#include <cstring>
-#include <functional>
-#include <iostream>
-#include <limits>
-#include <regex>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "UhdmAst.h"
-#include "frontends/ast/ast.h"
-#include "libs/sha1/sha1.h"
-
-#include "utils/memory.h"
-
-// UHDM
-#include <uhdm/ExprEval.h>
-#include <uhdm/uhdm.h>
-#include <uhdm/vpi_user.h>
-
-#include "third_party/yosys/const2ast.h"
-#include "third_party/yosys/simplify.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
-
-namespace attr_id
-{
-static bool already_initialized = false;
-static IdString partial;
-static IdString packed_ranges;
-static IdString unpacked_ranges;
-static IdString force_convert;
-static IdString is_imported;
-static IdString is_simplified_wire;
-static IdString low_high_bound;
-static IdString is_type_parameter;
-static IdString is_elaborated_module;
-}; // namespace attr_id
-
-// TODO(mglb): use attr_id::* directly everywhere and remove those methods.
-/*static*/ const IdString &UhdmAst::partial() { return attr_id::partial; }
-/*static*/ const IdString &UhdmAst::packed_ranges() { return attr_id::packed_ranges; }
-/*static*/ const IdString &UhdmAst::unpacked_ranges() { return attr_id::unpacked_ranges; }
-/*static*/ const IdString &UhdmAst::force_convert() { return attr_id::force_convert; }
-/*static*/ const IdString &UhdmAst::is_imported() { return attr_id::is_imported; }
-/*static*/ const IdString &UhdmAst::is_simplified_wire() { return attr_id::is_simplified_wire; }
-/*static*/ const IdString &UhdmAst::low_high_bound() { return attr_id::low_high_bound; }
-/*static*/ const IdString &UhdmAst::is_elaborated_module() { return attr_id::is_elaborated_module; }
-
-#define MAKE_INTERNAL_ID(X) IdString("$systemverilog_plugin$" #X)
-
-void attr_id_init()
-{
-    // Initialize only once
-    if (attr_id::already_initialized)
-        return;
-    attr_id::already_initialized = true;
-
-    // Actual initialization
-
-    // Register IdStrings. Can't be done statically, as the IdString class uses resources created during Yosys initialization which happens after
-    // static initialization of the plugin when everything is statically linked.
-    attr_id::partial = MAKE_INTERNAL_ID(partial);
-    attr_id::packed_ranges = MAKE_INTERNAL_ID(packed_ranges);
-    attr_id::unpacked_ranges = MAKE_INTERNAL_ID(unpacked_ranges);
-    attr_id::force_convert = MAKE_INTERNAL_ID(force_convert);
-    attr_id::is_imported = MAKE_INTERNAL_ID(is_imported);
-    attr_id::is_simplified_wire = MAKE_INTERNAL_ID(is_simplified_wire);
-    attr_id::low_high_bound = MAKE_INTERNAL_ID(low_high_bound);
-    attr_id::is_type_parameter = MAKE_INTERNAL_ID(is_type_parameter);
-    attr_id::is_elaborated_module = MAKE_INTERNAL_ID(is_elaborated_module);
-}
-
-void attr_id_cleanup()
-{
-    // Release static copies of private IdStrings.
-    attr_id::low_high_bound = IdString();
-    attr_id::is_simplified_wire = IdString();
-    attr_id::is_imported = IdString();
-    attr_id::force_convert = IdString();
-    attr_id::unpacked_ranges = IdString();
-    attr_id::packed_ranges = IdString();
-    attr_id::partial = IdString();
-    attr_id::is_type_parameter = IdString();
-    attr_id::is_elaborated_module = IdString();
-    attr_id::already_initialized = false;
-}
-
-static AST::AstNode *get_attribute(AST::AstNode *node, const IdString &attribute)
-{
-    log_assert(node);
-    if (!node->attributes.count(attribute))
-        return nullptr;
-
-    return node->attributes[attribute];
-}
-
-// Consumes attr_node.
-static void set_attribute(AST::AstNode *node, const IdString &attribute, AST::AstNode *attr_node)
-{
-    log_assert(node);
-    log_assert(attr_node);
-    delete node->attributes[attribute];
-    node->attributes[attribute] = attr_node;
-}
-
-// Delete the selected attribute if it exists.
-// Does nothing if the node doesn't exist, or the attribute doesn't exists.
-static void delete_attribute(AST::AstNode *node, const IdString &attribute)
-{
-    if (!node)
-        return;
-
-    if (node->attributes.count(attribute)) {
-        delete node->attributes[attribute];
-        node->attributes.erase(attribute);
-    }
-}
-
-// Delete all attributes that belong to the SV plugin.
-// The attributes beloning to Yosys are *not* deleted here.
-static void delete_internal_attributes(AST::AstNode *node)
-{
-    if (!node)
-        return;
-
-    for (auto &attr : {UhdmAst::partial(), UhdmAst::packed_ranges(), UhdmAst::unpacked_ranges(), UhdmAst::force_convert(), UhdmAst::is_imported(),
-                       UhdmAst::is_simplified_wire(), UhdmAst::low_high_bound(), attr_id::is_type_parameter, attr_id::is_elaborated_module}) {
-        delete_attribute(node, attr);
-    }
-}
-
-template <typename T> class ScopedValueChanger
-{
-    T &ref;
-    const T prev_val;
-
-  public:
-    ScopedValueChanger() = delete;
-
-    explicit ScopedValueChanger(T &r) : ref(r), prev_val(ref) {}
-
-    ScopedValueChanger(T &r, const T &val) : ref(r), prev_val(ref) { ref = val; }
-
-    ScopedValueChanger(ScopedValueChanger &&) = delete;
-    ScopedValueChanger &operator=(ScopedValueChanger &&) = delete;
-
-    ScopedValueChanger(const ScopedValueChanger &) = delete;
-    ScopedValueChanger &operator=(const ScopedValueChanger &) = delete;
-
-    ~ScopedValueChanger() { ref = prev_val; }
-};
-
-template <typename T> ScopedValueChanger(T &)->ScopedValueChanger<T>;
-
-template <typename T> ScopedValueChanger(T &, const T &)->ScopedValueChanger<T>;
-
-// Delete all children nodes.
-// Does *not* delete attributes.
-// This function exists as Yosys's function node->delete_children() does remove all children and attributes.
-static void delete_children(AST::AstNode *node)
-{
-    if (!node)
-        return;
-
-    for (auto *child : node->children) {
-        delete child;
-    }
-    node->children.clear();
-}
-
-static void simplify_sv(AST::AstNode *current_node, AST::AstNode *parent_node);
-
-static void sanitize_symbol_name(std::string &name)
-{
-    if (!name.empty()) {
-        auto pos = name.find_last_of('@');
-        name = name.substr(pos + 1);
-        // symbol names must begin with '\'
-        name.insert(0, "\\");
-    }
-}
-
-static std::string get_object_name(vpiHandle obj_h, const std::vector<int> &name_fields = {vpiName})
-{
-    std::string objectName;
-    for (auto name : name_fields) {
-        if (auto s = vpi_get_str(name, obj_h)) {
-            objectName = s;
-            sanitize_symbol_name(objectName);
-            break;
-        }
-    }
-    return objectName;
-}
-
-static std::string get_name(vpiHandle obj_h) { return get_object_name(obj_h, {vpiName, vpiDefName}); }
-
-static std::string strip_package_name(std::string name)
-{
-    auto sep_index = name.find("::");
-    if (sep_index != string::npos) {
-        name = name.substr(sep_index + 1);
-        name[0] = '\\';
-    }
-    return name;
-}
-
-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.
-    auto range = new AST::AstNode(AST::AST_RANGE);
-    range->range_left = left;
-    range->range_right = right;
-    range->range_valid = true;
-    range->children.push_back(AST::AstNode::mkconst_int(left, true));
-    range->children.push_back(AST::AstNode::mkconst_int(right, true));
-    range->is_signed = is_signed;
-    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());
-        }
-    }
-}
-
-static int get_max_offset_struct(AST::AstNode *node)
-{
-    // get the width from the MS member in the struct
-    // as members are laid out from left to right in the packed wire
-    log_assert(node->type == AST::AST_STRUCT || node->type == AST::AST_UNION);
-    while (node->range_left < 0) {
-        node = node->children[0];
-    }
-    return node->range_left;
-}
-
-static void visitEachDescendant(AST::AstNode *node, const std::function<void(AST::AstNode *)> &f)
-{
-    for (auto child : node->children) {
-        f(child);
-        visitEachDescendant(child, f);
-    }
-}
-
-static void add_multirange_wire(AST::AstNode *node, std::vector<AST::AstNode *> packed_ranges, std::vector<AST::AstNode *> unpacked_ranges,
-                                bool reverse = true)
-{
-    delete_attribute(node, UhdmAst::packed_ranges());
-    node->attributes[UhdmAst::packed_ranges()] = AST::AstNode::mkconst_int(1, false, 1);
-    if (!packed_ranges.empty()) {
-        if (reverse)
-            std::reverse(packed_ranges.begin(), packed_ranges.end());
-        node->attributes[UhdmAst::packed_ranges()]->children = std::move(packed_ranges);
-    }
-
-    delete_attribute(node, UhdmAst::unpacked_ranges());
-    node->attributes[UhdmAst::unpacked_ranges()] = AST::AstNode::mkconst_int(1, false, 1);
-    if (!unpacked_ranges.empty()) {
-        if (reverse)
-            std::reverse(unpacked_ranges.begin(), unpacked_ranges.end());
-        node->attributes[UhdmAst::unpacked_ranges()]->children = std::move(unpacked_ranges);
-    }
-}
-
-// Sets the `wire_node->multirange_dimensions` attribute and returns the total sizes of packed and unpacked ranges.
-static std::pair<size_t, size_t> set_multirange_dimensions(AST::AstNode *wire_node, const std::vector<AST::AstNode *> packed_ranges,
-                                                           const std::vector<AST::AstNode *> unpacked_ranges)
-{
-    // node->multirange_dimensions stores dimensions' offsets and widths.
-    // It shall have even number of elements.
-    // For a range of [A:B] it should be appended with {min(A,B)} and {max(A,B)-min(A,B)+1}
-    // For a range of [A] it should be appended with {0} and {A}
-
-    auto calc_range_size = [wire_node](const std::vector<AST::AstNode *> &ranges) -> size_t {
-        size_t size = 1;
-        for (size_t i = 0; i < ranges.size(); i++) {
-            log_assert(AST_INTERNAL::current_ast_mod);
-            simplify_sv(ranges[i], wire_node);
-            // If it's a range of [A], make it [A:A].
-            if (ranges[i]->children.size() == 1) {
-                ranges[i]->children.push_back(ranges[i]->children[0]->clone());
-            }
-            while (simplify(ranges[i], true, false, false, 1, -1, false, false)) {
-            }
-            // this workaround case, where yosys doesn't follow id2ast and simplifies it to resolve constant
-            if (ranges[i]->children[0]->id2ast) {
-                simplify_sv(ranges[i]->children[0]->id2ast, ranges[i]->children[0]);
-                while (simplify(ranges[i]->children[0]->id2ast, true, false, false, 1, -1, false, false)) {
-                }
-            }
-            if (ranges[i]->children[1]->id2ast) {
-                simplify_sv(ranges[i]->children[1]->id2ast, ranges[i]->children[1]);
-                while (simplify(ranges[i]->children[1]->id2ast, true, false, false, 1, -1, false, false)) {
-                }
-            }
-            simplify_sv(ranges[i], wire_node);
-            while (simplify(ranges[i], true, false, false, 1, -1, false, false)) {
-            }
-            log_assert(ranges[i]->children[0]->type == AST::AST_CONSTANT);
-            log_assert(ranges[i]->children[1]->type == AST::AST_CONSTANT);
-
-            const auto low = min(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer);
-            const auto high = max(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer);
-            const auto elem_size = high - low + 1;
-
-            wire_node->multirange_dimensions.push_back(low);
-            wire_node->multirange_dimensions.push_back(elem_size);
-            wire_node->multirange_swapped.push_back(ranges[i]->range_swapped);
-            size *= elem_size;
-        }
-        return size;
-    };
-    size_t packed_size = calc_range_size(packed_ranges);
-    size_t unpacked_size = calc_range_size(unpacked_ranges);
-    log_assert(wire_node->multirange_dimensions.size() % 2 == 0);
-    return {packed_size, unpacked_size};
-}
-
-static AST::AstNode *convert_range(AST::AstNode *id, int packed_ranges_size, int unpacked_ranges_size, int i)
-{
-    log_assert(AST_INTERNAL::current_ast_mod);
-    log_assert(AST_INTERNAL::current_scope.count(id->str));
-    AST::AstNode *wire_node = AST_INTERNAL::current_scope[id->str];
-    log_assert(!wire_node->multirange_dimensions.empty());
-    int elem_size = 1;
-    std::vector<int> single_elem_size;
-    single_elem_size.push_back(elem_size);
-    for (size_t j = 0; (j + 1) < wire_node->multirange_dimensions.size(); j = j + 2) {
-        // The ranges' widths are placed on odd indices of multirange_dimensions.
-        elem_size *= wire_node->multirange_dimensions[j + 1];
-        single_elem_size.push_back(elem_size);
-    }
-    std::reverse(single_elem_size.begin(), single_elem_size.end());
-    log_assert(i < (unpacked_ranges_size + packed_ranges_size));
-    log_assert(!id->children.empty());
-    AST::AstNode *result = nullptr;
-    // we want to start converting from the end
-    if (i < static_cast<int>(id->children.size()) - 1) {
-        result = convert_range(id, packed_ranges_size, unpacked_ranges_size, i + 1);
-    }
-    // special case, we want to select whole wire
-    if (id->children.size() == 0 && i == 0) {
-        result = make_range(single_elem_size[i] - 1, 0);
-    } else {
-        AST::AstNode *range_left = nullptr;
-        AST::AstNode *range_right = nullptr;
-        if (id->children[i]->children.size() == 2) {
-            range_left = id->children[i]->children[0]->clone();
-            range_right = id->children[i]->children[1]->clone();
-        } else {
-            range_left = id->children[i]->children[0]->clone();
-            range_right = id->children[i]->children[0]->clone();
-        }
-        if (!wire_node->multirange_swapped.empty()) {
-            bool is_swapped = wire_node->multirange_swapped[wire_node->multirange_swapped.size() - i - 1];
-            auto right_idx = wire_node->multirange_dimensions.size() - (i * 2) - 2;
-            if (is_swapped) {
-                auto left_idx = wire_node->multirange_dimensions.size() - (i * 2) - 1;
-                auto elem_size = wire_node->multirange_dimensions[left_idx] - wire_node->multirange_dimensions[right_idx];
-                range_left = new AST::AstNode(AST::AST_SUB, AST::AstNode::mkconst_int(elem_size - 1, false), range_left);
-                range_right = new AST::AstNode(AST::AST_SUB, AST::AstNode::mkconst_int(elem_size - 1, false), range_right);
-            } else if (wire_node->multirange_dimensions[right_idx] != 0) {
-                range_left =
-                  new AST::AstNode(AST::AST_SUB, range_left, AST::AstNode::mkconst_int(wire_node->multirange_dimensions[right_idx], false));
-                range_right =
-                  new AST::AstNode(AST::AST_SUB, range_right, AST::AstNode::mkconst_int(wire_node->multirange_dimensions[right_idx], false));
-            }
-        }
-        if (!result) {
-            range_left =
-              new AST::AstNode(AST::AST_SUB,
-                               new AST::AstNode(AST::AST_MUL, new AST::AstNode(AST::AST_ADD, range_left, AST::AstNode::mkconst_int(1, false)),
-                                                AST::AstNode::mkconst_int(single_elem_size[i + 1], false)),
-                               AST::AstNode::mkconst_int(1, false));
-        }
-        range_right = new AST::AstNode(AST::AST_MUL, range_right, AST::AstNode::mkconst_int(single_elem_size[i + 1], false));
-        if (result) {
-            range_right = new AST::AstNode(AST::AST_ADD, range_right, result->children[1]->clone());
-            delete range_left;
-            range_left = new AST::AstNode(AST::AST_SUB, new AST::AstNode(AST::AST_ADD, range_right->clone(), result->children[0]->clone()),
-                                          result->children[1]->clone());
-            delete result;
-            result = nullptr;
-        }
-        result = new AST::AstNode(AST::AST_RANGE, range_left, range_right);
-    }
-    // return range from *current* selected range
-    // in the end, it results in whole selected range
-    id->basic_prep = true;
-    return result;
-}
-
-static void resolve_wiretype(AST::AstNode *wire_node)
-{
-    AST::AstNode *wiretype_node = nullptr;
-    if (!wire_node->children.empty()) {
-        if (wire_node->children[0]->type == AST::AST_WIRETYPE) {
-            wiretype_node = wire_node->children[0];
-        }
-    }
-    if (wire_node->children.size() > 1) {
-        if (wire_node->children[1]->type == AST::AST_WIRETYPE) {
-            wiretype_node = wire_node->children[1];
-        }
-    }
-    if (wiretype_node == nullptr)
-        return;
-
-    unique_resource<std::vector<AST::AstNode *>> packed_ranges = wire_node->attributes.count(attr_id::packed_ranges)
-                                                                   ? std::move(wire_node->attributes[attr_id::packed_ranges]->children)
-                                                                   : std::vector<AST::AstNode *>{};
-    delete_attribute(wire_node, attr_id::packed_ranges);
-    unique_resource<std::vector<AST::AstNode *>> unpacked_ranges = wire_node->attributes.count(attr_id::unpacked_ranges)
-                                                                     ? std::move(wire_node->attributes[attr_id::unpacked_ranges]->children)
-                                                                     : std::vector<AST::AstNode *>{};
-    delete_attribute(wire_node, attr_id::unpacked_ranges);
-
-    AST::AstNode *wiretype_ast = nullptr;
-    log_assert(AST_INTERNAL::current_scope.count(wiretype_node->str));
-    wiretype_ast = AST_INTERNAL::current_scope[wiretype_node->str];
-    // we need to setup current top ast as this simplify
-    // needs to have access to all already defined ids
-    simplify_sv(wiretype_ast, nullptr);
-    while (simplify(wire_node, true, false, false, 1, -1, false, false)) {
-    }
-    log_assert(!wiretype_ast->children.empty());
-    if ((wiretype_ast->children[0]->type == AST::AST_STRUCT || wiretype_ast->children[0]->type == AST::AST_UNION) &&
-        wire_node->type == AST::AST_WIRE) {
-        auto struct_width = get_max_offset_struct(wiretype_ast->children[0]);
-        wire_node->range_left = struct_width;
-        wire_node->children[0]->range_left = struct_width;
-        wire_node->children[0]->children[0]->integer = struct_width;
-    }
-    if (wiretype_ast) {
-        log_assert(wire_node->attributes.count(ID::wiretype));
-        log_assert(wiretype_ast->type == AST::AST_TYPEDEF);
-        wire_node->attributes[ID::wiretype]->id2ast = wiretype_ast->children[0];
-    }
-    if (((wire_node->children.size() > 0 && wire_node->children[0]->type == AST::AST_RANGE) ||
-         (wire_node->children.size() > 1 && wire_node->children[1]->type == AST::AST_RANGE)) &&
-        wire_node->multirange_dimensions.empty()) {
-        // We need to save order in which ranges appear in wiretype and add them before wire range
-        // We need to copy this ranges, so create new vector for them
-        std::vector<AST::AstNode *> packed_ranges_wiretype;
-        std::vector<AST::AstNode *> unpacked_ranges_wiretype;
-        if (wiretype_ast && !wiretype_ast->children.empty() && wiretype_ast->children[0]->attributes.count(UhdmAst::packed_ranges()) &&
-            wiretype_ast->children[0]->attributes.count(UhdmAst::unpacked_ranges())) {
-            for (auto r : wiretype_ast->children[0]->attributes[UhdmAst::packed_ranges()]->children) {
-                packed_ranges_wiretype.push_back(r->clone());
-            }
-            for (auto r : wiretype_ast->children[0]->attributes[UhdmAst::unpacked_ranges()]->children) {
-                unpacked_ranges_wiretype.push_back(r->clone());
-            }
-        } else {
-            if (wire_node->children[0]->type == AST::AST_RANGE)
-                packed_ranges_wiretype.push_back(wire_node->children[0]->clone());
-            else if (wire_node->children[1]->type == AST::AST_RANGE)
-                packed_ranges_wiretype.push_back(wire_node->children[1]->clone());
-            else
-                log_error("Unhandled case in resolve_wiretype!\n");
-        }
-        // add wiretype range before current wire ranges
-        std::reverse(packed_ranges_wiretype.begin(), packed_ranges_wiretype.end());
-        std::reverse(unpacked_ranges_wiretype.begin(), unpacked_ranges_wiretype.end());
-        std::reverse(packed_ranges->begin(), packed_ranges->end());
-        std::reverse(unpacked_ranges->begin(), unpacked_ranges->end());
-        packed_ranges->insert(packed_ranges->begin(), packed_ranges_wiretype.begin(), packed_ranges_wiretype.end());
-        unpacked_ranges->insert(unpacked_ranges->begin(), unpacked_ranges_wiretype.begin(), unpacked_ranges_wiretype.end());
-        AST::AstNode *value = nullptr;
-        if (wire_node->children[0]->type != AST::AST_RANGE) {
-            value = wire_node->children[0]->clone();
-        }
-        delete_children(wire_node);
-        if (value)
-            wire_node->children.push_back(value);
-        add_multirange_wire(wire_node, packed_ranges.release(), unpacked_ranges.release(), false /* reverse */);
-    }
-}
-
-static void add_force_convert_attribute(AST::AstNode *wire_node, uint32_t val = 1)
-{
-    AST::AstNode *&attr = wire_node->attributes[UhdmAst::force_convert()];
-    if (!attr) {
-        attr = AST::AstNode::mkconst_int(val, true);
-    } else if (attr->integer != val) {
-        attr->integer = val;
-    }
-}
-
-static void check_memories(AST::AstNode *node, std::string scope, std::map<std::string, AST::AstNode *> &memories)
-{
-    for (auto *child : node->children) {
-        check_memories(child, node->type == AST::AST_GENBLOCK ? scope + "." + node->str : scope, memories);
-    }
-
-    if (node->str == "\\$readmemh") {
-        if (node->children.size() != 2 || node->children[1]->str.empty() || node->children[1]->type != AST::AST_IDENTIFIER) {
-            log_error("%s:%d: Wrong usage of '\\$readmemh'\n", node->filename.c_str(), node->location.first_line);
-        }
-        // TODO: Look for the memory in all other scope levels, like we do in case of AST::AST_IDENTIFIER,
-        // as here the memory can also be defined before before the current scope.
-        std::string name = scope + "." + node->children[1]->str;
-        const auto iter = memories.find(name);
-        if (iter != memories.end()) {
-            add_force_convert_attribute(iter->second, 0);
-        }
-    }
-
-    if (node->type == AST::AST_WIRE) {
-        const std::size_t packed_ranges_count =
-          node->attributes.count(UhdmAst::packed_ranges()) ? node->attributes[UhdmAst::packed_ranges()]->children.size() : 0;
-        const std::size_t unpacked_ranges_count =
-          node->attributes.count(UhdmAst::unpacked_ranges()) ? node->attributes[UhdmAst::unpacked_ranges()]->children.size() : 0;
-
-        if (packed_ranges_count == 1 && unpacked_ranges_count == 1) {
-            std::string name = scope + "." + node->str;
-            auto [iter, did_insert] = memories.insert_or_assign(std::move(name), node);
-            log_assert(did_insert);
-        }
-        return;
-    }
-
-    if (node->type == AST::AST_IDENTIFIER) {
-        std::string full_id = scope;
-        std::size_t scope_end_pos = scope.size();
-
-        for (;;) {
-            full_id += "." + node->str;
-            const auto iter = memories.find(full_id);
-            if (iter != memories.end()) {
-                // Memory node found!
-                if (!iter->second->attributes.count(UhdmAst::force_convert())) {
-                    const bool is_full_memory_access = (node->children.size() == 0);
-                    const bool is_slice_memory_access = (node->children.size() == 1 && node->children[0]->children.size() != 1);
-                    // convert memory to list of registers
-                    // in case of access to whole memory
-                    // or slice of memory
-                    // e.g.
-                    // logic [3:0] mem [8:0];
-                    // always_ff @ (posedge clk) begin
-                    //   mem <= '{default:0};
-                    //   mem[7:1] <= mem[6:0];
-                    // end
-                    // don't convert in case of accessing
-                    // memory using address, e.g.
-                    // mem[0] <= '{default:0}
-                    if (is_full_memory_access || is_slice_memory_access) {
-                        add_force_convert_attribute(iter->second);
-                    }
-                }
-                break;
-            } else {
-                if (scope_end_pos == 0) {
-                    // We reached the top scope and the memory node wasn't found.
-                    break;
-                } else {
-                    // Memory node wasn't found.
-                    // Erase node name and last segment of the scope to check the previous scope.
-                    // FIXME: This doesn't work with escaped identifiers containing a dot.
-                    scope_end_pos = full_id.find_last_of('.', scope_end_pos - 1);
-                    if (scope_end_pos == std::string::npos) {
-                        scope_end_pos = 0;
-                    }
-                    full_id.erase(scope_end_pos);
-                }
-            }
-        }
-    }
-}
-
-static void check_memories(AST::AstNode *node)
-{
-    std::map<std::string, AST::AstNode *> memories;
-    check_memories(node, "", memories);
-}
-
-static void warn_start_range(const std::vector<AST::AstNode *> ranges)
-{
-    for (size_t i = 0; i < ranges.size(); i++) {
-        auto start_elem = min(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer);
-        if (start_elem != 0) {
-            log_file_warning(ranges[i]->filename, ranges[i]->location.first_line, "Limited support for multirange wires that don't start from 0\n");
-        }
-    }
-}
-
-// This function is workaround missing support for multirange (with n-ranges) packed/unpacked nodes
-// It converts multirange node to single-range node and translates access to this node
-// to correct range
-static void convert_packed_unpacked_range(AST::AstNode *wire_node)
-{
-    resolve_wiretype(wire_node);
-    const std::vector<AST::AstNode *> packed_ranges = wire_node->attributes.count(UhdmAst::packed_ranges())
-                                                        ? wire_node->attributes[UhdmAst::packed_ranges()]->children
-                                                        : std::vector<AST::AstNode *>();
-    const std::vector<AST::AstNode *> unpacked_ranges = wire_node->attributes.count(UhdmAst::unpacked_ranges())
-                                                          ? wire_node->attributes[UhdmAst::unpacked_ranges()]->children
-                                                          : std::vector<AST::AstNode *>();
-    if (packed_ranges.empty() && unpacked_ranges.empty()) {
-        delete_attribute(wire_node, UhdmAst::packed_ranges());
-        delete_attribute(wire_node, UhdmAst::unpacked_ranges());
-        wire_node->range_left = 0;
-        wire_node->range_right = 0;
-        wire_node->range_valid = true;
-        return;
-    }
-    std::vector<AST::AstNode *> ranges;
-
-    // Convert only when node is not a memory and at least 1 of the ranges has more than 1 range
-    const bool convert_node = [&]() {
-        if (wire_node->type == AST::AST_MEMORY)
-            return false;
-        if (packed_ranges.size() > 1)
-            return true;
-        if (unpacked_ranges.size() > 1)
-            return true;
-        if (wire_node->attributes.count(ID::wiretype))
-            return true;
-        if (wire_node->type == AST::AST_PARAMETER)
-            return true;
-        if (wire_node->type == AST::AST_LOCALPARAM)
-            return true;
-        if ((wire_node->is_input || wire_node->is_output) && (packed_ranges.size() > 0 || unpacked_ranges.size() > 0))
-            return true;
-        if (wire_node->attributes.count(UhdmAst::force_convert()) && wire_node->attributes[UhdmAst::force_convert()]->integer == 1)
-            return true;
-        return false;
-    }();
-    if (convert_node) {
-        // if not already converted
-        if (wire_node->multirange_dimensions.empty()) {
-            const auto [packed_size, unpacked_size] = set_multirange_dimensions(wire_node, packed_ranges, unpacked_ranges);
-            if (packed_ranges.size() == 1 && unpacked_ranges.empty()) {
-                ranges.push_back(packed_ranges[0]->clone());
-            } else if (unpacked_ranges.size() == 1 && packed_ranges.empty()) {
-                ranges.push_back(unpacked_ranges[0]->clone());
-            } else {
-                // currently we have limited support
-                // for multirange wires that doesn't start from 0
-                warn_start_range(packed_ranges);
-                warn_start_range(unpacked_ranges);
-                const size_t size = packed_size * unpacked_size;
-                log_assert(size >= 1);
-                ranges.push_back(make_range(size - 1, 0));
-            }
-        }
-    } else {
-        for (auto r : packed_ranges) {
-            ranges.push_back(r->clone());
-        }
-        for (auto r : unpacked_ranges) {
-            ranges.push_back(r->clone());
-        }
-        // if there is only one packed and one unpacked range,
-        // and wire is not port wire, change type to AST_MEMORY
-        if (wire_node->type == AST::AST_WIRE && packed_ranges.size() == 1 && unpacked_ranges.size() == 1 && !wire_node->is_input &&
-            !wire_node->is_output) {
-            wire_node->type = AST::AST_MEMORY;
-            wire_node->is_logic = true;
-        }
-    }
-
-    // Insert new range
-    wire_node->children.insert(wire_node->children.end(), ranges.begin(), ranges.end());
-}
-
-// Assert macro that prints location in C++ code and location of currently processed UHDM object.
-// Use only inside UhdmAst methods.
-#ifndef NDEBUG
-#if __GNUC__
-// gcc/clang's __builtin_trap() makes gdb stop on the line containing an assertion.
-#define uhdmast_assert(expr)                                                                                                                         \
-    if ((expr)) {                                                                                                                                    \
-    } else {                                                                                                                                         \
-        this->uhdmast_assert_log(#expr, __PRETTY_FUNCTION__, __FILE__, __LINE__);                                                                    \
-        __builtin_trap();                                                                                                                            \
-    }
-#else // #if __GNUC__
-// Just abort when using compiler other than gcc/clang.
-#define uhdmast_assert(expr)                                                                                                                         \
-    if ((expr)) {                                                                                                                                    \
-    } else {                                                                                                                                         \
-        this->uhdmast_assert_log(#expr, __func__, __FILE__, __LINE__);                                                                               \
-        std::abort();                                                                                                                                \
-    }
-#endif // #if __GNUC__
-#else  // #ifndef NDEBUG
-#define uhdmast_assert(expr)                                                                                                                         \
-    if ((expr)) {                                                                                                                                    \
-    } else {                                                                                                                                         \
-    }
-#endif // #ifndef NDEBUG
-
-void UhdmAst::uhdmast_assert_log(const char *expr_str, const char *func, const char *file, int line) const
-{
-    std::cerr << file << ':' << line << ": error: Assertion failed: " << expr_str << std::endl;
-    std::cerr << file << ':' << line << ": note: In function: " << func << std::endl;
-    if (obj_h != 0) {
-        const char *const svfile = vpi_get_str(vpiFile, obj_h);
-        int svline = vpi_get(vpiLineNo, obj_h);
-        int svcolumn = vpi_get(vpiColumnNo, obj_h);
-        std::string obj_type_name = UHDM::VpiTypeName(obj_h);
-        const char *obj_name = vpi_get_str(vpiName, obj_h);
-        std::cerr << svfile << ':' << svline << ':' << svcolumn << ": note: When processing object of type '" << obj_type_name << '\'';
-        if (obj_name && obj_name[0] != '\0') {
-            std::cerr << " named '" << obj_name << '\'';
-        }
-        std::cerr << '.' << std::endl;
-    }
-}
-
-static AST::AstNode *expand_dot(const AST::AstNode *current_struct, const AST::AstNode *search_node)
-{
-    AST::AstNode *current_struct_elem = nullptr;
-    auto search_str = search_node->str.find("\\") == 0 ? search_node->str.substr(1) : search_node->str;
-    auto struct_elem_it =
-      std::find_if(current_struct->children.begin(), current_struct->children.end(), [&](AST::AstNode *node) { return node->str == search_str; });
-    if (struct_elem_it == current_struct->children.end()) {
-        current_struct->dumpAst(NULL, "struct >");
-        log_error("Couldn't find search elem: %s in struct\n", search_str.c_str());
-    }
-    current_struct_elem = *struct_elem_it;
-
-    AST::AstNode *sub_dot = nullptr;
-    std::vector<AST::AstNode *> struct_ranges;
-
-    for (auto c : search_node->children) {
-        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);
-        }
-        if (c->type == AST::AST_RANGE) {
-            struct_ranges.push_back(c);
-        }
-    }
-    AST::AstNode *left = nullptr, *right = nullptr;
-    switch (current_struct_elem->type) {
-    case AST::AST_STRUCT_ITEM:
-        left = AST::AstNode::mkconst_int(current_struct_elem->range_left, true);
-        right = AST::AstNode::mkconst_int(current_struct_elem->range_right, true);
-        break;
-    case AST::AST_STRUCT:
-    case AST::AST_UNION:
-        // TODO(krak): add proper support for accessing struct/union elements
-        // with multirange
-        // Currently support only special access to 2 dimensional packed element
-        // when selecting single range
-        log_assert(current_struct_elem->multirange_dimensions.size() % 2 == 0);
-        if (!struct_ranges.empty() && (current_struct_elem->multirange_dimensions.size() / 2) == 2) {
-            // get element size in number of bits
-            const int single_elem_size = current_struct_elem->children.front()->range_left + 1;
-            left = AST::AstNode::mkconst_int(single_elem_size * current_struct_elem->multirange_dimensions.back(), true);
-            right =
-              AST::AstNode::mkconst_int(current_struct_elem->children.back()->range_right * current_struct_elem->multirange_dimensions.back(), true);
-        } else {
-            left = AST::AstNode::mkconst_int(current_struct_elem->children.front()->range_left, true);
-            right = AST::AstNode::mkconst_int(current_struct_elem->children.back()->range_right, true);
-        }
-        break;
-    default:
-        // Structs currently can only have AST_STRUCT, AST_STRUCT_ITEM, or AST_UNION.
-        log_file_error(current_struct_elem->filename, current_struct_elem->location.first_line,
-                       "Accessing struct member of type %s is unsupported.\n", type2str(current_struct_elem->type).c_str());
-    };
-
-    auto elem_size =
-      new AST::AstNode(AST::AST_ADD, new AST::AstNode(AST::AST_SUB, left->clone(), right->clone()), AST::AstNode::mkconst_int(1, true));
-
-    if (sub_dot) {
-        // First select correct element in first struct
-        std::swap(left, sub_dot->children[0]);
-        std::swap(right, sub_dot->children[1]);
-        delete sub_dot;
-    }
-
-    for (size_t i = 0; i < struct_ranges.size(); i++) {
-        const auto *struct_range = struct_ranges[i];
-        auto const range_width_idx = i * 2 + 1;
-        auto const range_offset_idx = i * 2;
-
-        int range_width = 0;
-        if (current_struct_elem->multirange_dimensions.empty()) {
-            range_width = 1;
-        } else if (current_struct_elem->multirange_dimensions.size() > range_width_idx) {
-            range_width = current_struct_elem->multirange_dimensions[range_width_idx];
-            const auto range_offset = current_struct_elem->multirange_dimensions[range_offset_idx];
-            if (range_offset != 0) {
-                log_file_error(struct_range->filename, struct_range->location.first_line,
-                               "Accessing ranges that do not start from 0 is not supported.");
-            }
-        } else {
-            struct_range->dumpAst(NULL, "range >");
-            log_file_error(struct_range->filename, struct_range->location.first_line, "Couldn't find range width.");
-        }
-        // now we have correct element set,
-        // but we still need to set correct struct
-        log_assert(!struct_range->children.empty());
-        if (current_struct_elem->type == AST::AST_STRUCT_ITEM) {
-            // if we selecting range of struct item, just add this range
-            // to our current select
-            if (current_struct_elem->multirange_dimensions.size() > 2 && struct_range->children.size() == 2) {
-                log_error("Selecting a range of positions from a multirange is not supported in the dot notation.\n");
-            }
-            if (struct_range->children.size() == 2) {
-                auto range_size = new AST::AstNode(
-                  AST::AST_ADD, new AST::AstNode(AST::AST_SUB, struct_range->children[0]->clone(), struct_range->children[1]->clone()),
-                  AST::AstNode::mkconst_int(1, true));
-                right = new AST::AstNode(AST::AST_ADD, right, struct_range->children[1]->clone());
-                delete left;
-                left = new AST::AstNode(AST::AST_ADD, right->clone(), new AST::AstNode(AST::AST_SUB, range_size, AST::AstNode::mkconst_int(1, true)));
-
-            } else if (struct_range->children.size() == 1) {
-                // Selected a single position, as in `foo.bar[i]`.
-                if (range_width > 1 && current_struct_elem->multirange_dimensions.size() > range_width_idx + 2) {
-                    // if it's not the last dimension.
-                    right = new AST::AstNode(
-                      AST::AST_ADD, right,
-                      new AST::AstNode(AST::AST_MUL, struct_range->children[0]->clone(), AST::AstNode::mkconst_int(range_width, true)));
-                    delete left;
-                    left = new AST::AstNode(AST::AST_ADD, right->clone(), AST::AstNode::mkconst_int(range_width - 1, true));
-                } else {
-                    right = new AST::AstNode(AST::AST_ADD, right, struct_range->children[0]->clone());
-                    delete left;
-                    left = right->clone();
-                }
-            } else {
-                struct_range->dumpAst(NULL, "range >");
-                log_error("Unhandled range select (AST_STRUCT_ITEM) in AST_DOT!\n");
-            }
-        } else if (current_struct_elem->type == AST::AST_STRUCT) {
-            if (struct_range->children.size() == 2) {
-                right = new AST::AstNode(AST::AST_ADD, right, struct_range->children[1]->clone());
-                auto range_size = new AST::AstNode(
-                  AST::AST_ADD, new AST::AstNode(AST::AST_SUB, struct_range->children[0]->clone(), struct_range->children[1]->clone()),
-                  AST::AstNode::mkconst_int(1, true));
-                left = new AST::AstNode(AST::AST_ADD, left, new AST::AstNode(AST::AST_SUB, range_size, elem_size->clone()));
-            } else if (struct_range->children.size() == 1) {
-                AST::AstNode *mul = new AST::AstNode(AST::AST_MUL, elem_size->clone(), struct_range->children[0]->clone());
-
-                left = new AST::AstNode(AST::AST_ADD, left, mul);
-                right = new AST::AstNode(AST::AST_ADD, right, mul->clone());
-            } else {
-                struct_range->dumpAst(NULL, "range >");
-                log_error("Unhandled range select (AST_STRUCT) in AST_DOT!\n");
-            }
-        } else {
-            log_file_error(current_struct_elem->filename, current_struct_elem->location.first_line,
-                           "Accessing member of a slice of type %s is unsupported.\n", type2str(current_struct_elem->type).c_str());
-        }
-    }
-    delete elem_size;
-    // Return range from the begining of *current* struct
-    // When all AST_DOT are expanded it will return range
-    // from original wire
-    return new AST::AstNode(AST::AST_RANGE, left, right);
-}
-
-static AST::AstNode *convert_dot(AST::AstNode *wire_node, AST::AstNode *node, AST::AstNode *dot)
-{
-    AST::AstNode *struct_node = nullptr;
-    if (wire_node->type == AST::AST_STRUCT || wire_node->type == AST::AST_UNION) {
-        struct_node = wire_node;
-    } else if (wire_node->attributes.count(ID::wiretype)) {
-        log_assert(wire_node->attributes[ID::wiretype]->id2ast);
-        struct_node = wire_node->attributes[ID::wiretype]->id2ast;
-    } else {
-        log_file_error(wire_node->filename, wire_node->location.first_line, "Unsupported node type: %s\n", type2str(wire_node->type).c_str());
-    }
-    log_assert(struct_node);
-    auto expanded = expand_dot(struct_node, dot);
-    // Now expand ranges that are at instance part of dotted reference
-    // `expand_dot` returns AST_RANGE with 2 children that selects member pointed by dotted reference
-    // now we need to move this range to select correct struct
-    std::vector<AST::AstNode *> struct_ranges;
-    for (auto c : node->children) {
-        if (c->type == AST::AST_RANGE) {
-            struct_ranges.push_back(c);
-        }
-    }
-    log_assert(wire_node->attributes.count(UhdmAst::unpacked_ranges()));
-    log_assert(wire_node->attributes.count(UhdmAst::packed_ranges()));
-    log_assert(struct_ranges.size() <= (wire_node->multirange_dimensions.size() / 2));
-    const auto wire_node_unpacked_ranges_size = wire_node->attributes[UhdmAst::unpacked_ranges()]->children.size();
-    // TODO(krak): wire ranges are sometimes under wiretype node (e.g. in case of typedef)
-    // but wiretype ranges contains also struct range that is already expanded in 'expand_dot'
-    // we need to find a way to calculate size of wire ranges without struct range here to enable this assert
-    // const auto wire_node_packed_ranges_size = wire_node->attributes[UhdmAst::packed_ranges()]->children.size();
-    // const auto wire_node_ranges_size = wire_node_packed_ranges_size + wire_node_unpacked_ranges_size;
-    // log_assert(struct_ranges.size() == (wire_node_ranges_size - 1));
-
-    // Get size of single structure
-    int struct_size_int = get_max_offset_struct(struct_node) + 1;
-    auto wire_dimension_size_it = wire_node->multirange_dimensions.rbegin();
-    unsigned long range_id = 0;
-    for (auto it = struct_ranges.rbegin(); it != struct_ranges.rend(); it++) {
-        // in 'dot' context, we need to select specific struct element,
-        // so assert that there is only 1 child in struct range (range with single child)
-        log_assert((*it)->children.size() == 1);
-        bool is_unpacked_range = range_id < wire_node_unpacked_ranges_size;
-        // if unpacked range, select from back
-        auto elem = is_unpacked_range
-                      ? new AST::AstNode(AST::AST_SUB, AST::AstNode::mkconst_int(*wire_dimension_size_it - 1, true, 32), (*it)->children[0]->clone())
-                      : (*it)->children[0]->clone();
-        // calculate which struct we selected
-        auto move_offset = new AST::AstNode(AST::AST_MUL, AST::AstNode::mkconst_int(struct_size_int, true, 32), elem);
-        // move our expanded dot to currently selected struct
-        expanded->children[0] = new AST::AstNode(AST::AST_ADD, move_offset->clone(), expanded->children[0]);
-        expanded->children[1] = new AST::AstNode(AST::AST_ADD, move_offset, expanded->children[1]);
-        struct_size_int *= *wire_dimension_size_it;
-        // wire_dimension_size stores interleaved offset and size. Move to next dimension's size
-        wire_dimension_size_it += 2;
-        range_id++;
-    }
-    return expanded;
-}
-
-static void setup_current_scope(std::unordered_map<std::string, AST::AstNode *> top_nodes, AST::AstNode *current_top_node)
-{
-    for (auto it = top_nodes.begin(); it != top_nodes.end(); it++) {
-        if (!it->second)
-            continue;
-        if (it->second->type == AST::AST_PACKAGE) {
-            for (auto &o : it->second->children) {
-                // import only parameters
-                if (o->type == AST::AST_TYPEDEF || o->type == AST::AST_PARAMETER || o->type == AST::AST_LOCALPARAM) {
-                    // add imported nodes to current scope
-                    AST_INTERNAL::current_scope[it->second->str + std::string("::") + o->str.substr(1)] = o;
-                    AST_INTERNAL::current_scope[o->str] = o;
-                } else if (o->type == AST::AST_ENUM) {
-                    AST_INTERNAL::current_scope[o->str] = o;
-                    for (auto c : o->children) {
-                        AST_INTERNAL::current_scope[c->str] = c;
-                    }
-                }
-            }
-        }
-    }
-    for (auto &o : current_top_node->children) {
-        if (o->type == AST::AST_TYPEDEF || o->type == AST::AST_PARAMETER || o->type == AST::AST_LOCALPARAM) {
-            AST_INTERNAL::current_scope[o->str] = o;
-        } else if (o->type == AST::AST_ENUM) {
-            AST_INTERNAL::current_scope[o->str] = o;
-            for (auto c : o->children) {
-                AST_INTERNAL::current_scope[c->str] = c;
-            }
-        }
-    }
-    // hackish way of setting current_ast_mod as it is required
-    // for simplify to get references for already defined ids
-    AST_INTERNAL::current_ast_mod = current_top_node;
-    log_assert(AST_INTERNAL::current_ast_mod != nullptr);
-}
-
-static int range_width_local(AST::AstNode *node, AST::AstNode *rnode)
-{
-    log_assert(rnode->type == AST::AST_RANGE);
-    if (!rnode->range_valid) {
-        log_file_error(node->filename, node->location.first_line, "Size must be constant in packed struct/union member %s\n", node->str.c_str());
-    }
-    // note: range swapping has already been checked for
-    return rnode->range_left - rnode->range_right + 1;
-}
-
-static void save_struct_array_width_local(AST::AstNode *node, int width)
-{
-    // stash the stride for the array
-    node->multirange_dimensions.push_back(width);
-}
-
-static int simplify_struct(AST::AstNode *snode, int base_offset, AST::AstNode *parent_node)
-{
-    // Struct members will be laid out in the structure contiguously from left to right.
-    // Union members all have zero offset from the start of the union.
-    // Determine total packed size and assign offsets.  Store these in the member node.
-    bool is_union = (snode->type == AST::AST_UNION);
-    int offset = 0;
-    int packed_width = -1;
-    for (auto s : snode->children) {
-        if (s->type == AST::AST_RANGE) {
-            while (simplify(s, true, false, false, 1, -1, false, false)) {
-            };
-        }
-    }
-    // embeded struct or union with range?
-    auto it = std::remove_if(snode->children.begin(), snode->children.end(), [](AST::AstNode *node) { return node->type == AST::AST_RANGE; });
-    std::vector<AST::AstNode *> ranges(it, snode->children.end());
-    snode->children.erase(it, snode->children.end());
-    if (!ranges.empty()) {
-        for (auto range : ranges) {
-            snode->multirange_dimensions.push_back(min(range->range_left, range->range_right));
-            snode->multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1);
-            snode->multirange_swapped.push_back(range->range_swapped);
-            delete range;
-        }
-    }
-    // examine members from last to first
-    for (auto it = snode->children.rbegin(); it != snode->children.rend(); ++it) {
-        auto node = *it;
-        int width;
-        if (node->type == AST::AST_STRUCT || node->type == AST::AST_UNION) {
-            // embedded struct or union
-            width = simplify_struct(node, base_offset + offset, parent_node);
-            if (!node->multirange_dimensions.empty()) {
-                // Multiply widths of all dimensions.
-                // `multirange_dimensions` stores (repeating) pairs of [offset, width].
-                for (size_t i = 1; i < node->multirange_dimensions.size(); i += 2) {
-                    width *= node->multirange_dimensions[i];
-                }
-            }
-            // set range of struct
-            node->range_right = base_offset + offset;
-            node->range_left = base_offset + offset + width - 1;
-            node->range_valid = true;
-        } else {
-            log_assert(node->type == AST::AST_STRUCT_ITEM);
-            if (node->children.size() > 0 && node->children[0]->type == AST::AST_RANGE) {
-                // member width e.g. bit [7:0] a
-                width = range_width_local(node, node->children[0]);
-                if (node->children.size() == 2) {
-                    if (node->children[1]->type == AST::AST_RANGE) {
-                        // unpacked array e.g. bit [63:0] a [0:3]
-                        auto rnode = node->children[1];
-                        int array_count = range_width_local(node, rnode);
-                        if (array_count == 1) {
-                            // C-type array size e.g. bit [63:0] a [4]
-                            array_count = rnode->range_left;
-                        }
-                        save_struct_array_width_local(node, width);
-                        width *= array_count;
-                    } else {
-                        // array element must be single bit for a packed array
-                        log_file_error(node->filename, node->location.first_line, "Unpacked array in packed struct/union member %s\n",
-                                       node->str.c_str());
-                    }
-                }
-                // range nodes are now redundant
-                for (AST::AstNode *child : node->children)
-                    delete child;
-                node->children.clear();
-            } else if (node->children.size() == 1 && node->children[0]->type == AST::AST_MULTIRANGE) {
-                // packed 2D array, e.g. bit [3:0][63:0] a
-                auto rnode = node->children[0];
-                if (rnode->children.size() != 2) {
-                    // packed arrays can only be 2D
-                    log_file_error(node->filename, node->location.first_line, "Unpacked array in packed struct/union member %s\n", node->str.c_str());
-                }
-                int array_count = range_width_local(node, rnode->children[0]);
-                width = range_width_local(node, rnode->children[1]);
-                save_struct_array_width_local(node, width);
-                width *= array_count;
-                // range nodes are now redundant
-                for (AST::AstNode *child : node->children)
-                    delete child;
-                node->children.clear();
-            } else if (node->range_left < 0) {
-                // 1 bit signal: bit, logic or reg
-                width = 1;
-            } else {
-                // already resolved and compacted
-                width = node->range_left - node->range_right + 1;
-            }
-            if (is_union) {
-                node->range_right = base_offset;
-                node->range_left = base_offset + width - 1;
-            } else {
-                node->range_right = base_offset + offset;
-                node->range_left = base_offset + offset + width - 1;
-            }
-            node->range_valid = true;
-        }
-        if (is_union) {
-            // check that all members have the same size
-            if (packed_width == -1) {
-                // first member
-                packed_width = width;
-            } else {
-                if (packed_width != width) {
-
-                    log_file_error(node->filename, node->location.first_line, "member %s of a packed union has %d bits, expecting %d\n",
-                                   node->str.c_str(), width, packed_width);
-                }
-            }
-        } else {
-            offset += width;
-        }
-    }
-    if (!snode->str.empty() && parent_node && parent_node->type != AST::AST_TYPEDEF && parent_node->type != AST::AST_STRUCT &&
-        AST_INTERNAL::current_scope.count(snode->str) != 0) {
-        AST_INTERNAL::current_scope[snode->str]->attributes[ID::wiretype] = AST::AstNode::mkconst_str(snode->str);
-        AST_INTERNAL::current_scope[snode->str]->attributes[ID::wiretype]->id2ast = snode;
-    }
-    return (is_union ? packed_width : offset);
-}
-
-static void add_members_to_scope_local(AST::AstNode *snode, std::string name)
-{
-    // add all the members in a struct or union to local scope
-    // in case later referenced in assignments
-    log_assert(snode->type == AST::AST_STRUCT || snode->type == AST::AST_UNION);
-    for (auto *node : snode->children) {
-        auto member_name = name + "." + node->str;
-        AST_INTERNAL::current_scope[member_name] = node;
-        if (node->type != AST::AST_STRUCT_ITEM) {
-            // embedded struct or union
-            add_members_to_scope_local(node, name + "." + node->str);
-        }
-    }
-}
-
-static AST::AstNode *make_packed_struct_local(AST::AstNode *template_node, std::string &name)
-{
-    // create a wire for the packed struct
-    auto wnode = new AST::AstNode(AST::AST_WIRE);
-    wnode->str = name;
-    wnode->is_logic = true;
-    wnode->range_valid = true;
-    wnode->is_signed = template_node->is_signed;
-    int offset = get_max_offset_struct(template_node);
-    auto range = make_range(offset, 0);
-    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
-    add_members_to_scope_local(template_node, name);
-    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') {
-                simplify(node_arg, 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);
-}
-
-// A wrapper for Yosys simplify function.
-// Simplifies AST constructs specific to this plugin to a form understandable by Yosys' simplify and then calls the latter if necessary.
-// Since simplify from Yosys has been forked to this codebase, all new code should be added there instead.
-static void simplify_sv(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::Extended::AST_DOT); });
-    AST::AstNode *dot = (dot_it != current_node->children.end()) ? *dot_it : nullptr;
-
-    AST::AstNode *expanded = nullptr;
-    if (dot) {
-        if (!AST_INTERNAL::current_scope.count(current_node->str)) {
-            // for accessing elements currently unsupported with AST_DOT
-            // fallback to "." notation
-            AST::AstNode *prefix_node = nullptr;
-            AST::AstNode *parent_node = current_node;
-            while (dot && !dot->str.empty()) {
-                // it is not possible for AST_RANGE to be after AST::DOT (see process_hier_path function)
-                if (parent_node->children[0]->type == AST::AST_RANGE) {
-                    if (parent_node->children[1]->type == AST::AST_RANGE)
-                        log_error("Multirange in AST_DOT is currently unsupported\n");
-
-                    dot->type = AST::AST_IDENTIFIER;
-                    simplify_sv(dot, nullptr);
-                    AST::AstNode *range_const = parent_node->children[0]->children[0];
-                    prefix_node = new AST::AstNode(AST::AST_PREFIX, range_const->clone(), dot->clone());
-                    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::Extended::AST_DOT); });
-                    parent_node = dot;
-                    dot = (dot_it != dot->children.end()) ? *dot_it : nullptr;
-                }
-            }
-            delete_children(current_node);
-            if (prefix_node != nullptr) {
-                current_node->type = AST::AST_PREFIX;
-                current_node->children = prefix_node->children;
-
-                prefix_node->children.clear();
-                delete prefix_node;
-            }
-        } else {
-            auto wire_node = AST_INTERNAL::current_scope[current_node->str];
-            // make sure wire_node is already simplified
-            simplify_sv(wire_node, nullptr);
-            expanded = convert_dot(wire_node, current_node, dot);
-        }
-    }
-    if (expanded) {
-        delete_children(current_node);
-        current_node->children.push_back(expanded->clone());
-        current_node->basic_prep = true;
-        delete expanded;
-        expanded = nullptr;
-    }
-    // First simplify children
-    for (size_t i = 0; i < current_node->children.size(); i++) {
-        simplify_sv(current_node->children[i], current_node);
-    }
-    switch (current_node->type) {
-    case AST::AST_TYPEDEF:
-    case AST::AST_ENUM:
-    case AST::AST_FUNCTION:
-        AST_INTERNAL::current_scope[current_node->str] = current_node;
-        break;
-    case AST::AST_WIRE:
-    case AST::AST_PARAMETER:
-    case AST::AST_LOCALPARAM:
-        if (!current_node->attributes.count(UhdmAst::is_simplified_wire())) {
-            current_node->attributes[UhdmAst::is_simplified_wire()] = AST::AstNode::mkconst_int(1, true);
-            AST_INTERNAL::current_scope[current_node->str] = current_node;
-            convert_packed_unpacked_range(current_node);
-        }
-        break;
-    case AST::AST_IDENTIFIER:
-        if (!current_node->children.empty() && !current_node->basic_prep) {
-            log_assert(AST_INTERNAL::current_ast_mod);
-            if (!AST_INTERNAL::current_scope.count(current_node->str)) {
-                break;
-            }
-            AST::AstNode *wire_node = AST_INTERNAL::current_scope[current_node->str];
-
-            // if a wire is simplified multiple times, its ranges may be added multiple times and be redundant as a result
-            if (!wire_node->attributes.count(UhdmAst::is_simplified_wire())) {
-                simplify_sv(wire_node, nullptr);
-            }
-            const int packed_ranges_size =
-              wire_node->attributes.count(UhdmAst::packed_ranges()) ? wire_node->attributes[UhdmAst::packed_ranges()]->children.size() : 0;
-            const int unpacked_ranges_size =
-              wire_node->attributes.count(UhdmAst::unpacked_ranges()) ? wire_node->attributes[UhdmAst::unpacked_ranges()]->children.size() : 0;
-            if ((wire_node->type == AST::AST_WIRE || wire_node->type == AST::AST_PARAMETER || wire_node->type == AST::AST_LOCALPARAM) &&
-                (packed_ranges_size + unpacked_ranges_size > 1)) {
-                auto *result = convert_range(current_node, packed_ranges_size, unpacked_ranges_size, 0);
-                delete_children(current_node);
-                current_node->children.push_back(result);
-            }
-        }
-        break;
-    case AST::AST_STRUCT:
-    case AST::AST_UNION:
-        if (!current_node->attributes.count(UhdmAst::is_simplified_wire())) {
-            current_node->attributes[UhdmAst::is_simplified_wire()] = AST::AstNode::mkconst_int(1, true);
-            simplify_struct(current_node, 0, parent_node);
-            // instance rather than just a type in a typedef or outer struct?
-            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);
-                AST_INTERNAL::current_scope[wnode->str]->attributes[ID::wiretype]->id2ast = current_node;
-            }
-
-            current_node->basic_prep = true;
-        }
-        break;
-    case AST::AST_STRUCT_ITEM:
-        if (!current_node->attributes.count(UhdmAst::is_simplified_wire())) {
-            current_node->attributes[UhdmAst::is_simplified_wire()] = AST::AstNode::mkconst_int(1, true);
-            AST_INTERNAL::current_scope[current_node->str] = current_node;
-            convert_packed_unpacked_range(current_node);
-            while (simplify(current_node, 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;
-    case AST::AST_COND:
-    case AST::AST_CONDX:
-    case AST::AST_CONDZ:
-        // handle custom low high bound
-        if (current_node->attributes.count(UhdmAst::low_high_bound())) {
-            log_assert(!current_node->children.empty());
-            log_assert(current_node->children[0]->type == AST::AST_BLOCK);
-            log_assert(current_node->children[0]->children.size() == 2);
-            auto low_high_bound = current_node->children[0];
-            // this is executed when condition is met
-            // save pointer that will be added later again
-            // as conditions needs to go before this block
-            auto result = current_node->children[1];
-
-            current_node->children[0] = nullptr;
-            current_node->children[1] = nullptr;
-            delete_children(current_node);
-            while (simplify(low_high_bound->children[0], true, false, false, 1, -1, false, false)) {
-            };
-            while (simplify(low_high_bound->children[1], true, false, false, 1, -1, false, false)) {
-            };
-            log_assert(low_high_bound->children[0]->type == AST::AST_CONSTANT);
-            log_assert(low_high_bound->children[1]->type == AST::AST_CONSTANT);
-            const int low = low_high_bound->children[0]->integer;
-            const int high = low_high_bound->children[1]->integer;
-            const int range = low_high_bound->children[1]->range_valid
-                                ? low_high_bound->children[1]->range_left
-                                : low_high_bound->children[0]->range_valid ? low_high_bound->children[0]->range_left : 32;
-            delete low_high_bound;
-            // According to standard:
-            // If the bound to the left of the colon is greater than the
-            // bound to the right, the range is empty and contains no values.
-            for (int i = low; i >= low && i <= high; i++) {
-                current_node->children.push_back(AST::AstNode::mkconst_int(i, false, range));
-            }
-            current_node->children.push_back(result);
-            delete_attribute(current_node, UhdmAst::low_high_bound());
-        }
-        break;
-    default:
-        break;
-    }
-}
-
-static void clear_current_scope()
-{
-    // Remove clear current_scope from package nodes
-    AST_INTERNAL::current_scope.clear();
-    // unset current_ast_mod
-    AST_INTERNAL::current_ast_mod = nullptr;
-}
-
-void UhdmAst::visit_one_to_many(const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(AST::AstNode *)> &f)
-{
-    for (auto child : child_node_types) {
-        vpiHandle itr = vpi_iterate(child, parent_handle);
-        while (vpiHandle vpi_child_obj = vpi_scan(itr)) {
-            UhdmAst uhdm_ast(this, shared, indent + "  ");
-            auto *child_node = uhdm_ast.process_object(vpi_child_obj);
-            f(child_node);
-            vpi_release_handle(vpi_child_obj);
-        }
-        vpi_release_handle(itr);
-    }
-}
-
-void UhdmAst::visit_one_to_one(const std::vector<int> child_node_types, vpiHandle parent_handle, const std::function<void(AST::AstNode *)> &f)
-{
-    for (auto child : child_node_types) {
-        vpiHandle itr = vpi_handle(child, parent_handle);
-        if (itr) {
-            UhdmAst uhdm_ast(this, shared, indent + "  ");
-            auto *child_node = uhdm_ast.process_object(itr);
-            f(child_node);
-        }
-        vpi_release_handle(itr);
-    }
-}
-
-void UhdmAst::visit_range(vpiHandle obj_h, const std::function<void(AST::AstNode *)> &f)
-{
-    std::vector<AST::AstNode *> range_nodes;
-    visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { range_nodes.push_back(node); });
-    if (range_nodes.size() > 1) {
-        auto multirange_node = new AST::AstNode(AST::AST_MULTIRANGE);
-        multirange_node->children = range_nodes;
-        f(multirange_node);
-    } else if (!range_nodes.empty()) {
-        f(range_nodes[0]);
-    }
-}
-
-void UhdmAst::visit_default_expr(vpiHandle obj_h)
-{
-    UhdmAst initial_ast(parent, shared, indent);
-    UhdmAst block_ast(&initial_ast, shared, indent);
-    block_ast.visit_one_to_one({vpiExpr}, obj_h, [&](AST::AstNode *expr_node) {
-        auto mod = find_ancestor({AST::AST_MODULE});
-        AST::AstNode *initial_node = nullptr;
-        AST::AstNode *block_node = nullptr;
-        auto assign_node = new AST::AstNode(AST::AST_ASSIGN_EQ);
-        auto id_node = new AST::AstNode(AST::AST_IDENTIFIER);
-        id_node->str = current_node->str;
-
-        for (auto child : mod->children) {
-            if (child->type == AST::AST_INITIAL) {
-                initial_node = child;
-                break;
-            }
-        }
-        // Ensure single AST_INITIAL node is located in AST_MODULE
-        // before any AST_ALWAYS
-        if (initial_node == nullptr) {
-            initial_node = new AST::AstNode(AST::AST_INITIAL);
-            auto insert_it = find_if(mod->children.begin(), mod->children.end(), [](AST::AstNode *node) { return (node->type == AST::AST_ALWAYS); });
-            mod->children.insert(insert_it, initial_node);
-        }
-        // Ensure single AST_BLOCK node in AST_INITIAL
-        if (!initial_node->children.empty() && initial_node->children[0]) {
-            block_node = initial_node->children[0];
-        } else {
-            block_node = new AST::AstNode(AST::AST_BLOCK);
-            initial_node->children.push_back(block_node);
-        }
-        auto block_child =
-          find_if(block_node->children.begin(), block_node->children.end(), [](AST::AstNode *node) { return (node->type == AST::AST_ASSIGN_EQ); });
-        // Insert AST_ASSIGN_EQ nodes that came from
-        // custom_var or int_var before any other AST_ASSIGN_EQ
-        // Especially before ones explicitly placed in initial block in source code
-        block_node->children.insert(block_child, assign_node);
-        assign_node->children.push_back(id_node);
-        initial_ast.current_node = initial_node;
-        block_ast.current_node = block_node;
-        assign_node->children.push_back(expr_node);
-    });
-}
-
-AST::AstNode *UhdmAst::process_value(vpiHandle obj_h)
-{
-    s_vpi_value val;
-    vpi_get_value(obj_h, &val);
-    std::string strValType = "'";
-    bool is_signed = false;
-    if (vpiHandle typespec_h = vpi_handle(vpiTypespec, obj_h)) {
-        is_signed = vpi_get(vpiSigned, typespec_h);
-        if (is_signed) {
-            strValType += "s";
-        }
-        vpi_release_handle(typespec_h);
-    }
-    std::string val_str;
-    if (val.format) { // Needed to handle parameter nodes without typespecs and constants
-        switch (val.format) {
-        case vpiScalarVal:
-            return AST::AstNode::mkconst_int(val.value.scalar, false, 1);
-        case vpiBinStrVal: {
-            strValType += "b";
-            val_str = val.value.str;
-            break;
-        }
-        case vpiDecStrVal: {
-            strValType += "d";
-            val_str = val.value.str;
-            break;
-        }
-        case vpiHexStrVal: {
-            strValType += "h";
-            val_str = val.value.str;
-            break;
-        }
-        case vpiOctStrVal: {
-            strValType += "o";
-            val_str = val.value.str;
-            break;
-        }
-        // Surelog reports constant integers as a unsigned, but by default int is signed
-        // so we are treating here UInt in the same way as if they would be Int
-        case vpiUIntVal:
-            if (val.value.uint > std::numeric_limits<std::uint32_t>::max()) {
-                // an integer is by default signed, so use 'sd despite the variant vpiUIntVal
-                strValType = "'sd";
-                val_str = std::to_string(val.value.uint);
-                break;
-            }
-            [[fallthrough]];
-        case vpiIntVal: {
-            if (val.value.integer > std::numeric_limits<std::int32_t>::max()) {
-                strValType = "'sd";
-                val_str = std::to_string(val.value.integer);
-                break;
-            }
-
-            auto size = vpi_get(vpiSize, obj_h);
-            // Surelog by default returns 64 bit numbers and stardard says that they shall be at least 32bits
-            // yosys is assuming that int/uint is 32 bit, so we are setting here correct size
-            // NOTE: it *shouldn't* break on explicite 64 bit const values, as they *should* be handled
-            // above by vpi*StrVal
-            if (size == 64) {
-                size = 32;
-                is_signed = true;
-            }
-            auto c = AST::AstNode::mkconst_int(val.format == vpiUIntVal ? val.value.uint : val.value.integer, is_signed, size > 0 ? size : 32);
-            if (size == 0 || size == -1)
-                c->is_unsized = true;
-            return c;
-        }
-        case vpiRealVal:
-            return mkconst_real(val.value.real);
-        case vpiStringVal:
-            return AST::AstNode::mkconst_str(val.value.str);
-        default: {
-            const uhdm_handle *const handle = (const uhdm_handle *)obj_h;
-            const UHDM::BaseClass *const object = (const UHDM::BaseClass *)handle->object;
-            report_error("%.*s:%d: Encountered unhandled constant format %d\n", (int)object->VpiFile().length(), object->VpiFile().data(),
-                         object->VpiLineNo(), val.format);
-        }
-        }
-        // if this constant is under case/casex/casez
-        // get current case type
-        char caseType = ' ';
-        if (vpiHandle caseItem_h = vpi_handle(vpiParent, obj_h)) {
-            if (vpiHandle case_h = vpi_handle(vpiParent, caseItem_h)) {
-                switch (vpi_get(vpiCaseType, case_h)) {
-                case vpiCaseExact:
-                    caseType = ' ';
-                    break;
-                case vpiCaseX:
-                    caseType = 'x';
-                    break;
-                case vpiCaseZ:
-                    caseType = 'z';
-                    break;
-                default: {
-                    caseType = ' ';
-                    break;
-                }
-                }
-                vpi_release_handle(case_h);
-            }
-            vpi_release_handle(caseItem_h);
-        }
-        // handle vpiBinStrVal, vpiDecStrVal and vpiHexStrVal
-        if (val_str.find('\'') != std::string::npos) {
-            return ::systemverilog_plugin::const2ast(std::move(val_str), caseType, false);
-        } else {
-            auto size = vpi_get(vpiSize, obj_h);
-            std::string size_str;
-            if (size > 0) {
-                size_str = std::to_string(size);
-            } else if (strValType == "\'b") {
-                // probably unsized unbased const
-                // but to make sure parse vpiDecompile
-                auto decompile = vpi_get_str(vpiDecompile, obj_h);
-                if (decompile && !std::strchr(decompile, 'b')) {
-                    // unsized unbased
-                    // we can't left size_str empty, as then yosys parses this const as 32bit value
-                    size_str = "1";
-                }
-            }
-            auto c = ::systemverilog_plugin::const2ast(size_str + strValType + val_str, caseType, false);
-            if (size <= 0) {
-                // unsized unbased const
-                c->is_unsized = true;
-            }
-            return c;
-        }
-    }
-    return nullptr;
-}
-
-void UhdmAst::transform_breaks_continues(AST::AstNode *loop, AST::AstNode *decl_block)
-{
-    AST::AstNode *break_wire = nullptr;
-    AST::AstNode *continue_wire = nullptr;
-    // Creates a 1-bit wire with the given name
-    const auto make_cond_var = [this](const std::string &var_name) {
-        auto cond_var =
-          make_ast_node(AST::AST_WIRE, {make_ast_node(AST::AST_RANGE, {AST::AstNode::mkconst_int(0, false), AST::AstNode::mkconst_int(0, false)}),
-                                        AST::AstNode::mkconst_int(0, false)});
-        cond_var->str = var_name;
-        cond_var->is_reg = true;
-        return cond_var;
-    };
-    // Creates a conditional like 'if (!casevar) block'
-    auto make_case = [this](AST::AstNode *block, const std::string &casevar_name) {
-        auto *case_node = make_ast_node(AST::AST_CASE);
-        auto *id = make_identifier(casevar_name);
-        case_node->children.push_back(id);
-        auto *constant = AST::AstNode::mkconst_int(0, false, 1);
-        auto *cond_node = make_ast_node(AST::AST_COND);
-        cond_node->children.push_back(constant);
-        cond_node->children.push_back(block);
-        case_node->children.push_back(cond_node);
-        return case_node;
-    };
-    // Pre-declare this function to be able to call it recursively
-    std::function<bool(AST::AstNode *)> transform_block;
-    // Transforms the given block if it has a break or continue; recurses into child blocks; return true if a break/continue was encountered
-    transform_block = [&](AST::AstNode *block) {
-        auto wrap_and_transform = [&](decltype(block->children)::iterator it) {
-            // Move the (it, end()) statements into a new block under 'if (!continue) {...}'
-            auto *new_block = make_ast_node(AST::AST_BLOCK, {it, block->children.end()});
-            block->children.erase(it, block->children.end());
-            auto *case_node = make_case(new_block, continue_wire->str);
-            block->children.push_back(case_node);
-            transform_block(new_block);
-        };
-
-        for (auto it = block->children.begin(); it != block->children.end(); it++) {
-            auto type = static_cast<int>((*it)->type);
-            switch (type) {
-            case AST::AST_BLOCK: {
-                if (transform_block(*it)) {
-                    // If there was a break/continue, we need to wrap the rest of the block in an if
-                    wrap_and_transform(it + 1);
-                    return true;
-                }
-                break;
-            }
-            case AST::AST_CASE: {
-                // Go over each block in a case
-                bool has_jump = false;
-                for (auto *node : (*it)->children) {
-                    if (node->type == AST::AST_COND)
-                        has_jump = has_jump || transform_block(node->children.back());
-                }
-                if (has_jump) {
-                    // If there was a break/continue, we need to wrap the rest of the block in an if
-                    wrap_and_transform(it + 1);
-                    return true;
-                }
-                break;
-            }
-            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::Extended::AST_BREAK) {
-                    if (!break_wire)
-                        break_wire = make_cond_var("$break");
-                    auto *break_id = make_identifier(break_wire->str);
-                    block->children.push_back(make_ast_node(AST::AST_ASSIGN_EQ, {break_id, AST::AstNode::mkconst_int(1, false)}));
-                }
-                return true;
-            }
-            }
-        }
-        return false;
-    };
-
-    // Actual transformation starts here
-    transform_block(loop->children.back());
-    if (continue_wire) {
-        auto *continue_id = make_identifier(continue_wire->str);
-        // Reset $continue each iteration
-        auto *continue_assign = make_ast_node(AST::AST_ASSIGN_EQ, {continue_id, AST::AstNode::mkconst_int(0, false)});
-        decl_block->children.insert(decl_block->children.begin(), continue_wire);
-        loop->children.back()->children.insert(loop->children.back()->children.begin(), continue_assign);
-    }
-    if (break_wire) {
-        auto *break_id = make_identifier(break_wire->str);
-        // Reset $break before the loop
-        auto *break_assign = make_ast_node(AST::AST_ASSIGN_EQ, {break_id, AST::AstNode::mkconst_int(0, false)});
-        decl_block->children.insert(decl_block->children.begin(), break_assign);
-        decl_block->children.insert(decl_block->children.begin(), break_wire);
-        if (loop->type == AST::AST_REPEAT || loop->type == AST::AST_FOR) {
-            // Wrap loop body in 'if (!break) {...}'
-            // Changing the for loop condition won't work here,
-            // as then simplify fails with error "2nd expression of procedural for-loop is not constant!"
-            auto *case_node = make_case(loop->children.back(), break_wire->str);
-            auto *new_block = make_ast_node(AST::AST_BLOCK);
-            new_block->children.push_back(case_node);
-            new_block->str = loop->children.back()->str;
-            loop->children.back() = new_block;
-        } else if (loop->type == AST::AST_WHILE) {
-            // Add the break var to the loop condition
-            auto *break_id = make_identifier(break_wire->str);
-            AST::AstNode *&loop_cond = loop->children[0];
-            loop_cond = make_ast_node(AST::AST_LOGIC_AND, {make_ast_node(AST::AST_LOGIC_NOT, {break_id}), loop_cond});
-        } else {
-            log_error("break unsupported for this loop type");
-        }
-    }
-}
-
-void UhdmAst::apply_location_from_current_obj(AST::AstNode &target_node) const
-{
-    if (auto filename = vpi_get_str(vpiFile, obj_h)) {
-        target_node.filename = filename;
-    }
-    if (unsigned int first_line = vpi_get(vpiLineNo, obj_h)) {
-        target_node.location.first_line = first_line;
-    }
-    if (unsigned int last_line = vpi_get(vpiEndLineNo, obj_h)) {
-        target_node.location.last_line = last_line;
-    } else {
-        target_node.location.last_line = target_node.location.first_line;
-    }
-    if (unsigned int first_col = vpi_get(vpiColumnNo, obj_h)) {
-        target_node.location.first_column = first_col;
-    }
-    if (unsigned int last_col = vpi_get(vpiEndColumnNo, obj_h)) {
-        target_node.location.last_column = last_col;
-    } else {
-        target_node.location.last_column = target_node.location.first_column;
-    }
-}
-
-void UhdmAst::apply_name_from_current_obj(AST::AstNode &target_node) const
-{
-    target_node.str = get_name(obj_h);
-    auto it = node_renames.find(target_node.str);
-    if (it != node_renames.end())
-        target_node.str = it->second;
-}
-
-AstNodeBuilder UhdmAst::make_node(AST::AstNodeType type) const
-{
-    auto node = std::make_unique<AST::AstNode>(type);
-    apply_location_from_current_obj(*node);
-    return AstNodeBuilder(std::move(node));
-};
-
-AstNodeBuilder UhdmAst::make_named_node(AST::AstNodeType type) const
-{
-    auto node = std::make_unique<AST::AstNode>(type);
-    apply_location_from_current_obj(*node);
-    apply_name_from_current_obj(*node);
-    return AstNodeBuilder(std::move(node));
-};
-
-AstNodeBuilder UhdmAst::make_ident(std::string id) const { return make_node(::Yosys::AST::AST_IDENTIFIER).str(std::move(id)); };
-
-AstNodeBuilder UhdmAst::make_const(int32_t value, uint8_t width) const
-{
-    // Limited to width of the `value` argument.
-    log_assert(width <= 32);
-    return make_node(AST::AST_CONSTANT).value(value, true, width);
-};
-
-AstNodeBuilder UhdmAst::make_const(uint32_t value, uint8_t width) const
-{
-    // Limited to width of the `value` argument.
-    log_assert(width <= 32);
-    return make_node(AST::AST_CONSTANT).value(value, false, width);
-};
-
-AST::AstNode *UhdmAst::make_ast_node(AST::AstNodeType type, std::vector<AST::AstNode *> children)
-{
-    auto node = new AST::AstNode(type);
-    apply_name_from_current_obj(*node);
-    apply_location_from_current_obj(*node);
-    node->children = children;
-    return node;
-}
-
-AST::AstNode *UhdmAst::make_identifier(std::string name)
-{
-    auto *node = make_ast_node(AST::AST_IDENTIFIER);
-    node->str = std::move(name);
-    return node;
-}
-
-void UhdmAst::process_packed_array_typespec()
-{
-    std::vector<AST::AstNode *> packed_ranges;
-    std::vector<AST::AstNode *> unpacked_ranges;
-    current_node = make_ast_node(AST::AST_WIRE);
-    visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-    visit_one_to_one({vpiElemTypespec}, obj_h, [&](AST::AstNode *node) {
-        if (node && node->type == AST::AST_STRUCT) {
-            auto str = current_node->str;
-            // unnamed array of named (struct) array
-            if (str.empty() && !node->str.empty())
-                str = node->str;
-            node->cloneInto(current_node);
-            current_node->str = str;
-            delete node;
-        } else if (node) {
-            if (!node->str.empty()) {
-                AST::AstNode *const wiretype_node = make_named_node(AST::AST_WIRETYPE);
-                wiretype_node->str = node->str;
-                current_node->children.push_back(wiretype_node);
-                current_node->is_custom_type = true;
-                auto it = shared.param_types.find(wiretype_node->str);
-                if (it == shared.param_types.end())
-                    shared.param_types.insert(std::make_pair(wiretype_node->str, node));
-                else
-                    delete node;
-            } else {
-                delete node;
-            }
-        }
-    });
-    add_multirange_wire(current_node, std::move(packed_ranges), std::move(unpacked_ranges));
-}
-
-static void add_or_replace_child(AST::AstNode *parent, AST::AstNode *child)
-{
-    if (!child->str.empty()) {
-        auto it = std::find_if(parent->children.begin(), parent->children.end(),
-                               [child](AST::AstNode *existing_child) { return existing_child->str == child->str; });
-        if (it != parent->children.end()) {
-            // If port direction is already set, copy it to replaced child node
-            if ((*it)->is_input || (*it)->is_output) {
-                child->is_input = (*it)->is_input;
-                child->is_output = (*it)->is_output;
-                child->port_id = (*it)->port_id;
-                if (child->type == AST::AST_MEMORY)
-                    child->type = AST::AST_WIRE;
-            }
-            child->is_signed = child->is_signed || (*it)->is_signed;
-            if (!(*it)->children.empty() && child->children.empty()) {
-                // This is a bit ugly, but if the child we're replacing has children and
-                // our node doesn't, we copy its children to not lose any information
-                for (auto grandchild : (*it)->children) {
-                    child->children.push_back(grandchild->clone());
-                    if (child->type == AST::AST_WIRE && grandchild->type == AST::AST_WIRETYPE)
-                        child->is_custom_type = true;
-                }
-            }
-            if ((*it)->attributes.count(UhdmAst::packed_ranges()) && child->attributes.count(UhdmAst::packed_ranges())) {
-                if ((!(*it)->attributes[UhdmAst::packed_ranges()]->children.empty() &&
-                     child->attributes[UhdmAst::packed_ranges()]->children.empty())) {
-
-                    delete_attribute(child, UhdmAst::packed_ranges());
-                    child->attributes[UhdmAst::packed_ranges()] = (*it)->attributes[UhdmAst::packed_ranges()]->clone();
-                }
-            }
-            if ((*it)->attributes.count(UhdmAst::unpacked_ranges()) && child->attributes.count(UhdmAst::unpacked_ranges())) {
-                if ((!(*it)->attributes[UhdmAst::unpacked_ranges()]->children.empty() &&
-                     child->attributes[UhdmAst::unpacked_ranges()]->children.empty())) {
-
-                    delete_attribute(child, UhdmAst::unpacked_ranges());
-                    child->attributes[UhdmAst::unpacked_ranges()] = (*it)->attributes[UhdmAst::unpacked_ranges()]->clone();
-                }
-            }
-            // Surelog doesn't report correct sign value for param_assign nodes
-            // and only default vpiParameter node have correct sign value, so
-            // if we are overriding parameter, copy sign value from current node to the new node
-            if (((*it)->type == AST::AST_PARAMETER || (*it)->type == AST::AST_LOCALPARAM) && child->children.size() && (*it)->children.size()) {
-                child->children[0]->is_signed = (*it)->children[0]->is_signed;
-            }
-            delete *it;
-            *it = child;
-            return;
-        }
-        parent->children.push_back(child);
-    } else if (child->type == AST::AST_INITIAL) {
-        // Special case for initials
-        // Ensure that there is only one AST_INITIAL in the design
-        // And there is only one AST_BLOCK inside that initial
-        // Copy nodes from child initial to parent initial
-        auto initial_node_it =
-          find_if(parent->children.begin(), parent->children.end(), [](AST::AstNode *node) { return (node->type == AST::AST_INITIAL); });
-        if (initial_node_it != parent->children.end()) {
-            AST::AstNode *initial_node = *initial_node_it;
-
-            // 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);
-
-            AST::AstNode *block_node = initial_node->children[0];
-            AST::AstNode *child_block_node = child->children[0];
-
-            // Place the contents of child block node inside parent block
-            for (auto child_block_child : child_block_node->children)
-                block_node->children.push_back(child_block_child->clone());
-            // Place the remaining contents of child initial node inside the parent initial
-            for (auto initial_child = child->children.begin() + 1; initial_child != child->children.end(); ++initial_child) {
-                initial_node->children.push_back((*initial_child)->clone());
-            }
-            delete child;
-        } else {
-            // Parent AST_INITIAL does not exist
-            // Place child AST_INITIAL before AST_ALWAYS if found
-            auto insert_it =
-              find_if(parent->children.begin(), parent->children.end(), [](AST::AstNode *node) { return (node->type == AST::AST_ALWAYS); });
-            parent->children.insert(insert_it, 1, child);
-        }
-    } else {
-        parent->children.push_back(child);
-    }
-}
-
-void UhdmAst::make_cell(vpiHandle obj_h, AST::AstNode *cell_node, AST::AstNode *type_node)
-{
-    if (cell_node->children.empty() || (!cell_node->children.empty() && cell_node->children[0]->type != AST::AST_CELLTYPE)) {
-        auto typeNode = new AST::AstNode(AST::AST_CELLTYPE);
-        typeNode->str = type_node->str;
-        cell_node->children.insert(cell_node->children.begin(), typeNode);
-    }
-    // Add port connections as arguments
-    vpiHandle port_itr = vpi_iterate(vpiPort, obj_h);
-    while (vpiHandle port_h = vpi_scan(port_itr)) {
-        std::string arg_name;
-        if (auto s = vpi_get_str(vpiName, port_h)) {
-            arg_name = s;
-            sanitize_symbol_name(arg_name);
-        }
-        auto arg_node = new AST::AstNode(AST::AST_ARGUMENT);
-        arg_node->str = arg_name;
-        arg_node->filename = cell_node->filename;
-        arg_node->location = cell_node->location;
-        visit_one_to_one({vpiHighConn}, port_h, [&](AST::AstNode *node) {
-            if (node) {
-                if (node->type == AST::AST_PARAMETER || node->type == AST::AST_LOCALPARAM) {
-                    node->type = AST::AST_IDENTIFIER;
-                }
-                arg_node->children.push_back(node);
-            }
-        });
-        cell_node->children.push_back(arg_node);
-        vpi_release_handle(port_h);
-    }
-    vpi_release_handle(port_itr);
-}
-
-void UhdmAst::move_type_to_new_typedef(AST::AstNode *current_node, AST::AstNode *type_node)
-{
-    auto typedef_node = new AST::AstNode(AST::AST_TYPEDEF);
-    typedef_node->location = type_node->location;
-    typedef_node->filename = type_node->filename;
-    typedef_node->str = strip_package_name(type_node->str);
-    for (auto c : current_node->children) {
-        if (c->str == typedef_node->str) {
-            return;
-        }
-    }
-    if (type_node->type == AST::AST_STRUCT) {
-        type_node->str.clear();
-        typedef_node->children.push_back(type_node);
-        current_node->children.push_back(typedef_node);
-    } else if (type_node->type == AST::AST_ENUM) {
-        if (type_node->attributes.count("\\enum_base_type")) {
-            auto base_type = type_node->attributes["\\enum_base_type"];
-            auto wire_node = new AST::AstNode(AST::AST_WIRE);
-            wire_node->is_reg = true;
-            for (auto c : base_type->children) {
-                std::string enum_item_str = "\\enum_value_";
-                log_assert(!c->children.empty());
-                log_assert(c->children[0]->type == AST::AST_CONSTANT);
-                int width = 1;
-                bool is_signed = c->children[0]->is_signed;
-                if (c->children.size() == 2) {
-                    width = c->children[1]->children[0]->integer + 1;
-                }
-                RTLIL::Const val = c->children[0]->bitsAsConst(width, is_signed);
-                enum_item_str.append(val.as_string());
-                wire_node->attributes[enum_item_str.c_str()] = AST::AstNode::mkconst_str(c->str);
-            }
-            typedef_node->children.push_back(wire_node);
-            current_node->children.push_back(typedef_node);
-            delete type_node;
-        } else {
-            type_node->str = "$enum" + std::to_string(shared.next_enum_id());
-            std::vector<AST::AstNode *> packed_ranges;
-            auto wire_node = new AST::AstNode(AST::AST_WIRE);
-            wire_node->is_reg = true;
-            wire_node->attributes["\\enum_type"] = AST::AstNode::mkconst_str(type_node->str);
-            if (!type_node->children.empty() && type_node->children[0]->children.size() > 1) {
-                packed_ranges.push_back(type_node->children[0]->children[1]->clone());
-            } else {
-                // Add default range
-                packed_ranges.push_back(make_range(31, 0));
-            }
-            add_multirange_wire(wire_node, std::move(packed_ranges), {});
-            typedef_node->children.push_back(wire_node);
-            current_node->children.push_back(type_node);
-            current_node->children.push_back(typedef_node);
-        }
-    } else {
-        type_node->str.clear();
-        typedef_node->children.push_back(type_node);
-        current_node->children.push_back(typedef_node);
-    }
-}
-
-AST::AstNode *UhdmAst::find_ancestor(const std::unordered_set<AST::AstNodeType> &types)
-{
-    auto searched_node = this;
-    while (searched_node) {
-        if (searched_node->current_node) {
-            if (types.find(searched_node->current_node->type) != types.end()) {
-                return searched_node->current_node;
-            }
-        }
-        searched_node = searched_node->parent;
-    }
-    return nullptr;
-}
-
-void UhdmAst::process_design()
-{
-    current_node = make_ast_node(AST::AST_DESIGN);
-    visit_one_to_many({UHDM::uhdmallInterfaces, UHDM::uhdmtopPackages, UHDM::uhdmallModules, UHDM::uhdmtopModules, vpiTaskFunc}, obj_h,
-                      [&](AST::AstNode *node) {
-                          if (node) {
-                              shared.top_nodes[node->str] = node;
-                          }
-                      });
-    visit_one_to_many({vpiParameter, vpiParamAssign}, obj_h, [&](AST::AstNode *node) {
-        if (get_attribute(node, attr_id::is_type_parameter)) {
-            // Don't process type parameters.
-            delete node;
-            return;
-        }
-        add_or_replace_child(current_node, node);
-    });
-    visit_one_to_many({vpiTypedef}, obj_h, [&](AST::AstNode *node) {
-        if (node)
-            move_type_to_new_typedef(current_node, node);
-    });
-    // Add top level typedefs and params to scope
-    setup_current_scope(shared.top_nodes, current_node);
-    for (auto pair : shared.top_nodes) {
-        if (!pair.second)
-            continue;
-        if (pair.second->type == AST::AST_PACKAGE) {
-            check_memories(pair.second);
-            clear_current_scope();
-            setup_current_scope(shared.top_nodes, pair.second);
-            simplify_sv(pair.second, nullptr);
-            clear_current_scope();
-        }
-    }
-    setup_current_scope(shared.top_nodes, current_node);
-    // Once we walked everything, unroll that as children of this node
-    for (auto &pair : shared.top_nodes) {
-        if (!pair.second)
-            continue;
-        if (!pair.second->get_bool_attribute(UhdmAst::partial())) {
-            if (pair.second->type == AST::AST_PACKAGE)
-                current_node->children.insert(current_node->children.begin(), pair.second);
-            else {
-                check_memories(pair.second);
-                setup_current_scope(shared.top_nodes, pair.second);
-                simplify_sv(pair.second, nullptr);
-                clear_current_scope();
-                current_node->children.push_back(pair.second);
-            }
-        } else {
-            log_warning("Removing unelaborated module: %s from the design.\n", pair.second->str.c_str());
-            // TODO: This should be properly erased from the module, but it seems that it's
-            // needed to resolve scope
-            delete pair.second;
-            pair.second = nullptr;
-        }
-    }
-}
-
-void UhdmAst::simplify_parameter(AST::AstNode *parameter, AST::AstNode *module_node)
-{
-    setup_current_scope(shared.top_nodes, shared.current_top_node);
-    visitEachDescendant(shared.current_top_node, [&](AST::AstNode *current_scope_node) {
-        if (current_scope_node->type == AST::AST_TYPEDEF || current_scope_node->type == AST::AST_PARAMETER ||
-            current_scope_node->type == AST::AST_LOCALPARAM) {
-            AST_INTERNAL::current_scope[current_scope_node->str] = current_scope_node;
-        }
-    });
-    if (module_node) {
-        visitEachDescendant(module_node, [&](AST::AstNode *current_scope_node) {
-            if (current_scope_node->type == AST::AST_TYPEDEF || current_scope_node->type == AST::AST_PARAMETER ||
-                current_scope_node->type == AST::AST_LOCALPARAM) {
-                AST_INTERNAL::current_scope[current_scope_node->str] = current_scope_node;
-            }
-        });
-    }
-    // first apply custom simplification step if needed
-    simplify_sv(parameter, module_node);
-    // workaround for yosys sometimes not simplifying parameters children
-    // parameters can have 2 children:
-    // first child should be parameter value
-    // second child should be parameter range (optional)
-    log_assert(!parameter->children.empty());
-    simplify_sv(parameter->children[0], parameter);
-    while (simplify(parameter->children[0], true, false, false, 1, -1, false, false)) {
-    }
-    // follow id2ast as yosys doesn't do it by default
-    if (parameter->children[0]->id2ast) {
-        simplify_sv(parameter->children[0]->id2ast, parameter);
-        while (simplify(parameter->children[0]->id2ast, true, false, false, 1, -1, false, false)) {
-        }
-    }
-    if (parameter->children.size() > 1) {
-        simplify_sv(parameter->children[1], parameter);
-        while (simplify(parameter->children[1], true, false, false, 1, -1, false, false)) {
-        }
-        if (parameter->children[1]->id2ast) {
-            simplify_sv(parameter->children[1]->id2ast, parameter);
-            while (simplify(parameter->children[1]->id2ast, true, false, false, 1, -1, false, false)) {
-            }
-        }
-    }
-    // then simplify parameter to AST_CONSTANT or AST_REALVALUE
-    while (simplify(parameter, true, false, false, 1, -1, false, false)) {
-    }
-    clear_current_scope();
-}
-
-void UhdmAst::process_module()
-{
-    std::string type = vpi_get_str(vpiDefName, obj_h);
-    std::string name = vpi_get_str(vpiName, obj_h) ? vpi_get_str(vpiName, obj_h) : type;
-    bool is_module_instance = type != name;
-    sanitize_symbol_name(type);
-    sanitize_symbol_name(name);
-    type = strip_package_name(type);
-    name = strip_package_name(name);
-    if (!is_module_instance) {
-        if (shared.top_nodes.find(type) != shared.top_nodes.end()) {
-            current_node = shared.top_nodes[type];
-            shared.current_top_node = current_node;
-            auto process_it = std::find_if(current_node->children.begin(), current_node->children.end(),
-                                           [](auto node) { return node->type == AST::AST_INITIAL || node->type == AST::AST_ALWAYS; });
-            auto children_after_process = std::vector<AST::AstNode *>(process_it, current_node->children.end());
-            current_node->children.erase(process_it, current_node->children.end());
-            auto old_top = shared.current_top_node;
-            shared.current_top_node = current_node;
-            visit_one_to_many({vpiModule, vpiInterface, vpiParameter, vpiParamAssign, vpiPort, vpiNet, vpiArrayNet, vpiTaskFunc, vpiGenScopeArray,
-                               vpiContAssign, vpiVariables},
-                              obj_h, [&](AST::AstNode *node) {
-                                  if (node) {
-                                      if (get_attribute(node, attr_id::is_type_parameter)) {
-                                          // Don't process type parameters.
-                                          delete node;
-                                          return;
-                                      }
-                                      add_or_replace_child(current_node, node);
-                                  }
-                              });
-            // Primitives will have the same names (like "and"), so we need to make sure we don't replace them
-            visit_one_to_many({vpiPrimitive}, obj_h, [&](AST::AstNode *node) {
-                if (node) {
-                    current_node->children.push_back(node);
-                }
-            });
-            shared.current_top_node = old_top;
-            current_node->children.insert(current_node->children.end(), children_after_process.begin(), children_after_process.end());
-
-            delete_attribute(current_node, UhdmAst::partial());
-        } else {
-            // processing nodes belonging to 'uhdmallModules'
-            current_node = make_ast_node(AST::AST_MODULE);
-            current_node->str = type;
-            shared.top_nodes[current_node->str] = current_node;
-            shared.current_top_node = current_node;
-            current_node->attributes[UhdmAst::partial()] = AST::AstNode::mkconst_int(1, false, 1);
-            visit_one_to_many({vpiTypedef}, obj_h, [&](AST::AstNode *node) {
-                if (node) {
-                    move_type_to_new_typedef(current_node, node);
-                }
-            });
-            visit_one_to_many({vpiModule, vpiParameter, vpiParamAssign, vpiNet, vpiArrayNet, vpiProcess}, obj_h, [&](AST::AstNode *node) {
-                if (node) {
-                    if (get_attribute(node, attr_id::is_type_parameter)) {
-                        // Don't process type parameters.
-                        delete node;
-                        return;
-                    }
-                    if ((node->type == AST::AST_ASSIGN && node->children.size() < 2)) {
-                        delete node;
-                        return;
-                    }
-                    add_or_replace_child(current_node, node);
-                }
-            });
-        }
-    } else {
-        // A module instance inside another uhdmTopModules' module.
-        // Create standalone module instance AST and embed it in the instantiating module using AST_CELL.
-
-        const uhdm_handle *const handle = (const uhdm_handle *)obj_h;
-        const auto *const uhdm_obj = (const UHDM::any *)handle->object;
-        const auto current_instance_changer = ScopedValueChanger(shared.current_instance, uhdm_obj);
-
-        current_node = make_ast_node(AST::AST_CELL);
-        std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> parameters;
-
-        auto parameter_typedefs = make_unique_resource<std::vector<AST::AstNode *>>();
-
-        visit_one_to_many({vpiParameter}, obj_h, [&](AST::AstNode *node) {
-            log_assert(node);
-            AST::AstNode *attr = get_attribute(node, attr_id::is_type_parameter);
-
-            if (!attr) {
-                // Process type parameters only.
-                delete node;
-                return;
-            }
-
-            if (node->children.size() == 0) {
-                log_assert(!attr->str.empty());
-                // Anonymous types have no chidren, and store the parameter name in attr->str.
-                parameters.push_back(std::make_pair(node->str, attr->str));
-                delete node;
-                return;
-            }
-
-            for (auto child : node->children) {
-                if (child->type == AST::AST_TYPEDEF && !child->str.empty()) {
-                    // process_type_parameter should have created a node with the parameter name
-                    //   and a child with the name of the value assigned to the parameter.
-                    parameters.push_back(std::make_pair(node->str, child->str));
-                }
-
-                if (child->type == AST::AST_TYPEDEF || child->type == AST::AST_ENUM) {
-                    // Copy definition of the type provided as parameter.
-                    parameter_typedefs->push_back(child->clone());
-                }
-            }
-            delete node;
-        });
-
-        visit_one_to_many({vpiParamAssign}, obj_h, [&](AST::AstNode *node) {
-            if (node && node->type == AST::AST_PARAMETER) {
-                log_assert(!node->children.empty());
-                if (node->children[0]->type != AST::AST_CONSTANT) {
-                    if (shared.top_nodes.count(type)) {
-                        simplify_parameter(node, shared.top_nodes[type]);
-                    } else {
-                        simplify_parameter(node, nullptr);
-                    }
-                }
-                log_assert(node->children[0]->type == AST::AST_CONSTANT || node->children[0]->type == AST::AST_REALVALUE);
-                parameters.push_back(std::make_pair(node->str, node->children[0]->asParaConst()));
-            }
-            delete node;
-        });
-        // We need to rename module to prevent name collision with the same module, but with different parameters
-        std::string module_name = !parameters.empty() ? AST::derived_module_name(type, parameters).c_str() : type;
-        auto module_node = shared.top_nodes[module_name];
-        // true, when Surelog don't have definition of module while parsing design
-        // if so, we leaving module parameters to yosys and don't rename module
-        // as it will be done by yosys
-        bool isPrimitive = false;
-        if (!module_node) {
-            module_node = shared.top_nodes[type];
-            if (!module_node) {
-                module_node = new AST::AstNode(AST::AST_MODULE);
-                module_node->str = type;
-                module_node->attributes[UhdmAst::partial()] = AST::AstNode::mkconst_int(2, false, 1);
-                module_node->attributes[ID::whitebox] = AST::AstNode::mkconst_int(1, false, 1);
-            }
-            isPrimitive = module_node->attributes.count(UhdmAst::partial()) && module_node->attributes[UhdmAst::partial()]->integer == 2;
-            if (!parameters.empty() && !isPrimitive) {
-                module_node = module_node->clone();
-                module_node->str = module_name;
-            }
-        } else if (auto attribute = get_attribute(module_node, attr_id::is_elaborated_module); attribute && attribute->integer == 1) {
-            // we already processed module with this parameters, just create cell node
-            make_cell(obj_h, current_node, module_node);
-            return;
-        }
-        shared.top_nodes[module_node->str] = module_node;
-        visit_one_to_many({vpiParamAssign}, obj_h, [&](AST::AstNode *node) {
-            if (node) {
-                if (node->children[0]->type != AST::AST_CONSTANT) {
-                    if (shared.top_nodes[type]) {
-                        simplify_parameter(node, module_node);
-                        log_assert(node->children[0]->type == AST::AST_CONSTANT || node->children[0]->type == AST::AST_REALVALUE);
-                    }
-                }
-                // if module is primitive
-                // Surelog doesn't have definition of this module,
-                // so we need to left setting of parameters to yosys
-                if (isPrimitive) {
-                    node->type = AST::AST_PARASET;
-                    current_node->children.push_back(node);
-                } else {
-                    add_or_replace_child(module_node, node);
-                }
-            }
-        });
-        module_node->children.insert(std::end(module_node->children), std::begin(*parameter_typedefs), std::end(*parameter_typedefs));
-        parameter_typedefs->clear();
-        parameter_typedefs.reset();
-        if (module_node->attributes.count(UhdmAst::partial())) {
-            AST::AstNode *attr = module_node->attributes.at(UhdmAst::partial());
-            if (attr->type == AST::AST_CONSTANT)
-                if (attr->integer == 1) {
-                    delete_attribute(module_node, UhdmAst::partial());
-                }
-        }
-        auto typeNode = new AST::AstNode(AST::AST_CELLTYPE);
-        typeNode->str = module_node->str;
-        current_node->children.insert(current_node->children.begin(), typeNode);
-        auto old_top = shared.current_top_node;
-        shared.current_top_node = module_node;
-        visit_one_to_many({vpiVariables, vpiNet, vpiArrayNet, vpiInterface, vpiModule, vpiPort, vpiGenScopeArray, vpiContAssign, vpiTaskFunc}, obj_h,
-                          [&](AST::AstNode *node) {
-                              if (node) {
-                                  add_or_replace_child(module_node, node);
-                              }
-                          });
-        make_cell(obj_h, current_node, module_node);
-        shared.current_top_node = old_top;
-        set_attribute(module_node, attr_id::is_elaborated_module, AST::AstNode::mkconst_int(1, true));
-    }
-}
-
-void UhdmAst::process_struct_typespec()
-{
-    current_node = make_ast_node(AST::AST_STRUCT);
-    visit_one_to_many({vpiTypespecMember}, obj_h, [&](AST::AstNode *node) {
-        if (node->children.size() > 0 && node->children[0]->type == AST::AST_ENUM) {
-            log_assert(node->children.size() == 1);
-            log_assert(!node->children[0]->children.empty());
-            log_assert(!node->children[0]->children[0]->children.empty());
-            // TODO: add missing enum_type attribute
-            AST::AstNode *range = nullptr;
-            // check if single enum element is larger than 1 bit
-            if (node->children[0]->children[0]->children.size() == 2) {
-                range = node->children[0]->children[0]->children[1]->clone();
-            } else {
-                range = make_range(0, 0);
-            }
-            delete_children(node);
-            node->children.push_back(range);
-        }
-        current_node->children.push_back(node);
-    });
-}
-
-void UhdmAst::process_union_typespec()
-{
-    current_node = make_ast_node(AST::AST_UNION);
-    visit_one_to_many({vpiTypespecMember}, obj_h, [&](AST::AstNode *node) {
-        if (node->children.size() > 0 && node->children[0]->type == AST::AST_ENUM) {
-            log_assert(node->children.size() == 1);
-            log_assert(!node->children[0]->children.empty());
-            log_assert(!node->children[0]->children[0]->children.empty());
-            // TODO: add missing enum_type attribute
-            AST::AstNode *range = nullptr;
-            // check if single enum element is larger than 1 bit
-            if (node->children[0]->children[0]->children.size() == 2) {
-                range = node->children[0]->children[0]->children[1]->clone();
-            } else {
-                range = make_range(0, 0);
-            }
-            delete_children(node);
-            node->children.push_back(range);
-        }
-        current_node->children.push_back(node);
-    });
-}
-
-void UhdmAst::process_array_typespec()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    std::vector<AST::AstNode *> packed_ranges;
-    std::vector<AST::AstNode *> unpacked_ranges;
-    visit_one_to_one({vpiElemTypespec}, obj_h, [&](AST::AstNode *node) {
-        if (node && node->type == AST::AST_STRUCT) {
-            auto str = current_node->str;
-            node->cloneInto(current_node);
-            current_node->str = str;
-            delete node;
-        }
-    });
-    if (auto elemtypespec_h = vpi_handle(vpiElemTypespec, obj_h)) {
-        visit_one_to_many({vpiRange}, elemtypespec_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-        vpi_release_handle(elemtypespec_h);
-    }
-    visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { unpacked_ranges.push_back(node); });
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-}
-
-void UhdmAst::process_typespec_member()
-{
-    std::vector<AST::AstNode *> packed_ranges;
-    std::vector<AST::AstNode *> unpacked_ranges;
-    current_node = make_ast_node(AST::AST_STRUCT_ITEM);
-    current_node->str = current_node->str.substr(1);
-    vpiHandle typespec_h = vpi_handle(vpiTypespec, obj_h);
-    int typespec_type = vpi_get(vpiType, typespec_h);
-    const uhdm_handle *const handle = (const uhdm_handle *)typespec_h;
-    const UHDM::BaseClass *const object = (const UHDM::BaseClass *)handle->object;
-    switch (typespec_type) {
-    case vpiBitTypespec:
-    case vpiLogicTypespec: {
-        current_node->is_logic = true;
-        visit_one_to_many({vpiRange}, typespec_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-        break;
-    }
-    case vpiByteTypespec: {
-        current_node->is_signed = vpi_get(vpiSigned, typespec_h);
-        packed_ranges.push_back(make_range(7, 0));
-        break;
-    }
-    case vpiShortIntTypespec: {
-        current_node->is_signed = vpi_get(vpiSigned, typespec_h);
-        packed_ranges.push_back(make_range(15, 0));
-        break;
-    }
-    case vpiIntTypespec:
-    case vpiIntegerTypespec: {
-        current_node->is_signed = vpi_get(vpiSigned, typespec_h);
-        packed_ranges.push_back(make_range(31, 0));
-        break;
-    }
-    case vpiTimeTypespec:
-    case vpiLongIntTypespec: {
-        current_node->is_signed = vpi_get(vpiSigned, typespec_h);
-        packed_ranges.push_back(make_range(63, 0));
-        break;
-    }
-    case vpiStructTypespec:
-    case vpiUnionTypespec:
-    case vpiEnumTypespec: {
-        visit_one_to_one({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
-            if (typespec_type == vpiStructTypespec || typespec_type == vpiUnionTypespec) {
-                auto str = current_node->str;
-                node->cloneInto(current_node);
-                current_node->str = str;
-                delete node;
-            } else if (typespec_type == vpiEnumTypespec) {
-                current_node->children.push_back(node);
-            } else {
-                delete node;
-            }
-        });
-        break;
-    }
-    case vpiPackedArrayTypespec:
-        visit_one_to_one({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
-            if (node && node->type == AST::AST_STRUCT) {
-                auto str = current_node->str;
-                if (node->attributes.count(UhdmAst::packed_ranges())) {
-                    for (auto r : node->attributes[UhdmAst::packed_ranges()]->children) {
-                        packed_ranges.push_back(r->clone());
-                    }
-                    std::reverse(packed_ranges.begin(), packed_ranges.end());
-                    delete_attribute(node, UhdmAst::packed_ranges());
-                }
-                if (node->attributes.count(UhdmAst::unpacked_ranges())) {
-                    for (auto r : node->attributes[UhdmAst::unpacked_ranges()]->children) {
-                        unpacked_ranges.push_back(r->clone());
-                    }
-                    delete_attribute(node, UhdmAst::unpacked_ranges());
-                }
-                node->cloneInto(current_node);
-                current_node->str = str;
-                current_node->children.insert(current_node->children.end(), packed_ranges.begin(), packed_ranges.end());
-                packed_ranges.clear();
-                delete node;
-            } else if (node) {
-                auto str = current_node->str;
-                if (node->attributes.count(UhdmAst::packed_ranges())) {
-                    for (auto r : node->attributes[UhdmAst::packed_ranges()]->children) {
-                        packed_ranges.push_back(r->clone());
-                    }
-                    std::reverse(packed_ranges.begin(), packed_ranges.end());
-                    delete_attribute(node, UhdmAst::packed_ranges());
-                }
-                if (node->attributes.count(UhdmAst::unpacked_ranges())) {
-                    for (auto r : node->attributes[UhdmAst::unpacked_ranges()]->children) {
-                        unpacked_ranges.push_back(r->clone());
-                    }
-                    delete_attribute(node, UhdmAst::unpacked_ranges());
-                }
-                node->cloneInto(current_node);
-                current_node->str = str;
-                current_node->type = AST::AST_STRUCT_ITEM;
-                delete node;
-            }
-        });
-        break;
-    case vpiVoidTypespec: {
-        report_error("%.*s:%d: Void typespecs are currently unsupported", (int)object->VpiFile().length(), object->VpiFile().data(),
-                     object->VpiLineNo());
-        break;
-    }
-    case vpiClassTypespec: {
-        report_error("%.*s:%d: Class typespecs are unsupported", (int)object->VpiFile().length(), object->VpiFile().data(), object->VpiLineNo());
-        break;
-    }
-    default: {
-        report_error("%.*s:%d: Encountered unhandled typespec in process_typespec_member: '%.*s' of type '%s'\n", (int)object->VpiFile().length(),
-                     object->VpiFile().data(), object->VpiLineNo(), (int)object->VpiName().length(), object->VpiName().data(),
-                     UHDM::VpiTypeName(typespec_h).c_str());
-        break;
-    }
-    }
-    vpi_release_handle(typespec_h);
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-}
-
-static UHDM::expr *reduce_expression(const UHDM::any *expr, const UHDM::any *inst, const UHDM::any *pexpr)
-{
-    log_assert(expr);
-    log_assert(inst);
-
-    bool invalidvalue = false;
-    UHDM::ExprEval eval;
-    UHDM::expr *resolved_operation = eval.reduceExpr(expr, invalidvalue, inst, pexpr);
-    if (invalidvalue) {
-        log_file_warning(std::string(expr->VpiFile()), expr->VpiLineNo(), "Could not reduce expression.\n");
-    }
-    return resolved_operation;
-}
-
-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);
-
-    const uhdm_handle *const handle = (const uhdm_handle *)obj_h;
-    const auto *enum_object = (const UHDM::enum_typespec *)handle->object;
-    const auto *typespec = enum_object->Base_typespec();
-
-    if (current_node->str.empty()) {
-        // anonymous typespec, check if not already created
-        log_assert(shared.current_top_node);
-        auto check_created_anonymous_enums = [enum_object, this](std::string top_module_name) -> bool {
-            for (auto pair : shared.anonymous_enums[top_module_name]) {
-                UHDM::CompareContext ctx;
-                if (pair.first->Compare(enum_object, &ctx) == 0) {
-                    // we already created typedef for this.
-                    delete current_node;
-                    current_node = make_node(AST::AST_WIRETYPE);
-                    current_node->str = pair.second;
-                    return true;
-                }
-            }
-            return false;
-        };
-        std::string top_module_name = shared.current_top_node->str;
-        if (check_created_anonymous_enums(top_module_name)) {
-            return;
-        }
-        // in case of parametrized module, also check unparametrized top module
-        // as we could add this enum there and then copy it to parametrized
-        // version
-        if (top_module_name.find("$paramod") != std::string::npos) {
-            // possible names:
-            // $paramod\module_name\PARAM=VAL
-            // $paramod$81af6bf473845aee480c993b90a1ed0117ae9091\module_name
-            top_module_name = top_module_name.substr(top_module_name.find("\\"));
-            if (auto params = top_module_name.find("\\", 1 /* skip first \ */) != std::string::npos)
-                top_module_name = top_module_name.substr(0, params);
-        }
-        if (check_created_anonymous_enums(top_module_name)) {
-            return;
-        }
-    }
-
-    if (typespec && typespec->UhdmType() == UHDM::uhdmlogic_typespec) {
-        // If it's a logic_typespec, try to reduce expressions inside of it.
-        // The `reduceExpr` function needs the whole context of the enum typespec
-        //   so it's called here instead of `process_operation` or any other more specific function.
-
-        const UHDM::logic_typespec *logic_typespec_obj = enum_object->Base_typespec()->Cast<const UHDM::logic_typespec *>();
-        std::vector<UHDM::range *> ranges;
-        // Check if ranges exist, as Ranges() returns a pointer to std::vector.
-        if (logic_typespec_obj->Ranges()) {
-            ranges = *(logic_typespec_obj->Ranges());
-        }
-        for (UHDM::range *range_obj : ranges) {
-            // For each range, take both left and right and reduce them if they're of type uhdmoperation.
-            const auto *leftrange_obj = range_obj->Left_expr();
-            const auto *rightrange_obj = range_obj->Right_expr();
-            log_assert(leftrange_obj);
-            log_assert(rightrange_obj);
-
-            if (leftrange_obj->UhdmType() == UHDM::uhdmoperation) {
-                // Substitute the previous leftrange with the resolved operation result.
-                const UHDM::any *const instance =
-                  enum_object->Instance() ? enum_object->Instance() : enum_object->VpiParent() ? enum_object->VpiParent() : shared.current_instance;
-
-                range_obj->Left_expr(reduce_expression(leftrange_obj, instance, enum_object->VpiParent()));
-            }
-            if (rightrange_obj->UhdmType() == UHDM::uhdmoperation) {
-                // Substitute the previous rightrange with the resolved operation result.
-                const UHDM::any *const instance =
-                  enum_object->Instance() ? enum_object->Instance() : enum_object->VpiParent() ? enum_object->VpiParent() : shared.current_instance;
-
-                range_obj->Right_expr(reduce_expression(rightrange_obj, instance, enum_object->VpiParent()));
-            }
-        }
-    }
-
-    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;
-        }
-    });
-    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;
-        }
-        // IMPORTANT: invalidates `range_it`!
-        current_node->children.push_back(node);
-    });
-    if (range) {
-        delete range;
-    }
-    if (current_node->str.empty()) {
-        // anonymous typespec
-        std::string typedef_name = "$systemverilog_plugin$anonymous_enum" + std::to_string(shared.next_anonymous_enum_typedef_id());
-        current_node->str = typedef_name;
-        uhdmast_assert(shared.current_top_node != nullptr);
-        move_type_to_new_typedef(shared.current_top_node, current_node);
-        current_node = make_node(AST::AST_WIRETYPE);
-        current_node->str = typedef_name;
-        shared.anonymous_enums[shared.current_top_node->str][enum_object] = std::move(typedef_name);
-    }
-}
-
-void UhdmAst::process_enum_const()
-{
-    current_node = make_ast_node(AST::AST_ENUM_ITEM);
-    AST::AstNode *constant_node = process_value(obj_h);
-    if (constant_node) {
-        constant_node->filename = current_node->filename;
-        constant_node->location = current_node->location;
-        current_node->children.push_back(constant_node);
-    }
-}
-
-void UhdmAst::process_custom_var()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    visit_one_to_one({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
-        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);
-            wiretype_node->str = node->str;
-            current_node->children.push_back(wiretype_node);
-        }
-        delete node;
-    });
-    auto type = vpi_get(vpiType, obj_h);
-    if (type == vpiEnumVar || type == vpiStructVar || type == vpiUnionVar) {
-        visit_default_expr(obj_h);
-    }
-    current_node->is_custom_type = true;
-}
-
-void UhdmAst::process_int_var()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    auto left_const = AST::AstNode::mkconst_int(31, true);
-    auto right_const = AST::AstNode::mkconst_int(0, true);
-    auto range = new AST::AstNode(AST::AST_RANGE, left_const, right_const);
-    current_node->children.push_back(range);
-    current_node->is_signed = vpi_get(vpiSigned, obj_h);
-    visit_default_expr(obj_h);
-}
-
-void UhdmAst::process_real_var()
-{
-    auto module_node = find_ancestor({AST::AST_MODULE});
-    auto wire_node = make_ast_node(AST::AST_WIRE);
-    auto left_const = AST::AstNode::mkconst_int(63, true);
-    auto right_const = AST::AstNode::mkconst_int(0, true);
-    auto range = new AST::AstNode(AST::AST_RANGE, left_const, right_const);
-    wire_node->children.push_back(range);
-    wire_node->is_signed = true;
-    module_node->children.push_back(wire_node);
-    current_node = make_ast_node(AST::AST_IDENTIFIER);
-    visit_default_expr(obj_h);
-}
-
-void UhdmAst::process_array_var()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    std::vector<AST::AstNode *> packed_ranges;
-    std::vector<AST::AstNode *> unpacked_ranges;
-    visit_one_to_one({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
-        if (node->str.empty()) {
-            // anonymous typespec, move the children to variable
-            current_node->type = node->type;
-            current_node->children = std::move(node->children);
-        } else {
-            auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
-            wiretype_node->str = node->str;
-            current_node->children.push_back(wiretype_node);
-            current_node->is_custom_type = true;
-        }
-        delete node;
-    });
-    vpiHandle itr = vpi_iterate(vpi_get(vpiType, obj_h) == vpiArrayVar ? vpiReg : vpiElement, obj_h);
-    while (vpiHandle reg_h = vpi_scan(itr)) {
-        if (vpi_get(vpiType, reg_h) == vpiStructVar || vpi_get(vpiType, reg_h) == vpiEnumVar) {
-            visit_one_to_one({vpiTypespec}, reg_h, [&](AST::AstNode *node) {
-                if (node->str.empty()) {
-                    // anonymous typespec, move the children to variable
-                    current_node->type = node->type;
-                    current_node->children = std::move(node->children);
-                } else {
-                    auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
-                    wiretype_node->str = node->str;
-                    current_node->children.push_back(wiretype_node);
-                    current_node->is_custom_type = true;
-                }
-                delete node;
-            });
-        } else if (vpi_get(vpiType, reg_h) == vpiLogicVar) {
-            current_node->is_logic = true;
-            visit_one_to_one({vpiTypespec}, reg_h, [&](AST::AstNode *node) {
-                if (node->str.empty()) {
-                    // anonymous typespec, move the children to variable
-                    current_node->type = node->type;
-                    current_node->children = std::move(node->children);
-                } else {
-                    auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
-                    wiretype_node->str = node->str;
-                    current_node->children.push_back(wiretype_node);
-                    current_node->is_custom_type = true;
-                }
-                delete node;
-            });
-            visit_one_to_many({vpiRange}, reg_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-        } else if (vpi_get(vpiType, reg_h) == vpiIntVar) {
-            packed_ranges.push_back(make_range(31, 0));
-            visit_default_expr(reg_h);
-        }
-        vpi_release_handle(reg_h);
-    }
-    vpi_release_handle(itr);
-    visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { unpacked_ranges.push_back(node); });
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-    visit_default_expr(obj_h);
-}
-
-void UhdmAst::process_packed_array_var()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    std::vector<AST::AstNode *> packed_ranges;
-    std::vector<AST::AstNode *> unpacked_ranges;
-    visit_one_to_one({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
-        if (node->str.empty()) {
-            // anonymous typespec, move the children to variable
-            current_node->type = node->type;
-            current_node->children = std::move(node->children);
-        } else {
-            auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
-            wiretype_node->str = node->str;
-            current_node->children.push_back(wiretype_node);
-            current_node->is_custom_type = true;
-        }
-        delete node;
-    });
-    vpiHandle itr = vpi_iterate(vpi_get(vpiType, obj_h) == vpiArrayVar ? vpiReg : vpiElement, obj_h);
-    while (vpiHandle reg_h = vpi_scan(itr)) {
-        if (vpi_get(vpiType, reg_h) == vpiStructVar || vpi_get(vpiType, reg_h) == vpiEnumVar) {
-            visit_one_to_one({vpiTypespec}, reg_h, [&](AST::AstNode *node) {
-                if (node->str.empty()) {
-                    // anonymous typespec, move the children to variable
-                    current_node->type = node->type;
-                    current_node->children = std::move(node->children);
-                } else {
-                    auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
-                    wiretype_node->str = node->str;
-                    current_node->children.push_back(wiretype_node);
-                    current_node->is_custom_type = true;
-                }
-                delete node;
-            });
-        } else if (vpi_get(vpiType, reg_h) == vpiLogicVar) {
-            current_node->is_logic = true;
-            visit_one_to_one({vpiTypespec}, reg_h, [&](AST::AstNode *node) {
-                if (node->str.empty()) {
-                    // anonymous typespec, move the children to variable
-                    current_node->type = node->type;
-                    current_node->children = std::move(node->children);
-                } else {
-                    auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
-                    wiretype_node->str = node->str;
-                    current_node->children.push_back(wiretype_node);
-                    current_node->is_custom_type = true;
-                }
-                delete node;
-            });
-            visit_one_to_many({vpiRange}, reg_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-        } else if (vpi_get(vpiType, reg_h) == vpiIntVar) {
-            packed_ranges.push_back(make_range(31, 0));
-            visit_default_expr(reg_h);
-        }
-        vpi_release_handle(reg_h);
-    }
-    vpi_release_handle(itr);
-    visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-    visit_default_expr(obj_h);
-}
-
-void UhdmAst::process_param_assign()
-{
-    current_node = make_ast_node(AST::AST_PARAMETER);
-    visit_one_to_one({vpiLhs}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            current_node->type = node->type;
-            current_node->str = node->str;
-            // Here we need to copy any ranges that is already present in lhs,
-            // but we want to skip actual value, as it is set in rhs
-            for (auto *c : node->children) {
-                if (c->type != AST::AST_CONSTANT) {
-                    current_node->children.push_back(c->clone());
-                }
-            }
-            delete_children(node);
-            copy_packed_unpacked_attribute(node, current_node);
-            current_node->is_custom_type = node->is_custom_type;
-            auto it = shared.param_types.find(current_node->str);
-            if (it == shared.param_types.end())
-                shared.param_types[current_node->str] = shared.param_types[node->str];
-            delete node;
-        }
-    });
-    visit_one_to_one({vpiRhs}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if (node->children.size() > 1 && (node->children[1]->type == AST::AST_PARAMETER || node->children[1]->type == AST::AST_LOCALPARAM)) {
-                node->children[1]->type = AST::AST_IDENTIFIER;
-            }
-            current_node->children.insert(current_node->children.begin(), node);
-        }
-    });
-}
-
-void UhdmAst::process_cont_assign_var_init()
-{
-    current_node = make_ast_node(AST::AST_INITIAL);
-    auto block_node = make_ast_node(AST::AST_BLOCK);
-    auto assign_node = make_ast_node(AST::AST_ASSIGN_LE);
-    block_node->children.push_back(assign_node);
-    current_node->children.push_back(block_node);
-
-    visit_one_to_one({vpiLhs, vpiRhs}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if (node->type == AST::AST_WIRE || node->type == AST::AST_PARAMETER || node->type == AST::AST_LOCALPARAM) {
-                assign_node->children.push_back(new AST::AstNode(AST::AST_IDENTIFIER));
-                assign_node->children.back()->str = node->str;
-                delete node;
-            } else {
-                assign_node->children.push_back(node);
-            }
-        }
-    });
-}
-
-void UhdmAst::process_cont_assign_net()
-{
-    current_node = make_ast_node(AST::AST_ASSIGN);
-
-    visit_one_to_one({vpiLhs, vpiRhs}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if (node->type == AST::AST_WIRE || node->type == AST::AST_PARAMETER || node->type == AST::AST_LOCALPARAM) {
-                current_node->children.push_back(new AST::AstNode(AST::AST_IDENTIFIER));
-                current_node->children.back()->str = node->str;
-            } else {
-                current_node->children.push_back(node->clone());
-            }
-            delete node;
-        }
-    });
-}
-
-void UhdmAst::process_cont_assign()
-{
-    auto net_decl_assign = vpi_get(vpiNetDeclAssign, obj_h);
-    vpiHandle node_lhs_h = vpi_handle(vpiLhs, obj_h);
-    auto lhs_net_type = vpi_get(vpiNetType, node_lhs_h);
-    vpi_release_handle(node_lhs_h);
-
-    // Check if lhs is a subtype of a net
-    bool isNet;
-    if (lhs_net_type >= vpiWire && lhs_net_type <= vpiUwire)
-        isNet = true;
-    else
-        // lhs is a variable
-        isNet = false;
-    if (net_decl_assign && !isNet)
-        process_cont_assign_var_init();
-    else
-        process_cont_assign_net();
-}
-
-void UhdmAst::process_assignment(const UHDM::BaseClass *object)
-{
-    auto type = vpi_get(vpiBlocking, obj_h) == 1 ? AST::AST_ASSIGN_EQ : AST::AST_ASSIGN_LE;
-    bool shift_unsigned = false;
-    int op_type = vpi_get(vpiOpType, obj_h);
-    AST::AstNodeType node_type;
-    current_node = make_ast_node(type);
-
-    visit_one_to_one({vpiLhs, vpiRhs}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            // fix node types for some assignments
-            // yosys requires that declaration of variable
-            // and assignment are separated
-            switch (node->type) {
-            case AST::AST_WIRE:
-                // wires can be declarated inside initialization block of for block
-                if (AST::AstNode *for_block = find_ancestor({AST::AST_BLOCK})) {
-                    if (for_block->str.find("$fordecl_block") != std::string::npos)
-                        break;
-                }
-                [[fallthrough]];
-            case AST::AST_PARAMETER:
-            case AST::AST_LOCALPARAM:
-                node->type = AST::AST_IDENTIFIER;
-                delete_children(node);
-                delete_attribute(node, UhdmAst::packed_ranges());
-                delete_attribute(node, UhdmAst::unpacked_ranges());
-                break;
-            default:
-                break;
-            };
-            current_node->children.push_back(node);
-        }
-    });
-    if (op_type && op_type != vpiAssignmentOp) {
-        switch (op_type) {
-        case vpiSubOp:
-            node_type = AST::AST_SUB;
-            break;
-        case vpiDivOp:
-            node_type = AST::AST_DIV;
-            break;
-        case vpiModOp:
-            node_type = AST::AST_MOD;
-            break;
-        case vpiLShiftOp:
-            node_type = AST::AST_SHIFT_LEFT;
-            shift_unsigned = true;
-            break;
-        case vpiRShiftOp:
-            node_type = AST::AST_SHIFT_RIGHT;
-            shift_unsigned = true;
-            break;
-        case vpiAddOp:
-            node_type = AST::AST_ADD;
-            break;
-        case vpiMultOp:
-            node_type = AST::AST_MUL;
-            break;
-        case vpiBitAndOp:
-            node_type = AST::AST_BIT_AND;
-            break;
-        case vpiBitOrOp:
-            node_type = AST::AST_BIT_OR;
-            break;
-        case vpiBitXorOp:
-            node_type = AST::AST_BIT_XOR;
-            break;
-        case vpiArithLShiftOp:
-            node_type = AST::AST_SHIFT_SLEFT;
-            shift_unsigned = true;
-            break;
-        case vpiArithRShiftOp:
-            node_type = AST::AST_SHIFT_SRIGHT;
-            shift_unsigned = true;
-            break;
-        default:
-            delete current_node;
-            current_node = nullptr;
-            report_error("%.*s:%d: Encountered unhandled compound assignment with operation type %d\n", (int)object->VpiFile().length(),
-                         object->VpiFile().data(), object->VpiLineNo(), op_type);
-            return;
-        }
-        log_assert(current_node->children.size() == 2);
-        auto child_node = new AST::AstNode(node_type, current_node->children[0]->clone(), current_node->children[1]);
-        current_node->children[1] = child_node;
-        if (shift_unsigned) {
-            log_assert(current_node->children[1]->children.size() == 2);
-            auto unsigned_node = new AST::AstNode(AST::AST_TO_UNSIGNED, current_node->children[1]->children[1]);
-            current_node->children[1]->children[1] = unsigned_node;
-        }
-    }
-    if (current_node->children.size() == 1 && current_node->children[0]->type == AST::AST_WIRE) {
-        auto top_node = find_ancestor({AST::AST_MODULE});
-        if (!top_node)
-            return;
-        top_node->children.push_back(std::move(current_node->children[0]));
-        delete current_node;
-        current_node = nullptr;
-    }
-}
-
-void UhdmAst::process_packed_array_net()
-{
-    std::vector<AST::AstNode *> packed_ranges;
-    std::vector<AST::AstNode *> unpacked_ranges;
-    current_node = make_ast_node(AST::AST_WIRE);
-    visit_one_to_many({vpiElement}, obj_h, [&](AST::AstNode *node) {
-        if (node && GetSize(node->children) == 1)
-            current_node->children.push_back(node->children[0]->clone());
-        current_node->is_custom_type = node->is_custom_type;
-        delete node;
-    });
-    visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-}
-
-void UhdmAst::process_array_net(const UHDM::BaseClass *object)
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    vpiHandle itr = vpi_iterate(vpiNet, obj_h);
-    std::vector<AST::AstNode *> packed_ranges;
-    std::vector<AST::AstNode *> unpacked_ranges;
-    while (vpiHandle net_h = vpi_scan(itr)) {
-        auto net_type = vpi_get(vpiType, net_h);
-        if (net_type == vpiLogicNet) {
-            current_node->is_logic = true;
-            current_node->is_signed = vpi_get(vpiSigned, net_h);
-            vpiHandle typespec_h = vpi_handle(vpiTypespec, net_h);
-            if (!typespec_h) {
-                typespec_h = vpi_handle(vpiTypespec, obj_h);
-            }
-            if (typespec_h) {
-                visit_one_to_many({vpiRange}, typespec_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-                vpi_release_handle(typespec_h);
-            } else {
-                visit_one_to_many({vpiRange}, net_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-            }
-        } else if (net_type == vpiStructNet) {
-            visit_one_to_one({vpiTypespec}, net_h, [&](AST::AstNode *node) {
-                if (node->str.empty()) {
-                    // anonymous typespec, move the children to variable
-                    current_node->type = node->type;
-                    current_node->children = std::move(node->children);
-                } else {
-                    auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
-                    wiretype_node->str = node->str;
-                    current_node->children.push_back(wiretype_node);
-                    current_node->is_custom_type = true;
-                }
-                delete node;
-            });
-        }
-        vpi_release_handle(net_h);
-    }
-    vpi_release_handle(itr);
-    visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { unpacked_ranges.push_back(node); });
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-}
-
-void UhdmAst::process_package()
-{
-    current_node = make_ast_node(AST::AST_PACKAGE);
-    shared.current_top_node = current_node;
-    visit_one_to_many({vpiTypedef}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            move_type_to_new_typedef(current_node, node);
-        }
-    });
-    visit_one_to_many({vpiParameter, vpiParamAssign}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if (get_attribute(node, attr_id::is_type_parameter)) {
-                // Don't process type parameters.
-                delete node;
-                return;
-            }
-            node->str = strip_package_name(node->str);
-            for (auto c : node->children) {
-                c->str = strip_package_name(c->str);
-            }
-            add_or_replace_child(current_node, node);
-        }
-    });
-    visit_one_to_many({vpiTaskFunc}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            current_node->children.push_back(node);
-        }
-    });
-}
-
-void UhdmAst::process_interface()
-{
-    std::string type = vpi_get_str(vpiDefName, obj_h);
-    std::string name = vpi_get_str(vpiName, obj_h) ? vpi_get_str(vpiName, obj_h) : type;
-    sanitize_symbol_name(type);
-    sanitize_symbol_name(name);
-    AST::AstNode *elaboratedInterface;
-    // Check if we have encountered this object before
-    if (shared.top_nodes.find(type) != shared.top_nodes.end()) {
-        // Was created before, fill missing
-        elaboratedInterface = shared.top_nodes[type];
-        visit_one_to_many({vpiPort, vpiVariables}, obj_h, [&](AST::AstNode *node) {
-            if (node) {
-                add_or_replace_child(elaboratedInterface, node);
-            }
-        });
-    } else {
-        // Encountered for the first time
-        elaboratedInterface = new AST::AstNode(AST::AST_INTERFACE);
-        elaboratedInterface->str = name;
-        visit_one_to_many({vpiNet, vpiPort, vpiModport}, obj_h, [&](AST::AstNode *node) {
-            if (node) {
-                add_or_replace_child(elaboratedInterface, node);
-            }
-        });
-    }
-    shared.top_nodes[elaboratedInterface->str] = elaboratedInterface;
-    if (name != type) {
-        // Not a top module, create instance
-        current_node = make_ast_node(AST::AST_CELL);
-        make_cell(obj_h, current_node, elaboratedInterface);
-    } else {
-        current_node = elaboratedInterface;
-    }
-}
-
-void UhdmAst::process_modport()
-{
-    current_node = make_ast_node(AST::AST_MODPORT);
-    visit_one_to_many({vpiIODecl}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            current_node->children.push_back(node);
-        }
-    });
-}
-
-void UhdmAst::process_io_decl()
-{
-    current_node = nullptr;
-    std::vector<AST::AstNode *> packed_ranges;   // comes before wire name
-    std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
-    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) { unpacked_ranges.push_back(node); });
-    }
-    std::reverse(unpacked_ranges.begin(), unpacked_ranges.end());
-
-    visit_one_to_one({vpiTypedef}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if (!node->str.empty()) {
-                auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
-                wiretype_node->str = node->str;
-                // wiretype needs to be 1st node (if port have also another range nodes)
-                current_node->children.insert(current_node->children.begin(), wiretype_node);
-                current_node->is_custom_type = true;
-            } else {
-                // anonymous typedef, just move children
-                for (auto child : node->children) {
-                    current_node->children.push_back(child->clone());
-                }
-                if (node->attributes.count(UhdmAst::packed_ranges())) {
-                    for (auto r : node->attributes[UhdmAst::packed_ranges()]->children) {
-                        packed_ranges.push_back(r->clone());
-                    }
-                }
-                if (node->attributes.count(UhdmAst::unpacked_ranges())) {
-                    for (auto r : node->attributes[UhdmAst::unpacked_ranges()]->children) {
-                        unpacked_ranges.push_back(r->clone());
-                    }
-                }
-                current_node->is_logic = node->is_logic;
-                current_node->is_reg = node->is_reg;
-            }
-            current_node->is_signed = node->is_signed;
-            delete node;
-        }
-    });
-    if (const int n = vpi_get(vpiDirection, obj_h)) {
-        if (n == vpiInput) {
-            current_node->is_input = true;
-        } else if (n == vpiOutput) {
-            current_node->is_output = true;
-        } else if (n == vpiInout) {
-            current_node->is_input = true;
-            current_node->is_output = true;
-        }
-    }
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges, false);
-}
-
-void UhdmAst::process_always()
-{
-    current_node = make_ast_node(AST::AST_ALWAYS);
-    visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if (node->type != AST::AST_BLOCK) {
-                // Create implicit block.
-                AST::AstNode *block = make_ast_node(AST::AST_BLOCK);
-                // There are (at least) two cases where something could have been inserted into AST_ALWAYS node when `node` is not an AST_BLOCK:
-                // - stream_op inserts a block.
-                // - event_control inserts a non-block statement.
-                // Move the block inserted by a stream_op into an implicit group. Everything else stays where it is.
-                if (!current_node->children.empty() && current_node->children.back()->type == AST::AST_BLOCK) {
-                    block->children.push_back(current_node->children.back());
-                    current_node->children.pop_back();
-                }
-                block->children.push_back(node);
-                current_node->children.push_back(block);
-            } else {
-                // Child is an explicit block.
-                current_node->children.push_back(node);
-            }
-        } else {
-            // TODO (mglb): This branch is probably unreachable? Is it possible to have empty `always`?
-            // No children, so nothing should have been inserted into the always node during visitation.
-            log_assert(current_node->children.empty());
-            // Create implicit empty block.
-            current_node->children.push_back(make_ast_node(AST::AST_BLOCK));
-        }
-    });
-    switch (vpi_get(vpiAlwaysType, obj_h)) {
-    case vpiAlwaysComb:
-        current_node->attributes[ID::always_comb] = AST::AstNode::mkconst_int(1, false);
-        break;
-    case vpiAlwaysFF:
-        current_node->attributes[ID::always_ff] = AST::AstNode::mkconst_int(1, false);
-        break;
-    case vpiAlwaysLatch:
-        current_node->attributes[ID::always_latch] = AST::AstNode::mkconst_int(1, false);
-        break;
-    default:
-        break;
-    }
-}
-
-void UhdmAst::process_event_control(const UHDM::BaseClass *object)
-{
-    current_node = make_ast_node(AST::AST_BLOCK);
-    visit_one_to_one({vpiCondition}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            auto process_node = find_ancestor({AST::AST_ALWAYS});
-            if (!process_node) {
-                log_error("%.*s:%d: Currently supports only event control stmts inside 'always'\n", (int)object->VpiFile().length(),
-                          object->VpiFile().data(), object->VpiLineNo());
-            }
-            process_node->children.push_back(node);
-        }
-        // is added inside vpiOperation
-    });
-    visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            current_node->children.push_back(node);
-        }
-    });
-}
-
-void UhdmAst::process_initial()
-{
-    current_node = make_ast_node(AST::AST_INITIAL);
-    // TODO (mglb): handler below is identical as in `process_always`. Extract it to avoid duplication.
-    visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if (node->type != AST::AST_BLOCK) {
-                // Create an implicit block.
-                AST::AstNode *block = make_ast_node(AST::AST_BLOCK);
-                // There is (at least) one case where something could have been inserted into AST_INITIAL node when `node` is not an AST_BLOCK:
-                // - stream_op inserts a block.
-                // Move the block inserted by a stream_op into an implicit group.
-                if (!current_node->children.empty() && current_node->children.back()->type == AST::AST_BLOCK) {
-                    block->children.push_back(current_node->children.back());
-                    current_node->children.pop_back();
-                }
-                block->children.push_back(node);
-                current_node->children.push_back(block);
-            } else {
-                // Child is an explicit block.
-                current_node->children.push_back(node);
-            }
-        } else {
-            // TODO (mglb): This branch is probably unreachable? Is it possible to have empty `initial`?
-            // No children, so nothing should have been inserted into the always node during visitation.
-            log_assert(current_node->children.empty());
-            // Create implicit empty block.
-            current_node->children.push_back(make_ast_node(AST::AST_BLOCK));
-        }
-    });
-}
-
-void UhdmAst::process_begin(bool is_named)
-{
-    current_node = make_ast_node(AST::AST_BLOCK);
-    if (!is_named) {
-        // for unnamed block, reset block name
-        current_node->str = "";
-    }
-    AST::AstNode *hierarchy_node = nullptr;
-    static int unnamed_block_idx = 0;
-    visit_one_to_many({vpiVariables}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if (!is_named) {
-                if (!hierarchy_node) {
-                    // Create an implicit hierarchy scope
-                    // simplify checks if sv_mode is set to true when wire is declared inside unnamed block
-                    VERILOG_FRONTEND::sv_mode = true;
-                    hierarchy_node = make_ast_node(AST::AST_BLOCK);
-                    hierarchy_node->str = "$unnamed_block$" + std::to_string(unnamed_block_idx++);
-                }
-                hierarchy_node->children.push_back(node);
-            } else {
-                current_node->children.push_back(node);
-            }
-        }
-    });
-    visit_one_to_many({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if ((node->type == AST::AST_ASSIGN_EQ || node->type == AST::AST_ASSIGN_LE) && node->children.size() == 1) {
-                auto func_node = find_ancestor({AST::AST_FUNCTION, AST::AST_TASK});
-                if (!func_node) {
-                    delete node;
-                    return;
-                }
-                auto wire_node = new AST::AstNode(AST::AST_WIRE);
-                wire_node->type = AST::AST_WIRE;
-                wire_node->str = node->children[0]->str;
-                func_node->children.push_back(wire_node);
-                delete node;
-            } else {
-                if (hierarchy_node)
-                    hierarchy_node->children.push_back(node);
-                else
-                    current_node->children.push_back(node);
-            }
-        }
-    });
-    if (hierarchy_node)
-        current_node->children.push_back(hierarchy_node);
-}
-
-void UhdmAst::process_operation(const UHDM::BaseClass *object)
-{
-    auto operation = vpi_get(vpiOpType, obj_h);
-    switch (operation) {
-    case vpiStreamRLOp:
-        process_stream_op();
-        break;
-    case vpiEventOrOp:
-    case vpiListOp:
-        process_list_op();
-        break;
-    case vpiCastOp:
-        process_cast_op();
-        break;
-    case vpiInsideOp:
-        process_inside_op();
-        break;
-    case vpiAssignmentPatternOp:
-        process_assignment_pattern_op();
-        break;
-    case vpiWildEqOp:
-    case vpiWildNeqOp: {
-        report_error("%.*s:%d: Wildcard operators are not supported yet\n", (int)object->VpiFile().length(), object->VpiFile().data(),
-                     object->VpiLineNo());
-        break;
-    }
-    default: {
-        current_node = make_ast_node(AST::AST_NONE);
-        visit_one_to_many({vpiOperand}, obj_h, [&](AST::AstNode *node) {
-            if (node) {
-                current_node->children.push_back(node);
-            }
-        });
-        switch (operation) {
-        case vpiMinusOp:
-            current_node->type = AST::AST_NEG;
-            break;
-        case vpiPlusOp:
-            current_node->type = AST::AST_POS;
-            break;
-        case vpiPosedgeOp:
-            current_node->type = AST::AST_POSEDGE;
-            break;
-        case vpiNegedgeOp:
-            current_node->type = AST::AST_NEGEDGE;
-            break;
-        case vpiUnaryAndOp:
-            current_node->type = AST::AST_REDUCE_AND;
-            break;
-        case vpiUnaryOrOp:
-            current_node->type = AST::AST_REDUCE_OR;
-            break;
-        case vpiUnaryXorOp:
-            current_node->type = AST::AST_REDUCE_XOR;
-            break;
-        case vpiUnaryXNorOp:
-            current_node->type = AST::AST_REDUCE_XNOR;
-            break;
-        case vpiUnaryNandOp: {
-            auto not_node = new AST::AstNode(AST::AST_NONE, current_node);
-            if (current_node->children.size() == 2) {
-                current_node->type = AST::AST_BIT_AND;
-                not_node->type = AST::AST_BIT_NOT;
-            } else {
-                current_node->type = AST::AST_REDUCE_AND;
-                not_node->type = AST::AST_LOGIC_NOT;
-            }
-            current_node = not_node;
-            break;
-        }
-        case vpiUnaryNorOp: {
-            auto not_node = new AST::AstNode(AST::AST_NONE, current_node);
-            if (current_node->children.size() == 2) {
-                current_node->type = AST::AST_BIT_OR;
-                not_node->type = AST::AST_BIT_NOT;
-            } else {
-                current_node->type = AST::AST_REDUCE_OR;
-                not_node->type = AST::AST_LOGIC_NOT;
-            }
-            current_node = not_node;
-            break;
-        }
-        case vpiBitNegOp:
-            current_node->type = AST::AST_BIT_NOT;
-            break;
-        case vpiBitAndOp:
-            current_node->type = AST::AST_BIT_AND;
-            break;
-        case vpiBitOrOp:
-            current_node->type = AST::AST_BIT_OR;
-            break;
-        case vpiBitXorOp:
-            current_node->type = AST::AST_BIT_XOR;
-            break;
-        case vpiBitXnorOp:
-            current_node->type = AST::AST_BIT_XNOR;
-            break;
-        case vpiLShiftOp: {
-            current_node->type = AST::AST_SHIFT_LEFT;
-            log_assert(current_node->children.size() == 2);
-            auto unsigned_node = new AST::AstNode(AST::AST_TO_UNSIGNED, current_node->children[1]);
-            current_node->children[1] = unsigned_node;
-            break;
-        }
-        case vpiRShiftOp: {
-            current_node->type = AST::AST_SHIFT_RIGHT;
-            log_assert(current_node->children.size() == 2);
-            auto unsigned_node = new AST::AstNode(AST::AST_TO_UNSIGNED, current_node->children[1]);
-            current_node->children[1] = unsigned_node;
-            break;
-        }
-        case vpiNotOp:
-            current_node->type = AST::AST_LOGIC_NOT;
-            break;
-        case vpiLogAndOp:
-            current_node->type = AST::AST_LOGIC_AND;
-            break;
-        case vpiLogOrOp:
-            current_node->type = AST::AST_LOGIC_OR;
-            break;
-        case vpiEqOp:
-            current_node->type = AST::AST_EQ;
-            break;
-        case vpiNeqOp:
-            current_node->type = AST::AST_NE;
-            break;
-        case vpiCaseEqOp:
-            current_node->type = AST::AST_EQX;
-            break;
-        case vpiCaseNeqOp:
-            current_node->type = AST::AST_NEX;
-            break;
-        case vpiGtOp:
-            current_node->type = AST::AST_GT;
-            break;
-        case vpiGeOp:
-            current_node->type = AST::AST_GE;
-            break;
-        case vpiLtOp:
-            current_node->type = AST::AST_LT;
-            break;
-        case vpiLeOp:
-            current_node->type = AST::AST_LE;
-            break;
-        case vpiSubOp:
-            current_node->type = AST::AST_SUB;
-            if (!current_node->children.empty() && current_node->children[0]->type == AST::AST_LOCALPARAM) {
-                current_node->children[0]->type = AST::AST_IDENTIFIER;
-            }
-            break;
-        case vpiAddOp:
-            current_node->type = AST::AST_ADD;
-            break;
-        case vpiMultOp:
-            current_node->type = AST::AST_MUL;
-            break;
-        case vpiDivOp:
-            current_node->type = AST::AST_DIV;
-            break;
-        case vpiModOp:
-            current_node->type = AST::AST_MOD;
-            break;
-        case vpiArithLShiftOp: {
-            current_node->type = AST::AST_SHIFT_SLEFT;
-            log_assert(current_node->children.size() == 2);
-            auto unsigned_node = new AST::AstNode(AST::AST_TO_UNSIGNED, current_node->children[1]);
-            current_node->children[1] = unsigned_node;
-            break;
-        }
-        case vpiArithRShiftOp: {
-            current_node->type = AST::AST_SHIFT_SRIGHT;
-            log_assert(current_node->children.size() == 2);
-            auto unsigned_node = new AST::AstNode(AST::AST_TO_UNSIGNED, current_node->children[1]);
-            current_node->children[1] = unsigned_node;
-            break;
-        }
-        case vpiPowerOp:
-            current_node->type = AST::AST_POW;
-            break;
-        case vpiPostIncOp: {
-            // TODO: Make this an actual post-increment op (currently it's a pre-increment)
-            log_warning("%.*s:%d: Post-incrementation operations are handled as pre-incrementation.\n", (int)object->VpiFile().length(),
-                        object->VpiFile().data(), object->VpiLineNo());
-            [[fallthrough]];
-        }
-        case vpiPreIncOp: {
-            current_node->type = AST::AST_ASSIGN_EQ;
-            auto id = current_node->children[0]->clone();
-            auto add_node = new AST::AstNode(AST::AST_ADD, id, AST::AstNode::mkconst_int(1, true));
-            add_node->filename = current_node->filename;
-            add_node->location = current_node->location;
-            current_node->children.push_back(add_node);
-            break;
-        }
-        case vpiPostDecOp: {
-            // TODO: Make this an actual post-decrement op (currently it's a pre-decrement)
-            log_warning("%.*s:%d: Post-decrementation operations are handled as pre-decrementation.\n", (int)object->VpiFile().length(),
-                        object->VpiFile().data(), object->VpiLineNo());
-            [[fallthrough]];
-        }
-        case vpiPreDecOp: {
-            current_node->type = AST::AST_ASSIGN_EQ;
-            auto id = current_node->children[0]->clone();
-            auto add_node = new AST::AstNode(AST::AST_SUB, id, AST::AstNode::mkconst_int(1, true));
-            add_node->filename = current_node->filename;
-            add_node->location = current_node->location;
-            current_node->children.push_back(add_node);
-            break;
-        }
-        case vpiConditionOp:
-            current_node->type = AST::AST_TERNARY;
-            break;
-        case vpiConcatOp: {
-            current_node->type = AST::AST_CONCAT;
-            std::reverse(current_node->children.begin(), current_node->children.end());
-            break;
-        }
-        case vpiMultiConcatOp:
-        case vpiMultiAssignmentPatternOp:
-            current_node->type = AST::AST_REPLICATE;
-            break;
-        case vpiAssignmentOp:
-            current_node->type = AST::AST_ASSIGN_EQ;
-            break;
-        case vpiStreamLROp: {
-            auto concat_node = current_node->children.back();
-            current_node->children.pop_back();
-            delete current_node;
-            current_node = concat_node;
-            break;
-        }
-        case vpiNullOp: {
-            delete current_node;
-            current_node = nullptr;
-            break;
-        }
-        case vpiMinTypMaxOp: {
-            // ignore min and max and set only typ
-            log_assert(current_node->children.size() == 3);
-            auto tmp = current_node->children[1]->clone();
-            delete current_node;
-            current_node = tmp;
-            break;
-        }
-        default: {
-            delete current_node;
-            current_node = nullptr;
-            report_error("%.*s:%d: Encountered unhandled operation type %d\n", (int)object->VpiFile().length(), object->VpiFile().data(),
-                         object->VpiLineNo(), operation);
-        }
-        }
-    }
-    }
-}
-
-void UhdmAst::process_stream_op()
-{
-    // Closest ancestor where new statements can be inserted.
-    AST::AstNode *stmt_list_node = find_ancestor({
-      AST::AST_MODULE,
-      AST::AST_PACKAGE,
-      AST::AST_BLOCK,
-      AST::AST_INITIAL,
-      AST::AST_ALWAYS,
-      AST::AST_FUNCTION,
-    });
-    uhdmast_assert(stmt_list_node != nullptr);
-
-    // Detect whether we're in a procedural context. If yes, `for` loop will be generated, and `generate for` otherwise.
-    const AST::AstNode *const proc_ctx = find_ancestor({AST::AST_ALWAYS, AST::AST_INITIAL, AST::AST_FUNCTION});
-    const bool is_proc_ctx = (proc_ctx != nullptr);
-
-    // Get a prefix for internal identifiers.
-    const auto stream_op_id = shared.next_loop_id();
-    const auto make_id_str = [stream_op_id](const char *suffix) {
-        return std::string("$systemverilog_plugin$stream_op_") + std::to_string(stream_op_id) + "_" + suffix;
-    };
-
-    if (is_proc_ctx) {
-        // Put logic inside a sub-block to avoid issues with declarations not being at the beginning of a block.
-        AST::AstNode *block = make_node(Yosys::AST::AST_BLOCK).str(make_id_str("impl"));
-        stmt_list_node->children.push_back(block);
-        stmt_list_node = block;
-    }
-
-    // TODO (mglb): Only concat expression's size factors are supported as a slice size. Add support for other slice sizes as well.
-    AST::AstNode *slice_size_arg = nullptr;
-    AST::AstNode *stream_concat_arg = nullptr;
-    {
-        std::vector<AST::AstNode *> operands;
-        // Expected operands: [slice_size] stream_concatenation
-        visit_one_to_many({vpiOperand}, obj_h, [&](AST::AstNode *node) {
-            uhdmast_assert(node != nullptr);
-            uhdmast_assert(operands.size() < 2);
-            operands.push_back(node);
-        });
-        uhdmast_assert(operands.size() > 0);
-
-        if (operands.size() == 2) {
-            slice_size_arg = operands.at(0);
-            // SV spec says slice_size can be a constant or a type. However, Surelog converts type to its width, so we always expect a const.
-            uhdmast_assert(slice_size_arg->type == AST::AST_CONSTANT);
-        } else {
-            slice_size_arg = make_const(1u);
-        }
-        stream_concat_arg = operands.back();
-    }
-
-    AST::AstNode *const stream_concat_width_lp = //
-      (make_node(AST::AST_LOCALPARAM).str(make_id_str("width")))({
-        (make_node(AST::AST_FCALL).str("\\$bits"))({
-          (stream_concat_arg->clone()),
-        }),
-        (make_range(31, 0, true)),
-      });
-
-    // TODO (mglb): src_wire and dst_wire should probably take argument signedness and logicness into account.
-    AST::AstNode *const src_wire = //
-      (make_node(AST::AST_WIRE).str(make_id_str("src")).is_reg(is_proc_ctx))({
-        (make_node(AST::AST_RANGE))({
-          (make_const(0)),
-          (make_node(AST::AST_SUB))({
-            (make_ident(stream_concat_width_lp->str)),
-            (make_const(1)),
-          }),
-        }),
-      });
-
-    AST::AstNode *const dst_wire = //
-      (make_node(AST::AST_WIRE).str(make_id_str("dst")).is_reg(is_proc_ctx))({
-        (make_node(AST::AST_RANGE))({
-          (make_node(AST::AST_SUB))({
-            (make_ident(stream_concat_width_lp->str)),
-            (make_const(1)),
-          }),
-          (make_const(0)),
-        }),
-      });
-
-    AST::AstNode *const assign_stream_concat_to_src_wire = //
-      (make_node(is_proc_ctx ? AST::AST_ASSIGN_EQ : AST::AST_ASSIGN))({
-        (make_ident(src_wire->str)),
-        (stream_concat_arg),
-      });
-
-    AST::AstNode *const loop_counter = //
-      (make_node(is_proc_ctx ? AST::AST_WIRE : AST::AST_GENVAR).str(make_id_str("counter")).is_reg(true))({
-        (make_range(31, 0, true)),
-      });
-
-    AST::AstNode *const for_loop = //
-      (make_node(is_proc_ctx ? AST::AST_FOR : AST::AST_GENFOR))({
-        // init statement
-        (make_node(AST::AST_ASSIGN_EQ))({
-          (make_ident(loop_counter->str)),
-          (make_const(0)),
-        }),
-        // condition
-        (make_node(AST::AST_LT))({
-          (make_ident(loop_counter->str)),
-          (make_ident(stream_concat_width_lp->str)),
-        }),
-        // iteration expression
-        (make_node(AST::AST_ASSIGN_EQ))({
-          (make_ident(loop_counter->str)),
-          (make_node(Yosys::AST::AST_ADD))({
-            (make_ident(loop_counter->str)),
-            (slice_size_arg->clone()),
-          }),
-        }),
-        // loop body
-        (make_node(is_proc_ctx ? AST::AST_BLOCK : AST::AST_GENBLOCK).str(make_id_str("loop_body")))({
-          (make_node(is_proc_ctx ? AST::AST_ASSIGN_EQ : AST::AST_ASSIGN))({
-            (make_ident(dst_wire->str))({
-              (make_node(AST::AST_RANGE))({
-                (make_node(Yosys::AST::AST_SUB))({
-                  (make_node(Yosys::AST::AST_ADD))({
-                    (make_node(Yosys::AST::AST_SELFSZ))({
-                      (make_ident(loop_counter->str)),
-                    }),
-                    (slice_size_arg->clone()),
-                  }),
-                  (make_const(1)),
-                }),
-                (make_node(Yosys::AST::AST_ADD))({
-                  (make_node(Yosys::AST::AST_SELFSZ))({
-                    (make_ident(loop_counter->str)),
-                  }),
-                  (make_const(0)),
-                }),
-              }),
-            }),
-            (make_ident(src_wire->str))({
-              (make_node(AST::AST_RANGE))({
-                (make_node(Yosys::AST::AST_SUB))({
-                  (make_node(Yosys::AST::AST_ADD))({
-                    (make_node(Yosys::AST::AST_SELFSZ))({
-                      (make_ident(loop_counter->str)),
-                    }),
-                    (slice_size_arg),
-                  }),
-                  (make_const(1)),
-                }),
-                (make_node(Yosys::AST::AST_ADD))({
-                  (make_node(Yosys::AST::AST_SELFSZ))({
-                    (make_ident(loop_counter->str)),
-                  }),
-                  (make_const(0)),
-                }),
-              }),
-            }),
-          }),
-        }),
-      });
-
-    stmt_list_node->children.insert(stmt_list_node->children.end(), {
-                                                                      stream_concat_width_lp,
-                                                                      src_wire,
-                                                                      dst_wire,
-                                                                      assign_stream_concat_to_src_wire,
-                                                                      loop_counter,
-                                                                      for_loop,
-                                                                    });
-
-    current_node = make_ident(is_proc_ctx ? (stmt_list_node->str + '.' + dst_wire->str) : dst_wire->str);
-}
-
-void UhdmAst::process_list_op()
-{
-    // Add all operands as children of process node
-    if (auto parent_node = find_ancestor({AST::AST_ALWAYS, AST::AST_COND})) {
-        visit_one_to_many({vpiOperand}, obj_h, [&](AST::AstNode *node) {
-            // add directly to process/cond node
-            if (node) {
-                parent_node->children.push_back(node);
-            }
-        });
-    } else {
-        log_error("Unhandled list op, couldn't find parent node.");
-    }
-    // Do not create a node
-}
-
-void UhdmAst::process_cast_op()
-{
-    current_node = make_ast_node(AST::AST_NONE);
-    visit_one_to_many({vpiOperand}, obj_h, [&](AST::AstNode *node) {
-        node->cloneInto(current_node);
-        delete node;
-    });
-    vpiHandle typespec_h = vpi_handle(vpiTypespec, obj_h);
-    vpi_release_handle(typespec_h);
-}
-
-void UhdmAst::process_inside_op()
-{
-    current_node = make_ast_node(AST::AST_EQ);
-    AST::AstNode *lhs = nullptr;
-    visit_one_to_many({vpiOperand}, obj_h, [&](AST::AstNode *node) {
-        if (!lhs) {
-            lhs = node;
-        }
-        if (current_node->children.size() < 2) {
-            current_node->children.push_back(node);
-        } else {
-            auto or_node = new AST::AstNode(AST::AST_LOGIC_OR);
-            or_node->filename = current_node->filename;
-            or_node->location = current_node->location;
-            auto eq_node = new AST::AstNode(AST::AST_EQ);
-            eq_node->filename = current_node->filename;
-            eq_node->location = current_node->location;
-            or_node->children.push_back(current_node);
-            or_node->children.push_back(eq_node);
-            eq_node->children.push_back(lhs->clone());
-            eq_node->children.push_back(node);
-            current_node = or_node;
-        }
-    });
-}
-
-void UhdmAst::process_assignment_pattern_op()
-{
-    current_node = make_ast_node(AST::AST_CONCAT);
-    if (auto param_node = find_ancestor({AST::AST_PARAMETER, AST::AST_LOCALPARAM})) {
-        std::map<size_t, AST::AstNode *> ordered_children;
-        visit_one_to_many({vpiOperand}, obj_h, [&](AST::AstNode *node) {
-            if (node->type == AST::AST_ASSIGN || node->type == AST::AST_ASSIGN_EQ || node->type == AST::AST_ASSIGN_LE) {
-                // Get the name of the parameter or it's child, to which the pattern is assigned.
-                std::string key;
-                if (!node->children.empty() && !node->children[0]->children.empty() &&
-                    node->children[0]->children[0]->type == static_cast<AST::AstNodeType>(AST::Extended::AST_DOT)) {
-                    key = node->children[0]->children[0]->str;
-                } else if (!node->children.empty()) {
-                    key = node->children[0]->str;
-                } else {
-                    log_file_error(node->filename, node->location.first_line, "Couldn't find `key` in assignment pattern.\n");
-                }
-                auto param_type = shared.param_types[param_node->str];
-                if (!param_type) {
-                    log_error("Couldn't find parameter type for node: %s\n", param_node->str.c_str());
-                }
-                // Place the child node holding the value assigned in the pattern, in the right order,
-                // so the overall value of the param_node is correct.
-                size_t pos =
-                  std::find_if(param_type->children.begin(), param_type->children.end(), [key](AST::AstNode *child) { return child->str == key; }) -
-                  param_type->children.begin();
-                ordered_children.insert(std::make_pair(pos, node->children[1]->clone()));
-                delete node;
-            } else {
-                current_node->children.push_back(node);
-            }
-        });
-        for (auto p : ordered_children) {
-            current_node->children.push_back(p.second);
-        }
-        std::reverse(current_node->children.begin(), current_node->children.end());
-        return;
-    }
-    auto assign_node = find_ancestor({AST::AST_ASSIGN, AST::AST_ASSIGN_EQ, AST::AST_ASSIGN_LE});
-
-    auto proc_node =
-      find_ancestor({AST::AST_BLOCK, AST::AST_GENBLOCK, AST::AST_ALWAYS, AST::AST_INITIAL, AST::AST_MODULE, AST::AST_PACKAGE, AST::AST_CELL});
-    if (proc_node && proc_node->type == AST::AST_CELL && shared.top_nodes.count(proc_node->children[0]->str)) {
-        proc_node = shared.top_nodes[proc_node->children[0]->str];
-    }
-    std::vector<AST::AstNode *> assignments;
-    visit_one_to_many({vpiOperand}, obj_h, [&](AST::AstNode *node) {
-        if (node->type == AST::AST_ASSIGN || node->type == AST::AST_ASSIGN_EQ || node->type == AST::AST_ASSIGN_LE) {
-            assignments.push_back(node);
-        } else {
-            current_node->children.push_back(node);
-        }
-    });
-    std::reverse(current_node->children.begin(), current_node->children.end());
-    if (!assignments.empty()) {
-        if (current_node->children.empty()) {
-            delete assign_node->children[0];
-            assign_node->children[0] = assignments[0]->children[0];
-            delete current_node;
-            current_node = assignments[0]->children[1];
-            assignments[0]->children.clear();
-            delete assignments[0];
-            proc_node->children.insert(proc_node->children.end(), assignments.begin() + 1, assignments.end());
-        } else {
-            proc_node->children.insert(proc_node->children.end(), assignments.begin(), assignments.end());
-        }
-    }
-}
-
-void UhdmAst::process_bit_select()
-{
-    current_node = make_ast_node(AST::AST_IDENTIFIER);
-    visit_one_to_one({vpiIndex}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(make_node(AST::AST_RANGE)({node})); });
-}
-
-void UhdmAst::process_part_select()
-{
-    current_node = make_ast_node(AST::AST_IDENTIFIER);
-    AST::AstNode *range_node = make_node(AST::AST_RANGE);
-    visit_one_to_one({vpiLeftRange, vpiRightRange}, obj_h, [&](AST::AstNode *node) { range_node->children.push_back(node); });
-    current_node->children.push_back(range_node);
-}
-
-void UhdmAst::process_indexed_part_select()
-{
-    current_node = make_ast_node(AST::AST_IDENTIFIER);
-    // TODO: check if there are other types, for now only handle 1 and 2 (+: and -:)
-    auto indexed_part_select_type = vpi_get(vpiIndexedPartSelectType, obj_h) == 1 ? AST::AST_ADD : AST::AST_SUB;
-    AST::AstNode *range_node = make_node(AST::AST_RANGE);
-    visit_one_to_one({vpiBaseExpr}, obj_h, [&](AST::AstNode *node) { range_node->children.push_back(node); });
-    visit_one_to_one({vpiWidthExpr}, obj_h, [&](AST::AstNode *node) {
-        AST::AstNode *right_range_node = make_node(indexed_part_select_type);
-        right_range_node->children.push_back(range_node->children[0]->clone());
-        right_range_node->children.push_back(node);
-        AST::AstNode *sub = make_node(indexed_part_select_type == AST::AST_ADD ? AST::AST_SUB : AST::AST_ADD);
-        sub->children.push_back(right_range_node);
-        sub->children.push_back(AST::AstNode::mkconst_int(1, false, 1));
-        range_node->children.push_back(sub);
-    });
-    if (indexed_part_select_type == AST::AST_ADD) {
-        std::reverse(range_node->children.begin(), range_node->children.end());
-    }
-    current_node->children.push_back(range_node);
-}
-
-void UhdmAst::process_if_else()
-{
-    current_node = make_ast_node(AST::AST_CASE);
-    visit_one_to_one({vpiCondition}, obj_h, [&](AST::AstNode *node) {
-        if (!node) {
-            log_error("Couldn't find node in if stmt. This can happend if unsupported '$value$plusargs' function is used inside if.\n");
-        }
-        auto reduce_node = new AST::AstNode(AST::AST_REDUCE_BOOL, node);
-        current_node->children.push_back(reduce_node);
-    });
-    // If true:
-    auto *condition = new AST::AstNode(AST::AST_COND);
-    auto *constant = AST::AstNode::mkconst_int(1, false, 1);
-    condition->children.push_back(constant);
-    visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        auto *statements = new AST::AstNode(AST::AST_BLOCK);
-        if (node)
-            statements->children.push_back(node);
-        condition->children.push_back(statements);
-    });
-    current_node->children.push_back(condition);
-    // Else:
-    if (vpi_get(vpiType, obj_h) == vpiIfElse) {
-        auto *condition = new AST::AstNode(AST::AST_COND);
-        auto *elseBlock = new AST::AstNode(AST::AST_DEFAULT);
-        condition->children.push_back(elseBlock);
-        visit_one_to_one({vpiElseStmt}, obj_h, [&](AST::AstNode *node) {
-            auto *statements = new AST::AstNode(AST::AST_BLOCK);
-            if (node)
-                statements->children.push_back(node);
-            condition->children.push_back(statements);
-        });
-        current_node->children.push_back(condition);
-    }
-}
-
-void UhdmAst::process_for()
-{
-    current_node = make_ast_node(AST::AST_BLOCK);
-    auto loop_id = shared.next_loop_id();
-    current_node->str = "$fordecl_block" + std::to_string(loop_id);
-    auto loop = make_ast_node(AST::AST_FOR);
-    loop->str = "$loop" + std::to_string(loop_id);
-    visit_one_to_many({vpiForInitStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node->type == AST::AST_ASSIGN_LE)
-            node->type = AST::AST_ASSIGN_EQ;
-        auto lhs = node->children[0];
-        if (lhs->type == AST::AST_WIRE) {
-            auto *wire = lhs->clone();
-            wire->is_logic = true;
-            current_node->children.push_back(wire);
-            lhs->type = AST::AST_IDENTIFIER;
-            lhs->is_signed = false;
-            lhs->delete_children();
-        }
-        loop->children.push_back(node);
-    });
-    visit_one_to_one({vpiCondition}, obj_h, [&](AST::AstNode *node) { loop->children.push_back(node); });
-    visit_one_to_many({vpiForIncStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node->type == AST::AST_ASSIGN_LE)
-            node->type = AST::AST_ASSIGN_EQ;
-        loop->children.push_back(node);
-    });
-    visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node->type != AST::AST_BLOCK) {
-            auto *statements = make_ast_node(AST::AST_BLOCK);
-            statements->str = current_node->str; // Needed in simplify step
-            statements->children.push_back(node);
-            loop->children.push_back(statements);
-        } else {
-            if (node->str == "") {
-                node->str = loop->str;
-            }
-            loop->children.push_back(node);
-        }
-    });
-    current_node->children.push_back(loop);
-    transform_breaks_continues(loop, current_node);
-}
-
-void UhdmAst::process_gen_scope()
-{
-    current_node = make_ast_node(AST::AST_GENBLOCK);
-    visit_one_to_many({vpiTypedef}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            move_type_to_new_typedef(current_node, node);
-        }
-    });
-
-    visit_one_to_many(
-      {vpiParameter, vpiParamAssign, vpiNet, vpiArrayNet, vpiVariables, vpiContAssign, vpiProcess, vpiModule, vpiGenScopeArray, vpiTaskFunc}, obj_h,
-      [&](AST::AstNode *node) {
-          if (node) {
-              if (get_attribute(node, attr_id::is_type_parameter)) {
-                  // Don't process type parameters.
-                  delete node;
-                  return;
-              }
-              add_or_replace_child(current_node, node);
-          }
-      });
-}
-
-void UhdmAst::process_case()
-{
-    current_node = make_ast_node(AST::AST_CASE);
-    visit_one_to_one({vpiCondition}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(node); });
-    visit_one_to_many({vpiCaseItem}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(node); });
-}
-
-void UhdmAst::process_case_item()
-{
-    auto cond_type = AST::AST_COND;
-    if (vpiHandle parent_h = vpi_handle(vpiParent, obj_h)) {
-        switch (vpi_get(vpiCaseType, parent_h)) {
-        case vpiCaseExact:
-            cond_type = AST::AST_COND;
-            break;
-        case vpiCaseX:
-            cond_type = AST::AST_CONDX;
-            break;
-        case vpiCaseZ:
-            cond_type = AST::AST_CONDZ;
-            break;
-        default: {
-            const uhdm_handle *const handle = (const uhdm_handle *)obj_h;
-            const UHDM::BaseClass *const object = (const UHDM::BaseClass *)handle->object;
-            report_error("%.*s:%d: Unknown case type", (int)object->VpiFile().length(), object->VpiFile().data(), object->VpiLineNo());
-        }
-        }
-        vpi_release_handle(parent_h);
-    }
-    current_node = make_ast_node(cond_type);
-    vpiHandle itr = vpi_iterate(vpiExpr, obj_h);
-    while (vpiHandle expr_h = vpi_scan(itr)) {
-        // case ... inside statement, the operation is stored in UHDM inside case items
-        // Retrieve just the InsideOp arguments here, we don't add any special handling
-        if (vpi_get(vpiType, expr_h) == vpiOperation && vpi_get(vpiOpType, expr_h) == vpiInsideOp) {
-            visit_one_to_many({vpiOperand}, expr_h, [&](AST::AstNode *node) {
-                // Currently we are adding nodes directly to ancestor
-                // inside process_list_op, so after this function, we have
-                // nodes already in `current_node`.
-                // We should probably refactor this to return node instead.
-                // For now, make sure this function doesn't return any nodes.
-                log_assert(node == nullptr);
-            });
-            // vpiListOp is returned in 2 cases:
-            // a, b, c ... -> multiple vpiListOp with single item
-            // [a : b] -> single vpiListOp with 2 items
-            // single item is handled by default,
-            // here handle 2 items with custom low_high_bound attribute
-            if (current_node->children.size() == 2) {
-                auto block = make_ast_node(AST::AST_BLOCK);
-                block->children = std::move(current_node->children);
-                current_node->children.clear();
-                current_node->children.push_back(block);
-                current_node->attributes[UhdmAst::low_high_bound()] = AST::AstNode::mkconst_int(1, false, 1);
-            }
-        } else {
-            UhdmAst uhdm_ast(this, shared, indent + "  ");
-            auto *node = uhdm_ast.process_object(expr_h);
-            if (node) {
-                current_node->children.push_back(node);
-            }
-        }
-        vpi_release_handle(expr_h);
-    }
-    vpi_release_handle(itr);
-    if (current_node->children.empty()) {
-        current_node->children.push_back(new AST::AstNode(AST::AST_DEFAULT));
-    }
-    visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *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);
-        }
-    });
-}
-
-void UhdmAst::process_range(const UHDM::BaseClass *object)
-{
-    current_node = make_ast_node(AST::AST_RANGE);
-    visit_one_to_one({vpiLeftRange, vpiRightRange}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(node); });
-    if (current_node->children.size() > 0) {
-        if (current_node->children[0]->str == "unsized") {
-            log_error("%.*s:%d: Currently not supported object of type 'unsized range'\n", (int)object->VpiFile().length(), object->VpiFile().data(),
-                      object->VpiLineNo());
-        }
-    }
-    if (current_node->children.size() > 1) {
-        if (current_node->children[1]->str == "unsized") {
-            log_error("%.*s:%d: Currently not supported object of type 'unsized range'\n", (int)object->VpiFile().length(), object->VpiFile().data(),
-                      object->VpiLineNo());
-        }
-    }
-}
-
-void UhdmAst::process_return()
-{
-    current_node = make_ast_node(AST::AST_ASSIGN_EQ);
-    auto func_node = find_ancestor({AST::AST_FUNCTION, AST::AST_TASK});
-    if (!func_node->children.empty()) {
-        auto lhs = new AST::AstNode(AST::AST_IDENTIFIER);
-        lhs->str = func_node->children[0]->str;
-        current_node->children.push_back(lhs);
-    }
-    visit_one_to_one({vpiCondition}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(node); });
-}
-
-void UhdmAst::process_function()
-{
-    current_node = make_ast_node(vpi_get(vpiType, obj_h) == vpiFunction ? AST::AST_FUNCTION : AST::AST_TASK);
-    visit_one_to_one({vpiReturn}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            auto net_type = vpi_get(vpiNetType, obj_h);
-            node->is_reg = net_type == vpiReg;
-            node->str = current_node->str;
-            current_node->children.push_back(node);
-        }
-    });
-    visit_one_to_many({vpiParameter, vpiParamAssign}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if (get_attribute(node, attr_id::is_type_parameter)) {
-                // Don't process type parameters.
-                delete node;
-                return;
-            }
-            add_or_replace_child(current_node, node);
-        }
-    });
-    visit_one_to_many({vpiIODecl}, obj_h, [&](AST::AstNode *node) {
-        node->type = AST::AST_WIRE;
-        node->port_id = shared.next_port_id();
-        current_node->children.push_back(node);
-    });
-    visit_one_to_many({vpiVariables}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(node); });
-    visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            current_node->children.push_back(node);
-        }
-    });
-}
-
-void UhdmAst::process_hier_path()
-{
-    AST::AstNode *top_node = nullptr;
-    visit_one_to_many({vpiActual}, obj_h, [&](AST::AstNode *node) {
-        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 = node;
-                top_node = current_node;
-            } else {
-                if (node->type == AST::AST_IDENTIFIER && !node->str.empty()) {
-                    node->type = static_cast<AST::AstNodeType>(AST::Extended::AST_DOT);
-                    top_node->children.push_back(node);
-                    top_node = node;
-                } else {
-                    top_node->children.push_back(node->children[0]);
-                    node->children.erase(node->children.begin());
-                    delete node;
-                }
-            }
-        }
-    });
-}
-
-void UhdmAst::process_gen_scope_array()
-{
-    current_node = make_ast_node(AST::AST_GENBLOCK);
-    visit_one_to_many({vpiGenScope}, obj_h, [&](AST::AstNode *genscope_node) {
-        for (auto *child : genscope_node->children) {
-            if (child->type == AST::AST_PARAMETER || child->type == AST::AST_LOCALPARAM) {
-                auto param_str = child->str.substr(1);
-                auto array_str = "[" + param_str + "]";
-                visitEachDescendant(genscope_node, [&](AST::AstNode *node) {
-                    auto pos = node->str.find(array_str);
-                    if (pos != std::string::npos) {
-                        node->type = AST::AST_PREFIX;
-                        auto *param = new AST::AstNode(AST::AST_IDENTIFIER);
-                        param->str = child->str;
-                        node->children.push_back(param);
-                        auto bracket = node->str.rfind(']');
-                        if (bracket + 2 <= node->str.size()) {
-                            auto *field = new AST::AstNode(AST::AST_IDENTIFIER);
-                            field->str = "\\" + node->str.substr(bracket + 2);
-                            node->children.push_back(field);
-                        }
-                        node->str = node->str.substr(0, node->str.find('['));
-                    }
-                });
-            }
-        }
-        current_node->children.insert(current_node->children.end(), genscope_node->children.begin(), genscope_node->children.end());
-        genscope_node->children.clear();
-        delete genscope_node;
-    });
-}
-
-void UhdmAst::process_tagged_pattern()
-{
-    auto assign_node = find_ancestor({AST::AST_ASSIGN, AST::AST_ASSIGN_EQ, AST::AST_ASSIGN_LE});
-    auto assign_type = AST::AST_ASSIGN;
-    AST::AstNode *lhs_node = nullptr;
-    if (assign_node) {
-        assign_type = assign_node->type;
-        lhs_node = assign_node->children[0]->clone();
-    } else {
-        lhs_node = new AST::AstNode(AST::AST_IDENTIFIER);
-        auto ancestor = find_ancestor({AST::AST_WIRE, AST::AST_MEMORY, AST::AST_PARAMETER, AST::AST_LOCALPARAM});
-        if (!ancestor) {
-            const uhdm_handle *const handle = (const uhdm_handle *)obj_h;
-            const UHDM::BaseClass *const object = (const UHDM::BaseClass *)handle->object;
-            report_error("%.*s:%d: Couldn't find ancestor for tagged pattern!\n", (int)object->VpiFile().length(), object->VpiFile().data(),
-                         object->VpiLineNo());
-        }
-        lhs_node->str = ancestor->str;
-    }
-    current_node = new AST::AstNode(assign_type);
-    current_node->children.push_back(lhs_node);
-    auto typespec_h = vpi_handle(vpiTypespec, obj_h);
-    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::Extended::AST_DOT));
-            field->str = field_name;
-            current_node->children[0]->children.push_back(field);
-        }
-    } else if (vpi_get(vpiType, typespec_h) == vpiIntegerTypespec) {
-        s_vpi_value val;
-        vpi_get_value(typespec_h, &val);
-        auto range = new AST::AstNode(AST::AST_RANGE);
-        auto index = AST::AstNode::mkconst_int(val.value.integer, false);
-        range->children.push_back(index);
-        current_node->children[0]->children.push_back(range);
-    }
-    vpi_release_handle(typespec_h);
-    visit_one_to_one({vpiPattern}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(node); });
-}
-
-void UhdmAst::process_logic_var()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    current_node->is_logic = true;
-    std::vector<AST::AstNode *> packed_ranges;   // comes before wire name
-    std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
-    // TODO: add const attribute, but it seems it is little more
-    // then just setting boolean value
-    // current_node->is_const = vpi_get(vpiConstantVariable, obj_h);
-    visit_one_to_one({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
-        if (node->str.empty()) {
-            // anonymous typespec, move the children to variable
-            current_node->type = node->type;
-            current_node->children = std::move(node->children);
-        } else {
-            auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
-            wiretype_node->str = node->str;
-            current_node->children.push_back(wiretype_node);
-            current_node->is_custom_type = true;
-        }
-        current_node->is_signed = node->is_signed;
-        delete node;
-    });
-    // TODO: Handling below seems similar to other typespec accesses for range. Candidate for extraction to a function.
-    if (auto typespec_h = vpi_handle(vpiTypespec, obj_h)) {
-        visit_one_to_many({vpiRange}, typespec_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-        vpi_release_handle(typespec_h);
-    } else {
-        visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-    }
-    visit_default_expr(obj_h);
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-}
-
-void UhdmAst::process_sys_func_call()
-{
-    current_node = make_ast_node(AST::AST_FCALL);
-
-    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 (std::find(std::begin(task_calls), std::end(task_calls), current_node->str) != std::end(task_calls)) {
-        current_node->type = AST::AST_TCALL;
-    }
-
-    visit_one_to_many({vpiArgument}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            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_tf_call(AST::AstNodeType type)
-{
-    current_node = make_ast_node(type);
-    visit_one_to_many({vpiArgument}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if (node->type == AST::AST_PARAMETER || node->type == AST::AST_LOCALPARAM) {
-                node->type = AST::AST_IDENTIFIER;
-                node->children.clear();
-            }
-            current_node->children.push_back(node);
-        }
-    });
-
-    // Calls to functions imported from packages do not contain package name in vpiName. A full function name, containing package name,
-    // is necessary e.g. when call to a function is used as a value assigned to a port of a module instantiated inside generate for loop.
-    // However, we can't use full function name when it refers to a module's local function.
-    // To make it work the called function name is used instead of vpiName from the call object only when it contains package name (detected here
-    // by presence of "::").
-    // TODO(mglb): This can fail when "::" is just a part of an escaped identifier. Handle such cases properly here and in other places.
-    const uhdm_handle *const handle = (const uhdm_handle *)obj_h;
-    if (handle->type == UHDM::uhdmfunc_call) {
-        const auto *const base_object = (const UHDM::BaseClass *)handle->object;
-        const auto *const fcall = base_object->Cast<const UHDM::func_call *>();
-        if (fcall->Function()) {
-            auto fname = fcall->Function()->VpiFullName();
-            if (fname.find("::") != std::string_view::npos) {
-                current_node->str = fname;
-                sanitize_symbol_name(current_node->str);
-            }
-        }
-    }
-}
-
-void UhdmAst::process_immediate_assert()
-{
-    current_node = make_ast_node(AST::AST_ASSERT);
-    visit_one_to_one({vpiExpr}, obj_h, [&](AST::AstNode *n) {
-        if (n) {
-            current_node->children.push_back(n);
-        }
-    });
-}
-
-void UhdmAst::process_logic_typespec()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    current_node->is_logic = true;
-    std::vector<AST::AstNode *> packed_ranges;   // comes before wire name
-    std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
-    if (!current_node->str.empty() && current_node->str.find("::") == std::string::npos) {
-        std::string package_name = "";
-        if (vpiHandle instance_h = vpi_handle(vpiInstance, obj_h)) {
-            if (vpi_get(vpiType, instance_h) == vpiPackage) {
-                package_name = get_object_name(instance_h, {vpiDefName});
-                current_node->str = package_name + "::" + current_node->str.substr(1);
-            }
-            vpi_release_handle(instance_h);
-        }
-    }
-    visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-    if (packed_ranges.empty())
-        packed_ranges.push_back(make_range(0, 0));
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-    current_node->is_signed = vpi_get(vpiSigned, obj_h);
-}
-
-void UhdmAst::process_int_typespec()
-{
-    std::vector<AST::AstNode *> packed_ranges;   // comes before wire name
-    std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
-    current_node = make_ast_node(AST::AST_WIRE);
-    packed_ranges.push_back(make_range(31, 0));
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-    current_node->is_signed = vpi_get(vpiSigned, obj_h);
-}
-
-void UhdmAst::process_shortint_typespec()
-{
-    std::vector<AST::AstNode *> packed_ranges;   // comes before wire name
-    std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
-    current_node = make_ast_node(AST::AST_WIRE);
-    packed_ranges.push_back(make_range(15, 0));
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-    current_node->is_signed = vpi_get(vpiSigned, obj_h);
-}
-
-void UhdmAst::process_longint_typespec()
-{
-    std::vector<AST::AstNode *> packed_ranges;   // comes before wire name
-    std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
-    current_node = make_ast_node(AST::AST_WIRE);
-    packed_ranges.push_back(make_range(63, 0));
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-    current_node->is_signed = vpi_get(vpiSigned, obj_h);
-}
-
-void UhdmAst::process_byte_typespec()
-{
-    std::vector<AST::AstNode *> packed_ranges;   // comes before wire name
-    std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
-    current_node = make_ast_node(AST::AST_WIRE);
-    packed_ranges.push_back(make_range(7, 0));
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-    current_node->is_signed = vpi_get(vpiSigned, obj_h);
-}
-
-void UhdmAst::process_time_typespec()
-{
-    std::vector<AST::AstNode *> packed_ranges;   // comes before wire name
-    std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
-    current_node = make_ast_node(AST::AST_WIRE);
-    packed_ranges.push_back(make_range(63, 0));
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-    current_node->is_signed = false;
-}
-
-void UhdmAst::process_string_var()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    current_node->is_string = true;
-    // FIXME:
-    // this is only basic support for strings,
-    // currently yosys doesn't support dynamic resize of wire
-    // based on string size
-    // here we try to get size of string based on provided const string
-    // if it is not available, we are setting size to explicite 64 bits
-    visit_one_to_one({vpiExpr}, obj_h, [&](AST::AstNode *expr_node) {
-        if (expr_node->type == AST::AST_CONSTANT) {
-            auto left_const = AST::AstNode::mkconst_int(expr_node->range_left, true);
-            auto right_const = AST::AstNode::mkconst_int(expr_node->range_right, true);
-            auto range = make_ast_node(AST::AST_RANGE, {left_const, right_const});
-            current_node->children.push_back(range);
-        }
-    });
-    if (current_node->children.empty()) {
-        auto left_const = AST::AstNode::mkconst_int(64, true);
-        auto right_const = AST::AstNode::mkconst_int(0, true);
-        auto range = make_ast_node(AST::AST_RANGE, {left_const, right_const});
-        current_node->children.push_back(range);
-    }
-    visit_default_expr(obj_h);
-}
-
-void UhdmAst::process_string_typespec()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    current_node->is_string = true;
-    // FIXME:
-    // this is only basic support for strings,
-    // currently yosys doesn't support dynamic resize of wire
-    // based on string size
-    // here, we are setting size to explicite 64 bits
-    auto left_const = AST::AstNode::mkconst_int(64, true);
-    auto right_const = AST::AstNode::mkconst_int(0, true);
-    auto range = make_ast_node(AST::AST_RANGE, {left_const, right_const});
-    current_node->children.push_back(range);
-}
-
-void UhdmAst::process_bit_typespec()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    visit_range(obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            current_node->children.push_back(node);
-        }
-    });
-    current_node->is_signed = vpi_get(vpiSigned, obj_h);
-}
-
-void UhdmAst::process_repeat()
-{
-    auto loop_id = shared.next_loop_id();
-    current_node = make_ast_node(AST::AST_BLOCK);
-    current_node->str = "$repeatdecl_block" + std::to_string(loop_id);
-    auto *loop = make_ast_node(AST::AST_REPEAT);
-    loop->str = "$loop" + std::to_string(loop_id);
-    current_node->children.push_back(loop);
-    visit_one_to_one({vpiCondition}, obj_h, [&](AST::AstNode *node) { loop->children.push_back(node); });
-    visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node->type != AST::AST_BLOCK) {
-            node = new AST::AstNode(AST::AST_BLOCK, node);
-        }
-        if (node->str.empty()) {
-            node->str = loop->str; // Needed in simplify step
-        }
-        loop->children.push_back(node);
-    });
-    transform_breaks_continues(loop, current_node);
-}
-
-void UhdmAst::process_var_select()
-{
-    current_node = make_ast_node(AST::AST_IDENTIFIER);
-    visit_one_to_many({vpiIndex}, obj_h, [&](AST::AstNode *node) {
-        if (node->str == current_node->str) {
-            for (auto child : node->children) {
-                current_node->children.push_back(child);
-            }
-            node->children.clear();
-            delete node;
-        } else {
-            auto range_node = new AST::AstNode(AST::AST_RANGE);
-            range_node->filename = current_node->filename;
-            range_node->location = current_node->location;
-            range_node->children.push_back(node);
-            current_node->children.push_back(range_node);
-        }
-    });
-}
-
-void UhdmAst::process_port()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    current_node->port_id = shared.next_port_id();
-    vpiHandle lowConn_h = vpi_handle(vpiLowConn, obj_h);
-    std::vector<AST::AstNode *> packed_ranges;   // comes before wire name
-    std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
-    if (lowConn_h) {
-        vpiHandle actual_h = vpi_handle(vpiActual, lowConn_h);
-        auto actual_type = vpi_get(vpiType, actual_h);
-        switch (actual_type) {
-        case vpiModport: {
-            vpiHandle iface_h = vpi_handle(vpiInterface, actual_h);
-            if (iface_h) {
-                std::string cellName, ifaceName;
-                if (auto s = vpi_get_str(vpiName, actual_h)) {
-                    cellName = s;
-                    sanitize_symbol_name(cellName);
-                }
-                if (auto s = vpi_get_str(vpiDefName, iface_h)) {
-                    ifaceName = s;
-                    sanitize_symbol_name(ifaceName);
-                }
-                current_node->type = AST::AST_INTERFACEPORT;
-                auto typeNode = new AST::AstNode(AST::AST_INTERFACEPORTTYPE);
-                // Skip '\' in cellName
-                typeNode->str = ifaceName + '.' + cellName.substr(1, cellName.length());
-                current_node->children.push_back(typeNode);
-                vpi_release_handle(iface_h);
-            }
-            break;
-        }
-        case vpiInterface: {
-            auto typeNode = new AST::AstNode(AST::AST_INTERFACEPORTTYPE);
-            if (auto s = vpi_get_str(vpiDefName, actual_h)) {
-                typeNode->str = s;
-                sanitize_symbol_name(typeNode->str);
-            }
-            current_node->type = AST::AST_INTERFACEPORT;
-            current_node->children.push_back(typeNode);
-            break;
-        }
-        case vpiLogicVar:
-        case vpiLogicNet: {
-            current_node->is_logic = true;
-            current_node->is_signed = vpi_get(vpiSigned, actual_h);
-            visit_one_to_many({vpiRange}, actual_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-            break;
-        }
-        case vpiPackedArrayVar:
-            visit_one_to_many({vpiElement}, actual_h, [&](AST::AstNode *node) {
-                if (node && GetSize(node->children) == 1) {
-                    current_node->children.push_back(node->children[0]->clone());
-                    if (node->children[0]->type == AST::AST_WIRETYPE) {
-                        current_node->is_custom_type = true;
-                    }
-                }
-                delete node;
-            });
-            visit_one_to_many({vpiRange}, actual_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-            break;
-        case vpiPackedArrayNet:
-            visit_one_to_many({vpiRange}, actual_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-            break;
-        case vpiArrayVar:
-            visit_one_to_many({vpiRange}, actual_h, [&](AST::AstNode *node) { unpacked_ranges.push_back(node); });
-            break;
-        case vpiEnumNet:
-        case vpiStructNet:
-        case vpiArrayNet:
-        case vpiStructVar:
-        case vpiUnionVar:
-        case vpiEnumVar:
-        case vpiBitVar:
-        case vpiByteVar:
-        case vpiShortIntVar:
-        case vpiLongIntVar:
-        case vpiIntVar:
-        case vpiIntegerVar:
-            break;
-        default: {
-            const uhdm_handle *const handle = (const uhdm_handle *)actual_h;
-            const UHDM::BaseClass *const object = (const UHDM::BaseClass *)handle->object;
-            report_error("%.*s:%d: Encountered unhandled type in process_port: %s\n", (int)object->VpiFile().length(), object->VpiFile().data(),
-                         object->VpiLineNo(), UHDM::VpiTypeName(actual_h).c_str());
-            break;
-        }
-        }
-        vpi_release_handle(actual_h);
-        vpi_release_handle(lowConn_h);
-    }
-    visit_one_to_one({vpiTypedef}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            if (current_node->children.empty() || current_node->children[0]->type != AST::AST_WIRETYPE) {
-                if (!node->str.empty()) {
-                    auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
-                    wiretype_node->str = node->str;
-                    // wiretype needs to be 1st node (if port have also another range nodes)
-                    current_node->children.insert(current_node->children.begin(), wiretype_node);
-                    current_node->is_custom_type = true;
-                } else {
-                    // anonymous typedef, just move children
-                    current_node->children = std::move(node->children);
-                }
-            }
-            current_node->is_signed = current_node->is_signed || node->is_signed;
-            delete node;
-        }
-    });
-    if (const int n = vpi_get(vpiDirection, obj_h)) {
-        if (n == vpiInput) {
-            current_node->is_input = true;
-        } else if (n == vpiOutput) {
-            current_node->is_output = true;
-        } else if (n == vpiInout) {
-            current_node->is_input = true;
-            current_node->is_output = true;
-        }
-    }
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-}
-
-void UhdmAst::process_net()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    auto net_type = vpi_get(vpiNetType, obj_h);
-    current_node->is_reg = net_type == vpiReg;
-    current_node->is_output = net_type == vpiOutput;
-    current_node->is_logic = !current_node->is_reg;
-    current_node->is_signed = vpi_get(vpiSigned, obj_h);
-    visit_one_to_one({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
-        if (!node)
-            return;
-        if (!node->str.empty()) {
-            auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
-            wiretype_node->str = node->str;
-            // wiretype needs to be 1st node
-            current_node->children.insert(current_node->children.begin(), wiretype_node);
-            current_node->is_custom_type = true;
-        } else {
-            // Ranges from the typespec are copied to the current node as attributes.
-            // So that multiranges can be replaced with a single range as a node later.
-            copy_packed_unpacked_attribute(node, current_node);
-        }
-        delete node;
-    });
-}
-
-void UhdmAst::process_parameter()
-{
-    auto type = vpi_get(vpiLocalParam, obj_h) == 1 ? AST::AST_LOCALPARAM : AST::AST_PARAMETER;
-    current_node = make_ast_node(type);
-    std::vector<AST::AstNode *> packed_ranges;   // comes before wire name
-    std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
-    visit_one_to_many({vpiRange}, obj_h, [&](AST::AstNode *node) { unpacked_ranges.push_back(node); });
-    vpiHandle typespec_h = vpi_handle(vpiTypespec, obj_h);
-    if (typespec_h) {
-        int typespec_type = vpi_get(vpiType, typespec_h);
-        switch (typespec_type) {
-        case vpiBitTypespec:
-        case vpiLogicTypespec: {
-            current_node->is_logic = true;
-            visit_one_to_many({vpiRange}, typespec_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-            break;
-        }
-        case vpiByteTypespec: {
-            packed_ranges.push_back(make_range(7, 0));
-            break;
-        }
-        case vpiEnumTypespec:
-        case vpiRealTypespec:
-        case vpiStringTypespec: {
-            break;
-        }
-        case vpiIntTypespec:
-        case vpiIntegerTypespec: {
-            visit_one_to_many({vpiRange}, typespec_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
-            if (packed_ranges.empty()) {
-                packed_ranges.push_back(make_range(31, 0));
-            }
-            break;
-        }
-        case vpiShortIntTypespec: {
-            packed_ranges.push_back(make_range(15, 0));
-            break;
-        }
-        case vpiTimeTypespec:
-        case vpiLongIntTypespec: {
-            packed_ranges.push_back(make_range(63, 0));
-            break;
-        }
-        case vpiUnionTypespec:
-        case vpiStructTypespec: {
-            visit_one_to_one({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
-                if (node && !node->str.empty()) {
-                    auto wiretype_node = make_ast_node(AST::AST_WIRETYPE);
-                    wiretype_node->str = node->str;
-                    current_node->children.push_back(wiretype_node);
-                }
-                current_node->is_custom_type = true;
-                auto it = shared.param_types.find(current_node->str);
-                if (it == shared.param_types.end()) {
-                    shared.param_types.insert(std::make_pair(current_node->str, node));
-                } else {
-                    delete node;
-                }
-            });
-            break;
-        }
-        case vpiPackedArrayTypespec:
-        case vpiArrayTypespec: {
-            visit_one_to_one({vpiElemTypespec}, typespec_h, [&](AST::AstNode *node) {
-                if (!node->str.empty()) {
-                    auto wiretype_node = make_ast_node(AST::AST_WIRETYPE);
-                    wiretype_node->str = node->str;
-                    current_node->children.push_back(wiretype_node);
-                    current_node->is_custom_type = true;
-                    auto it = shared.param_types.find(current_node->str);
-                    if (it == shared.param_types.end())
-                        shared.param_types.insert(std::make_pair(current_node->str, node->clone()));
-                }
-                if (node && node->attributes.count(UhdmAst::packed_ranges())) {
-                    for (auto r : node->attributes[UhdmAst::packed_ranges()]->children) {
-                        packed_ranges.push_back(r->clone());
-                    }
-                }
-                delete node;
-            });
-            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_parameter: '%.*s' of type '%s'\n", (int)object->VpiFile().length(),
-                         object->VpiFile().data(), object->VpiLineNo(), (int)object->VpiName().length(), object->VpiName().data(),
-                         UHDM::VpiTypeName(typespec_h).c_str());
-            break;
-        }
-        }
-        vpi_release_handle(typespec_h);
-    }
-    AST::AstNode *constant_node = process_value(obj_h);
-    if (constant_node) {
-        constant_node->filename = current_node->filename;
-        constant_node->location = current_node->location;
-        current_node->children.push_back(constant_node);
-    }
-    add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
-}
-
-void UhdmAst::process_byte_var()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    current_node->children.push_back(make_range(7, 0));
-    current_node->is_signed = vpi_get(vpiSigned, obj_h);
-}
-
-void UhdmAst::process_long_int_var()
-{
-    current_node = make_ast_node(AST::AST_WIRE);
-    current_node->children.push_back(make_range(63, 0));
-    current_node->is_signed = vpi_get(vpiSigned, obj_h);
-}
-
-void UhdmAst::process_immediate_cover()
-{
-    current_node = make_ast_node(AST::AST_COVER);
-    visit_one_to_one({vpiExpr}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            current_node->children.push_back(node);
-        }
-    });
-}
-
-void UhdmAst::process_immediate_assume()
-{
-    current_node = make_ast_node(AST::AST_ASSUME);
-    visit_one_to_one({vpiExpr}, obj_h, [&](AST::AstNode *node) {
-        if (node) {
-            current_node->children.push_back(node);
-        }
-    });
-}
-
-void UhdmAst::process_while()
-{
-    auto loop_id = shared.next_loop_id();
-    current_node = make_ast_node(AST::AST_BLOCK);
-    current_node->str = "$whiledecl_block" + std::to_string(loop_id);
-    auto *loop = make_ast_node(AST::AST_WHILE);
-    loop->str = "$loop" + std::to_string(loop_id);
-    current_node->children.push_back(loop);
-    visit_one_to_one({vpiCondition}, obj_h, [&](AST::AstNode *node) { loop->children.push_back(node); });
-    visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) {
-        if (node->type != AST::AST_BLOCK) {
-            node = make_ast_node(AST::AST_BLOCK, {node});
-        }
-        if (node->str.empty()) {
-            node->str = loop->str; // Needed in simplify step
-        }
-        loop->children.push_back(node);
-    });
-    transform_breaks_continues(loop, current_node);
-}
-
-void UhdmAst::process_gate()
-{
-    current_node = make_ast_node(AST::AST_PRIMITIVE);
-    switch (vpi_get(vpiPrimType, obj_h)) {
-    case vpiAndPrim:
-        current_node->str = "and";
-        break;
-    case vpiNandPrim:
-        current_node->str = "nand";
-        break;
-    case vpiNorPrim:
-        current_node->str = "nor";
-        break;
-    case vpiOrPrim:
-        current_node->str = "or";
-        break;
-    case vpiXorPrim:
-        current_node->str = "xor";
-        break;
-    case vpiXnorPrim:
-        current_node->str = "xnor";
-        break;
-    case vpiBufPrim:
-        current_node->str = "buf";
-        break;
-    case vpiNotPrim:
-        current_node->str = "not";
-        break;
-    default:
-        log_file_error(current_node->filename, current_node->location.first_line, "Encountered unhandled gate type: %s", current_node->str.c_str());
-        break;
-    }
-    visit_one_to_many({vpiPrimTerm}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(node); });
-}
-
-void UhdmAst::process_primterm()
-{
-    current_node = make_ast_node(AST::AST_ARGUMENT);
-    visit_one_to_one({vpiExpr}, obj_h, [&](AST::AstNode *node) { current_node->children.push_back(node); });
-}
-
-void UhdmAst::process_unsupported_stmt(const UHDM::BaseClass *object, bool is_error)
-{
-    const auto log_func = is_error ? log_error : log_warning;
-    std::string prefix = object->VpiLineNo() ? (std::string(object->VpiFile()) + ":" + std::to_string(object->VpiLineNo()) + ": ") : "";
-    log_func("%sCurrently not supported object of type '%s'\n", prefix.c_str(), UHDM::VpiTypeName(obj_h).c_str());
-}
-
-void UhdmAst::process_type_parameter()
-{
-    current_node = make_ast_node(AST::AST_PARAMETER);
-
-    // Use an attribute to distinguish "type parameters" from other parameters
-    set_attribute(current_node, attr_id::is_type_parameter, AST::AstNode::mkconst_int(1, false, 1));
-    std::string renamed_enum;
-
-    visit_one_to_one({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
-        if (!node)
-            return;
-
-        if (node->type == AST::AST_WIRE && node->str.empty()) {
-            // anonymous type
-            get_attribute(current_node, attr_id::is_type_parameter)->str = "anonymous_parameter" + std::to_string(shared.next_anonymous_type_id());
-            delete node;
-            return;
-        }
-
-        if (node->type == AST::AST_ENUM) {
-            // Enum typedefs are composed of AST_ENUM and AST_TYPEDEF where the enum shall be renamed,
-            // so that the original name used in code is assigned to the AST_TYPEDEF node,
-            // and a mangled name is assigned to the AST_ENUM node.
-            renamed_enum = node->str + "$enum" + std::to_string(shared.next_enum_id());
-        }
-
-        current_node->children.push_back(node->clone());
-
-        // The child stores information about the type assigned to the parameter
-        //   this information will be used to rename the module
-
-        // find the typedef for `node` in the upper scope and copy it to .children of the AST_PARAMETER node
-        // if unable to find the typedef, continue without error as this could be a globally available type
-
-        if (shared.current_top_node) {
-            for (auto child : shared.current_top_node->children) {
-                // name of the type we're looking for
-                if (child->str == node->str && child->type == AST::AST_TYPEDEF) {
-                    current_node->children.push_back(child->clone());
-                    break;
-                }
-            }
-        }
-        delete node;
-    });
-
-    if (!renamed_enum.empty()) {
-        for (auto child : current_node->children) {
-            if (child->type == AST::AST_TYPEDEF) {
-                log_assert(child->children.size() > 0);
-                set_attribute(child->children[0], ID::enum_type, AST::AstNode::mkconst_str(renamed_enum));
-            }
-            if (child->type == AST::AST_ENUM) {
-                child->str = renamed_enum;
-                // Names of enum variants need to be unique even accross Enums, otherwise Yosys fails.
-                for (auto grandchild : child->children) {
-                    grandchild->str = renamed_enum + "." + grandchild->str;
-                }
-            }
-        }
-    }
-}
-
-AST::AstNode *UhdmAst::process_object(vpiHandle obj_handle)
-{
-    obj_h = obj_handle;
-    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) {
-        UHDM::CompareContext ctx;
-        if (!object->Compare(obj, &ctx)) {
-            log_warning("%.*s:%d: Skipping non-synthesizable object of type '%s'\n", (int)object->VpiFile().length(), object->VpiFile().data(),
-                        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;
-    }
-
-    switch (object_type) {
-    case vpiDesign:
-        process_design();
-        break;
-    case vpiParameter:
-        process_parameter();
-        break;
-    case vpiPort:
-        process_port();
-        break;
-    case vpiModule:
-        process_module();
-        break;
-    case vpiStructTypespec:
-        process_struct_typespec();
-        break;
-    case vpiUnionTypespec:
-        process_union_typespec();
-        break;
-    case vpiPackedArrayTypespec:
-        process_packed_array_typespec();
-        break;
-    case vpiArrayTypespec:
-        process_array_typespec();
-        break;
-    case vpiTypespecMember:
-        process_typespec_member();
-        break;
-    case vpiEnumTypespec:
-        process_enum_typespec();
-        break;
-    case vpiEnumConst:
-        process_enum_const();
-        break;
-    case vpiEnumVar:
-    case vpiEnumNet:
-    case vpiStructVar:
-    case vpiStructNet:
-    case vpiUnionVar:
-        process_custom_var();
-        break;
-    case vpiShortIntVar:
-    case vpiIntVar:
-    case vpiIntegerVar:
-        process_int_var();
-        break;
-    case vpiShortRealVar:
-    case vpiRealVar:
-        process_real_var();
-        break;
-    case vpiPackedArrayVar:
-        process_packed_array_var();
-        break;
-    case vpiArrayVar:
-        process_array_var();
-        break;
-    case vpiParamAssign:
-        process_param_assign();
-        break;
-    case vpiContAssign:
-        process_cont_assign();
-        break;
-    case vpiAssignStmt:
-    case vpiAssignment:
-        process_assignment(object);
-        break;
-    case vpiInterfaceTypespec:
-    case vpiRefVar:
-    case vpiRefObj:
-        current_node = make_ast_node(AST::AST_IDENTIFIER);
-        break;
-    case vpiNet:
-        process_net();
-        break;
-    case vpiArrayNet:
-        process_array_net(object);
-        break;
-    case vpiPackedArrayNet:
-        process_packed_array_net();
-        break;
-    case vpiPackage:
-        process_package();
-        break;
-    case vpiInterface:
-        process_interface();
-        break;
-    case vpiModport:
-        process_modport();
-        break;
-    case vpiIODecl:
-        process_io_decl();
-        break;
-    case vpiAlways:
-        process_always();
-        break;
-    case vpiEventControl:
-        process_event_control(object);
-        break;
-    case vpiInitial:
-        process_initial();
-        break;
-    case vpiFinal:
-        process_unsupported_stmt(object, false);
-        break;
-    case vpiNamedBegin:
-        process_begin(true);
-        break;
-    case vpiBegin:
-        process_begin(false);
-        break;
-    case vpiCondition:
-    case vpiOperation:
-        process_operation(object);
-        break;
-    case vpiTaggedPattern:
-        process_tagged_pattern();
-        break;
-    case vpiBitSelect:
-        process_bit_select();
-        break;
-    case vpiPartSelect:
-        process_part_select();
-        break;
-    case vpiIndexedPartSelect:
-        process_indexed_part_select();
-        break;
-    case vpiVarSelect:
-        process_var_select();
-        break;
-    case vpiIf:
-    case vpiIfElse:
-        process_if_else();
-        break;
-    case vpiFor:
-        process_for();
-        break;
-    case vpiBreak:
-        // Will be resolved later by loop processor
-        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::Extended::AST_CONTINUE));
-        break;
-    case vpiGenScopeArray:
-        process_gen_scope_array();
-        break;
-    case vpiGenScope:
-        process_gen_scope();
-        break;
-    case vpiCase:
-        process_case();
-        break;
-    case vpiCaseItem:
-        process_case_item();
-        break;
-    case vpiConstant:
-        current_node = process_value(obj_h);
-        break;
-    case vpiRange:
-        process_range(object);
-        break;
-    case vpiReturn:
-        process_return();
-        break;
-    case vpiFunction:
-    case vpiTask:
-        process_function();
-        break;
-    case vpiBitVar:
-    case vpiLogicVar:
-        process_logic_var();
-        break;
-    case vpiSysFuncCall:
-        process_sys_func_call();
-        break;
-    case vpiFuncCall:
-        process_tf_call(AST::AST_FCALL);
-        break;
-    case vpiTaskCall:
-        process_tf_call(AST::AST_TCALL);
-        break;
-    case vpiImmediateAssert:
-        if (!shared.no_assert)
-            process_immediate_assert();
-        break;
-    case vpiAssert:
-        if (!shared.no_assert)
-            process_unsupported_stmt(object);
-        break;
-    case vpiHierPath:
-        process_hier_path();
-        break;
-    case UHDM::uhdmimport_typespec:
-        break;
-    case vpiLogicTypespec:
-        process_logic_typespec();
-        break;
-    case vpiIntTypespec:
-    case vpiIntegerTypespec:
-        process_int_typespec();
-        break;
-    case vpiShortIntTypespec:
-        process_shortint_typespec();
-        break;
-    case vpiLongIntTypespec:
-        process_longint_typespec();
-        break;
-    case vpiTimeTypespec:
-        process_time_typespec();
-        break;
-    case vpiBitTypespec:
-        process_bit_typespec();
-        break;
-    case vpiByteTypespec:
-        process_byte_typespec();
-        break;
-    case vpiStringVar:
-        process_string_var();
-        break;
-    case vpiStringTypespec:
-        process_string_typespec();
-        break;
-    case vpiRepeat:
-        process_repeat();
-        break;
-    case vpiByteVar:
-        process_byte_var();
-        break;
-    case vpiLongIntVar:
-        process_long_int_var();
-        break;
-    case vpiImmediateCover:
-        process_immediate_cover();
-        break;
-    case vpiImmediateAssume:
-        process_immediate_assume();
-        break;
-    case vpiAssume:
-        process_unsupported_stmt(object);
-        break;
-    case vpiWhile:
-        process_while();
-        break;
-    case vpiGate:
-        process_gate();
-        break;
-    case vpiPrimTerm:
-        process_primterm();
-        break;
-    case vpiClockingBlock:
-        process_unsupported_stmt(object);
-        break;
-    case vpiTypeParameter:
-        process_type_parameter();
-        break;
-    case vpiProgram:
-    default:
-        report_error("%.*s:%d: Encountered unhandled object '%.*s' of type '%s'\n", (int)object->VpiFile().length(), object->VpiFile().data(),
-                     object->VpiLineNo(), (int)object->VpiName().length(), object->VpiName().data(), UHDM::VpiTypeName(obj_h).c_str());
-        break;
-    }
-
-    // Check if we initialized the node in switch-case
-    if (current_node) {
-        if (current_node->type != AST::AST_NONE) {
-            return current_node;
-        }
-    }
-    return nullptr;
-}
-
-AST::AstNode *UhdmAst::visit_designs(const std::vector<vpiHandle> &designs)
-{
-    attr_id_init();
-
-    current_node = new AST::AstNode(AST::AST_DESIGN);
-    for (auto design : designs) {
-        UhdmAst ast(this, shared, indent);
-        auto *processed_design_node = ast.process_object(design);
-        // Flatten multiple designs into one
-        current_node->children = std::move(processed_design_node->children);
-        delete processed_design_node;
-    }
-
-    for (auto &[name, node] : shared.param_types) {
-        delete node;
-    }
-    shared.param_types.clear();
-
-    // Remove all internal attributes from the AST.
-    visitEachDescendant(current_node, delete_internal_attributes);
-
-    attr_id_cleanup();
-
-    return current_node;
-}
-
-void UhdmAst::report_error(const char *format, ...) const
-{
-    va_list args;
-    va_start(args, format);
-    if (shared.stop_on_error) {
-        logv_error(format, args);
-    } else {
-        logv_warning(format, args);
-    }
-}
-
-} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/UhdmAst.h b/systemverilog-plugin/UhdmAst.h
deleted file mode 100644
index d60e827..0000000
--- a/systemverilog-plugin/UhdmAst.h
+++ /dev/null
@@ -1,327 +0,0 @@
-#ifndef _UHDM_AST_H_
-#define _UHDM_AST_H_ 1
-
-#include "frontends/ast/ast.h"
-#include <vector>
-#undef cover
-
-#include "uhdmastshared.h"
-#include <memory>
-#include <uhdm/uhdm.h>
-
-namespace systemverilog_plugin
-{
-
-class AstNodeBuilder;
-
-class UhdmAst
-{
-  private:
-    // Logging method for exclusive use of `uhdmast_assert` macro.
-    void uhdmast_assert_log(const char *expr_str, const char *func, const char *file, int line) const;
-
-    // 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(::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(::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(::Yosys::AST::AstNode *)> &f);
-
-    // Visit the default expression assigned to a variable.
-    void visit_default_expr(vpiHandle obj_h);
-
-    // Reads location info (start/end line/column numbers, file name) from `obj_h` and sets them on `target_node`.
-    void apply_location_from_current_obj(::Yosys::AST::AstNode &target_node) const;
-    // Reads object name from `obj_h` and assigns it to `target_node`.
-    void apply_name_from_current_obj(::Yosys::AST::AstNode &target_node) const;
-
-    // Creates node of specified `type` with location properties read from `obj_h`.
-    AstNodeBuilder make_node(::Yosys::AST::AstNodeType type) const;
-    // Creates node of specified `type` with location properties and name read from `obj_h`.
-    AstNodeBuilder make_named_node(::Yosys::AST::AstNodeType type) const;
-    // Creates AST_IDENTIFIER node with specified `id` and location properties read from `obj_h`.
-    AstNodeBuilder make_ident(std::string id) const;
-    // Creates signed AST_CONSTANT node with specified `value` and location properties read from `obj_h`.
-    AstNodeBuilder make_const(int32_t value, uint8_t width = 32) const;
-    // Creates unsigned AST_CONSTANT node with specified `value` and location properties read from `obj_h`.
-    AstNodeBuilder make_const(uint32_t value, uint8_t width = 32) const;
-
-    // Create an AstNode of the specified type with metadata extracted from
-    // the given vpiHandle.
-    // OBSOLETE: use `make_node` or `make_named_node` instead.
-    ::Yosys::AST::AstNode *make_ast_node(::Yosys::AST::AstNodeType type, std::vector<::Yosys::AST::AstNode *> children = {});
-
-    // Create an identifier AstNode
-    // OBSOLETE: use `make_ident` instead.
-    ::Yosys::AST::AstNode *make_identifier(std::string name);
-
-    // Makes the passed node a cell node of the specified 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(::Yosys::AST::AstNode *current_node, ::Yosys::AST::AstNode *type_node);
-
-    // Go up the UhdmAst to find a parent node of the specified type
-    ::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
-    ::Yosys::AST::AstNode *process_value(vpiHandle obj_h);
-
-    // Transforms break and continue nodes into structures accepted by the AST frontend
-    void transform_breaks_continues(::Yosys::AST::AstNode *loop, ::Yosys::AST::AstNode *decl_block);
-
-    // The parent UhdmAst
-    UhdmAst *parent;
-
-    // Data shared between all UhdmAst objects
-    UhdmAstShared &shared;
-
-    // The current VPI/UHDM handle
-    vpiHandle obj_h = 0;
-
-    // The current Yosys AST node
-    ::Yosys::AST::AstNode *current_node = nullptr;
-
-    // Indentation used for debug printing
-    std::string indent;
-
-    // Mapping of names that should be replaced to new names
-    std::unordered_map<std::string, std::string> node_renames;
-
-    // Functions that process specific types of nodes
-    void process_design();
-    void process_parameter();
-    void process_port();
-    void process_module();
-    void process_struct_typespec();
-    void process_union_typespec();
-    void process_packed_array_typespec();
-    void process_array_typespec();
-    void process_typespec_member();
-    void process_enum_typespec();
-    void process_enum_const();
-    void process_custom_var();
-    void process_int_var();
-    void process_real_var();
-    void process_array_var();
-    void process_packed_array_var();
-    void process_param_assign();
-    void process_cont_assign();
-    void process_cont_assign_net();
-    void process_cont_assign_var_init();
-    void process_assignment(const UHDM::BaseClass *object);
-    void process_net();
-    void process_packed_array_net();
-    void process_array_net(const UHDM::BaseClass *object);
-    void process_package();
-    void process_interface();
-    void process_modport();
-    void process_io_decl();
-    void process_always();
-    void process_event_control(const UHDM::BaseClass *object);
-    void process_initial();
-    void process_begin(bool is_named);
-    void process_operation(const UHDM::BaseClass *object);
-    void process_stream_op();
-    void process_list_op();
-    void process_cast_op();
-    void process_inside_op();
-    void process_assignment_pattern_op();
-    void process_tagged_pattern();
-    void process_bit_select();
-    void process_part_select();
-    void process_indexed_part_select();
-    void process_var_select();
-    void process_if_else();
-    void process_for();
-    void process_gen_scope_array();
-    void process_gen_scope();
-    void process_case();
-    void process_case_item();
-    void process_range(const UHDM::BaseClass *object);
-    void process_return();
-    void process_function();
-    void process_logic_var();
-    void process_sys_func_call();
-    // use for task calls and function calls
-    void process_tf_call(::Yosys::AST::AstNodeType type);
-    void process_immediate_assert();
-    void process_hier_path();
-    void process_logic_typespec();
-    void process_int_typespec();
-    void process_shortint_typespec();
-    void process_longint_typespec();
-    void process_time_typespec();
-    void process_bit_typespec();
-    void process_string_var();
-    void process_string_typespec();
-    void process_repeat();
-    void process_byte_var();
-    void process_byte_typespec();
-    void process_long_int_var();
-    void process_immediate_cover();
-    void process_immediate_assume();
-    void process_while();
-    void process_gate();
-    void process_primterm();
-    void process_type_parameter();
-    void simplify_parameter(::Yosys::AST::AstNode *parameter, ::Yosys::AST::AstNode *module_node = nullptr);
-    void process_unsupported_stmt(const UHDM::BaseClass *object, bool is_error = true);
-
-    UhdmAst(UhdmAst *p, UhdmAstShared &s, const std::string &i) : parent(p), shared(s), indent(i)
-    {
-        if (parent)
-            node_renames = parent->node_renames;
-    }
-
-  public:
-    UhdmAst(UhdmAstShared &s, const std::string &i = "") : UhdmAst(nullptr, s, i) {}
-
-    // Visits single VPI object and creates proper AST node
-    ::Yosys::AST::AstNode *process_object(vpiHandle obj_h);
-
-    // Visits all VPI design objects and returns created ASTs
-    ::Yosys::AST::AstNode *visit_designs(const std::vector<vpiHandle> &designs);
-
-    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 ::Yosys::IdString &force_convert();
-    static const ::Yosys::IdString &is_imported();
-    static const ::Yosys::IdString &is_simplified_wire();
-    static const ::Yosys::IdString &low_high_bound();
-    static const ::Yosys::IdString &is_elaborated_module();
-};
-
-// Utility for building AstNode trees.
-//
-// The object members that set AstNode properties return rvalue reference to *this (i.e. to the builder object), so they can be chained.
-// The children list is set using call operator (`builder_object({child0, child1, ...})`).
-// Build finalization is done through cast operator to either `AstNode*` or `std::unique_ptr<AstNode>`.
-//
-// Usage example:
-//
-// 1. Define one or more factory functions for creating base AstNode object:
-//
-//     const auto make_node = [](AST::AstNodeType type) {
-//         auto node = std::make_unique<AST::AstNode>(type);
-//         // ...initialize the node if needed...
-//         return AstNodeBuilder(std::move(node));
-//     };
-//
-// 2. Use the factories to create a tree:
-//
-//     // AST::AstNode *const variable_node = ...
-//     // AST::AstNode *const value_node = ...
-//     AST::AstNode *const assign = //
-//       (make_node(AST::AST_ASSIGN_EQ))({
-//         (make_node(AST::AST_IDENTIFIER).str(variable_node->str)),
-//         (make_node(Yosys::AST::AST_ADD))({
-//           (make_node(AST::AST_IDENTIFIER).str(value_node->str)),
-//           (make_node(AST::AST_CONSTANT).value(4)),
-//         }),
-//       });
-//
-// In the real code instead of custom factories illustrated in point 1 above, you probably should use predefined methods from `UhdmAst` class.
-// The syntax above puts the factory call and all its method calls (but not the function call operator with the children list) in `()`. This is done
-// to make `clang-format` format the code as presented. Otherwise it is heavily wrapped and a lot less readable. `()` are technically not required
-// in leafs to make them format as expected, but its nice to use them for consistency.
-class AstNodeBuilder
-{
-    using AstNode = ::Yosys::AST::AstNode;
-    using AstNodeType = ::Yosys::AST::AstNodeType;
-
-    std::unique_ptr<AstNode> node;
-
-  public:
-    explicit AstNodeBuilder(AstNodeType node_type) : node(new AstNode(node_type)) {}
-    explicit AstNodeBuilder(std::unique_ptr<AstNode> node) : node(std::move(node)) {}
-    ~AstNodeBuilder() { log_assert(node == nullptr); }
-
-    AstNodeBuilder(AstNodeBuilder &&) = default;
-
-    AstNodeBuilder() = delete;
-    AstNodeBuilder(const AstNodeBuilder &) = delete;
-    AstNodeBuilder &operator=(const AstNodeBuilder &) = delete;
-    AstNodeBuilder &operator=(AstNodeBuilder &&) = delete;
-
-    // Property setters
-
-    // Sets `AstNode::children` vector
-    AstNodeBuilder &&operator()(std::vector<AstNode *> children) { return node->children = std::move(children), std::move(*this); }
-
-    // Sets `AstNode::str` value.
-    AstNodeBuilder &&str(std::string s) { return node->str = std::move(s), std::move(*this); }
-
-    // Sets `AstNode::integer` value.
-    AstNodeBuilder &&integer(uint32_t v) { return node->integer = v, std::move(*this); }
-
-    // Sets `AstNode::is_signed` value.
-    AstNodeBuilder &&is_signed(bool v) { return node->is_signed = v, std::move(*this); }
-
-    // Sets `AstNode::is_reg` value.
-    AstNodeBuilder &&is_reg(bool v) { return node->is_reg = v, std::move(*this); }
-
-    // Sets `AstNode::range_valid`.
-    AstNodeBuilder &&range_valid(bool v) { return node->range_valid = v, std::move(*this); }
-
-    // Convenience range setters
-
-    // Sets `AstNode::range_left`, `AstNode::range_right`, `AstNode::range_valid`.
-    AstNodeBuilder &&range(bool v, int left = -1, int right = 0)
-    {
-        node->range_valid = v;
-        node->range_left = left;
-        node->range_right = right;
-        return std::move(*this);
-    }
-
-    // Sets `AstNode::range_left`, `AstNode::range_right`, `AstNode::range_valid = true`.
-    AstNodeBuilder &&range(int left, int right) { return range(true, left, right); }
-
-    // Convenience value setters, mainly for constants.
-
-    // Sets node's value.
-    // Sets: `AstNode::integer`, `AstNode::is_signed`, `AstNode::bits`.
-    AstNodeBuilder &&value(uint32_t v, bool is_signed, int width = 32)
-    {
-        log_assert(width >= 0);
-        node->integer = v;
-        node->is_signed = is_signed;
-        // `AstNode::mkconst_int` does this too.
-        for (int i = 0; i < width; i++) {
-            node->bits.push_back((v & 1) ? Yosys::RTLIL::State::S1 : Yosys::RTLIL::State::S0);
-            v = v >> 1;
-        }
-        range(width - 1, 0);
-        return std::move(*this);
-    }
-
-    // Sets node's value to signed 32 bit integer.
-    // Sets: `AstNode::integer`, `AstNode::is_signed`, `AstNode::bits`.
-    AstNodeBuilder &&value(int32_t v) { return value(v, true); }
-
-    // Sets node's value to unsigned 32 bit integer.
-    // Sets: `AstNode::integer`, `AstNode::is_signed`, `AstNode::bits`.
-    AstNodeBuilder &&value(uint32_t v) { return value(v, false); }
-
-    // Type-cast operators used for building.
-
-    operator AstNode *() { return node.release(); }
-
-    operator std::unique_ptr<AstNode>() { return std::move(node); }
-};
-
-} // namespace systemverilog_plugin
-
-#endif
diff --git a/systemverilog-plugin/tests/Makefile b/systemverilog-plugin/tests/Makefile
deleted file mode 100644
index 3caff14..0000000
--- a/systemverilog-plugin/tests/Makefile
+++ /dev/null
@@ -1,41 +0,0 @@
-# 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
-
-TESTS = counter \
-		break_continue \
-		separate-compilation \
-		debug-flag \
-		defines \
-		defaults \
-		formal \
-		translate_off
-
-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
-defaults_verify = true
-defines_verify = true
-formal_verify = true
-translate_off_verify = true
-
-.PHONY: systemverilog_tests_clean
-systemverilog_tests_clean:
-	@rm -rf $(foreach test,$(TESTS),$(test)/tmp)
-
-clean: systemverilog_tests_clean
diff --git a/systemverilog-plugin/tests/break_continue/break_continue.golden.out b/systemverilog-plugin/tests/break_continue/break_continue.golden.out
deleted file mode 100644
index 74a27c2..0000000
--- a/systemverilog-plugin/tests/break_continue/break_continue.golden.out
+++ /dev/null
@@ -1,2 +0,0 @@
-top	a	-	-	po	110
-top	b	-	-	po	15
diff --git a/systemverilog-plugin/tests/break_continue/break_continue.tcl b/systemverilog-plugin/tests/break_continue/break_continue.tcl
deleted file mode 100644
index d496367..0000000
--- a/systemverilog-plugin/tests/break_continue/break_continue.tcl
+++ /dev/null
@@ -1,11 +0,0 @@
-yosys -import
-if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
-yosys -import  ;# ingest plugin commands
-
-set TMP_DIR $::env(TEST_OUTPUT_PREFIX)/tmp
-file mkdir $TMP_DIR
-
-# Testing simple round-trip
-read_systemverilog -o $TMP_DIR $::env(DESIGN_TOP).v
-prep
-write_table [test_output_path $::env(DESIGN_TOP).out]
diff --git a/systemverilog-plugin/tests/break_continue/break_continue.v b/systemverilog-plugin/tests/break_continue/break_continue.v
deleted file mode 100644
index d06d60b..0000000
--- a/systemverilog-plugin/tests/break_continue/break_continue.v
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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(output int a, output int b);
-   initial begin
-      a = 0;
-      b = 0;
-      repeat(15) begin
-         if(a > 100) begin
-            if (b > 10)
-               break;
-            b = b + 5;
-            continue;
-         end
-         a = a + 10;
-      end
-   end
-endmodule
diff --git a/systemverilog-plugin/tests/counter/counter.tcl b/systemverilog-plugin/tests/counter/counter.tcl
deleted file mode 100644
index 28a4447..0000000
--- a/systemverilog-plugin/tests/counter/counter.tcl
+++ /dev/null
@@ -1,10 +0,0 @@
-yosys -import
-if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
-yosys -import  ;# ingest plugin commands
-
-set TMP_DIR $::env(TEST_OUTPUT_PREFIX)/tmp
-file mkdir $TMP_DIR
-
-# Testing simple round-trip
-read_systemverilog -o $TMP_DIR $::env(DESIGN_TOP).v
-write_verilog
diff --git a/systemverilog-plugin/tests/counter/counter.v b/systemverilog-plugin/tests/counter/counter.v
deleted file mode 100644
index 3dabd7e..0000000
--- a/systemverilog-plugin/tests/counter/counter.v
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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
-);
-  localparam BITS = 4;
-  localparam LOG2DELAY = 22;
-
-  wire bufg;
-  BUFG bufgctrl (
-      .I(clk),
-      .O(bufg)
-  );
-  reg [BITS+LOG2DELAY-1:0] counter = 0;
-  always @(posedge bufg) begin
-    counter <= counter + 1;
-  end
-  assign led[3:0] = counter >> LOG2DELAY;
-endmodule
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv b/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv
deleted file mode 100644
index 565946b..0000000
--- a/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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
deleted file mode 100644
index b0362fc..0000000
--- a/systemverilog-plugin/tests/debug-flag/debug-flag-pkg.sv
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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
deleted file mode 100644
index 3b3a568..0000000
--- a/systemverilog-plugin/tests/debug-flag/debug-flag.tcl
+++ /dev/null
@@ -1,14 +0,0 @@
-yosys -import
-if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
-yosys -import  ;# ingest plugin commands
-
-set TMP_DIR $::env(TEST_OUTPUT_PREFIX)/tmp
-file mkdir $TMP_DIR
-
-# Testing simple round-trip
-read_systemverilog -debug -odir $TMP_DIR -defer $::env(DESIGN_TOP)-pkg.sv
-read_systemverilog -debug -odir $TMP_DIR -defer $::env(DESIGN_TOP)-buf.sv
-read_systemverilog -debug -odir $TMP_DIR -defer $::env(DESIGN_TOP).v
-read_systemverilog -debug -odir $TMP_DIR -link
-hierarchy
-write_verilog
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag.v b/systemverilog-plugin/tests/debug-flag/debug-flag.v
deleted file mode 100644
index 5bd294a..0000000
--- a/systemverilog-plugin/tests/debug-flag/debug-flag.v
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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
deleted file mode 100644
index 804d2e5..0000000
--- a/systemverilog-plugin/tests/defaults/defaults.tcl
+++ /dev/null
@@ -1,21 +0,0 @@
-yosys -import
-if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
-yosys -import  ;# ingest plugin commands
-
-set TMP_DIR $::env(TEST_OUTPUT_PREFIX)/tmp
-file mkdir $TMP_DIR
-
-# Define forbidden value
-systemverilog_defaults -add -DPAKALA
-# Stash it
-systemverilog_defaults -push
-systemverilog_defaults -clear
-read_systemverilog -o $TMP_DIR $::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 -o $TMP_DIR $::env(DESIGN_TOP).v
-hierarchy
-write_verilog
diff --git a/systemverilog-plugin/tests/defaults/defaults.v b/systemverilog-plugin/tests/defaults/defaults.v
deleted file mode 100644
index f565a77..0000000
--- a/systemverilog-plugin/tests/defaults/defaults.v
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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
deleted file mode 100644
index 14b37ad..0000000
--- a/systemverilog-plugin/tests/defines/defines.tcl
+++ /dev/null
@@ -1,13 +0,0 @@
-yosys -import
-if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
-yosys -import  ;# ingest plugin commands
-
-set TMP_DIR $::env(TEST_OUTPUT_PREFIX)/tmp
-file mkdir $TMP_DIR
-
-systemverilog_defines -DPONA
-systemverilog_defines -DPAKALA
-systemverilog_defines -UPAKALA
-read_systemverilog -o $TMP_DIR $::env(DESIGN_TOP).v
-hierarchy
-write_verilog
diff --git a/systemverilog-plugin/tests/defines/defines.v b/systemverilog-plugin/tests/defines/defines.v
deleted file mode 100644
index 528e9f1..0000000
--- a/systemverilog-plugin/tests/defines/defines.v
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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/formal/formal.tcl b/systemverilog-plugin/tests/formal/formal.tcl
deleted file mode 100644
index b2590d3..0000000
--- a/systemverilog-plugin/tests/formal/formal.tcl
+++ /dev/null
@@ -1,10 +0,0 @@
-yosys -import
-if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
-yosys -import  ;# ingest plugin commands
-
-set TMP_DIR $::env(TEST_OUTPUT_PREFIX)/tmp
-file mkdir $TMP_DIR
-
-read_systemverilog -o $TMP_DIR -formal $::env(DESIGN_TOP).v
-hierarchy
-write_verilog
diff --git a/systemverilog-plugin/tests/formal/formal.v b/systemverilog-plugin/tests/formal/formal.v
deleted file mode 100644
index 04e346c..0000000
--- a/systemverilog-plugin/tests/formal/formal.v
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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
-);
-
-`ifdef SYNTHESIS
-  initial $stop("SYNTHESIS should be undefined");
-`endif
-`ifndef YOSYS
-  initial $stop("YOSYS should be defined");
-`endif
-`ifndef FORMAL
-  initial $stop("FORMAL should be defined");
-`endif
-  assign out = clk;
-endmodule
diff --git a/systemverilog-plugin/tests/separate-compilation/separate-compilation-buf.sv b/systemverilog-plugin/tests/separate-compilation/separate-compilation-buf.sv
deleted file mode 100644
index 565946b..0000000
--- a/systemverilog-plugin/tests/separate-compilation/separate-compilation-buf.sv
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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/separate-compilation/separate-compilation-pkg.sv b/systemverilog-plugin/tests/separate-compilation/separate-compilation-pkg.sv
deleted file mode 100644
index b0362fc..0000000
--- a/systemverilog-plugin/tests/separate-compilation/separate-compilation-pkg.sv
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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/separate-compilation/separate-compilation.tcl b/systemverilog-plugin/tests/separate-compilation/separate-compilation.tcl
deleted file mode 100644
index 46b029a..0000000
--- a/systemverilog-plugin/tests/separate-compilation/separate-compilation.tcl
+++ /dev/null
@@ -1,14 +0,0 @@
-yosys -import
-if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
-yosys -import  ;# ingest plugin commands
-
-set TMP_DIR $::env(TEST_OUTPUT_PREFIX)/tmp
-file mkdir $TMP_DIR
-
-# Testing simple round-trip
-read_systemverilog -odir $TMP_DIR -defer $::env(DESIGN_TOP)-pkg.sv
-read_systemverilog -odir $TMP_DIR -defer $::env(DESIGN_TOP)-buf.sv
-read_systemverilog -odir $TMP_DIR -defer $::env(DESIGN_TOP).v
-read_systemverilog -odir $TMP_DIR -link
-hierarchy
-write_verilog
diff --git a/systemverilog-plugin/tests/separate-compilation/separate-compilation.v b/systemverilog-plugin/tests/separate-compilation/separate-compilation.v
deleted file mode 100644
index 5bd294a..0000000
--- a/systemverilog-plugin/tests/separate-compilation/separate-compilation.v
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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/translate_off/translate_off.tcl b/systemverilog-plugin/tests/translate_off/translate_off.tcl
deleted file mode 100644
index d836d1e..0000000
--- a/systemverilog-plugin/tests/translate_off/translate_off.tcl
+++ /dev/null
@@ -1,8 +0,0 @@
-yosys -import
-if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
-yosys -import  ;# ingest plugin commands
-
-set TMP_DIR $::env(TEST_OUTPUT_PREFIX)/tmp
-file mkdir $TMP_DIR
-
-read_systemverilog -o $TMP_DIR $::env(DESIGN_TOP).v
diff --git a/systemverilog-plugin/tests/translate_off/translate_off.v b/systemverilog-plugin/tests/translate_off/translate_off.v
deleted file mode 100644
index 3ca8840..0000000
--- a/systemverilog-plugin/tests/translate_off/translate_off.v
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2020-2023 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 i, output o);
-    // synopsys translate_off
-    initial $stop("Code between translate_off...translate_on should be ignored.");
-    // synopsys translate_on
-    assign o = i;
-endmodule
diff --git a/systemverilog-plugin/third_party/yosys/README b/systemverilog-plugin/third_party/yosys/README
deleted file mode 100644
index df69e69..0000000
--- a/systemverilog-plugin/third_party/yosys/README
+++ /dev/null
@@ -1,31 +0,0 @@
-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.
-- simplify.cc: yosys/frontends/ast/simplify.cc (rev. ceef00c)
-  - The file is a part of Yosys AST frontend. It has been placed in the plugin,
-    as in some cases we need to adjust it to support certain functionalities
-    in the plugin. Since it is included now in the plugin, we can skip caling
-    the original Yosys' simplify() during AST preparation. The original Yosys'
-    simplify() is only called in uhdmcommonfrontend.cc when Yosys' process()
-    is called, after having AST done.
-  - Changes:
-    - Removed unneeded code and member functions of AstNode::
-    - Modified usage of AstNode:: members that are called from the Yosys'
-      AstNode:: struct.
-  - The file will be extended in the future instead of simplify_sv()
-    in UhdmAst.cc, and it will be moved to other directory then.
-
-Non-copied files placed here for interfacing purposes:
-
-- const2ast.h
-- simplify.h
diff --git a/systemverilog-plugin/third_party/yosys/const2ast.cc b/systemverilog-plugin/third_party/yosys/const2ast.cc
deleted file mode 100644
index 96ea6cc..0000000
--- a/systemverilog-plugin/third_party/yosys/const2ast.cc
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- *  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
deleted file mode 100644
index f7130a2..0000000
--- a/systemverilog-plugin/third_party/yosys/const2ast.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#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/third_party/yosys/simplify.cc b/systemverilog-plugin/third_party/yosys/simplify.cc
deleted file mode 100644
index cdc39b4..0000000
--- a/systemverilog-plugin/third_party/yosys/simplify.cc
+++ /dev/null
@@ -1,4086 +0,0 @@
-/*
- *  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.
- *
- *  ---
- *
- *  This is the AST frontend library.
- *
- *  The AST frontend library is not a frontend on it's own but provides a
- *  generic abstract syntax tree (AST) abstraction for HDL code and can be
- *  used by HDL frontends. See "ast.h" for an overview of the API and the
- *  Verilog frontend for an usage example.
- *
- */
-
-#include "kernel/log.h"
-#include "libs/sha1/sha1.h"
-
-#include "const2ast.h"
-
-#include <sstream>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include "simplify.h"
-
-YOSYS_NAMESPACE_BEGIN
-namespace VERILOG_FRONTEND
-{
-extern bool sv_mode;
-}
-YOSYS_NAMESPACE_END
-
-namespace systemverilog_plugin
-{
-
-using namespace ::Yosys;
-using namespace ::Yosys::AST_INTERNAL;
-
-void annotateTypedEnums(Yosys::AST::AstNode *ast_node, Yosys::AST::AstNode *template_node)
-{
-	//check if enum
-	if (template_node->attributes.count(ID::enum_type)) {
-		//get reference to enum node:
-		std::string enum_type = template_node->attributes[ID::enum_type]->str.c_str();
-		//			log("enum_type=%s (count=%lu)\n", enum_type.c_str(), current_scope.count(enum_type));
-		//			log("current scope:\n");
-		//			for (auto &it : current_scope)
-		//				log("  %s\n", it.first.c_str());
-		log_assert(current_scope.count(enum_type) == 1);
-		Yosys::AST::AstNode *enum_node = current_scope.at(enum_type);
-		log_assert(enum_node->type == Yosys::AST::AST_ENUM);
-		while (simplify(enum_node, true, false, false, 1, -1, false, true)) { }
-		//get width from 1st enum item:
-		log_assert(enum_node->children.size() >= 1);
-		Yosys::AST::AstNode *enum_item0 = enum_node->children[0];
-		log_assert(enum_item0->type == Yosys::AST::AST_ENUM_ITEM);
-		int width;
-		if (!enum_item0->range_valid)
-			width = 1;
-		else if (enum_item0->range_swapped)
-			width = enum_item0->range_right - enum_item0->range_left + 1;
-		else
-			width = enum_item0->range_left - enum_item0->range_right + 1;
-		log_assert(width > 0);
-		//add declared enum items:
-		for (auto enum_item : enum_node->children){
-			log_assert(enum_item->type == Yosys::AST::AST_ENUM_ITEM);
-			//get is_signed
-			bool is_signed;
-			if (enum_item->children.size() == 1){
-				is_signed = false;
-			} else if (enum_item->children.size() == 2){
-				log_assert(enum_item->children[1]->type == Yosys::AST::AST_RANGE);
-				is_signed = enum_item->children[1]->is_signed;
-			} else {
-				log_error("enum_item children size==%lu, expected 1 or 2 for %s (%s)\n",
-						  enum_item->children.size(),
-						  enum_item->str.c_str(), enum_node->str.c_str()
-				);
-			}
-			//start building attribute string
-			std::string enum_item_str = "\\enum_value_";
-			//get enum item value
-			if(enum_item->children[0]->type != Yosys::AST::AST_CONSTANT){
-				log_error("expected const, got %s for %s (%s)\n",
-						  type2str(enum_item->children[0]->type).c_str(),
-						  enum_item->str.c_str(), enum_node->str.c_str()
-						);
-			}
-			RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed);
-			enum_item_str.append(val.as_string());
-			//set attribute for available val to enum item name mappings
-			ast_node->attributes[enum_item_str.c_str()] = Yosys::AST::AstNode::mkconst_str(enum_item->str);
-		}
-	}
-}
-
-static bool name_has_dot(const std::string &name, std::string &struct_name)
-{
-	// check if plausible struct member name \sss.mmm
-	std::string::size_type pos;
-	if (name.substr(0, 1) == "\\" && (pos = name.find('.', 0)) != std::string::npos) {
-		struct_name = name.substr(0, pos);
-		return true;
-	}
-	return false;
-}
-
-static Yosys::AST::AstNode *make_range(int left, int right, bool is_signed = false)
-{
-	// generate a pre-validated range node for a fixed signal range.
-	auto range = new Yosys::AST::AstNode(Yosys::AST::AST_RANGE);
-	range->range_left = left;
-	range->range_right = right;
-	range->range_valid = true;
-	range->children.push_back(Yosys::AST::AstNode::mkconst_int(left, true));
-	range->children.push_back(Yosys::AST::AstNode::mkconst_int(right, true));
-	range->is_signed = is_signed;
-	return range;
-}
-
-static int range_width(Yosys::AST::AstNode *node, Yosys::AST::AstNode *rnode)
-{
-	log_assert(rnode->type==Yosys::AST::AST_RANGE);
-	if (!rnode->range_valid) {
-		log_file_error(node->filename, node->location.first_line, "Size must be constant in packed struct/union member %s\n", node->str.c_str());
-
-	}
-	// note: range swapping has already been checked for
-	return rnode->range_left - rnode->range_right + 1;
-}
-
-[[noreturn]] static void struct_array_packing_error(Yosys::AST::AstNode *node)
-{
-	log_file_error(node->filename, node->location.first_line, "Unpacked array in packed struct/union member %s\n", node->str.c_str());
-}
-
-static void save_struct_range_dimensions(Yosys::AST::AstNode *node, Yosys::AST::AstNode *rnode)
-{
-	node->multirange_dimensions.push_back(rnode->range_right);
-	node->multirange_dimensions.push_back(range_width(node, rnode));
-	node->multirange_swapped.push_back(rnode->range_swapped);
-}
-
-static int get_struct_range_offset(Yosys::AST::AstNode *node, int dimension)
-{
-	return node->multirange_dimensions[2*dimension];
-}
-
-static int get_struct_range_width(Yosys::AST::AstNode *node, int dimension)
-{
-	return node->multirange_dimensions[2*dimension + 1];
-}
-
-static int size_packed_struct(Yosys::AST::AstNode *snode, int base_offset)
-{
-	// Struct members will be laid out in the structure contiguously from left to right.
-	// Union members all have zero offset from the start of the union.
-	// Determine total packed size and assign offsets.  Store these in the member node.
-	bool is_union = (snode->type == Yosys::AST::AST_UNION);
-	int offset = 0;
-	int packed_width = -1;
-
-	// embedded struct or union with range?
-	auto it = std::remove_if(snode->children.begin(), snode->children.end(), [](Yosys::AST::AstNode *node) { return node->type == Yosys::AST::AST_RANGE; });
-	std::vector<Yosys::AST::AstNode *> ranges(it, snode->children.end());
-	snode->children.erase(it, snode->children.end());
-	if (!ranges.empty()) {
-		if (ranges.size() > 1) {
-			log_file_error(ranges[1]->filename, ranges[1]->location.first_line,
-						   "Currently support for custom-type with range is limited to single range\n");
-		}
-		for (auto range : ranges) {
-			snode->multirange_dimensions.push_back(min(range->range_left, range->range_right));
-			snode->multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1);
-			snode->multirange_swapped.push_back(range->range_swapped);
-		}
-	}
-	// examine members from last to first
-	for (auto it = snode->children.rbegin(); it != snode->children.rend(); ++it) {
-		auto node = *it;
-		int width;
-		if (node->type == Yosys::AST::AST_STRUCT || node->type == Yosys::AST::AST_UNION) {
-			// embedded struct or union
-			width = size_packed_struct(node, base_offset + offset);
-			// set range of struct
-			node->range_right = base_offset + offset;
-			node->range_left = base_offset + offset + width - 1;
-			node->range_valid = true;
-		}
-		else {
-			log_assert(node->type == Yosys::AST::AST_STRUCT_ITEM);
-			if (node->children.size() > 0 && node->children[0]->type == Yosys::AST::AST_RANGE) {
-				// member width e.g. bit [7:0] a
-				width = range_width(node, node->children[0]);
-				if (node->children.size() == 2) {
-					// Unpacked array. Note that this is a Yosys extension; only packed data types
-					// and integer data types are allowed in packed structs / unions in SystemVerilog.
-					if (node->children[1]->type == Yosys::AST::AST_RANGE) {
-						// Unpacked array, e.g. bit [63:0] a [0:3]
-						auto rnode = node->children[1];
-						if (rnode->children.size() == 1) {
-							// C-style array size, e.g. bit [63:0] a [4]
-							node->multirange_dimensions.push_back(0);
-							node->multirange_dimensions.push_back(rnode->range_left);
-							node->multirange_swapped.push_back(true);
-							width *= rnode->range_left;
-						} else {
-							save_struct_range_dimensions(node, rnode);
-							width *= range_width(node, rnode);
-						}
-						save_struct_range_dimensions(node, node->children[0]);
-					}
-					else {
-						// The Yosys extension for unpacked arrays in packed structs / unions
-						// only supports memories, i.e. e.g. logic [7:0] a [256] - see above.
-						struct_array_packing_error(node);
-					}
-				} else {
-					// Vector
-					save_struct_range_dimensions(node, node->children[0]);
-				}
-				// range nodes are now redundant
-				for (Yosys::AST::AstNode *child : node->children)
-					delete child;
-				node->children.clear();
-			}
-			else if (node->children.size() > 0 && node->children[0]->type == Yosys::AST::AST_MULTIRANGE) {
-				// Packed array, e.g. bit [3:0][63:0] a
-				if (node->children.size() != 1) {
-					// The Yosys extension for unpacked arrays in packed structs / unions
-					// only supports memories, i.e. e.g. logic [7:0] a [256] - see above.
-					struct_array_packing_error(node);
-				}
-				width = 1;
-				for (auto rnode : node->children[0]->children) {
-					save_struct_range_dimensions(node, rnode);
-					width *= range_width(node, rnode);
-				}
-				// range nodes are now redundant
-				for (Yosys::AST::AstNode *child : node->children)
-					delete child;
-				node->children.clear();
-			}
-			else if (node->range_left < 0) {
-				// 1 bit signal: bit, logic or reg
-				width = 1;
-			}
-			else {
-				// already resolved and compacted
-				width = node->range_left - node->range_right + 1;
-			}
-			if (is_union) {
-				node->range_right = base_offset;
-				node->range_left = base_offset + width - 1;
-			}
-			else {
-				node->range_right = base_offset + offset;
-				node->range_left = base_offset + offset + width - 1;
-			}
-			node->range_valid = true;
-		}
-		if (is_union) {
-			// check that all members have the same size
-			if (packed_width == -1) {
-				// first member
-				packed_width = width;
-			}
-			else {
-				if (packed_width != width) {
-
-					log_file_error(node->filename, node->location.first_line, "member %s of a packed union has %d bits, expecting %d\n", node->str.c_str(), width, packed_width);
-				}
-			}
-		}
-		else {
-			offset += width;
-		}
-	}
-	return (is_union ? packed_width : offset);
-}
-
-Yosys::AST::AstNode *get_struct_member(const Yosys::AST::AstNode *node)
-{
-	Yosys::AST::AstNode *member_node;
-	if (node->attributes.count(ID::wiretype) && (member_node = node->attributes.at(ID::wiretype)) &&
-	    (member_node->type == Yosys::AST::AST_STRUCT_ITEM || member_node->type == Yosys::AST::AST_STRUCT || member_node->type == Yosys::AST::AST_UNION))
-	{
-		return member_node;
-	}
-	return NULL;
-}
-
-static void add_members_to_scope(Yosys::AST::AstNode *snode, std::string name)
-{
-	// add all the members in a struct or union to local scope
-	// in case later referenced in assignments
-	log_assert(snode->type==Yosys::AST::AST_STRUCT || snode->type==Yosys::AST::AST_UNION);
-	for (auto *node : snode->children) {
-		auto member_name = name + "." + node->str;
-		current_scope[member_name] = node;
-		if (node->type != Yosys::AST::AST_STRUCT_ITEM) {
-			// embedded struct or union
-			add_members_to_scope(node, name + "." + node->str);
-		}
-	}
-}
-
-static int get_max_offset(Yosys::AST::AstNode *node)
-{
-	// get the width from the MS member in the struct
-	// as members are laid out from left to right in the packed wire
-	log_assert(node->type==Yosys::AST::AST_STRUCT || node->type==Yosys::AST::AST_UNION);
-	while (node->type != Yosys::AST::AST_STRUCT_ITEM) {
-		node = node->children[0];
-	}
-	return node->range_left;
-}
-
-static Yosys::AST::AstNode *make_packed_struct(Yosys::AST::AstNode *template_node, std::string &name)
-{
-	// create a wire for the packed struct
-	auto wnode = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE);
-	wnode->str = name;
-	wnode->is_logic = true;
-	wnode->range_valid = true;
-	wnode->is_signed = template_node->is_signed;
-	int offset = get_max_offset(template_node);
-	auto range = make_range(offset, 0);
-	wnode->children.push_back(range);
-	// make sure this node is the one in scope for this name
-	current_scope[name] = wnode;
-	// add all the struct members to scope under the wire's name
-	add_members_to_scope(template_node, name);
-	return wnode;
-}
-
-// check if a node or its children contains an assignment to the given variable
-static bool node_contains_assignment_to(const Yosys::AST::AstNode* node, const Yosys::AST::AstNode* var)
-{
-	if (node->type == Yosys::AST::AST_ASSIGN_EQ || node->type == Yosys::AST::AST_ASSIGN_LE) {
-		// current node is iteslf an assignment
-		log_assert(node->children.size() >= 2);
-		const Yosys::AST::AstNode* lhs = node->children[0];
-		if (lhs->type == Yosys::AST::AST_IDENTIFIER && lhs->str == var->str)
-			return false;
-	}
-	for (const Yosys::AST::AstNode* child : node->children) {
-		// if this child shadows the given variable
-		if (child != var && child->str == var->str && child->type == Yosys::AST::AST_WIRE)
-			break; // skip the remainder of this block/scope
-		// depth-first short circuit
-		if (!node_contains_assignment_to(child, var))
-			return false;
-	}
-	return true;
-}
-
-static std::string prefix_id(const std::string &prefix, const std::string &str)
-{
-	log_assert(!prefix.empty() && (prefix.front() == '$' || prefix.front() == '\\'));
-	log_assert(!str.empty() && (str.front() == '$' || str.front() == '\\'));
-	log_assert(prefix.back() == '.');
-	if (str.front() == '\\')
-		return prefix + str.substr(1);
-	return prefix + str;
-}
-
-// returns whether an expression contains an unbased unsized literal; does not
-// check the literal exists in a self-determined context
-static bool contains_unbased_unsized(const Yosys::AST::AstNode *node)
-{
-	if (node->type == Yosys::AST::AST_CONSTANT)
-		return node->is_unsized;
-	for (const Yosys::AST::AstNode *child : node->children)
-		if (contains_unbased_unsized(child))
-			return true;
-	return false;
-}
-
-// adds a wire to the current module with the given name that matches the
-// dimensions of the given wire reference
-void add_wire_for_ref(const RTLIL::Wire *ref, const std::string &str)
-{
-	Yosys::AST::AstNode *left = Yosys::AST::AstNode::mkconst_int(ref->width - 1 + ref->start_offset, true);
-	Yosys::AST::AstNode *right = Yosys::AST::AstNode::mkconst_int(ref->start_offset, true);
-	if (ref->upto)
-		std::swap(left, right);
-	Yosys::AST::AstNode *range = new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, left, right);
-
-	Yosys::AST::AstNode *wire = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE, range);
-	wire->is_signed = ref->is_signed;
-	wire->is_logic = true;
-	wire->str = str;
-
-	current_ast_mod->children.push_back(wire);
-	current_scope[str] = wire;
-}
-
-enum class IdentUsage {
-	NotReferenced, // target variable is neither read or written in the block
-	Assigned, // target variable is always assigned before use
-	SyncRequired, // target variable may be used before it has been assigned
-};
-
-// determines whether a local variable a block is always assigned before it is
-// used, meaning the nosync attribute can automatically be added to that
-// variable
-static IdentUsage always_asgn_before_use(const Yosys::AST::AstNode *node, const std::string &target)
-{
-	// This variable has been referenced before it has necessarily been assigned
-	// a value in this procedure.
-	if (node->type == Yosys::AST::AST_IDENTIFIER && node->str == target)
-		return IdentUsage::SyncRequired;
-
-	// For case statements (which are also used for if/else), we check each
-	// possible branch. If the variable is assigned in all branches, then it is
-	// assigned, and a sync isn't required. If it used before assignment in any
-	// branch, then a sync is required.
-	if (node->type == Yosys::AST::AST_CASE) {
-		bool all_defined = true;
-		bool any_used = false;
-		bool has_default = false;
-		for (const Yosys::AST::AstNode *child : node->children) {
-			if (child->type == Yosys::AST::AST_COND && child->children.at(0)->type == Yosys::AST::AST_DEFAULT)
-				has_default = true;
-			IdentUsage nested = always_asgn_before_use(child, target);
-			if (nested != IdentUsage::Assigned && child->type == Yosys::AST::AST_COND)
-				all_defined = false;
-			if (nested == IdentUsage::SyncRequired)
-				any_used = true;
-		}
-		if (any_used)
-			return IdentUsage::SyncRequired;
-		else if (all_defined && has_default)
-			return IdentUsage::Assigned;
-		else
-			return IdentUsage::NotReferenced;
-	}
-
-	// Check if this is an assignment to the target variable. For simplicity, we
-	// don't analyze sub-ranges of the variable.
-	if (node->type == Yosys::AST::AST_ASSIGN_EQ) {
-		const Yosys::AST::AstNode *ident = node->children.at(0);
-		if (ident->type == Yosys::AST::AST_IDENTIFIER && ident->str == target)
-			return IdentUsage::Assigned;
-	}
-
-	for (const Yosys::AST::AstNode *child : node->children) {
-		IdentUsage nested = always_asgn_before_use(child, target);
-		if (nested != IdentUsage::NotReferenced)
-			return nested;
-	}
-	return IdentUsage::NotReferenced;
-}
-
-static const std::string auto_nosync_prefix = "\\AutoNosync";
-
-// mark a local variable in an always_comb block for automatic nosync
-// consideration
-static void mark_auto_nosync(Yosys::AST::AstNode *block, const Yosys::AST::AstNode *wire)
-{
-	log_assert(block->type == Yosys::AST::AST_BLOCK);
-	log_assert(wire->type == Yosys::AST::AST_WIRE);
-	block->attributes[auto_nosync_prefix + wire->str] = Yosys::AST::AstNode::mkconst_int(1,
-			false);
-}
-
-// block names can be prefixed with an explicit scope during elaboration
-static bool is_autonamed_block(const std::string &str) {
-	size_t last_dot = str.rfind('.');
-	// unprefixed names: autonamed if the first char is a dollar sign
-	if (last_dot == std::string::npos)
-		return str.at(0) == '$'; // e.g., `$fordecl_block$1`
-	// prefixed names: autonamed if the final chunk begins with a dollar sign
-	return str.rfind(".$") == last_dot; // e.g., `\foo.bar.$fordecl_block$1`
-}
-
-// check a procedural block for auto-nosync markings, remove them, and add
-// nosync to local variables as necessary
-static void check_auto_nosync(Yosys::AST::AstNode *node)
-{
-	std::vector<RTLIL::IdString> attrs_to_drop;
-	for (const auto& elem : node->attributes) {
-		// skip attributes that don't begin with the prefix
-		if (elem.first.compare(0, auto_nosync_prefix.size(),
-					auto_nosync_prefix.c_str()))
-			continue;
-
-		// delete and remove the attribute once we're done iterating
-		attrs_to_drop.push_back(elem.first);
-
-		// find the wire based on the attribute
-		std::string wire_name = elem.first.substr(auto_nosync_prefix.size());
-		auto it = current_scope.find(wire_name);
-		if (it == current_scope.end())
-			continue;
-
-		// analyze the usage of the local variable in this block
-		IdentUsage ident_usage = always_asgn_before_use(node, wire_name);
-		if (ident_usage != IdentUsage::Assigned)
-			continue;
-
-		// mark the wire with `nosync`
-		Yosys::AST::AstNode *wire = it->second;
-		log_assert(wire->type == Yosys::AST::AST_WIRE);
-		wire->attributes[ID::nosync] = node->mkconst_int(1, false);
-	}
-
-	// remove the attributes we've "consumed"
-	for (const RTLIL::IdString &str : attrs_to_drop) {
-		auto it = node->attributes.find(str);
-		delete it->second;
-		node->attributes.erase(it);
-	}
-
-	// check local variables in any nested blocks
-	for (Yosys::AST::AstNode *child : node->children)
-		check_auto_nosync(child);
-}
-
-static inline std::string encode_filename(const std::string &filename)
-{    
-    std::stringstream val; 
-    if (!std::any_of(filename.begin(), filename.end(), [](char c) { 
-        return static_cast<unsigned char>(c) < 33 || static_cast<unsigned char>(c) > 126; 
-    })) return filename;
-    for (unsigned char const c : filename) {
-        if (c < 33 || c > 126) 
-            val << stringf("$%02x", c);
-        else 
-            val << c;
-    }    
-    return val.str();
-}
-
-// convert the AST into a simpler AST that has all parameters substituted by their
-// values, unrolled for-loops, expanded generate blocks, etc. when this function
-// is done with an AST it can be converted into RTLIL using genRTLIL().
-//
-// this function also does all name resolving and sets the id2ast member of all
-// nodes that link to a different node using names and lexical scoping.
-bool simplify(Yosys::AST::AstNode *ast_node, bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
-{
-	static int recursion_counter = 0;
-	static bool deep_recursion_warning = false;
-
-	if (recursion_counter++ == 1000 && deep_recursion_warning) {
-		log_warning("Deep recursion in AST simplifier.\nDoes this design contain overly long or deeply nested expressions, or excessive recursion?\n");
-		deep_recursion_warning = false;
-	}
-
-	static bool unevaluated_tern_branch = false;
-
-	Yosys::AST::AstNode *newNode = NULL;
-	bool did_something = false;
-
-#if 0
-	log("-------------\n");
-	log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), location.first_line, type2str(type).c_str(), this);
-	log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n",
-			int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param));
-	// dumpAst(NULL, "> ");
-#endif
-
-	if (stage == 0)
-	{
-		log_assert(ast_node->type == Yosys::AST::AST_MODULE || ast_node->type == Yosys::AST::AST_INTERFACE);
-
-		deep_recursion_warning = true;
-		while (simplify(ast_node, const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
-
-		if (!flag_nomem2reg && !ast_node->get_bool_attribute(ID::nomem2reg))
-		{
-			dict<Yosys::AST::AstNode*, pool<std::string>> mem2reg_places;
-			dict<Yosys::AST::AstNode*, uint32_t> mem2reg_candidates, dummy_proc_flags;
-			uint32_t flags = flag_mem2reg ? Yosys::AST::AstNode::MEM2REG_FL_ALL : 0;
-			ast_node->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, dummy_proc_flags, flags); // not sure if correct MAND
-
-			pool<Yosys::AST::AstNode*> mem2reg_set;
-			for (auto &it : mem2reg_candidates)
-			{
-				Yosys::AST::AstNode *mem = it.first;
-				uint32_t memflags = it.second;
-				bool this_nomeminit = flag_nomeminit;
-				log_assert((memflags & ~0x00ffff00) == 0);
-
-				if (mem->get_bool_attribute(ID::nomem2reg))
-					continue;
-
-				if (mem->get_bool_attribute(ID::nomeminit) || ast_node->get_bool_attribute(ID::nomeminit))
-					this_nomeminit = true;
-
-				if (memflags & Yosys::AST::AstNode::MEM2REG_FL_FORCED)
-					goto silent_activate;
-
-				if (memflags & Yosys::AST::AstNode::MEM2REG_FL_EQ2)
-					goto verbose_activate;
-
-				if (memflags & Yosys::AST::AstNode::MEM2REG_FL_SET_ASYNC)
-					goto verbose_activate;
-
-				if ((memflags & Yosys::AST::AstNode::MEM2REG_FL_SET_INIT) && (memflags & Yosys::AST::AstNode::MEM2REG_FL_SET_ELSE) && this_nomeminit)
-					goto verbose_activate;
-
-				if (memflags & Yosys::AST::AstNode::MEM2REG_FL_CMPLX_LHS)
-					goto verbose_activate;
-
-				if ((memflags & Yosys::AST::AstNode::MEM2REG_FL_CONST_LHS) && !(memflags & Yosys::AST::AstNode::MEM2REG_FL_VAR_LHS))
-					goto verbose_activate;
-
-				// log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags));
-				continue;
-
-			verbose_activate:
-				if (mem2reg_set.count(mem) == 0) {
-					std::string message = stringf("Replacing memory %s with list of registers.", mem->str.c_str());
-					bool first_element = true;
-					for (auto &place : mem2reg_places[it.first]) {
-						message += stringf("%s%s", first_element ? " See " : ", ", place.c_str());
-						first_element = false;
-					}
-					log_warning("%s\n", message.c_str());
-				}
-
-			silent_activate:
-				// log("Note: Replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags));
-				mem2reg_set.insert(mem);
-			}
-
-			for (auto node : mem2reg_set)
-			{
-				int mem_width, mem_size, addr_bits;
-				node->meminfo(mem_width, mem_size, addr_bits);
-
-				int data_range_left = node->children[0]->range_left;
-				int data_range_right = node->children[0]->range_right;
-
-				if (node->children[0]->range_swapped)
-					std::swap(data_range_left, data_range_right);
-
-				for (int i = 0; i < mem_size; i++) {
-					Yosys::AST::AstNode *reg = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE, new Yosys::AST::AstNode(Yosys::AST::AST_RANGE,
-							node->mkconst_int(data_range_left, true), node->mkconst_int(data_range_right, true)));
-					reg->str = stringf("%s[%d]", node->str.c_str(), i);
-					reg->is_reg = true;
-					reg->is_signed = node->is_signed;
-					for (auto &it : node->attributes)
-						if (it.first != ID::mem2reg)
-							reg->attributes.emplace(it.first, it.second->clone());
-					reg->filename = node->filename;
-					reg->location = node->location;
-					ast_node->children.push_back(reg);
-					while (simplify(reg, true, false, false, 1, -1, false, false)) { } // <- not sure about reg being the first arg here...
-				}
-			}
-
-			Yosys::AST::AstNode *async_block = NULL;
-			while (ast_node->mem2reg_as_needed_pass2(mem2reg_set, ast_node, NULL, async_block)) { }
-
-			vector<Yosys::AST::AstNode*> delnodes;
-			ast_node->mem2reg_remove(mem2reg_set, delnodes);
-
-			for (auto node : delnodes)
-				delete node;
-		}
-
-		while (simplify(ast_node, const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { }
-		recursion_counter--;
-		return false;
-	}
-
-	Yosys::AST::current_filename = ast_node->filename;
-
-	// we do not look inside a task or function
-	// (but as soon as a task or function is instantiated we process the generated AST as usual)
-	if (ast_node->type == Yosys::AST::AST_FUNCTION || ast_node->type == Yosys::AST::AST_TASK) {
-		recursion_counter--;
-		return false;
-	}
-
-	// deactivate all calls to non-synthesis system tasks
-	// note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list
-	if ((ast_node->type == Yosys::AST::AST_FCALL || ast_node->type == Yosys::AST::AST_TCALL) && (ast_node->str == "$strobe" || ast_node->str == "$monitor" || ast_node->str == "$time" ||
-			ast_node->str == "$dumpfile" || ast_node->str == "$dumpvars" || ast_node->str == "$dumpon" || ast_node->str == "$dumpoff" || ast_node->str == "$dumpall")) {
-		log_file_warning(ast_node->filename, ast_node->location.first_line, "Ignoring call to system %s %s.\n", ast_node->type == Yosys::AST::AST_FCALL ? "function" : "task", ast_node->str.c_str());
-		ast_node->delete_children();
-		ast_node->str = std::string();
-	}
-
-	if ((ast_node->type == Yosys::AST::AST_TCALL) && (ast_node->str == "$display" || ast_node->str == "$write") && (!current_always || current_always->type != Yosys::AST::AST_INITIAL)) {
-		log_file_warning(ast_node->filename, ast_node->location.first_line, "System task `%s' outside initial block is unsupported.\n", ast_node->str.c_str());
-		ast_node->delete_children();
-		ast_node->str = std::string();
-	}
-
-	// print messages if this a call to $display() or $write()
-	// This code implements only a small subset of Verilog-2005 $display() format specifiers,
-	// but should be good enough for most uses
-	if ((ast_node->type == Yosys::AST::AST_TCALL) && ((ast_node->str == "$display") || (ast_node->str == "$write")))
-	{
-		int nargs = GetSize(ast_node->children);
-		if (nargs < 1)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "System task `%s' got %d arguments, expected >= 1.\n",
-					ast_node->str.c_str(), int(ast_node->children.size()));
-
-		// First argument is the format string
-		Yosys::AST::AstNode *node_string = ast_node->children[0];
-		while (simplify(node_string, true, false, false, stage, width_hint, sign_hint, false)) { }
-		if (node_string->type != Yosys::AST::AST_CONSTANT)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", ast_node->str.c_str());
-		std::string sformat = node_string->bitsAsConst().decode_string();
-		std::string sout = ast_node->process_format_str(sformat, 1, stage, width_hint, sign_hint);
-		// Finally, print the message (only include a \n for $display, not for $write)
-		log("%s", sout.c_str());
-		if (ast_node->str == "$display")
-			log("\n");
-		ast_node->delete_children();
-		ast_node->str = std::string();
-	}
-
-	// activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.)
-	if (ast_node->type == Yosys::AST::AST_WIRE || ast_node->type == Yosys::AST::AST_PARAMETER || ast_node->type == Yosys::AST::AST_LOCALPARAM || ast_node->type == Yosys::AST::AST_ENUM_ITEM || ast_node->type == Yosys::AST::AST_DEFPARAM || ast_node->type == Yosys::AST::AST_PARASET || ast_node->type == Yosys::AST::AST_RANGE || ast_node->type == Yosys::AST::AST_PREFIX || ast_node->type == Yosys::AST::AST_TYPEDEF)
-		const_fold = true;
-	if (ast_node->type == Yosys::AST::AST_IDENTIFIER && current_scope.count(ast_node->str) > 0 && (current_scope[ast_node->str]->type == Yosys::AST::AST_PARAMETER || current_scope[ast_node->str]->type == Yosys::AST::AST_LOCALPARAM || current_scope[ast_node->str]->type == Yosys::AST::AST_ENUM_ITEM))
-		const_fold = true;
-
-	// in certain cases a function must be evaluated constant. this is what in_param controls.
-	if (ast_node->type == Yosys::AST::AST_PARAMETER || ast_node->type == Yosys::AST::AST_LOCALPARAM || ast_node->type == Yosys::AST::AST_DEFPARAM || ast_node->type == Yosys::AST::AST_PARASET || ast_node->type == Yosys::AST::AST_PREFIX)
-		in_param = true;
-
-	std::map<std::string, Yosys::AST::AstNode*> backup_scope;
-
-	// create name resolution entries for all objects with names
-	// also merge multiple declarations for the same wire (e.g. "output foobar; reg foobar;")
-	if (ast_node->type == Yosys::AST::AST_MODULE || ast_node->type == Yosys::AST::AST_INTERFACE) {
-		current_scope.clear();
-		std::set<std::string> existing;
-		int counter = 0;
-		ast_node->label_genblks(existing, counter);
-		std::map<std::string, Yosys::AST::AstNode*> this_wire_scope;
-		for (size_t i = 0; i < ast_node->children.size(); i++) {
-			Yosys::AST::AstNode *node = ast_node->children[i];
-
-			if (node->type == Yosys::AST::AST_WIRE) {
-				if (node->children.size() == 1 && node->children[0]->type == Yosys::AST::AST_RANGE) {
-					for (auto c : node->children[0]->children) {
-						if (!c->is_simple_const_expr()) {
-							if (ast_node->attributes.count(ID::dynports))
-								delete ast_node->attributes.at(ID::dynports);
-							node->attributes[ID::dynports] = node->mkconst_int(1, true);
-						}
-					}
-				}
-				if (this_wire_scope.count(node->str) > 0) {
-					Yosys::AST::AstNode *first_node = this_wire_scope[node->str];
-					if (first_node->is_input && node->is_reg)
-						goto wires_are_incompatible;
-					if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0)
-						goto wires_are_compatible;
-					if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == Yosys::AST::AST_RANGE) {
-						Yosys::AST::AstNode *r = node->children[0];
-						if (r->range_valid && r->range_left == 0 && r->range_right == 0) {
-							delete r;
-							node->children.pop_back();
-						}
-					}
-					if (first_node->children.size() != node->children.size())
-						goto wires_are_incompatible;
-					for (size_t j = 0; j < node->children.size(); j++) {
-						Yosys::AST::AstNode *n1 = first_node->children[j], *n2 = node->children[j];
-						if (n1->type == Yosys::AST::AST_RANGE && n2->type == Yosys::AST::AST_RANGE && n1->range_valid && n2->range_valid) {
-							if (n1->range_left != n2->range_left)
-								goto wires_are_incompatible;
-							if (n1->range_right != n2->range_right)
-								goto wires_are_incompatible;
-						} else if (*n1 != *n2)
-							goto wires_are_incompatible;
-					}
-					if (first_node->range_left != node->range_left)
-						goto wires_are_incompatible;
-					if (first_node->range_right != node->range_right)
-						goto wires_are_incompatible;
-					if (first_node->port_id == 0 && (node->is_input || node->is_output))
-						goto wires_are_incompatible;
-				wires_are_compatible:
-					if (node->is_input)
-						first_node->is_input = true;
-					if (node->is_output)
-						first_node->is_output = true;
-					if (node->is_reg)
-						first_node->is_reg = true;
-					if (node->is_logic)
-						first_node->is_logic = true;
-					if (node->is_signed)
-						first_node->is_signed = true;
-					for (auto &it : node->attributes) {
-						if (first_node->attributes.count(it.first) > 0)
-							delete first_node->attributes[it.first];
-						first_node->attributes[it.first] = it.second->clone();
-					}
-					ast_node->children.erase(ast_node->children.begin()+(i--));
-					did_something = true;
-					delete node;
-					continue;
-				wires_are_incompatible:
-					if (stage > 1)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Incompatible re-declaration of wire %s.\n", node->str.c_str());
-					continue;
-				}
-				this_wire_scope[node->str] = node;
-			}
-			// these nodes appear at the top level in a module and can define names
-			if (node->type == Yosys::AST::AST_PARAMETER || node->type == Yosys::AST::AST_LOCALPARAM || node->type == Yosys::AST::AST_WIRE || node->type == Yosys::AST::AST_AUTOWIRE || node->type == Yosys::AST::AST_GENVAR ||
-					node->type == Yosys::AST::AST_MEMORY || node->type == Yosys::AST::AST_FUNCTION || node->type == Yosys::AST::AST_TASK || node->type == Yosys::AST::AST_DPI_FUNCTION || node->type == Yosys::AST::AST_CELL ||
-					node->type == Yosys::AST::AST_TYPEDEF) {
-				backup_scope[node->str] = current_scope[node->str];
-				current_scope[node->str] = node;
-			}
-			if (node->type == Yosys::AST::AST_ENUM) {
-				current_scope[node->str] = node;
-				for (auto enode : node->children) {
-					log_assert(enode->type==Yosys::AST::AST_ENUM_ITEM);
-					if (current_scope.count(enode->str) == 0)
-						current_scope[enode->str] = enode;
-					else
-						log_file_error(ast_node->filename, ast_node->location.first_line, "enum item %s already exists\n", enode->str.c_str());
-				}
-			}
-		}
-		for (size_t i = 0; i < ast_node->children.size(); i++) {
-			Yosys::AST::AstNode *node = ast_node->children[i];
-			if (node->type == Yosys::AST::AST_PARAMETER || node->type == Yosys::AST::AST_LOCALPARAM || node->type == Yosys::AST::AST_WIRE || node->type == Yosys::AST::AST_AUTOWIRE || node->type == Yosys::AST::AST_MEMORY || node->type == Yosys::AST::AST_TYPEDEF)
-				while (simplify(node, true, false, false, 1, -1, false, node->type == Yosys::AST::AST_PARAMETER || node->type == Yosys::AST::AST_LOCALPARAM))
-					did_something = true;
-			if (node->type == Yosys::AST::AST_ENUM) {
-				for (auto enode : node->children){
-					log_assert(enode->type==Yosys::AST::AST_ENUM_ITEM);
-					while (simplify(node, true, false, false, 1, -1, false, in_param))
-						did_something = true;
-				}
-			}
-		}
-
-		for (Yosys::AST::AstNode *child : ast_node->children)
-			if (child->type == Yosys::AST::AST_ALWAYS &&
-					child->attributes.count(ID::always_comb))
-				check_auto_nosync(child);
-	}
-
-	// create name resolution entries for all objects with names
-	if (ast_node->type == Yosys::AST::AST_PACKAGE) {
-		//add names to package scope
-		for (size_t i = 0; i < ast_node->children.size(); i++) {
-			Yosys::AST::AstNode *node = ast_node->children[i];
-			// these nodes appear at the top level in a package and can define names
-			if (node->type == Yosys::AST::AST_PARAMETER || node->type == Yosys::AST::AST_LOCALPARAM || node->type == Yosys::AST::AST_TYPEDEF || node->type == Yosys::AST::AST_FUNCTION || node->type == Yosys::AST::AST_TASK) {
-				current_scope[node->str] = node;
-			}
-			if (node->type == Yosys::AST::AST_ENUM) {
-				current_scope[node->str] = node;
-				for (auto enode : node->children) {
-					log_assert(enode->type==Yosys::AST::AST_ENUM_ITEM);
-					if (current_scope.count(enode->str) == 0)
-						current_scope[enode->str] = enode;
-					else
-						log_file_error(ast_node->filename, ast_node->location.first_line, "enum item %s already exists in package\n", enode->str.c_str());
-				}
-			}
-		}
-	}
-
-
-	auto backup_current_block = current_block;
-	auto backup_current_block_child = current_block_child;
-	auto backup_current_top_block = current_top_block;
-	auto backup_current_always = current_always;
-	auto backup_current_always_clocked = current_always_clocked;
-
-	if (ast_node->type == Yosys::AST::AST_ALWAYS || ast_node->type == Yosys::AST::AST_INITIAL)
-	{
-		if (current_always != nullptr)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Invalid nesting of always blocks and/or initializations.\n");
-
-		current_always = ast_node;
-		current_always_clocked = false;
-
-		if (ast_node->type == Yosys::AST::AST_ALWAYS)
-			for (auto child : ast_node->children) {
-				if (child->type == Yosys::AST::AST_POSEDGE || child->type == Yosys::AST::AST_NEGEDGE)
-					current_always_clocked = true;
-				if (child->type == Yosys::AST::AST_EDGE && GetSize(child->children) == 1 &&
-						child->children[0]->type == Yosys::AST::AST_IDENTIFIER && child->children[0]->str == "\\$global_clock")
-					current_always_clocked = true;
-			}
-	}
-
-	if (ast_node->type == Yosys::AST::AST_CELL) {
-		bool lookup_suggested = false;
-
-		for (Yosys::AST::AstNode *child : ast_node->children) {
-			// simplify any parameters to constants
-			if (child->type == Yosys::AST::AST_PARASET)
-				while (simplify(child, true, false, false, 1, -1, false, true)) { }
-
-			// look for patterns which _may_ indicate ambiguity requiring
-			// resolution of the underlying module
-			if (child->type == Yosys::AST::AST_ARGUMENT) {
-				if (child->children.size() != 1)
-					continue;
-				const Yosys::AST::AstNode *value = child->children[0];
-				if (value->type == Yosys::AST::AST_IDENTIFIER) {
-					const Yosys::AST::AstNode *elem = value->id2ast;
-					if (elem == nullptr) {
-						if (current_scope.count(value->str))
-							elem = current_scope.at(value->str);
-						else
-							continue;
-					}
-					if (elem->type == Yosys::AST::AST_MEMORY)
-						// need to determine is the is a read or wire
-						lookup_suggested = true;
-					else if (elem->type == Yosys::AST::AST_WIRE && elem->is_signed && !value->children.empty())
-						// this may be a fully sliced signed wire which needs
-						// to be indirected to produce an unsigned connection
-						lookup_suggested = true;
-				}
-				else if (contains_unbased_unsized(value))
-					// unbased unsized literals extend to width of the context
-					lookup_suggested = true;
-			}
-		}
-
-		const RTLIL::Module *module = nullptr;
-		if (lookup_suggested)
-			module = ast_node->lookup_cell_module();
-		if (module) {
-			size_t port_counter = 0;
-			for (Yosys::AST::AstNode *child : ast_node->children) {
-				if (child->type != Yosys::AST::AST_ARGUMENT)
-					continue;
-
-				// determine the full name of port this argument is connected to
-				RTLIL::IdString port_name;
-				if (child->str.size())
-					port_name = child->str;
-				else {
-					if (port_counter >= module->ports.size())
-						log_file_error(ast_node->filename, ast_node->location.first_line,
-								"Cell instance has more ports than the module!\n");
-					port_name = module->ports[port_counter++];
-				}
-
-				// find the port's wire in the underlying module
-				const RTLIL::Wire *ref = module->wire(port_name);
-				if (ref == nullptr)
-					log_file_error(ast_node->filename, ast_node->location.first_line,
-							"Cell instance refers to port %s which does not exist in module %s!.\n",
-							log_id(port_name), log_id(module->name));
-
-				// select the argument, if present
-				log_assert(child->children.size() <= 1);
-				if (child->children.empty())
-					continue;
-				Yosys::AST::AstNode *arg = child->children[0];
-
-				// plain identifiers never need indirection; this also prevents
-				// adding infinite levels of indirection
-				if (arg->type == Yosys::AST::AST_IDENTIFIER && arg->children.empty())
-					continue;
-
-				// only add indirection for standard inputs or outputs
-				if (ref->port_input == ref->port_output)
-					continue;
-
-				did_something = true;
-
-				// create the indirection wire
-				std::stringstream sstr;
-				sstr << "$indirect$" << ref->name.c_str() << "$" << encode_filename(ast_node->filename) << ":" << ast_node->location.first_line << "$" << (autoidx++);
-				std::string tmp_str = sstr.str();
-				add_wire_for_ref(ref, tmp_str);
-
-				Yosys::AST::AstNode *asgn = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN);
-				current_ast_mod->children.push_back(asgn);
-
-				Yosys::AST::AstNode *ident = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-				ident->str = tmp_str;
-				child->children[0] = ident->clone();
-
-				if (ref->port_input && !ref->port_output) {
-					asgn->children.push_back(ident);
-					asgn->children.push_back(arg);
-				} else {
-					log_assert(!ref->port_input && ref->port_output);
-					asgn->children.push_back(arg);
-					asgn->children.push_back(ident);
-				}
-			}
-
-
-		}
-	}
-
-	int backup_width_hint = width_hint;
-	bool backup_sign_hint = sign_hint;
-
-	bool detect_width_simple = false;
-	bool child_0_is_self_determined = false;
-	bool child_1_is_self_determined = false;
-	bool child_2_is_self_determined = false;
-	bool children_are_self_determined = false;
-	bool reset_width_after_children = false;
-
-	switch (ast_node->type)
-	{
-	case Yosys::AST::AST_ASSIGN_EQ:
-	case Yosys::AST::AST_ASSIGN_LE:
-	case Yosys::AST::AST_ASSIGN:
-		while (!ast_node->children[0]->basic_prep && simplify(ast_node->children[0], false, false, true, stage, -1, false, in_param) == true)
-			did_something = true;
-		while (!ast_node->children[1]->basic_prep && simplify(ast_node->children[1], false, false, false, stage, -1, false, in_param) == true)
-			did_something = true;
-		ast_node->children[0]->detectSignWidth(backup_width_hint, backup_sign_hint);
-		ast_node->children[1]->detectSignWidth(width_hint, sign_hint);
-		width_hint = max(width_hint, backup_width_hint);
-		child_0_is_self_determined = true;
-		// test only once, before optimizations and memory mappings but after assignment LHS was mapped to an identifier
-		if (ast_node->children[0]->id2ast && !ast_node->children[0]->was_checked) {
-			if ((ast_node->type == Yosys::AST::AST_ASSIGN_LE || ast_node->type == Yosys::AST::AST_ASSIGN_EQ) && ast_node->children[0]->id2ast->is_logic)
-				ast_node->children[0]->id2ast->is_reg = true; // if logic type is used in a block asignment
-			if ((ast_node->type == Yosys::AST::AST_ASSIGN_LE || ast_node->type == Yosys::AST::AST_ASSIGN_EQ) && !ast_node->children[0]->id2ast->is_reg)
-				log_warning("wire '%s' is assigned in a block at %s.\n", ast_node->children[0]->str.c_str(), ast_node->loc_string().c_str());
-			if (ast_node->type == Yosys::AST::AST_ASSIGN && ast_node->children[0]->id2ast->is_reg) {
-				bool is_rand_reg = false;
-				if (ast_node->children[1]->type == Yosys::AST::AST_FCALL) {
-					if (ast_node->children[1]->str == "\\$anyconst")
-						is_rand_reg = true;
-					if (ast_node->children[1]->str == "\\$anyseq")
-						is_rand_reg = true;
-					if (ast_node->children[1]->str == "\\$allconst")
-						is_rand_reg = true;
-					if (ast_node->children[1]->str == "\\$allseq")
-						is_rand_reg = true;
-				}
-				if (!is_rand_reg)
-					log_warning("reg '%s' is assigned in a continuous assignment at %s.\n", ast_node->children[0]->str.c_str(), ast_node->loc_string().c_str());
-			}
-			ast_node->children[0]->was_checked = true;
-		}
-		break;
-
-	case Yosys::AST::AST_STRUCT:
-	case Yosys::AST::AST_UNION:
-		if (!ast_node->basic_prep) {
-			for (auto *node : ast_node->children) {
-				// resolve any ranges
-				while (!node->basic_prep && simplify(node, true, false, false, stage, -1, false, false)) {
-					did_something = true;
-				}
-			}
-			// determine member offsets and widths
-			size_packed_struct(ast_node, 0);
-
-			// instance rather than just a type in a typedef or outer struct?
-			if (!ast_node->str.empty() && ast_node->str[0] == '\\') {
-				// instance so add a wire for the packed structure
-				auto wnode = make_packed_struct(ast_node, ast_node->str);
-				log_assert(current_ast_mod);
-				current_ast_mod->children.push_back(wnode);
-			}
-			ast_node->basic_prep = true;
-		}
-		break;
-
-	case Yosys::AST::AST_STRUCT_ITEM:
-		break;
-
-	case Yosys::AST::AST_ENUM:
-		//log("\nENUM %s: %d child %d\n", ast_node->str.c_str(), ast_node->basic_prep, ast_node->children[0]->basic_prep);
-		if (!ast_node->basic_prep) {
-			for (auto item_node : ast_node->children) {
-				while (!item_node->basic_prep && simplify(item_node, false, false, false, stage, -1, false, in_param))
-					did_something = true;
-			}
-			// allocate values (called more than once)
-			ast_node->allocateDefaultEnumValues();
-		}
-		break;
-
-	case Yosys::AST::AST_PARAMETER:
-	case Yosys::AST::AST_LOCALPARAM:
-		// if parameter is implicit type which is the typename of a struct or union,
-		// save information about struct in wiretype attribute
-		if (ast_node->children[0]->type == Yosys::AST::AST_IDENTIFIER && current_scope.count(ast_node->children[0]->str) > 0) {
-			auto item_node = current_scope[ast_node->children[0]->str];
-			if (item_node->type == Yosys::AST::AST_STRUCT || item_node->type == Yosys::AST::AST_UNION) {
-				ast_node->attributes[ID::wiretype] = item_node->clone();
-				size_packed_struct(ast_node->attributes[ID::wiretype], 0);
-				add_members_to_scope(ast_node->attributes[ID::wiretype], ast_node->str);
-			}
-		}
-		while (!ast_node->children[0]->basic_prep && simplify(ast_node->children[0], false, false, false, stage, -1, false, true) == true)
-			did_something = true;
-		ast_node->children[0]->detectSignWidth(width_hint, sign_hint);
-		if (ast_node->children.size() > 1 && ast_node->children[1]->type == Yosys::AST::AST_RANGE) {
-			while (!ast_node->children[1]->basic_prep && simplify(ast_node->children[1], false, false, false, stage, -1, false, true) == true)
-				did_something = true;
-			if (!ast_node->children[1]->range_valid)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Non-constant width range on parameter decl.\n");
-			width_hint = max(width_hint, ast_node->children[1]->range_left - ast_node->children[1]->range_right + 1);
-		}
-		break;
-	case Yosys::AST::AST_ENUM_ITEM:
-		while (!ast_node->children[0]->basic_prep && simplify(ast_node->children[0], false, false, false, stage, -1, false, in_param))
-			did_something = true;
-		ast_node->children[0]->detectSignWidth(width_hint, sign_hint);
-		if (ast_node->children.size() > 1 && ast_node->children[1]->type == Yosys::AST::AST_RANGE) {
-			while (!ast_node->children[1]->basic_prep && simplify(ast_node->children[1], false, false, false, stage, -1, false, in_param))
-				did_something = true;
-			if (!ast_node->children[1]->range_valid)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Non-constant width range on enum item decl.\n");
-			width_hint = max(width_hint, ast_node->children[1]->range_left - ast_node->children[1]->range_right + 1);
-		}
-		break;
-
-	case Yosys::AST::AST_TO_BITS:
-	case Yosys::AST::AST_TO_SIGNED:
-	case Yosys::AST::AST_TO_UNSIGNED:
-	case Yosys::AST::AST_SELFSZ:
-	case Yosys::AST::AST_CAST_SIZE:
-	case Yosys::AST::AST_CONCAT:
-	case Yosys::AST::AST_REPLICATE:
-	case Yosys::AST::AST_REDUCE_AND:
-	case Yosys::AST::AST_REDUCE_OR:
-	case Yosys::AST::AST_REDUCE_XOR:
-	case Yosys::AST::AST_REDUCE_XNOR:
-	case Yosys::AST::AST_REDUCE_BOOL:
-		detect_width_simple = true;
-		children_are_self_determined = true;
-		break;
-
-	case Yosys::AST::AST_NEG:
-	case Yosys::AST::AST_BIT_NOT:
-	case Yosys::AST::AST_POS:
-	case Yosys::AST::AST_BIT_AND:
-	case Yosys::AST::AST_BIT_OR:
-	case Yosys::AST::AST_BIT_XOR:
-	case Yosys::AST::AST_BIT_XNOR:
-	case Yosys::AST::AST_ADD:
-	case Yosys::AST::AST_SUB:
-	case Yosys::AST::AST_MUL:
-	case Yosys::AST::AST_DIV:
-	case Yosys::AST::AST_MOD:
-		detect_width_simple = true;
-		break;
-
-	case Yosys::AST::AST_SHIFT_LEFT:
-	case Yosys::AST::AST_SHIFT_RIGHT:
-	case Yosys::AST::AST_SHIFT_SLEFT:
-	case Yosys::AST::AST_SHIFT_SRIGHT:
-	case Yosys::AST::AST_POW:
-		detect_width_simple = true;
-		child_1_is_self_determined = true;
-		break;
-
-	case Yosys::AST::AST_LT:
-	case Yosys::AST::AST_LE:
-	case Yosys::AST::AST_EQ:
-	case Yosys::AST::AST_NE:
-	case Yosys::AST::AST_EQX:
-	case Yosys::AST::AST_NEX:
-	case Yosys::AST::AST_GE:
-	case Yosys::AST::AST_GT:
-		width_hint = -1;
-		sign_hint = true;
-		for (auto child : ast_node->children) {
-			while (!child->basic_prep && simplify(child, false, false, in_lvalue, stage, -1, false, in_param) == true)
-				did_something = true;
-			child->detectSignWidthWorker(width_hint, sign_hint);
-		}
-		reset_width_after_children = true;
-		break;
-
-	case Yosys::AST::AST_LOGIC_AND:
-	case Yosys::AST::AST_LOGIC_OR:
-	case Yosys::AST::AST_LOGIC_NOT:
-		detect_width_simple = true;
-		children_are_self_determined = true;
-		break;
-
-	case Yosys::AST::AST_TERNARY:
-		child_0_is_self_determined = true;
-		break;
-
-	case Yosys::AST::AST_MEMRD:
-		detect_width_simple = true;
-		children_are_self_determined = true;
-		break;
-
-	case Yosys::AST::AST_FCALL:
-	case Yosys::AST::AST_TCALL:
-		children_are_self_determined = true;
-		break;
-
-	default:
-		width_hint = -1;
-		sign_hint = false;
-	}
-
-	if (detect_width_simple && width_hint < 0) {
-		if (ast_node->type == Yosys::AST::AST_REPLICATE)
-			while (simplify(ast_node->children[0], true, false, in_lvalue, stage, -1, false, true) == true)
-				did_something = true;
-		for (auto child : ast_node->children)
-			while (!child->basic_prep && simplify(child, false, false, in_lvalue, stage, -1, false, in_param) == true)
-				did_something = true;
-		ast_node->detectSignWidth(width_hint, sign_hint);
-	}
-
-	if (ast_node->type == Yosys::AST::AST_FCALL && ast_node->str == "\\$past")
-		ast_node->detectSignWidth(width_hint, sign_hint);
-
-	if (ast_node->type == Yosys::AST::AST_TERNARY) {
-		if (width_hint < 0) {
-			while (!ast_node->children[0]->basic_prep && simplify(ast_node->children[0], true, false, in_lvalue, stage, -1, false, in_param))
-				did_something = true;
-
-			bool backup_unevaluated_tern_branch = unevaluated_tern_branch;
-			Yosys::AST::AstNode *chosen = ast_node->get_tern_choice().first;
-
-			unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == ast_node->children[2];
-			while (!ast_node->children[1]->basic_prep && simplify(ast_node->children[1], false, false, in_lvalue, stage, -1, false, in_param))
-				did_something = true;
-
-			unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == ast_node->children[1];
-			while (!ast_node->children[2]->basic_prep && simplify(ast_node->children[2], false, false, in_lvalue, stage, -1, false, in_param))
-				did_something = true;
-
-			unevaluated_tern_branch = backup_unevaluated_tern_branch;
-			ast_node->detectSignWidth(width_hint, sign_hint);
-		}
-		int width_hint_left, width_hint_right;
-		bool sign_hint_left, sign_hint_right;
-		bool found_real_left, found_real_right;
-		ast_node->children[1]->detectSignWidth(width_hint_left, sign_hint_left, &found_real_left);
-		ast_node->children[2]->detectSignWidth(width_hint_right, sign_hint_right, &found_real_right);
-		if (found_real_left || found_real_right) {
-			child_1_is_self_determined = true;
-			child_2_is_self_determined = true;
-		}
-	}
-
-	if (ast_node->type == Yosys::AST::AST_CONDX && ast_node->children.size() > 0 && ast_node->children.at(0)->type == Yosys::AST::AST_CONSTANT) {
-		for (auto &bit : ast_node->children.at(0)->bits)
-			if (bit == State::Sz || bit == State::Sx)
-				bit = State::Sa;
-	}
-
-	if (ast_node->type == Yosys::AST::AST_CONDZ && ast_node->children.size() > 0 && ast_node->children.at(0)->type == Yosys::AST::AST_CONSTANT) {
-		for (auto &bit : ast_node->children.at(0)->bits)
-			if (bit == State::Sz)
-				bit = State::Sa;
-	}
-
-	if (const_fold && ast_node->type == Yosys::AST::AST_CASE)
-	{
-		ast_node->detectSignWidth(width_hint, sign_hint);
-		while (simplify(ast_node->children[0], const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
-		if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT && ast_node->children[0]->bits_only_01()) {
-			ast_node->children[0]->is_signed = sign_hint;
-			RTLIL::Const case_expr = ast_node->children[0]->bitsAsConst(width_hint, sign_hint);
-			std::vector<Yosys::AST::AstNode*> new_children;
-			new_children.push_back(ast_node->children[0]);
-			for (int i = 1; i < GetSize(ast_node->children); i++) {
-				Yosys::AST::AstNode *child = ast_node->children[i];
-				log_assert(child->type == Yosys::AST::AST_COND || child->type == Yosys::AST::AST_CONDX || child->type == Yosys::AST::AST_CONDZ);
-				for (auto v : child->children) {
-					if (v->type == Yosys::AST::AST_DEFAULT)
-						goto keep_const_cond;
-					if (v->type == Yosys::AST::AST_BLOCK)
-						continue;
-					while (simplify(v, const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
-					if (v->type == Yosys::AST::AST_CONSTANT && v->bits_only_01()) {
-						RTLIL::Const case_item_expr = v->bitsAsConst(width_hint, sign_hint);
-						RTLIL::Const match = const_eq(case_expr, case_item_expr, sign_hint, sign_hint, 1);
-						log_assert(match.bits.size() == 1);
-						if (match.bits.front() == RTLIL::State::S1) {
-							while (i+1 < GetSize(ast_node->children))
-								delete ast_node->children[++i];
-							goto keep_const_cond;
-						}
-						continue;
-					}
-					goto keep_const_cond;
-				}
-				if (0)
-			keep_const_cond:
-					new_children.push_back(child);
-				else
-					delete child;
-			}
-			new_children.swap(ast_node->children);
-		}
-	}
-
-	dict<std::string, pool<int>> backup_memwr_visible;
-	dict<std::string, pool<int>> final_memwr_visible;
-
-	if (ast_node->type == Yosys::AST::AST_CASE && stage == 2) {
-		backup_memwr_visible = current_memwr_visible;
-		final_memwr_visible = current_memwr_visible;
-	}
-
-	// simplify all children first
-	// (iterate by index as e.g. auto wires can add new children in the process)
-	for (size_t i = 0; i < ast_node->children.size(); i++) {
-		bool did_something_here = true;
-		bool backup_flag_autowire = flag_autowire;
-		bool backup_unevaluated_tern_branch = unevaluated_tern_branch;
-		if ((ast_node->type == Yosys::AST::AST_GENFOR || ast_node->type == Yosys::AST::AST_FOR) && i >= 3)
-			break;
-		if ((ast_node->type == Yosys::AST::AST_GENIF || ast_node->type == Yosys::AST::AST_GENCASE) && i >= 1)
-			break;
-		if (ast_node->type == Yosys::AST::AST_GENBLOCK)
-			break;
-		if (ast_node->type == Yosys::AST::AST_CELLARRAY && ast_node->children[i]->type == Yosys::AST::AST_CELL)
-			continue;
-		if (ast_node->type == Yosys::AST::AST_BLOCK && !ast_node->str.empty())
-			break;
-		if (ast_node->type == Yosys::AST::AST_PREFIX && i >= 1)
-			break;
-		if (ast_node->type == Yosys::AST::AST_DEFPARAM && i == 0)
-			flag_autowire = true;
-		if (ast_node->type == Yosys::AST::AST_TERNARY && i > 0 && !unevaluated_tern_branch) {
-			Yosys::AST::AstNode *chosen = ast_node->get_tern_choice().first;
-			unevaluated_tern_branch = chosen && chosen != ast_node->children[i];
-		}
-		while (did_something_here && i < ast_node->children.size()) {
-			bool const_fold_here = const_fold, in_lvalue_here = in_lvalue;
-			int width_hint_here = width_hint;
-			bool sign_hint_here = sign_hint;
-			bool in_param_here = in_param;
-			if (i == 0 && (ast_node->type == Yosys::AST::AST_REPLICATE || ast_node->type == Yosys::AST::AST_WIRE))
-				const_fold_here = true, in_param_here = true;
-			if (i == 0 && (ast_node->type == Yosys::AST::AST_GENIF || ast_node->type == Yosys::AST::AST_GENCASE))
-				in_param_here = true;
-			if (i == 1 && (ast_node->type == Yosys::AST::AST_FOR || ast_node->type == Yosys::AST::AST_GENFOR))
-				in_param_here = true;
-			if (ast_node->type == Yosys::AST::AST_PARAMETER || ast_node->type == Yosys::AST::AST_LOCALPARAM)
-				const_fold_here = true;
-			if (i == 0 && (ast_node->type == Yosys::AST::AST_ASSIGN || ast_node->type == Yosys::AST::AST_ASSIGN_EQ || ast_node->type == Yosys::AST::AST_ASSIGN_LE))
-				in_lvalue_here = true;
-			if (ast_node->type == Yosys::AST::AST_BLOCK) {
-				current_block = ast_node;
-				current_block_child = ast_node->children[i];
-			}
-			if ((ast_node->type == Yosys::AST::AST_ALWAYS || ast_node->type == Yosys::AST::AST_INITIAL) && ast_node->children[i]->type == Yosys::AST::AST_BLOCK)
-				current_top_block = ast_node->children[i];
-			if (i == 0 && child_0_is_self_determined)
-				width_hint_here = -1, sign_hint_here = false;
-			if (i == 1 && child_1_is_self_determined)
-				width_hint_here = -1, sign_hint_here = false;
-			if (i == 2 && child_2_is_self_determined)
-				width_hint_here = -1, sign_hint_here = false;
-			if (children_are_self_determined)
-				width_hint_here = -1, sign_hint_here = false;
-			did_something_here = simplify(ast_node->children[i], const_fold_here, at_zero, in_lvalue_here, stage, width_hint_here, sign_hint_here, in_param_here);
-			if (did_something_here)
-				did_something = true;
-		}
-		if (stage == 2 && ast_node->children[i]->type == Yosys::AST::AST_INITIAL && current_ast_mod != ast_node) {
-			current_ast_mod->children.push_back(ast_node->children[i]);
-			ast_node->children.erase(ast_node->children.begin() + (i--));
-			did_something = true;
-		}
-		flag_autowire = backup_flag_autowire;
-		unevaluated_tern_branch = backup_unevaluated_tern_branch;
-		if (stage == 2 && ast_node->type == Yosys::AST::AST_CASE) {
-			for (auto &x : current_memwr_visible) {
-				for (int y : x.second)
-					final_memwr_visible[x.first].insert(y);
-			}
-			current_memwr_visible = backup_memwr_visible;
-		}
-	}
-	for (auto &attr : ast_node->attributes) {
-		while (simplify(attr.second, true, false, false, stage, -1, false, true))
-			did_something = true;
-	}
-	if (ast_node->type == Yosys::AST::AST_CASE && stage == 2) {
-		current_memwr_visible = final_memwr_visible;
-	}
-	if (ast_node->type == Yosys::AST::AST_ALWAYS && stage == 2) {
-		current_memwr_visible.clear();
-		current_memwr_count.clear();
-	}
-
-	if (reset_width_after_children) {
-		width_hint = backup_width_hint;
-		sign_hint = backup_sign_hint;
-		if (width_hint < 0)
-			ast_node->detectSignWidth(width_hint, sign_hint);
-	}
-
-	current_block = backup_current_block;
-	current_block_child = backup_current_block_child;
-	current_top_block = backup_current_top_block;
-	current_always = backup_current_always;
-	current_always_clocked = backup_current_always_clocked;
-
-	for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) {
-		if (it->second == NULL)
-			current_scope.erase(it->first);
-		else
-			current_scope[it->first] = it->second;
-	}
-
-	Yosys::AST::current_filename = ast_node->filename;
-
-	if (ast_node->type == Yosys::AST::AST_MODULE || ast_node->type == Yosys::AST::AST_INTERFACE)
-		current_scope.clear();
-
-	// convert defparam nodes to cell parameters
-	if (ast_node->type == Yosys::AST::AST_DEFPARAM && !ast_node->children.empty())
-	{
-		if (ast_node->children[0]->type != Yosys::AST::AST_IDENTIFIER)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Module name in defparam contains non-constant expressions!\n");
-
-		string modname, paramname = ast_node->children[0]->str;
-
-		size_t pos = paramname.rfind('.');
-
-		while (pos != 0 && pos != std::string::npos)
-		{
-			modname = paramname.substr(0, pos);
-
-			if (current_scope.count(modname))
-				break;
-
-			pos = paramname.rfind('.', pos - 1);
-		}
-
-		if (pos == std::string::npos)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Can't find object for defparam `%s`!\n", RTLIL::unescape_id(paramname).c_str());
-
-		paramname = "\\" + paramname.substr(pos+1);
-
-		if (current_scope.at(modname)->type != Yosys::AST::AST_CELL)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Defparam argument `%s . %s` does not match a cell!\n",
-					RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str());
-
-		Yosys::AST::AstNode *paraset = new Yosys::AST::AstNode(Yosys::AST::AST_PARASET, ast_node->children[1]->clone(), GetSize(ast_node->children) > 2 ? ast_node->children[2]->clone() : NULL);
-		paraset->str = paramname;
-
-		Yosys::AST::AstNode *cell = current_scope.at(modname);
-		cell->children.insert(cell->children.begin() + 1, paraset);
-		ast_node->delete_children();
-	}
-
-	// resolve typedefs
-	if (ast_node->type == Yosys::AST::AST_TYPEDEF) {
-		log_assert(ast_node->children.size() == 1);
-		auto type_node = ast_node->children[0];
-		log_assert(type_node->type == Yosys::AST::AST_WIRE || type_node->type == Yosys::AST::AST_MEMORY || type_node->type == Yosys::AST::AST_STRUCT || type_node->type == Yosys::AST::AST_UNION);
-		while (simplify(type_node, const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {
-			did_something = true;
-		}
-		log_assert(!type_node->is_custom_type);
-	}
-
-	// resolve types of wires
-	if (ast_node->type == Yosys::AST::AST_WIRE || ast_node->type == Yosys::AST::AST_MEMORY || ast_node->type == Yosys::AST::AST_STRUCT_ITEM) {
-		if (ast_node->is_custom_type) {
-			log_assert(ast_node->children.size() >= 1);
-			log_assert(ast_node->children[0]->type == Yosys::AST::AST_WIRETYPE);
-			auto type_name = ast_node->children[0]->str;
-			if (!current_scope.count(type_name)) {
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Unknown identifier `%s' used as type name\n", type_name.c_str());
-			}
-			Yosys::AST::AstNode *resolved_type_node = current_scope.at(type_name);
-			if (resolved_type_node->type != Yosys::AST::AST_TYPEDEF)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "`%s' does not name a type\n", type_name.c_str());
-			log_assert(resolved_type_node->children.size() == 1);
-			Yosys::AST::AstNode *template_node = resolved_type_node->children[0];
-
-			// Ensure typedef itself is fully simplified
-			while (simplify(template_node, const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};
-
-			if (template_node->type == Yosys::AST::AST_STRUCT || template_node->type == Yosys::AST::AST_UNION) {
-				// replace with wire representing the packed structure
-				newNode = make_packed_struct(template_node, ast_node->str);
-				newNode->attributes[ID::wiretype] = ast_node->mkconst_str(resolved_type_node->str);
-				// add original input/output attribute to resolved wire
-				newNode->is_input = ast_node->is_input;
-				newNode->is_output = ast_node->is_output;
-				current_scope[ast_node->str] = ast_node;
-				goto apply_newNode;
-			}
-
-			// Remove type reference
-			delete ast_node->children[0];
-			ast_node->children.erase(ast_node->children.begin());
-
-			if (ast_node->type == Yosys::AST::AST_WIRE)
-				ast_node->type = template_node->type;
-			ast_node->is_reg = template_node->is_reg;
-			ast_node->is_logic = template_node->is_logic;
-			ast_node->is_signed = template_node->is_signed;
-			ast_node->is_string = template_node->is_string;
-			ast_node->is_custom_type = template_node->is_custom_type;
-
-			ast_node->range_valid = template_node->range_valid;
-			ast_node->range_swapped = template_node->range_swapped;
-			ast_node->range_left = template_node->range_left;
-			ast_node->range_right = template_node->range_right;
-
-			ast_node->attributes[ID::wiretype] = ast_node->mkconst_str(resolved_type_node->str);
-
-			// if an enum then add attributes to support simulator tracing
-			annotateTypedEnums(ast_node, template_node);
-
-			// Insert clones children from template at beginning
-			for (int i  = 0; i < GetSize(template_node->children); i++)
-				ast_node->children.insert(ast_node->children.begin() + i, template_node->children[i]->clone());
-
-			if (ast_node->type == Yosys::AST::AST_MEMORY && GetSize(ast_node->children) == 1) {
-				// Single-bit memories must have [0:0] range
-				Yosys::AST::AstNode *rng = make_range(0, 0);
-				ast_node->children.insert(ast_node->children.begin(), rng);
-			}
-			did_something = true;
-		}
-		log_assert(!ast_node->is_custom_type);
-	}
-
-	// resolve types of parameters
-	if (ast_node->type == Yosys::AST::AST_LOCALPARAM || ast_node->type == Yosys::AST::AST_PARAMETER) {
-		if (ast_node->is_custom_type) {
-			log_assert(ast_node->children.size() == 2);
-			log_assert(ast_node->children[1]->type == Yosys::AST::AST_WIRETYPE);
-			auto type_name = ast_node->children[1]->str;
-			if (!current_scope.count(type_name)) {
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Unknown identifier `%s' used as type name\n", type_name.c_str());
-			}
-			Yosys::AST::AstNode *resolved_type_node = current_scope.at(type_name);
-			if (resolved_type_node->type != Yosys::AST::AST_TYPEDEF)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "`%s' does not name a type\n", type_name.c_str());
-			log_assert(resolved_type_node->children.size() == 1);
-			Yosys::AST::AstNode *template_node = resolved_type_node->children[0];
-
-			// Ensure typedef itself is fully simplified
-			while (simplify(template_node, const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};
-
-			if (template_node->type == Yosys::AST::AST_STRUCT || template_node->type == Yosys::AST::AST_UNION) {
-				// replace with wire representing the packed structure
-				newNode = make_packed_struct(template_node, ast_node->str);
-				newNode->attributes[ID::wiretype] = ast_node->mkconst_str(resolved_type_node->str);
-				newNode->type = ast_node->type;
-				current_scope[ast_node->str] = ast_node;
-				// copy param value, it needs to be 1st value
-				delete ast_node->children[1];
-				ast_node->children.pop_back();
-				newNode->children.insert(newNode->children.begin(), ast_node->children[0]->clone());
-				goto apply_newNode;
-			}
-			delete ast_node->children[1];
-			ast_node->children.pop_back();
-
-			if (template_node->type == Yosys::AST::AST_MEMORY)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "unpacked array type `%s' cannot be used for a parameter\n", ast_node->children[1]->str.c_str());
-			ast_node->is_signed = template_node->is_signed;
-			ast_node->is_string = template_node->is_string;
-			ast_node->is_custom_type = template_node->is_custom_type;
-
-			ast_node->range_valid = template_node->range_valid;
-			ast_node->range_swapped = template_node->range_swapped;
-			ast_node->range_left = template_node->range_left;
-			ast_node->range_right = template_node->range_right;
-			ast_node->attributes[ID::wiretype] = ast_node->mkconst_str(resolved_type_node->str);
-			for (auto template_child : template_node->children)
-				ast_node->children.push_back(template_child->clone());
-			did_something = true;
-		}
-		log_assert(!ast_node->is_custom_type);
-	}
-
-	// resolve constant prefixes
-	if (ast_node->type == Yosys::AST::AST_PREFIX) {
-		if (ast_node->children[0]->type != Yosys::AST::AST_CONSTANT) {
-			// dumpAst(NULL, ">   ");
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Index in generate block prefix syntax is not constant!\n");
-		}
-		if (ast_node->children[1]->type == Yosys::AST::AST_PREFIX)
-			simplify(ast_node->children[1], const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param);
-		log_assert(ast_node->children[1]->type == Yosys::AST::AST_IDENTIFIER);
-		newNode = ast_node->children[1]->clone();
-		const char *second_part = ast_node->children[1]->str.c_str();
-		if (second_part[0] == '\\')
-			second_part++;
-		newNode->str = stringf("%s[%d].%s", ast_node->str.c_str(), ast_node->children[0]->integer, second_part);
-		goto apply_newNode;
-	}
-
-	// evaluate TO_BITS nodes
-	if (ast_node->type == Yosys::AST::AST_TO_BITS) {
-		if (ast_node->children[0]->type != Yosys::AST::AST_CONSTANT)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Left operand of to_bits expression is not constant!\n");
-		if (ast_node->children[1]->type != Yosys::AST::AST_CONSTANT)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Right operand of to_bits expression is not constant!\n");
-		RTLIL::Const new_value = ast_node->children[1]->bitsAsConst(ast_node->children[0]->bitsAsConst().as_int(), ast_node->children[1]->is_signed);
-		newNode = Yosys::AST::AstNode::mkconst_bits(new_value.bits, ast_node->children[1]->is_signed);
-		goto apply_newNode;
-	}
-
-	// annotate constant ranges
-	if (ast_node->type == Yosys::AST::AST_RANGE) {
-		bool old_range_valid = ast_node->range_valid;
-		ast_node->range_valid = false;
-		ast_node->range_swapped = false;
-		ast_node->range_left = -1;
-		ast_node->range_right = 0;
-		log_assert(ast_node->children.size() >= 1);
-		if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT) {
-			ast_node->range_valid = true;
-			ast_node->range_left = ast_node->children[0]->integer;
-			if (ast_node->children.size() == 1)
-				ast_node->range_right = ast_node->range_left;
-		}
-		if (ast_node->children.size() >= 2) {
-			if (ast_node->children[1]->type == Yosys::AST::AST_CONSTANT)
-				ast_node->range_right = ast_node->children[1]->integer;
-			else
-				ast_node->range_valid = false;
-		}
-		if (old_range_valid != ast_node->range_valid)
-			did_something = true;
-		if (ast_node->range_valid && ast_node->range_right > ast_node->range_left) {
-			int tmp = ast_node->range_right;
-			ast_node->range_right = ast_node->range_left;
-			ast_node->range_left = tmp;
-			ast_node->range_swapped = true;
-		}
-	}
-
-	// annotate wires with their ranges
-	if (ast_node->type == Yosys::AST::AST_WIRE) {
-		if (ast_node->children.size() > 0) {
-			if (ast_node->children[0]->range_valid) {
-				if (!ast_node->range_valid)
-					did_something = true;
-				ast_node->range_valid = true;
-				ast_node->range_swapped = ast_node->children[0]->range_swapped;
-				ast_node->range_left = ast_node->children[0]->range_left;
-				ast_node->range_right = ast_node->children[0]->range_right;
-				bool force_upto = false, force_downto = false;
-				if (ast_node->attributes.count(ID::force_upto)) {
-					Yosys::AST::AstNode *val = ast_node->attributes[ID::force_upto];
-					if (val->type != Yosys::AST::AST_CONSTANT)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Attribute `force_upto' with non-constant value!\n");
-					force_upto = val->asAttrConst().as_bool();
-				}
-				if (ast_node->attributes.count(ID::force_downto)) {
-					Yosys::AST::AstNode *val = ast_node->attributes[ID::force_downto];
-					if (val->type != Yosys::AST::AST_CONSTANT)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Attribute `force_downto' with non-constant value!\n");
-					force_downto = val->asAttrConst().as_bool();
-				}
-				if (force_upto && force_downto)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "Attributes `force_downto' and `force_upto' cannot be both set!\n");
-				if ((force_upto && !ast_node->range_swapped) || (force_downto && ast_node->range_swapped)) {
-					std::swap(ast_node->range_left, ast_node->range_right);
-					ast_node->range_swapped = force_upto;
-				}
-			}
-		} else {
-			if (!ast_node->range_valid)
-				did_something = true;
-			ast_node->range_valid = true;
-			ast_node->range_swapped = false;
-			ast_node->range_left = 0;
-			ast_node->range_right = 0;
-		}
-	}
-
-	// resolve multiranges on memory decl
-	if (ast_node->type == Yosys::AST::AST_MEMORY && ast_node->children.size() > 1 && ast_node->children[1]->type == Yosys::AST::AST_MULTIRANGE)
-	{
-		int total_size = 1;
-		ast_node->multirange_dimensions.clear();
-		ast_node->multirange_swapped.clear();
-		for (auto range : ast_node->children[1]->children) {
-			if (!range->range_valid)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Non-constant range on memory decl.\n");
-			ast_node->multirange_dimensions.push_back(min(range->range_left, range->range_right));
-			ast_node->multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1);
-			ast_node->multirange_swapped.push_back(range->range_swapped);
-			total_size *= ast_node->multirange_dimensions.back();
-		}
-		delete ast_node->children[1];
-		ast_node->children[1] = new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, ast_node->mkconst_int(0, true), ast_node->mkconst_int(total_size-1, true));
-		did_something = true;
-	}
-
-	// resolve multiranges on memory access
-	if (ast_node->type == Yosys::AST::AST_IDENTIFIER && ast_node->id2ast && ast_node->id2ast->type == Yosys::AST::AST_MEMORY && ast_node->children.size() > 0 && ast_node->children[0]->type == Yosys::AST::AST_MULTIRANGE)
-	{
-		Yosys::AST::AstNode *index_expr = nullptr;
-
-		ast_node->integer = ast_node->children[0]->children.size(); // save original number of dimensions for $size() etc.
-		for (int i = 0; 2*i < GetSize(ast_node->id2ast->multirange_dimensions); i++)
-		{
-			if (GetSize(ast_node->children[0]->children) <= i)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Insufficient number of array indices for %s.\n", log_id(ast_node->str));
-
-			Yosys::AST::AstNode *new_index_expr = ast_node->children[0]->children[i]->children.at(0)->clone();
-
-			if (ast_node->id2ast->multirange_dimensions[2*i])
-				new_index_expr = new Yosys::AST::AstNode(Yosys::AST::AST_SUB, new_index_expr, ast_node->mkconst_int(ast_node->id2ast->multirange_dimensions[2*i], true));
-
-			if (i == 0)
-				index_expr = new_index_expr;
-			else
-				index_expr = new Yosys::AST::AstNode(Yosys::AST::AST_ADD, new Yosys::AST::AstNode(Yosys::AST::AST_MUL, index_expr, ast_node->mkconst_int(ast_node->id2ast->multirange_dimensions[2*i+1], true)), new_index_expr);
-		}
-
-		for (int i = GetSize(ast_node->id2ast->multirange_dimensions)/2; i < GetSize(ast_node->children[0]->children); i++)
-			ast_node->children.push_back(ast_node->children[0]->children[i]->clone());
-
-		delete ast_node->children[0];
-		if (index_expr == nullptr)
-			ast_node->children.erase(ast_node->children.begin());
-		else
-			ast_node->children[0] = new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, index_expr);
-
-		did_something = true;
-	}
-
-	// trim/extend parameters
-	if (ast_node->type == Yosys::AST::AST_PARAMETER || ast_node->type == Yosys::AST::AST_LOCALPARAM || ast_node->type == Yosys::AST::AST_ENUM_ITEM) {
-		if (ast_node->children.size() > 1 && ast_node->children[1]->type == Yosys::AST::AST_RANGE) {
-			if (!ast_node->children[1]->range_valid)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Non-constant width range on parameter decl.\n");
-			int width = std::abs(ast_node->children[1]->range_left - ast_node->children[1]->range_right) + 1;
-			if (ast_node->children[0]->type == Yosys::AST::AST_REALVALUE) {
-				RTLIL::Const constvalue = ast_node->children[0]->realAsConst(width);
-				log_file_warning(ast_node->filename, ast_node->location.first_line, "converting real value %e to binary %s.\n",
-						ast_node->children[0]->realvalue, log_signal(constvalue));
-				delete ast_node->children[0];
-				ast_node->children[0] = Yosys::AST::AstNode::mkconst_bits(constvalue.bits, sign_hint);
-				did_something = true;
-			}
-			if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT) {
-				if (width != int(ast_node->children[0]->bits.size())) {
-					RTLIL::SigSpec sig(ast_node->children[0]->bits);
-					sig.extend_u0(width, ast_node->children[0]->is_signed);
-					Yosys::AST::AstNode *old_child_0 = ast_node->children[0];
-					ast_node->children[0] = Yosys::AST::AstNode::mkconst_bits(sig.as_const().bits, ast_node->is_signed);
-					delete old_child_0;
-				}
-				ast_node->children[0]->is_signed = ast_node->is_signed;
-			}
-			ast_node->range_valid = true;
-			ast_node->range_swapped = ast_node->children[1]->range_swapped;
-			ast_node->range_left = ast_node->children[1]->range_left;
-			ast_node->range_right = ast_node->children[1]->range_right;
-		} else
-		if (ast_node->children.size() > 1 && ast_node->children[1]->type == Yosys::AST::AST_REALVALUE && ast_node->children[0]->type == Yosys::AST::AST_CONSTANT) {
-			double as_realvalue = ast_node->children[0]->asReal(sign_hint);
-			delete ast_node->children[0];
-			ast_node->children[0] = new Yosys::AST::AstNode(Yosys::AST::AST_REALVALUE);
-			ast_node->children[0]->realvalue = as_realvalue;
-			did_something = true;
-		}
-	}
-
-	if (ast_node->type == Yosys::AST::AST_IDENTIFIER && !ast_node->basic_prep) {
-		// check if a plausible struct member sss.mmmm
-		std::string sname;
-		if (name_has_dot(ast_node->str, sname)) {
-			if (current_scope.count(ast_node->str) > 0) {
-				auto item_node = current_scope[ast_node->str];
-				if (item_node->type == Yosys::AST::AST_STRUCT_ITEM || item_node->type == Yosys::AST::AST_STRUCT || item_node->type == Yosys::AST::AST_UNION) {
-					// structure member, rewrite ast_node node to reference the packed struct wire
-					auto range = Yosys::AST::make_struct_member_range(ast_node, item_node);
-					newNode = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER, range);
-					newNode->str = sname;
-					// save type and original number of dimensions for $size() etc.
-					newNode->attributes[ID::wiretype] = item_node->clone();
-					if (!item_node->multirange_dimensions.empty() && ast_node->children.size() > 0) {
-						if (ast_node->children[0]->type == Yosys::AST::AST_RANGE)
-							newNode->integer = 1;
-						else if (ast_node->children[0]->type == Yosys::AST::AST_MULTIRANGE)
-							newNode->integer = ast_node->children[0]->children.size();
-					}
-					newNode->basic_prep = true;
-					if (item_node->is_signed)
-						newNode = new Yosys::AST::AstNode(Yosys::AST::AST_TO_SIGNED, newNode);
-					goto apply_newNode;
-				}
-			}
-		}
-	}
-	// annotate identifiers using scope resolution and create auto-wires as needed
-	if (ast_node->type == Yosys::AST::AST_IDENTIFIER) {
-		if (current_scope.count(ast_node->str) == 0) {
-			Yosys::AST::AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod;
-			ast_node->str = ast_node->try_pop_module_prefix();
-			for (auto node : current_scope_ast->children) {
-				//log("looking at mod scope child %s\n", type2str(node->type).c_str());
-				switch (node->type) {
-				case Yosys::AST::AST_PARAMETER:
-				case Yosys::AST::AST_LOCALPARAM:
-				case Yosys::AST::AST_WIRE:
-				case Yosys::AST::AST_AUTOWIRE:
-				case Yosys::AST::AST_GENVAR:
-				case Yosys::AST::AST_MEMORY:
-				case Yosys::AST::AST_FUNCTION:
-				case Yosys::AST::AST_TASK:
-				case Yosys::AST::AST_DPI_FUNCTION:
-					//log("found child %s, %s\n", type2str(node->type).c_str(), node->str.c_str());
-					if (ast_node->str == node->str) {
-						//log("add %s, type %s to scope\n", ast_node->str.c_str(), type2str(node->type).c_str());
-						current_scope[node->str] = node;
-					}
-					break;
-				case Yosys::AST::AST_ENUM:
-					current_scope[node->str] = node;
-					for (auto enum_node : node->children) {
-						log_assert(enum_node->type==Yosys::AST::AST_ENUM_ITEM);
-						if (ast_node->str == enum_node->str) {
-							//log("\nadding enum item %s to scope\n", ast_node->str.c_str());
-							current_scope[ast_node->str] = enum_node;
-						}
-					}
-					break;
-				default:
-					break;
-				}
-			}
-		}
-		if (current_scope.count(ast_node->str) == 0) {
-			if (current_ast_mod == nullptr) {
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Identifier `%s' is implicitly declared outside of a module.\n", ast_node->str.c_str());
-			} else if (flag_autowire || ast_node->str == "\\$global_clock") {
-				Yosys::AST::AstNode *auto_wire = new Yosys::AST::AstNode(Yosys::AST::AST_AUTOWIRE);
-				auto_wire->str = ast_node->str;
-				current_ast_mod->children.push_back(auto_wire);
-				current_scope[ast_node->str] = auto_wire;
-				did_something = true;
-			} else {
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", ast_node->str.c_str());
-			}
-		}
-		if (ast_node->id2ast != current_scope[ast_node->str]) {
-			ast_node->id2ast = current_scope[ast_node->str];
-			did_something = true;
-		}
-	}
-
-	// split memory access with bit select to individual statements
-	if (ast_node->type == Yosys::AST::AST_IDENTIFIER && ast_node->children.size() == 2 && ast_node->children[0]->type == Yosys::AST::AST_RANGE && ast_node->children[1]->type == Yosys::AST::AST_RANGE && !in_lvalue && stage == 2)
-	{
-		if (ast_node->id2ast == NULL || ast_node->id2ast->type != Yosys::AST::AST_MEMORY || ast_node->children[0]->children.size() != 1)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Invalid bit-select on memory access!\n");
-
-		int mem_width, mem_size, addr_bits;
-		ast_node->id2ast->meminfo(mem_width, mem_size, addr_bits);
-
-		int data_range_left = ast_node->id2ast->children[0]->range_left;
-		int data_range_right = ast_node->id2ast->children[0]->range_right;
-
-		if (ast_node->id2ast->children[0]->range_swapped)
-			std::swap(data_range_left, data_range_right);
-
-		std::stringstream sstr;
-		sstr << "$mem2bits$" << ast_node->str << "$" << encode_filename(ast_node->filename) << ":" << ast_node->location.first_line << "$" << (autoidx++);
-		std::string wire_id = sstr.str();
-
-		Yosys::AST::AstNode *wire = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE, new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, ast_node->mkconst_int(data_range_left, true), ast_node->mkconst_int(data_range_right, true)));
-		wire->str = wire_id;
-		if (current_block)
-			wire->attributes[ID::nosync] = ast_node->mkconst_int(1, false);
-		current_ast_mod->children.push_back(wire);
-		while (simplify(wire, true, false, false, 1, -1, false, false)) { }
-
-		Yosys::AST::AstNode *data = ast_node->clone();
-		delete data->children[1];
-		data->children.pop_back();
-
-		Yosys::AST::AstNode *assign = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), data);
-		assign->children[0]->str = wire_id;
-		assign->children[0]->was_checked = true;
-
-		if (current_block)
-		{
-			size_t assign_idx = 0;
-			while (assign_idx < current_block->children.size() && current_block->children[assign_idx] != current_block_child)
-				assign_idx++;
-			log_assert(assign_idx < current_block->children.size());
-			current_block->children.insert(current_block->children.begin()+assign_idx, assign);
-			wire->is_reg = true;
-		}
-		else
-		{
-			Yosys::AST::AstNode *proc = new Yosys::AST::AstNode(Yosys::AST::AST_ALWAYS, new Yosys::AST::AstNode(Yosys::AST::AST_BLOCK));
-			proc->children[0]->children.push_back(assign);
-			current_ast_mod->children.push_back(proc);
-		}
-
-		newNode = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER, ast_node->children[1]->clone());
-		newNode->str = wire_id;
-		newNode->integer = ast_node->integer; // save original number of dimensions for $size() etc.
-		newNode->id2ast = wire;
-		goto apply_newNode;
-	}
-
-	if (ast_node->type == Yosys::AST::AST_WHILE)
-		log_file_error(ast_node->filename, ast_node->location.first_line, "While loops are only allowed in constant functions!\n");
-
-	if (ast_node->type == Yosys::AST::AST_REPEAT)
-	{
-		Yosys::AST::AstNode *count = ast_node->children[0];
-		Yosys::AST::AstNode *body = ast_node->children[1];
-
-		// eval count expression
-		while (simplify(count, true, false, false, stage, 32, true, false)) { }
-
-		if (count->type != Yosys::AST::AST_CONSTANT)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Repeat loops outside must have constant repeat counts!\n");
-
-		// convert to a block with the body repeated n times
-		ast_node->type = Yosys::AST::AST_BLOCK;
-		ast_node->children.clear();
-		for (int i = 0; i < count->bitsAsConst().as_int(); i++)
-			ast_node->children.insert(ast_node->children.begin(), body->clone());
-
-		delete count;
-		delete body;
-		did_something = true;
-	}
-
-	// unroll for loops and generate-for blocks
-	if ((ast_node->type == Yosys::AST::AST_GENFOR || ast_node->type == Yosys::AST::AST_FOR) && ast_node->children.size() != 0)
-	{
-		Yosys::AST::AstNode *init_ast = ast_node->children[0];
-		Yosys::AST::AstNode *while_ast = ast_node->children[1];
-		Yosys::AST::AstNode *next_ast = ast_node->children[2];
-		Yosys::AST::AstNode *body_ast = ast_node->children[3];
-
-		while (body_ast->type == Yosys::AST::AST_GENBLOCK && body_ast->str.empty() &&
-				body_ast->children.size() == 1 && body_ast->children.at(0)->type == Yosys::AST::AST_GENBLOCK)
-			body_ast = body_ast->children.at(0);
-
-		const char* loop_type_str = "procedural";
-		const char* var_type_str = "register";
-		Yosys::AST::AstNodeType var_type = Yosys::AST::AST_WIRE;
-		if (ast_node->type == Yosys::AST::AST_GENFOR) {
-			loop_type_str = "generate";
-			var_type_str = "genvar";
-			var_type = Yosys::AST::AST_GENVAR;
-		}
-
-		if (init_ast->type != Yosys::AST::AST_ASSIGN_EQ)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Unsupported 1st expression of %s for-loop!\n", loop_type_str);
-		if (next_ast->type != Yosys::AST::AST_ASSIGN_EQ)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Unsupported 3rd expression of %s for-loop!\n", loop_type_str);
-
-		if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != var_type)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Left hand side of 1st expression of %s for-loop is not a %s!\n", loop_type_str, var_type_str);
-		if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != var_type)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Left hand side of 3rd expression of %s for-loop is not a %s!\n", loop_type_str, var_type_str);
-
-		if (init_ast->children[0]->id2ast != next_ast->children[0]->id2ast)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Incompatible left-hand sides in 1st and 3rd expression of %s for-loop!\n", loop_type_str);
-
-		// eval 1st expression
-		Yosys::AST::AstNode *varbuf = init_ast->children[1]->clone();
-		{
-			int expr_width_hint = -1;
-			bool expr_sign_hint = true;
-			varbuf->detectSignWidth(expr_width_hint, expr_sign_hint);
-			while (simplify(varbuf, true, false, false, stage, 32, true, false)) { }
-		}
-
-		if (varbuf->type != Yosys::AST::AST_CONSTANT)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Right hand side of 1st expression of %s for-loop is not constant!\n", loop_type_str);
-
-		auto resolved = current_scope.at(init_ast->children[0]->str);
-		if (resolved->range_valid) {
-			int const_size = varbuf->range_left - varbuf->range_right;
-			int resolved_size = resolved->range_left - resolved->range_right;
-			if (const_size < resolved_size) {
-				for (int i = const_size; i < resolved_size; i++)
-					varbuf->bits.push_back(resolved->is_signed ? varbuf->bits.back() : State::S0);
-				varbuf->range_left = resolved->range_left;
-				varbuf->range_right = resolved->range_right;
-				varbuf->range_swapped = resolved->range_swapped;
-				varbuf->range_valid = resolved->range_valid;
-			}
-		}
-
-		varbuf = new Yosys::AST::AstNode(Yosys::AST::AST_LOCALPARAM, varbuf);
-		varbuf->str = init_ast->children[0]->str;
-
-		Yosys::AST::AstNode *backup_scope_varbuf = current_scope[varbuf->str];
-		current_scope[varbuf->str] = varbuf;
-
-		size_t current_block_idx = 0;
-		if (ast_node->type == Yosys::AST::AST_FOR) {
-			while (current_block_idx < current_block->children.size() &&
-					current_block->children[current_block_idx] != current_block_child)
-				current_block_idx++;
-		}
-
-		while (1)
-		{
-			// eval 2nd expression
-			Yosys::AST::AstNode *buf = while_ast->clone();
-			{
-				int expr_width_hint = -1;
-				bool expr_sign_hint = true;
-				buf->detectSignWidth(expr_width_hint, expr_sign_hint);
-				while (simplify(buf, true, false, false, stage, expr_width_hint, expr_sign_hint, false)) { }
-			}
-
-			if (buf->type != Yosys::AST::AST_CONSTANT)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "2nd expression of %s for-loop is not constant!\n", loop_type_str);
-
-			if (buf->integer == 0) {
-				delete buf;
-				break;
-			}
-			delete buf;
-
-			// expand body
-			int index = varbuf->children[0]->integer;
-			log_assert(body_ast->type == Yosys::AST::AST_GENBLOCK || body_ast->type == Yosys::AST::AST_BLOCK);
-			log_assert(!body_ast->str.empty());
-			buf = body_ast->clone();
-
-			std::stringstream sstr;
-			sstr << buf->str << "[" << index << "].";
-			std::string prefix = sstr.str();
-
-			// create a scoped localparam for the current value of the loop variable
-			Yosys::AST::AstNode *local_index = varbuf->clone();
-			size_t pos = local_index->str.rfind('.');
-			if (pos != std::string::npos) // remove outer prefix
-				local_index->str = "\\" + local_index->str.substr(pos + 1);
-			local_index->str = prefix_id(prefix, local_index->str);
-			current_scope[local_index->str] = local_index;
-			current_ast_mod->children.push_back(local_index);
-
-			buf->expand_genblock(prefix);
-
-			if (ast_node->type == Yosys::AST::AST_GENFOR) {
-				for (size_t i = 0; i < buf->children.size(); i++) {
-					simplify(buf->children[i], const_fold, false, false, stage, -1, false, false);
-					current_ast_mod->children.push_back(buf->children[i]);
-				}
-			} else {
-				for (size_t i = 0; i < buf->children.size(); i++)
-					current_block->children.insert(current_block->children.begin() + current_block_idx++, buf->children[i]);
-			}
-			buf->children.clear();
-			delete buf;
-
-			// eval 3rd expression
-			buf = next_ast->children[1]->clone();
-			{
-				int expr_width_hint = -1;
-				bool expr_sign_hint = true;
-				buf->detectSignWidth(expr_width_hint, expr_sign_hint);
-				while (simplify(buf, true, false, false, stage, expr_width_hint, expr_sign_hint, true)) { }
-			}
-
-			if (buf->type != Yosys::AST::AST_CONSTANT)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Right hand side of 3rd expression of %s for-loop is not constant (%s)!\n", loop_type_str, type2str(buf->type).c_str());
-
-			delete varbuf->children[0];
-			varbuf->children[0] = buf;
-		}
-
-		if (ast_node->type == Yosys::AST::AST_FOR) {
-			Yosys::AST::AstNode *buf = next_ast->clone();
-			delete buf->children[1];
-			buf->children[1] = varbuf->children[0]->clone();
-			current_block->children.insert(current_block->children.begin() + current_block_idx++, buf);
-		}
-
-		current_scope[varbuf->str] = backup_scope_varbuf;
-		delete varbuf;
-		ast_node->delete_children();
-		did_something = true;
-	}
-
-	// check for local objects in unnamed block
-	if (ast_node->type == Yosys::AST::AST_BLOCK && ast_node->str.empty())
-	{
-		for (size_t i = 0; i < ast_node->children.size(); i++)
-			if (ast_node->children[i]->type == Yosys::AST::AST_WIRE || ast_node->children[i]->type == Yosys::AST::AST_MEMORY || ast_node->children[i]->type == Yosys::AST::AST_PARAMETER || ast_node->children[i]->type == Yosys::AST::AST_LOCALPARAM || ast_node->children[i]->type == Yosys::AST::AST_TYPEDEF)
-			{
-				log_assert(!VERILOG_FRONTEND::sv_mode);
-				log_file_error(ast_node->children[i]->filename, ast_node->children[i]->location.first_line, "Local declaration in unnamed block is only supported in SystemVerilog mode!\n");
-			}
-	}
-
-	// transform block with name
-	if (ast_node->type == Yosys::AST::AST_BLOCK && !ast_node->str.empty())
-	{
-		ast_node->expand_genblock(ast_node->str + ".");
-
-		// if ast_node is an autonamed block is in an always_comb
-		if (current_always && current_always->attributes.count(ID::always_comb)
-				&& is_autonamed_block(ast_node->str))
-			// track local variables in ast_node block so we can consider adding
-			// nosync once the block has been fully elaborated
-			for (Yosys::AST::AstNode *child : ast_node->children)
-				if (child->type == Yosys::AST::AST_WIRE &&
-						!child->attributes.count(ID::nosync))
-					mark_auto_nosync(ast_node, child);
-
-		std::vector<Yosys::AST::AstNode*> new_children;
-		for (size_t i = 0; i < ast_node->children.size(); i++)
-			if (ast_node->children[i]->type == Yosys::AST::AST_WIRE || ast_node->children[i]->type == Yosys::AST::AST_MEMORY || ast_node->children[i]->type == Yosys::AST::AST_PARAMETER || ast_node->children[i]->type == Yosys::AST::AST_LOCALPARAM || ast_node->children[i]->type == Yosys::AST::AST_TYPEDEF) {
-				simplify(ast_node->children[i], false, false, false, stage, -1, false, false);
-				current_ast_mod->children.push_back(ast_node->children[i]);
-				current_scope[ast_node->children[i]->str] = ast_node->children[i];
-			} else
-				new_children.push_back(ast_node->children[i]);
-
-		ast_node->children.swap(new_children);
-		did_something = true;
-		ast_node->str.clear();
-	}
-
-	// simplify unconditional generate block
-	if (ast_node->type == Yosys::AST::AST_GENBLOCK && ast_node->children.size() != 0)
-	{
-		if (!ast_node->str.empty()) {
-			ast_node->expand_genblock(ast_node->str + ".");
-		}
-
-		for (size_t i = 0; i < ast_node->children.size(); i++) {
-			simplify(ast_node->children[i], const_fold, false, false, stage, -1, false, false);
-			current_ast_mod->children.push_back(ast_node->children[i]);
-		}
-
-		ast_node->children.clear();
-		did_something = true;
-	}
-
-	// simplify generate-if blocks
-	if (ast_node->type == Yosys::AST::AST_GENIF && ast_node->children.size() != 0)
-	{
-		Yosys::AST::AstNode *buf = ast_node->children[0]->clone();
-		while (simplify(buf, true, false, false, stage, width_hint, sign_hint, false)) { }
-		if (buf->type != Yosys::AST::AST_CONSTANT) {
-			// for (auto f : log_files)
-			// 	dumpAst(f, "verilog-ast> ");
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Condition for generate if is not constant!\n");
-		}
-		if (buf->asBool() != 0) {
-			delete buf;
-			buf = ast_node->children[1]->clone();
-		} else {
-			delete buf;
-			buf = ast_node->children.size() > 2 ? ast_node->children[2]->clone() : NULL;
-		}
-
-		if (buf)
-		{
-			if (buf->type != Yosys::AST::AST_GENBLOCK)
-				buf = new Yosys::AST::AstNode(Yosys::AST::AST_GENBLOCK, buf);
-
-			if (!buf->str.empty()) {
-				buf->expand_genblock(buf->str + ".");
-			}
-
-			for (size_t i = 0; i < buf->children.size(); i++) {
-				simplify(buf->children[i], const_fold, false, false, stage, -1, false, false);
-				current_ast_mod->children.push_back(buf->children[i]);
-			}
-
-			buf->children.clear();
-			delete buf;
-		}
-
-		ast_node->delete_children();
-		did_something = true;
-	}
-
-	// simplify generate-case blocks
-	if (ast_node->type == Yosys::AST::AST_GENCASE && ast_node->children.size() != 0)
-	{
-		Yosys::AST::AstNode *buf = ast_node->children[0]->clone();
-		while (simplify(buf, true, false, false, stage, width_hint, sign_hint, false)) { }
-		if (buf->type != Yosys::AST::AST_CONSTANT) {
-			// for (auto f : log_files)
-			// 	dumpAst(f, "verilog-ast> ");
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Condition for generate case is not constant!\n");
-		}
-
-		bool ref_signed = buf->is_signed;
-		RTLIL::Const ref_value = buf->bitsAsConst();
-		delete buf;
-
-		Yosys::AST::AstNode *selected_case = NULL;
-		for (size_t i = 1; i < ast_node->children.size(); i++)
-		{
-			log_assert(ast_node->children.at(i)->type == Yosys::AST::AST_COND || ast_node->children.at(i)->type == Yosys::AST::AST_CONDX || ast_node->children.at(i)->type == Yosys::AST::AST_CONDZ);
-
-			Yosys::AST::AstNode *this_genblock = NULL;
-			for (auto child : ast_node->children.at(i)->children) {
-				log_assert(this_genblock == NULL);
-				if (child->type == Yosys::AST::AST_GENBLOCK)
-					this_genblock = child;
-			}
-
-			for (auto child : ast_node->children.at(i)->children)
-			{
-				if (child->type == Yosys::AST::AST_DEFAULT) {
-					if (selected_case == NULL)
-						selected_case = this_genblock;
-					continue;
-				}
-				if (child->type == Yosys::AST::AST_GENBLOCK)
-					continue;
-
-				buf = child->clone();
-				while (simplify(buf, true, false, false, stage, width_hint, sign_hint, true)) { }
-				if (buf->type != Yosys::AST::AST_CONSTANT) {
-					// for (auto f : log_files)
-					// 	dumpAst(f, "verilog-ast> ");
-					log_file_error(ast_node->filename, ast_node->location.first_line, "Expression in generate case is not constant!\n");
-				}
-
-				bool is_selected = RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool();
-				delete buf;
-
-				if (is_selected) {
-					selected_case = this_genblock;
-					i = ast_node->children.size();
-					break;
-				}
-			}
-		}
-
-		if (selected_case != NULL)
-		{
-			log_assert(selected_case->type == Yosys::AST::AST_GENBLOCK);
-			buf = selected_case->clone();
-
-			if (!buf->str.empty()) {
-				buf->expand_genblock(buf->str + ".");
-			}
-
-			for (size_t i = 0; i < buf->children.size(); i++) {
-				simplify(buf->children[i], const_fold, false, false, stage, -1, false, false);
-				current_ast_mod->children.push_back(buf->children[i]);
-			}
-
-			buf->children.clear();
-			delete buf;
-		}
-
-		ast_node->delete_children();
-		did_something = true;
-	}
-
-	// unroll cell arrays
-	if (ast_node->type == Yosys::AST::AST_CELLARRAY)
-	{
-		if (!ast_node->children.at(0)->range_valid)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Non-constant array range on cell array.\n");
-
-		newNode = new Yosys::AST::AstNode(Yosys::AST::AST_GENBLOCK);
-		int num = max(ast_node->children.at(0)->range_left, ast_node->children.at(0)->range_right) - min(ast_node->children.at(0)->range_left, ast_node->children.at(0)->range_right) + 1;
-
-		for (int i = 0; i < num; i++) {
-			int idx = ast_node->children.at(0)->range_left > ast_node->children.at(0)->range_right ? ast_node->children.at(0)->range_right + i : ast_node->children.at(0)->range_right - i;
-			Yosys::AST::AstNode *new_cell = ast_node->children.at(1)->clone();
-			newNode->children.push_back(new_cell);
-			new_cell->str += stringf("[%d]", idx);
-			if (new_cell->type == Yosys::AST::AST_PRIMITIVE) {
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Cell arrays of primitives are currently not supported.\n");
-			} else {
-				log_assert(new_cell->children.at(0)->type == Yosys::AST::AST_CELLTYPE);
-				new_cell->children.at(0)->str = stringf("$array:%d:%d:%s", i, num, new_cell->children.at(0)->str.c_str());
-			}
-		}
-
-		goto apply_newNode;
-	}
-
-	// replace primitives with assignments
-	if (ast_node->type == Yosys::AST::AST_PRIMITIVE)
-	{
-		if (ast_node->children.size() < 2)
-			log_file_error(ast_node->filename, ast_node->location.first_line, "Insufficient number of arguments for primitive `%s'!\n", ast_node->str.c_str());
-
-		std::vector<Yosys::AST::AstNode*> children_list;
-		for (auto child : ast_node->children) {
-			log_assert(child->type == Yosys::AST::AST_ARGUMENT);
-			log_assert(child->children.size() == 1);
-			children_list.push_back(child->children[0]);
-			child->children.clear();
-			delete child;
-		}
-		ast_node->children.clear();
-
-		if (ast_node->str == "bufif0" || ast_node->str == "bufif1" || ast_node->str == "notif0" || ast_node->str == "notif1")
-		{
-			if (children_list.size() != 3)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Invalid number of arguments for primitive `%s'!\n", ast_node->str.c_str());
-
-			std::vector<RTLIL::State> z_const(1, RTLIL::State::Sz);
-
-			Yosys::AST::AstNode *mux_input = children_list.at(1);
-			if (ast_node->str == "notif0" || ast_node->str == "notif1") {
-				mux_input = new Yosys::AST::AstNode(Yosys::AST::AST_BIT_NOT, mux_input);
-			}
-			Yosys::AST::AstNode *node = new Yosys::AST::AstNode(Yosys::AST::AST_TERNARY, children_list.at(2));
-			if (ast_node->str == "bufif0") {
-				node->children.push_back(Yosys::AST::AstNode::mkconst_bits(z_const, false));
-				node->children.push_back(mux_input);
-			} else {
-				node->children.push_back(mux_input);
-				node->children.push_back(Yosys::AST::AstNode::mkconst_bits(z_const, false));
-			}
-
-			ast_node->str.clear();
-			ast_node->type = Yosys::AST::AST_ASSIGN;
-			ast_node->children.push_back(children_list.at(0));
-			ast_node->children.back()->was_checked = true;
-			ast_node->children.push_back(node);
-			did_something = true;
-		}
-		else if (ast_node->str == "buf" || ast_node->str == "not")
-		{
-			Yosys::AST::AstNode *input = children_list.back();
-			if (ast_node->str == "not")
-				input = new Yosys::AST::AstNode(Yosys::AST::AST_BIT_NOT, input);
-
-			newNode = new Yosys::AST::AstNode(Yosys::AST::AST_GENBLOCK);
-			for (auto it = children_list.begin(); it != std::prev(children_list.end()); it++) {
-				newNode->children.push_back(new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN, *it, input->clone()));
-				newNode->children.back()->was_checked = true;
-			}
-			delete input;
-
-			did_something = true;
-		}
-		else
-		{
-			Yosys::AST::AstNodeType op_type = Yosys::AST::AST_NONE;
-			bool invert_results = false;
-
-			if (ast_node->str == "and")
-				op_type = Yosys::AST::AST_BIT_AND;
-			if (ast_node->str == "nand")
-				op_type = Yosys::AST::AST_BIT_AND, invert_results = true;
-			if (ast_node->str == "or")
-				op_type = Yosys::AST::AST_BIT_OR;
-			if (ast_node->str == "nor")
-				op_type = Yosys::AST::AST_BIT_OR, invert_results = true;
-			if (ast_node->str == "xor")
-				op_type = Yosys::AST::AST_BIT_XOR;
-			if (ast_node->str == "xnor")
-				op_type = Yosys::AST::AST_BIT_XOR, invert_results = true;
-			log_assert(op_type != Yosys::AST::AST_NONE);
-
-			Yosys::AST::AstNode *node = children_list[1];
-			if (op_type != Yosys::AST::AST_POS)
-				for (size_t i = 2; i < children_list.size(); i++) {
-					node = new Yosys::AST::AstNode(op_type, node, children_list[i]);
-					node->location = ast_node->location;
-				}
-			if (invert_results)
-				node = new Yosys::AST::AstNode(Yosys::AST::AST_BIT_NOT, node);
-
-			ast_node->str.clear();
-			ast_node->type = Yosys::AST::AST_ASSIGN;
-			ast_node->children.push_back(children_list[0]);
-			ast_node->children.back()->was_checked = true;
-			ast_node->children.push_back(node);
-			did_something = true;
-		}
-	}
-
-	// replace dynamic ranges in left-hand side expressions (e.g. "foo[bar] <= 1'b1;") with
-	// either a big case block that selects the correct single-bit assignment, or mask and
-	// shift operations.
-	if (ast_node->type == Yosys::AST::AST_ASSIGN_EQ || ast_node->type == Yosys::AST::AST_ASSIGN_LE)
-	{
-		if (ast_node->children[0]->type != Yosys::AST::AST_IDENTIFIER || ast_node->children[0]->children.size() == 0)
-			goto skip_dynamic_range_lvalue_expansion;
-		if (ast_node->children[0]->children[0]->range_valid || did_something)
-			goto skip_dynamic_range_lvalue_expansion;
-		if (ast_node->children[0]->id2ast == NULL || ast_node->children[0]->id2ast->type != Yosys::AST::AST_WIRE)
-			goto skip_dynamic_range_lvalue_expansion;
-		if (!ast_node->children[0]->id2ast->range_valid)
-			goto skip_dynamic_range_lvalue_expansion;
-
-		int source_width = ast_node->children[0]->id2ast->range_left - ast_node->children[0]->id2ast->range_right + 1;
-		int source_offset = ast_node->children[0]->id2ast->range_right;
-		int result_width = 1;
-		Yosys::AST::AstNode *member_node = systemverilog_plugin::get_struct_member(ast_node->children[0]);
-		if (member_node) {
-			// Clamp chunk to range of member within struct/union.
-			log_assert(!source_offset && !ast_node->children[0]->id2ast->range_swapped);
-			source_width = member_node->range_left - member_node->range_right + 1;
-		}
-
-		Yosys::AST::AstNode *shift_expr = NULL;
-		Yosys::AST::AstNode *range = ast_node->children[0]->children[0];
-
-		if (range->children.size() == 1) {
-			shift_expr = range->children[0]->clone();
-		} else {
-			shift_expr = range->children[1]->clone();
-			Yosys::AST::AstNode *left_at_zero_ast = range->children[0]->clone();
-			Yosys::AST::AstNode *right_at_zero_ast = range->children[1]->clone();
-			while (simplify(left_at_zero_ast, true, true, false, stage, -1, false, false)) { }
-			while (simplify(right_at_zero_ast, true, true, false, stage, -1, false, false)) { }
-			if (left_at_zero_ast->type != Yosys::AST::AST_CONSTANT || right_at_zero_ast->type != Yosys::AST::AST_CONSTANT)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Unsupported expression on dynamic range select on signal `%s'!\n", ast_node->str.c_str());
-			result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
-			delete left_at_zero_ast;
-			delete right_at_zero_ast;
-		}
-
-		bool use_case_method = false;
-
-		if (ast_node->children[0]->id2ast->attributes.count(ID::nowrshmsk)) {
-			Yosys::AST::AstNode *node = ast_node->children[0]->id2ast->attributes.at(ID::nowrshmsk);
-			while (simplify(node, true, false, false, stage, -1, false, false)) { }
-			if (node->type != Yosys::AST::AST_CONSTANT)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Non-constant value for `nowrshmsk' attribute on `%s'!\n", ast_node->children[0]->id2ast->str.c_str());
-			if (node->asAttrConst().as_bool())
-				use_case_method = true;
-		}
-
-		if (!use_case_method && current_always->detect_latch(ast_node->children[0]->str))
-			use_case_method = true;
-
-		if (use_case_method)
-		{
-			// big case block
-
-			did_something = true;
-			newNode = new Yosys::AST::AstNode(Yosys::AST::AST_CASE, shift_expr);
-			for (int i = 0; i < source_width; i++) {
-				int start_bit = source_offset + i;
-				int end_bit = std::min(start_bit+result_width,source_width) - 1;
-				Yosys::AST::AstNode *cond = new Yosys::AST::AstNode(Yosys::AST::AST_COND, ast_node->mkconst_int(start_bit, true));
-				Yosys::AST::AstNode *lvalue = ast_node->children[0]->clone();
-				lvalue->delete_children();
-				if (member_node)
-					lvalue->attributes[ID::wiretype] = member_node->clone();
-				lvalue->children.push_back(new Yosys::AST::AstNode(Yosys::AST::AST_RANGE,
-						ast_node->mkconst_int(end_bit, true), ast_node->mkconst_int(start_bit, true)));
-				cond->children.push_back(new Yosys::AST::AstNode(Yosys::AST::AST_BLOCK, new Yosys::AST::AstNode(ast_node->type, lvalue, ast_node->children[1]->clone())));
-				newNode->children.push_back(cond);
-			}
-		}
-		else
-		{
-			// mask and shift operations, disabled for now
-
-			Yosys::AST::AstNode *wire_mask = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE, new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, ast_node->mkconst_int(source_width-1, true), ast_node->mkconst_int(0, true)));
-			wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", encode_filename(ast_node->filename).c_str(), ast_node->location.first_line, autoidx++);
-			wire_mask->attributes[ID::nosync] = ast_node->mkconst_int(1, false);
-			wire_mask->is_logic = true;
-			while (simplify(wire_mask, true, false, false, 1, -1, false, false)) { }
-			current_ast_mod->children.push_back(wire_mask);
-
-			Yosys::AST::AstNode *wire_data = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE, new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, ast_node->mkconst_int(source_width-1, true), ast_node->mkconst_int(0, true)));
-			wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", encode_filename(ast_node->filename).c_str(), ast_node->location.first_line, autoidx++);
-			wire_data->attributes[ID::nosync] = ast_node->mkconst_int(1, false);
-			wire_data->is_logic = true;
-			while (simplify(wire_data, true, false, false, 1, -1, false, false)) { }
-			current_ast_mod->children.push_back(wire_data);
-
-			int shamt_width_hint = -1;
-			bool shamt_sign_hint = true;
-			shift_expr->detectSignWidth(shamt_width_hint, shamt_sign_hint);
-
-			Yosys::AST::AstNode *wire_sel = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE, new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, ast_node->mkconst_int(shamt_width_hint-1, true), ast_node->mkconst_int(0, true)));
-			wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", encode_filename(ast_node->filename).c_str(), ast_node->location.first_line, autoidx++);
-			wire_sel->attributes[ID::nosync] = ast_node->mkconst_int(1, false);
-			wire_sel->is_logic = true;
-			wire_sel->is_signed = shamt_sign_hint;
-			while (simplify(wire_sel, true, false, false, 1, -1, false, false)) { }
-			current_ast_mod->children.push_back(wire_sel);
-
-			did_something = true;
-			newNode = new Yosys::AST::AstNode(Yosys::AST::AST_BLOCK);
-
-			Yosys::AST::AstNode *lvalue = ast_node->children[0]->clone();
-			lvalue->delete_children();
-			if (member_node)
-				lvalue->attributes[ID::wiretype] = member_node->clone();
-
-			Yosys::AST::AstNode *ref_mask = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-			ref_mask->str = wire_mask->str;
-			ref_mask->id2ast = wire_mask;
-			ref_mask->was_checked = true;
-
-			Yosys::AST::AstNode *ref_data = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-			ref_data->str = wire_data->str;
-			ref_data->id2ast = wire_data;
-			ref_data->was_checked = true;
-
-			Yosys::AST::AstNode *ref_sel = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-			ref_sel->str = wire_sel->str;
-			ref_sel->id2ast = wire_sel;
-			ref_sel->was_checked = true;
-
-			Yosys::AST::AstNode *old_data = lvalue->clone();
-			if (ast_node->type == Yosys::AST::AST_ASSIGN_LE)
-				old_data->lookahead = true;
-
-			Yosys::AST::AstNode *s = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, ref_sel->clone(), shift_expr);
-			newNode->children.push_back(s);
-
-			Yosys::AST::AstNode *shamt = ref_sel;
-
-			// convert to signed while preserving the sign and value
-			shamt = new Yosys::AST::AstNode(Yosys::AST::AST_CAST_SIZE, ast_node->mkconst_int(shamt_width_hint + 1, true), shamt);
-			shamt = new Yosys::AST::AstNode(Yosys::AST::AST_TO_SIGNED, shamt);
-
-			// offset the shift amount by the lower bound of the dimension
-			int start_bit = source_offset;
-			shamt = new Yosys::AST::AstNode(Yosys::AST::AST_SUB, shamt, ast_node->mkconst_int(start_bit, true));
-
-			// reflect the shift amount if the dimension is swapped
-			if (ast_node->children[0]->id2ast->range_swapped)
-				shamt = new Yosys::AST::AstNode(Yosys::AST::AST_SUB, ast_node->mkconst_int(source_width - result_width, true), shamt);
-
-			// AST_SHIFT uses negative amounts for shifting left
-			shamt = new Yosys::AST::AstNode(Yosys::AST::AST_NEG, shamt);
-
-			Yosys::AST::AstNode *t;
-
-			t = Yosys::AST::AstNode::mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false);
-			t = new Yosys::AST::AstNode(Yosys::AST::AST_SHIFT, t, shamt->clone());
-			t = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, ref_mask->clone(), t);
-			newNode->children.push_back(t);
-
-			t = new Yosys::AST::AstNode(Yosys::AST::AST_BIT_AND, Yosys::AST::AstNode::mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), ast_node->children[1]->clone());
-			t = new Yosys::AST::AstNode(Yosys::AST::AST_SHIFT, t, shamt);
-			t = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, ref_data->clone(), t);
-			newNode->children.push_back(t);
-
-			t = new Yosys::AST::AstNode(Yosys::AST::AST_BIT_AND, old_data, new Yosys::AST::AstNode(Yosys::AST::AST_BIT_NOT, ref_mask));
-			t = new Yosys::AST::AstNode(Yosys::AST::AST_BIT_OR, t, ref_data);
-			t = new Yosys::AST::AstNode(ast_node->type, lvalue, t);
-			newNode->children.push_back(t);
-		}
-
-		goto apply_newNode;
-	}
-skip_dynamic_range_lvalue_expansion:;
-
-	if (stage > 1 && (ast_node->type == Yosys::AST::AST_ASSERT || ast_node->type == Yosys::AST::AST_ASSUME || ast_node->type == Yosys::AST::AST_LIVE || ast_node->type == Yosys::AST::AST_FAIR || ast_node->type == Yosys::AST::AST_COVER) && current_block != NULL)
-	{
-		std::stringstream sstr;
-		sstr << "$formal$" << encode_filename(ast_node->filename) << ":" << ast_node->location.first_line << "$" << (autoidx++);
-		std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN";
-
-		Yosys::AST::AstNode *wire_check = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE);
-		wire_check->str = id_check;
-		wire_check->was_checked = true;
-		current_ast_mod->children.push_back(wire_check);
-		current_scope[wire_check->str] = wire_check;
-		while (simplify(wire_check, true, false, false, 1, -1, false, false)) { }
-
-		Yosys::AST::AstNode *wire_en = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE);
-		wire_en->str = id_en;
-		wire_en->was_checked = true;
-		current_ast_mod->children.push_back(wire_en);
-		if (current_always_clocked) {
-			current_ast_mod->children.push_back(new Yosys::AST::AstNode(Yosys::AST::AST_INITIAL, new Yosys::AST::AstNode(Yosys::AST::AST_BLOCK, new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_LE, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), ast_node->mkconst_int(0, false, 1)))));
-			current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en;
-			current_ast_mod->children.back()->children[0]->children[0]->children[0]->was_checked = true;
-		}
-		current_scope[wire_en->str] = wire_en;
-		while (simplify(wire_en, true, false, false, 1, -1, false, false)) { }
-
-		Yosys::AST::AstNode *check_defval;
-		if (ast_node->type == Yosys::AST::AST_LIVE || ast_node->type == Yosys::AST::AST_FAIR) {
-			check_defval = new Yosys::AST::AstNode(Yosys::AST::AST_REDUCE_BOOL, ast_node->children[0]->clone());
-		} else {
-			std::vector<RTLIL::State> x_bit;
-			x_bit.push_back(RTLIL::State::Sx);
-			check_defval = Yosys::AST::AstNode::mkconst_bits(x_bit, false);
-		}
-
-		Yosys::AST::AstNode *assign_check = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_LE, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), check_defval);
-		assign_check->children[0]->str = id_check;
-		assign_check->children[0]->was_checked = true;
-
-		Yosys::AST::AstNode *assign_en = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_LE, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), ast_node->mkconst_int(0, false, 1));
-		assign_en->children[0]->str = id_en;
-		assign_en->children[0]->was_checked = true;
-
-		Yosys::AST::AstNode *default_signals = new Yosys::AST::AstNode(Yosys::AST::AST_BLOCK);
-		default_signals->children.push_back(assign_check);
-		default_signals->children.push_back(assign_en);
-		current_top_block->children.insert(current_top_block->children.begin(), default_signals);
-
-		if (ast_node->type == Yosys::AST::AST_LIVE || ast_node->type == Yosys::AST::AST_FAIR) {
-			assign_check = nullptr;
-		} else {
-			assign_check = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_LE, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), new Yosys::AST::AstNode(Yosys::AST::AST_REDUCE_BOOL, ast_node->children[0]->clone()));
-			assign_check->children[0]->str = id_check;
-			assign_check->children[0]->was_checked = true;
-		}
-
-		if (current_always == nullptr || current_always->type != Yosys::AST::AST_INITIAL) {
-			assign_en = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_LE, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), ast_node->mkconst_int(1, false, 1));
-		} else {
-			assign_en = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_LE, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), new Yosys::AST::AstNode(Yosys::AST::AST_FCALL));
-			assign_en->children[1]->str = "\\$initstate";
-		}
-		assign_en->children[0]->str = id_en;
-		assign_en->children[0]->was_checked = true;
-
-		newNode = new Yosys::AST::AstNode(Yosys::AST::AST_BLOCK);
-		if (assign_check != nullptr)
-			newNode->children.push_back(assign_check);
-		newNode->children.push_back(assign_en);
-
-		Yosys::AST::AstNode *assertnode = new Yosys::AST::AstNode(ast_node->type);
-		assertnode->location = ast_node->location;
-		assertnode->str = ast_node->str;
-		assertnode->children.push_back(new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER));
-		assertnode->children.push_back(new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER));
-		assertnode->children[0]->str = id_check;
-		assertnode->children[1]->str = id_en;
-		assertnode->attributes.swap(ast_node->attributes);
-		current_ast_mod->children.push_back(assertnode);
-
-		goto apply_newNode;
-	}
-
-	if (stage > 1 && (ast_node->type == Yosys::AST::AST_ASSERT || ast_node->type == Yosys::AST::AST_ASSUME || ast_node->type == Yosys::AST::AST_LIVE || ast_node->type == Yosys::AST::AST_FAIR || ast_node->type == Yosys::AST::AST_COVER) && ast_node->children.size() == 1)
-	{
-		ast_node->children.push_back(ast_node->mkconst_int(1, false, 1));
-		did_something = true;
-	}
-
-	// found right-hand side identifier for memory -> replace with memory read port
-	if (stage > 1 && ast_node->type == Yosys::AST::AST_IDENTIFIER && ast_node->id2ast != NULL && ast_node->id2ast->type == Yosys::AST::AST_MEMORY && !in_lvalue &&
-			ast_node->children.size() == 1 && ast_node->children[0]->type == Yosys::AST::AST_RANGE && ast_node->children[0]->children.size() == 1) {
-		newNode = new Yosys::AST::AstNode(Yosys::AST::AST_MEMRD, ast_node->children[0]->children[0]->clone());
-		newNode->str = ast_node->str;
-		newNode->id2ast = ast_node->id2ast;
-		goto apply_newNode;
-	}
-
-	// assignment with nontrivial member in left-hand concat expression -> split assignment
-	if ((ast_node->type == Yosys::AST::AST_ASSIGN_EQ || ast_node->type == Yosys::AST::AST_ASSIGN_LE) && ast_node->children[0]->type == Yosys::AST::AST_CONCAT && width_hint > 0)
-	{
-		bool found_nontrivial_member = false;
-
-		for (auto child : ast_node->children[0]->children) {
-			if (child->type == Yosys::AST::AST_IDENTIFIER && child->id2ast != NULL && child->id2ast->type == Yosys::AST::AST_MEMORY)
-				found_nontrivial_member = true;
-		}
-
-		if (found_nontrivial_member)
-		{
-			newNode = new Yosys::AST::AstNode(Yosys::AST::AST_BLOCK);
-
-			Yosys::AST::AstNode *wire_tmp = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE, new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, ast_node->mkconst_int(width_hint-1, true), ast_node->mkconst_int(0, true)));
-			wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", encode_filename(ast_node->filename).c_str(), ast_node->location.first_line, autoidx++);
-			current_ast_mod->children.push_back(wire_tmp);
-			current_scope[wire_tmp->str] = wire_tmp;
-			wire_tmp->attributes[ID::nosync] = ast_node->mkconst_int(1, false);
-			while (simplify(wire_tmp, true, false, false, 1, -1, false, false)) { }
-			wire_tmp->is_logic = true;
-
-			Yosys::AST::AstNode *wire_tmp_id = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-			wire_tmp_id->str = wire_tmp->str;
-
-			newNode->children.push_back(new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, wire_tmp_id, ast_node->children[1]->clone()));
-			newNode->children.back()->was_checked = true;
-
-			int cursor = 0;
-			for (auto child : ast_node->children[0]->children)
-			{
-				int child_width_hint = -1;
-				bool child_sign_hint = true;
-				child->detectSignWidth(child_width_hint, child_sign_hint);
-
-				Yosys::AST::AstNode *rhs = wire_tmp_id->clone();
-				rhs->children.push_back(new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, ast_node->mkconst_int(cursor+child_width_hint-1, true), ast_node->mkconst_int(cursor, true)));
-				newNode->children.push_back(new Yosys::AST::AstNode(ast_node->type, child->clone(), rhs));
-
-				cursor += child_width_hint;
-			}
-
-			goto apply_newNode;
-		}
-	}
-
-	// assignment with memory in left-hand side expression -> replace with memory write port
-	if (stage > 1 && (ast_node->type == Yosys::AST::AST_ASSIGN_EQ || ast_node->type == Yosys::AST::AST_ASSIGN_LE) && ast_node->children[0]->type == Yosys::AST::AST_IDENTIFIER &&
-			ast_node->children[0]->id2ast && ast_node->children[0]->id2ast->type == Yosys::AST::AST_MEMORY && ast_node->children[0]->id2ast->children.size() >= 2 &&
-			ast_node->children[0]->id2ast->children[0]->range_valid && ast_node->children[0]->id2ast->children[1]->range_valid &&
-			(ast_node->children[0]->children.size() == 1 || ast_node->children[0]->children.size() == 2) && ast_node->children[0]->children[0]->type == Yosys::AST::AST_RANGE)
-	{
-		std::stringstream sstr;
-		sstr << "$memwr$" << ast_node->children[0]->str << "$" << encode_filename(ast_node->filename) << ":" << ast_node->location.first_line << "$" << (autoidx++);
-		std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
-
-		int mem_width, mem_size, addr_bits;
-		bool mem_signed = ast_node->children[0]->id2ast->is_signed;
-		ast_node->children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
-
-		newNode = new Yosys::AST::AstNode(Yosys::AST::AST_BLOCK);
-		Yosys::AST::AstNode *defNode = new Yosys::AST::AstNode(Yosys::AST::AST_BLOCK);
-
-		int data_range_left = ast_node->children[0]->id2ast->children[0]->range_left;
-		int data_range_right = ast_node->children[0]->id2ast->children[0]->range_right;
-		int mem_data_range_offset = std::min(data_range_left, data_range_right);
-
-		int addr_width_hint = -1;
-		bool addr_sign_hint = true;
-		ast_node->children[0]->children[0]->children[0]->detectSignWidthWorker(addr_width_hint, addr_sign_hint);
-		addr_bits = std::max(addr_bits, addr_width_hint);
-
-		std::vector<RTLIL::State> x_bits_addr, x_bits_data, set_bits_en;
-		for (int i = 0; i < addr_bits; i++)
-			x_bits_addr.push_back(RTLIL::State::Sx);
-		for (int i = 0; i < mem_width; i++)
-			x_bits_data.push_back(RTLIL::State::Sx);
-		for (int i = 0; i < mem_width; i++)
-			set_bits_en.push_back(RTLIL::State::S1);
-
-		Yosys::AST::AstNode *node_addr = nullptr;
-		if (ast_node->children[0]->children[0]->children[0]->isConst()) {
-			node_addr = ast_node->children[0]->children[0]->children[0]->clone();
-		} else {
-			Yosys::AST::AstNode *wire_addr = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE, new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, ast_node->mkconst_int(addr_bits-1, true), ast_node->mkconst_int(0, true)));
-			wire_addr->str = id_addr;
-			wire_addr->was_checked = true;
-			current_ast_mod->children.push_back(wire_addr);
-			current_scope[wire_addr->str] = wire_addr;
-			while (simplify(wire_addr, true, false, false, 1, -1, false, false)) { }
-
-			Yosys::AST::AstNode *assign_addr = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), Yosys::AST::AstNode::mkconst_bits(x_bits_addr, false));
-			assign_addr->children[0]->str = id_addr;
-			assign_addr->children[0]->was_checked = true;
-			defNode->children.push_back(assign_addr);
-
-			assign_addr = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), ast_node->children[0]->children[0]->children[0]->clone());
-			assign_addr->children[0]->str = id_addr;
-			assign_addr->children[0]->was_checked = true;
-			newNode->children.push_back(assign_addr);
-
-			node_addr = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-			node_addr->str = id_addr;
-		}
-
-		Yosys::AST::AstNode *node_data = nullptr;
-		if (ast_node->children[0]->children.size() == 1 && ast_node->children[1]->isConst()) {
-			node_data = ast_node->children[1]->clone();
-		} else {
-			Yosys::AST::AstNode *wire_data = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE, new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, ast_node->mkconst_int(mem_width-1, true), ast_node->mkconst_int(0, true)));
-			wire_data->str = id_data;
-			wire_data->was_checked = true;
-			wire_data->is_signed = mem_signed;
-			current_ast_mod->children.push_back(wire_data);
-			current_scope[wire_data->str] = wire_data;
-			while (simplify(wire_data, true, false, false, 1, -1, false, false)) { }
-
-			Yosys::AST::AstNode *assign_data = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), Yosys::AST::AstNode::mkconst_bits(x_bits_data, false));
-			assign_data->children[0]->str = id_data;
-			assign_data->children[0]->was_checked = true;
-			defNode->children.push_back(assign_data);
-
-			node_data = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-			node_data->str = id_data;
-		}
-
-		Yosys::AST::AstNode *wire_en = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE, new Yosys::AST::AstNode(Yosys::AST::AST_RANGE, ast_node->mkconst_int(mem_width-1, true), ast_node->mkconst_int(0, true)));
-		wire_en->str = id_en;
-		wire_en->was_checked = true;
-		current_ast_mod->children.push_back(wire_en);
-		current_scope[wire_en->str] = wire_en;
-		while (simplify(wire_en, true, false, false, 1, -1, false, false)) { }
-
-		Yosys::AST::AstNode *assign_en_first = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), ast_node->mkconst_int(0, false, mem_width));
-		assign_en_first->children[0]->str = id_en;
-		assign_en_first->children[0]->was_checked = true;
-		defNode->children.push_back(assign_en_first);
-
-		Yosys::AST::AstNode *node_en = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-		node_en->str = id_en;
-
-		if (!defNode->children.empty())
-			current_top_block->children.insert(current_top_block->children.begin(), defNode);
-		else
-			delete defNode;
-
-		Yosys::AST::AstNode *assign_data = nullptr;
-		Yosys::AST::AstNode *assign_en = nullptr;
-		if (ast_node->children[0]->children.size() == 2)
-		{
-			if (ast_node->children[0]->children[1]->range_valid)
-			{
-				int offset = ast_node->children[0]->children[1]->range_right;
-				int width = ast_node->children[0]->children[1]->range_left - offset + 1;
-				offset -= mem_data_range_offset;
-
-				std::vector<RTLIL::State> padding_x(offset, RTLIL::State::Sx);
-
-				assign_data = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER),
-						new Yosys::AST::AstNode(Yosys::AST::AST_CONCAT, Yosys::AST::AstNode::mkconst_bits(padding_x, false), ast_node->children[1]->clone()));
-				assign_data->children[0]->str = id_data;
-				assign_data->children[0]->was_checked = true;
-
-				for (int i = 0; i < mem_width; i++)
-					set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
-				assign_en = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), Yosys::AST::AstNode::mkconst_bits(set_bits_en, false));
-				assign_en->children[0]->str = id_en;
-				assign_en->children[0]->was_checked = true;
-			}
-			else
-			{
-				Yosys::AST::AstNode *the_range = ast_node->children[0]->children[1];
-				Yosys::AST::AstNode *left_at_zero_ast = the_range->children[0]->clone();
-				Yosys::AST::AstNode *right_at_zero_ast = the_range->children.size() >= 2 ? the_range->children[1]->clone() : left_at_zero_ast->clone();
-				Yosys::AST::AstNode *offset_ast = right_at_zero_ast->clone();
-
-				if (mem_data_range_offset)
-					offset_ast = new Yosys::AST::AstNode(Yosys::AST::AST_SUB, offset_ast, ast_node->mkconst_int(mem_data_range_offset, true));
-
-				while (simplify(left_at_zero_ast, true, true, false, 1, -1, false, false)) { }
-				while (simplify(right_at_zero_ast, true, true, false, 1, -1, false, false)) { }
-				if (left_at_zero_ast->type != Yosys::AST::AST_CONSTANT || right_at_zero_ast->type != Yosys::AST::AST_CONSTANT)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "Unsupported expression on dynamic range select on signal `%s'!\n", ast_node->str.c_str());
-				int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
-
-				assign_data = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER),
-						new Yosys::AST::AstNode(Yosys::AST::AST_SHIFT_LEFT, ast_node->children[1]->clone(), offset_ast->clone()));
-				assign_data->children[0]->str = id_data;
-				assign_data->children[0]->was_checked = true;
-
-				for (int i = 0; i < mem_width; i++)
-					set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
-				assign_en = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER),
-						new Yosys::AST::AstNode(Yosys::AST::AST_SHIFT_LEFT, Yosys::AST::AstNode::mkconst_bits(set_bits_en, false), offset_ast->clone()));
-				assign_en->children[0]->str = id_en;
-				assign_en->children[0]->was_checked = true;
-
-				delete left_at_zero_ast;
-				delete right_at_zero_ast;
-				delete offset_ast;
-			}
-		}
-		else
-		{
-			if (!(ast_node->children[0]->children.size() == 1 && ast_node->children[1]->isConst())) {
-				assign_data = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), ast_node->children[1]->clone());
-				assign_data->children[0]->str = id_data;
-				assign_data->children[0]->was_checked = true;
-			}
-
-			assign_en = new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER), Yosys::AST::AstNode::mkconst_bits(set_bits_en, false));
-			assign_en->children[0]->str = id_en;
-			assign_en->children[0]->was_checked = true;
-		}
-		if (assign_data)
-			newNode->children.push_back(assign_data);
-		if (assign_en)
-			newNode->children.push_back(assign_en);
-
-		Yosys::AST::AstNode *wrnode;
-		if (current_always->type == Yosys::AST::AST_INITIAL)
-			wrnode = new Yosys::AST::AstNode(Yosys::AST::AST_MEMINIT, node_addr, node_data, node_en, ast_node->mkconst_int(1, false));
-		else
-			wrnode = new Yosys::AST::AstNode(Yosys::AST::AST_MEMWR, node_addr, node_data, node_en);
-		wrnode->str = ast_node->children[0]->str;
-		wrnode->id2ast = ast_node->children[0]->id2ast;
-		wrnode->location = ast_node->location;
-		if (wrnode->type == Yosys::AST::AST_MEMWR) {
-			int portid = current_memwr_count[wrnode->str]++;
-			wrnode->children.push_back(ast_node->mkconst_int(portid, false));
-			std::vector<RTLIL::State> priority_mask;
-			for (int i = 0; i < portid; i++) {
-				bool has_prio = current_memwr_visible[wrnode->str].count(i);
-				priority_mask.push_back(State(has_prio));
-			}
-			wrnode->children.push_back(Yosys::AST::AstNode::mkconst_bits(priority_mask, false));
-			current_memwr_visible[wrnode->str].insert(portid);
-			current_always->children.push_back(wrnode);
-		} else {
-			current_ast_mod->children.push_back(wrnode);
-		}
-
-		if (newNode->children.empty()) {
-			delete newNode;
-			newNode = new Yosys::AST::AstNode();
-		}
-		goto apply_newNode;
-	}
-
-	// replace function and task calls with the code from the function or task
-	if ((ast_node->type == Yosys::AST::AST_FCALL || ast_node->type == Yosys::AST::AST_TCALL) && !ast_node->str.empty())
-	{
-		if (ast_node->type == Yosys::AST::AST_FCALL)
-		{
-			if (ast_node->str == "\\$initstate")
-			{
-				int myidx = autoidx++;
-
-				Yosys::AST::AstNode *wire = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE);
-				wire->str = stringf("$initstate$%d_wire", myidx);
-				current_ast_mod->children.push_back(wire);
-				while (simplify(wire, true, false, false, 1, -1, false, false)) { }
-
-				Yosys::AST::AstNode *cell = new Yosys::AST::AstNode(Yosys::AST::AST_CELL, new Yosys::AST::AstNode(Yosys::AST::AST_CELLTYPE), new Yosys::AST::AstNode(Yosys::AST::AST_ARGUMENT, new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER)));
-				cell->str = stringf("$initstate$%d", myidx);
-				cell->children[0]->str = "$initstate";
-				cell->children[1]->str = "\\Y";
-				cell->children[1]->children[0]->str = wire->str;
-				cell->children[1]->children[0]->id2ast = wire;
-				current_ast_mod->children.push_back(cell);
-				while (simplify(cell, true, false, false, 1, -1, false, false)) { }
-
-				newNode = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-				newNode->str = wire->str;
-				newNode->id2ast = wire;
-				goto apply_newNode;
-			}
-
-			if (ast_node->str == "\\$past")
-			{
-				if (width_hint < 0)
-					goto replace_fcall_later;
-
-				int num_steps = 1;
-
-				if (GetSize(ast_node->children) != 1 && GetSize(ast_node->children) != 2)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s got %d arguments, expected 1 or 2.\n",
-							RTLIL::unescape_id(ast_node->str).c_str(), int(ast_node->children.size()));
-
-				if (!current_always_clocked)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s is only allowed in clocked blocks.\n",
-							RTLIL::unescape_id(ast_node->str).c_str());
-
-				if (GetSize(ast_node->children) == 2)
-				{
-					Yosys::AST::AstNode *buf = ast_node->children[1]->clone();
-					while (simplify(buf, true, false, false, stage, -1, false, false)) { }
-					if (buf->type != Yosys::AST::AST_CONSTANT)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system function `%s' with non-constant value.\n", ast_node->str.c_str());
-
-					num_steps = buf->asInt(true);
-					delete buf;
-				}
-
-				Yosys::AST::AstNode *block = nullptr;
-
-				for (auto child : current_always->children)
-					if (child->type == Yosys::AST::AST_BLOCK)
-						block = child;
-
-				log_assert(block != nullptr);
-
-				if (num_steps == 0) {
-					newNode = ast_node->children[0]->clone();
-					goto apply_newNode;
-				}
-
-				int myidx = autoidx++;
-				Yosys::AST::AstNode *outreg = nullptr;
-
-				for (int i = 0; i < num_steps; i++)
-				{
-					Yosys::AST::AstNode *reg = new Yosys::AST::AstNode(Yosys::AST::AST_WIRE, new Yosys::AST::AstNode(Yosys::AST::AST_RANGE,
-							ast_node->mkconst_int(width_hint-1, true), ast_node->mkconst_int(0, true)));
-
-					reg->str = stringf("$past$%s:%d$%d$%d", encode_filename(ast_node->filename).c_str(), ast_node->location.first_line, myidx, i);
-					reg->is_reg = true;
-					reg->is_signed = sign_hint;
-
-					current_ast_mod->children.push_back(reg);
-
-					while (simplify(reg, true, false, false, 1, -1, false, false)) { }
-
-					Yosys::AST::AstNode *regid = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-					regid->str = reg->str;
-					regid->id2ast = reg;
-					regid->was_checked = true;
-
-					Yosys::AST::AstNode *rhs = nullptr;
-
-					if (outreg == nullptr) {
-						rhs = ast_node->children.at(0)->clone();
-					} else {
-						rhs = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-						rhs->str = outreg->str;
-						rhs->id2ast = outreg;
-					}
-
-					block->children.push_back(new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_LE, regid, rhs));
-					outreg = reg;
-				}
-
-				newNode = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-				newNode->str = outreg->str;
-				newNode->id2ast = outreg;
-				goto apply_newNode;
-			}
-
-			if (ast_node->str == "\\$stable" || ast_node->str == "\\$rose" || ast_node->str == "\\$fell" || ast_node->str == "\\$changed")
-			{
-				if (GetSize(ast_node->children) != 1)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s got %d arguments, expected 1.\n",
-							RTLIL::unescape_id(ast_node->str).c_str(), int(ast_node->children.size()));
-
-				if (!current_always_clocked)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s is only allowed in clocked blocks.\n",
-							RTLIL::unescape_id(ast_node->str).c_str());
-
-				Yosys::AST::AstNode *present = ast_node->children.at(0)->clone();
-				Yosys::AST::AstNode *past = ast_node->clone();
-				past->str = "\\$past";
-
-				if (ast_node->str == "\\$stable")
-					newNode = new Yosys::AST::AstNode(Yosys::AST::AST_EQ, past, present);
-
-				else if (ast_node->str == "\\$changed")
-					newNode = new Yosys::AST::AstNode(Yosys::AST::AST_NE, past, present);
-
-				else if (ast_node->str == "\\$rose")
-					newNode = new Yosys::AST::AstNode(Yosys::AST::AST_LOGIC_AND,
-							new Yosys::AST::AstNode(Yosys::AST::AST_LOGIC_NOT, new Yosys::AST::AstNode(Yosys::AST::AST_BIT_AND, past, ast_node->mkconst_int(1,false))),
-							new Yosys::AST::AstNode(Yosys::AST::AST_BIT_AND, present, ast_node->mkconst_int(1,false)));
-
-				else if (ast_node->str == "\\$fell")
-					newNode = new Yosys::AST::AstNode(Yosys::AST::AST_LOGIC_AND,
-							new Yosys::AST::AstNode(Yosys::AST::AST_BIT_AND, past, ast_node->mkconst_int(1,false)),
-							new Yosys::AST::AstNode(Yosys::AST::AST_LOGIC_NOT, new Yosys::AST::AstNode(Yosys::AST::AST_BIT_AND, present, ast_node->mkconst_int(1,false))));
-
-				else
-					log_abort();
-
-				goto apply_newNode;
-			}
-
-			// $anyconst and $anyseq are mapped in genRTLIL()
-			if (ast_node->str == "\\$anyconst" || ast_node->str == "\\$anyseq" || ast_node->str == "\\$allconst" || ast_node->str == "\\$allseq") {
-				recursion_counter--;
-				return false;
-			}
-
-			if (ast_node->str == "\\$clog2")
-			{
-				if (ast_node->children.size() != 1)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s got %d arguments, expected 1.\n",
-							RTLIL::unescape_id(ast_node->str).c_str(), int(ast_node->children.size()));
-
-				Yosys::AST::AstNode *buf = ast_node->children[0]->clone();
-				while (simplify(buf, true, false, false, stage, width_hint, sign_hint, false)) { }
-				if (buf->type != Yosys::AST::AST_CONSTANT)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system function `%s' with non-constant value.\n", ast_node->str.c_str());
-
-				RTLIL::Const arg_value = buf->bitsAsConst();
-				if (arg_value.as_bool())
-					arg_value = const_sub(arg_value, 1, false, false, GetSize(arg_value));
-				delete buf;
-
-				uint32_t result = 0;
-				for (size_t i = 0; i < arg_value.bits.size(); i++)
-					if (arg_value.bits.at(i) == RTLIL::State::S1)
-						result = i + 1;
-
-				newNode = ast_node->mkconst_int(result, true);
-				goto apply_newNode;
-			}
-
-			if (ast_node->str == "\\$size" || ast_node->str == "\\$bits" || ast_node->str == "\\$high" || ast_node->str == "\\$low" || ast_node->str == "\\$left" || ast_node->str == "\\$right")
-			{
-				int dim = 1;
-				if (ast_node->str == "\\$bits") {
-					if (ast_node->children.size() != 1)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s got %d arguments, expected 1.\n",
-								RTLIL::unescape_id(ast_node->str).c_str(), int(ast_node->children.size()));
-				} else {
-					if (ast_node->children.size() != 1 && ast_node->children.size() != 2)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s got %d arguments, expected 1 or 2.\n",
-							RTLIL::unescape_id(ast_node->str).c_str(), int(ast_node->children.size()));
-					if (ast_node->children.size() == 2) {
-						Yosys::AST::AstNode *buf = ast_node->children[1]->clone();
-						// Evaluate constant expression
-						while (simplify(buf, true, false, false, stage, width_hint, sign_hint, false)) { }
-						dim = buf->asInt(false);
-						delete buf;
-					}
-				}
-				Yosys::AST::AstNode *buf = ast_node->children[0]->clone();
-				int mem_depth = 1;
-				int result, high = 0, low = 0, left = 0, right = 0, width = 1; // defaults for a simple wire
-				Yosys::AST::AstNode *id_ast = NULL;
-
-				// Is this needed?
-				//while (simplify(buf, true, false, false, stage, width_hint, sign_hint, false)) { }
-				buf->detectSignWidth(width_hint, sign_hint);
-
-				if (buf->type == Yosys::AST::AST_IDENTIFIER) {
-					id_ast = buf->id2ast;
-					if (id_ast == NULL && current_scope.count(buf->str))
-						id_ast = current_scope.at(buf->str);
-					if (!id_ast)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to resolve identifier %s for width detection!\n", buf->str.c_str());
-
-					// Check for item in packed struct / union
-					Yosys::AST::AstNode *item_node = systemverilog_plugin::get_struct_member(buf);
-					if (id_ast->type == Yosys::AST::AST_WIRE && item_node) {
-						// The dimension of the original array expression is saved in the 'integer' field
-						dim += buf->integer;
-						if (item_node->multirange_dimensions.empty()) {
-							if (dim != 1)
-								log_file_error(ast_node->filename, ast_node->location.first_line, "Dimension %d out of range in `%s', as it only has one dimension!\n", dim, item_node->str.c_str());
-							left  = high = item_node->range_left;
-							right = low  = item_node->range_right;
-						} else {
-							int dims = GetSize(item_node->multirange_dimensions)/2;
-							if (dim < 1 || dim > dims)
-								log_file_error(ast_node->filename, ast_node->location.first_line, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, item_node->str.c_str(), dims);
-							right = low  = get_struct_range_offset(item_node, dim - 1);
-							left  = high = low + get_struct_range_width(item_node, dim - 1) - 1;
-							if (item_node->multirange_swapped[dim - 1]) {
-								std::swap(left, right);
-							}
-							for (int i = dim; i < dims; i++) {
-							    mem_depth *= get_struct_range_width(item_node, i);
-							}
-						}
-					}
-					// Otherwise, we have 4 cases:
-					// wire x;                ==> AST_WIRE, no AST_RANGE children
-					// wire [1:0]x;           ==> AST_WIRE, AST_RANGE children
-					// wire [1:0]x[1:0];      ==> AST_MEMORY, two AST_RANGE children (1st for packed, 2nd for unpacked)
-					// wire [1:0]x[1:0][1:0]; ==> AST_MEMORY, one AST_RANGE child (0) for packed, then AST_MULTIRANGE child (1) for unpacked
-					// (updated: actually by the time we are here, AST_MULTIRANGE is converted into one big AST_RANGE)
-					// case 0 handled by default
-					else if ((id_ast->type == Yosys::AST::AST_WIRE || id_ast->type == Yosys::AST::AST_MEMORY) && id_ast->children.size() > 0) {
-						// handle packed array left/right for case 1, and cases 2/3 when requesting the last dimension (packed side)
-						Yosys::AST::AstNode *wire_range = id_ast->children[0];
-						left = wire_range->children[0]->integer;
-						right = wire_range->children[1]->integer;
-						high = max(left, right);
-						low  = min(left, right);
-					}
-					if (id_ast->type == Yosys::AST::AST_MEMORY) {
-						// a slice of our identifier means we advance to the next dimension, e.g. $size(a[3])
-						if (buf->children.size() > 0) {
-							// something is hanging below this identifier
-							if (buf->children[0]->type == Yosys::AST::AST_RANGE && buf->integer == 0)
-								// if integer == 0, ast_node node was originally created as Yosys::AST::AST_RANGE so it's dimension is 1
-								dim++;
-							// more than one range, e.g. $size(a[3][2])
-							else // created an Yosys::AST::AST_MULTIRANGE, converted to Yosys::AST::AST_RANGE, but original dimension saved in 'integer' field
-								dim += buf->integer; // increment by multirange size
-						}
-
-						// We got here only if the argument is a memory
-						// Otherwise $size() and $bits() return the expression width
-						Yosys::AST::AstNode *mem_range = id_ast->children[1];
-						if (ast_node->str == "\\$bits") {
-							if (mem_range->type == Yosys::AST::AST_RANGE) {
-								if (!mem_range->range_valid)
-									log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to detect width of memory access `%s'!\n", buf->str.c_str());
-								mem_depth = mem_range->range_left - mem_range->range_right + 1;
-							} else
-								log_file_error(ast_node->filename, ast_node->location.first_line, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str());
-						} else {
-							// $size(), $left(), $right(), $high(), $low()
-							int dims = 1;
-							if (mem_range->type == Yosys::AST::AST_RANGE) {
-								if (id_ast->multirange_dimensions.empty()) {
-									if (!mem_range->range_valid)
-										log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to detect width of memory access `%s'!\n", buf->str.c_str());
-									if (dim == 1) {
-										left  = mem_range->range_right;
-										right = mem_range->range_left;
-										high = max(left, right);
-										low  = min(left, right);
-									}
-								} else {
-									dims = GetSize(id_ast->multirange_dimensions)/2;
-									if (dim <= dims) {
-										width_hint = id_ast->multirange_dimensions[2*dim-1];
-										high = id_ast->multirange_dimensions[2*dim-2] + id_ast->multirange_dimensions[2*dim-1] - 1;
-										low  = id_ast->multirange_dimensions[2*dim-2];
-										if (id_ast->multirange_swapped[dim-1]) {
-											left = low;
-											right = high;
-										} else {
-											right = low;
-											left = high;
-										}
-									} else if ((dim > dims+1) || (dim < 0))
-										log_file_error(ast_node->filename, ast_node->location.first_line, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, buf->str.c_str(), dims+1);
-								}
-							} else {
-								log_file_error(ast_node->filename, ast_node->location.first_line, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str());
-							}
-						}
-					}
-					width = high - low + 1;
-				} else {
-					width = width_hint;
-				}
-				delete buf;
-				if (ast_node->str == "\\$high")
-					result = high;
-				else if (ast_node->str == "\\$low")
-					result = low;
-				else if (ast_node->str == "\\$left")
-					result = left;
-				else if (ast_node->str == "\\$right")
-					result = right;
-				else if (ast_node->str == "\\$size")
-					result = width;
-				else { // ast_node->str == "\\$bits"
-					result = width * mem_depth;
-				}
-				newNode = ast_node->mkconst_int(result, true);
-				goto apply_newNode;
-			}
-
-			if (ast_node->str == "\\$ln" || ast_node->str == "\\$log10" || ast_node->str == "\\$exp" || ast_node->str == "\\$sqrt" || ast_node->str == "\\$pow" ||
-					ast_node->str == "\\$floor" || ast_node->str == "\\$ceil" || ast_node->str == "\\$sin" || ast_node->str == "\\$cos" || ast_node->str == "\\$tan" ||
-					ast_node->str == "\\$asin" || ast_node->str == "\\$acos" || ast_node->str == "\\$atan" || ast_node->str == "\\$atan2" || ast_node->str == "\\$hypot" ||
-					ast_node->str == "\\$sinh" || ast_node->str == "\\$cosh" || ast_node->str == "\\$tanh" || ast_node->str == "\\$asinh" || ast_node->str == "\\$acosh" || ast_node->str == "\\$atanh" ||
-					ast_node->str == "\\$rtoi" || ast_node->str == "\\$itor")
-			{
-				bool func_with_two_arguments = ast_node->str == "\\$pow" || ast_node->str == "\\$atan2" || ast_node->str == "\\$hypot";
-				double x = 0, y = 0;
-
-				if (func_with_two_arguments) {
-					if (ast_node->children.size() != 2)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s got %d arguments, expected 2.\n",
-								RTLIL::unescape_id(ast_node->str).c_str(), int(ast_node->children.size()));
-				} else {
-					if (ast_node->children.size() != 1)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s got %d arguments, expected 1.\n",
-								RTLIL::unescape_id(ast_node->str).c_str(), int(ast_node->children.size()));
-				}
-
-				if (ast_node->children.size() >= 1) {
-					while (simplify(ast_node->children[0], true, false, false, stage, width_hint, sign_hint, false)) { }
-					if (!ast_node->children[0]->isConst())
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system function `%s' with non-constant argument.\n",
-								RTLIL::unescape_id(ast_node->str).c_str());
-					int child_width_hint = width_hint;
-					bool child_sign_hint = sign_hint;
-					ast_node->children[0]->detectSignWidth(child_width_hint, child_sign_hint);
-					x = ast_node->children[0]->asReal(child_sign_hint);
-				}
-
-				if (ast_node->children.size() >= 2) {
-					while (simplify(ast_node->children[1], true, false, false, stage, width_hint, sign_hint, false)) { }
-					if (!ast_node->children[1]->isConst())
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system function `%s' with non-constant argument.\n",
-								RTLIL::unescape_id(ast_node->str).c_str());
-					int child_width_hint = width_hint;
-					bool child_sign_hint = sign_hint;
-					ast_node->children[1]->detectSignWidth(child_width_hint, child_sign_hint);
-					y = ast_node->children[1]->asReal(child_sign_hint);
-				}
-
-				if (ast_node->str == "\\$rtoi") {
-					newNode = ast_node->mkconst_int(x, true);
-				} else {
-					newNode = new Yosys::AST::AstNode(Yosys::AST::AST_REALVALUE);
-					if (ast_node->str == "\\$ln")         newNode->realvalue = ::log(x);
-					else if (ast_node->str == "\\$log10") newNode->realvalue = ::log10(x);
-					else if (ast_node->str == "\\$exp")   newNode->realvalue = ::exp(x);
-					else if (ast_node->str == "\\$sqrt")  newNode->realvalue = ::sqrt(x);
-					else if (ast_node->str == "\\$pow")   newNode->realvalue = ::pow(x, y);
-					else if (ast_node->str == "\\$floor") newNode->realvalue = ::floor(x);
-					else if (ast_node->str == "\\$ceil")  newNode->realvalue = ::ceil(x);
-					else if (ast_node->str == "\\$sin")   newNode->realvalue = ::sin(x);
-					else if (ast_node->str == "\\$cos")   newNode->realvalue = ::cos(x);
-					else if (ast_node->str == "\\$tan")   newNode->realvalue = ::tan(x);
-					else if (ast_node->str == "\\$asin")  newNode->realvalue = ::asin(x);
-					else if (ast_node->str == "\\$acos")  newNode->realvalue = ::acos(x);
-					else if (ast_node->str == "\\$atan")  newNode->realvalue = ::atan(x);
-					else if (ast_node->str == "\\$atan2") newNode->realvalue = ::atan2(x, y);
-					else if (ast_node->str == "\\$hypot") newNode->realvalue = ::hypot(x, y);
-					else if (ast_node->str == "\\$sinh")  newNode->realvalue = ::sinh(x);
-					else if (ast_node->str == "\\$cosh")  newNode->realvalue = ::cosh(x);
-					else if (ast_node->str == "\\$tanh")  newNode->realvalue = ::tanh(x);
-					else if (ast_node->str == "\\$asinh") newNode->realvalue = ::asinh(x);
-					else if (ast_node->str == "\\$acosh") newNode->realvalue = ::acosh(x);
-					else if (ast_node->str == "\\$atanh") newNode->realvalue = ::atanh(x);
-					else if (ast_node->str == "\\$itor")  newNode->realvalue = x;
-					else log_abort();
-				}
-				goto apply_newNode;
-			}
-
-			if (ast_node->str == "\\$sformatf") {
-				Yosys::AST::AstNode *node_string = ast_node->children[0];
-				while (simplify(node_string, true, false, false, stage, width_hint, sign_hint, false)) { }
-				if (node_string->type != Yosys::AST::AST_CONSTANT)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", ast_node->str.c_str());
-				std::string sformat = node_string->bitsAsConst().decode_string();
-				std::string sout = ast_node->process_format_str(sformat, 1, stage, width_hint, sign_hint);
-				newNode = ast_node->mkconst_str(sout);
-				goto apply_newNode;
-			}
-
-			if (ast_node->str == "\\$countbits") {
-				if (ast_node->children.size() < 2)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s got %d arguments, expected at least 2.\n",
-							RTLIL::unescape_id(ast_node->str).c_str(), int(ast_node->children.size()));
-
-				std::vector<RTLIL::State> control_bits;
-
-				// Determine which bits to count
-				for (size_t i = 1; i < ast_node->children.size(); i++) {
-					Yosys::AST::AstNode *node = ast_node->children[i];
-					while (simplify(node, true, false, false, stage, -1, false, false)) { }
-					if (node->type != Yosys::AST::AST_CONSTANT)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system function `%s' with non-constant control bit argument.\n", ast_node->str.c_str());
-					if (node->bits.size() != 1)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system function `%s' with control bit width != 1.\n", ast_node->str.c_str());
-					control_bits.push_back(node->bits[0]);
-				}
-
-				// Detect width of exp (first argument of $countbits)
-				int  exp_width = -1;
-				bool exp_sign  = false;
-				Yosys::AST::AstNode *exp = ast_node->children[0];
-				exp->detectSignWidth(exp_width, exp_sign, NULL);
-
-				newNode = ast_node->mkconst_int(0, false);
-
-				for (int i = 0; i < exp_width; i++) {
-					// Generate nodes for:  exp << i >> ($size(exp) - 1)
-					//                          ^^   ^^
-					Yosys::AST::AstNode *lsh_node = new Yosys::AST::AstNode(Yosys::AST::AST_SHIFT_LEFT, exp->clone(), Yosys::AST::AstNode::mkconst_int(i, false));
-					Yosys::AST::AstNode *rsh_node = new Yosys::AST::AstNode(Yosys::AST::AST_SHIFT_RIGHT, lsh_node, Yosys::AST::AstNode::mkconst_int(exp_width - 1, false));
-
-					Yosys::AST::AstNode *or_node = nullptr;
-
-					for (RTLIL::State control_bit : control_bits) {
-						// Generate node for:  (exp << i >> ($size(exp) - 1)) === control_bit
-						//                                                    ^^^
-						Yosys::AST::AstNode *eq_node = new Yosys::AST::AstNode(Yosys::AST::AST_EQX, rsh_node->clone(), Yosys::AST::AstNode::mkconst_bits({control_bit}, false));
-
-						// Or the result for each checked bit value
-						if (or_node)
-							or_node = new Yosys::AST::AstNode(Yosys::AST::AST_LOGIC_OR, or_node, eq_node);
-						else
-							or_node = eq_node;
-					}
-
-					// We should have at least one element in control_bits,
-					// because we checked for the number of arguments above
-					log_assert(or_node != nullptr);
-
-					delete rsh_node;
-
-					// Generate node for adding with result of previous bit
-					newNode = new Yosys::AST::AstNode(Yosys::AST::AST_ADD, newNode, or_node);
-				}
-
-				goto apply_newNode;
-			}
-
-			if (ast_node->str == "\\$countones" || ast_node->str == "\\$isunknown" || ast_node->str == "\\$onehot" || ast_node->str == "\\$onehot0") {
-				if (ast_node->children.size() != 1)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s got %d arguments, expected 1.\n",
-							RTLIL::unescape_id(ast_node->str).c_str(), int(ast_node->children.size()));
-
-				Yosys::AST::AstNode *countbits = ast_node->clone();
-				countbits->str = "\\$countbits";
-
-				if (ast_node->str == "\\$countones") {
-					countbits->children.push_back(Yosys::AST::AstNode::mkconst_bits({RTLIL::State::S1}, false));
-					newNode = countbits;
-				} else if (ast_node->str == "\\$isunknown") {
-					countbits->children.push_back(Yosys::AST::AstNode::mkconst_bits({RTLIL::Sx}, false));
-					countbits->children.push_back(Yosys::AST::AstNode::mkconst_bits({RTLIL::Sz}, false));
-					newNode = new Yosys::AST::AstNode(Yosys::AST::AST_GT, countbits, Yosys::AST::AstNode::mkconst_int(0, false));
-				} else if (ast_node->str == "\\$onehot") {
-					countbits->children.push_back(Yosys::AST::AstNode::mkconst_bits({RTLIL::State::S1}, false));
-					newNode = new Yosys::AST::AstNode(Yosys::AST::AST_EQ, countbits, Yosys::AST::AstNode::mkconst_int(1, false));
-				} else if (ast_node->str == "\\$onehot0") {
-					countbits->children.push_back(Yosys::AST::AstNode::mkconst_bits({RTLIL::State::S1}, false));
-					newNode = new Yosys::AST::AstNode(Yosys::AST::AST_LE, countbits, Yosys::AST::AstNode::mkconst_int(1, false));
-				} else {
-					log_abort();
-				}
-
-				goto apply_newNode;
-			}
-
-			if (current_scope.count(ast_node->str) != 0 && current_scope[ast_node->str]->type == Yosys::AST::AST_DPI_FUNCTION)
-			{
-				Yosys::AST::AstNode *dpi_decl = current_scope[ast_node->str];
-
-				std::string rtype, fname;
-				std::vector<std::string> argtypes;
-				std::vector<Yosys::AST::AstNode*> args;
-
-				rtype = RTLIL::unescape_id(dpi_decl->children.at(0)->str);
-				fname = RTLIL::unescape_id(dpi_decl->children.at(1)->str);
-
-				for (int i = 2; i < GetSize(dpi_decl->children); i++)
-				{
-					if (i-2 >= GetSize(ast_node->children))
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Insufficient number of arguments in DPI function call.\n");
-
-					argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str));
-					args.push_back(ast_node->children.at(i-2)->clone());
-					while (simplify(args.back(), true, false, false, stage, -1, false, true)) { }
-
-					if (args.back()->type != Yosys::AST::AST_CONSTANT && args.back()->type != Yosys::AST::AST_REALVALUE)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate DPI function with non-constant argument.\n");
-				}
-
-				newNode = dpi_call(rtype, fname, argtypes, args);
-
-				for (auto arg : args)
-					delete arg;
-
-				goto apply_newNode;
-			}
-
-			if (current_scope.count(ast_node->str) == 0)
-				ast_node->str = ast_node->try_pop_module_prefix();
-			if (current_scope.count(ast_node->str) == 0 || current_scope[ast_node->str]->type != Yosys::AST::AST_FUNCTION)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Can't resolve function name `%s'.\n", ast_node->str.c_str());
-		}
-
-		if (ast_node->type == Yosys::AST::AST_TCALL)
-		{
-			if (ast_node->str == "$finish" || ast_node->str == "$stop")
-			{
-				if (!current_always || current_always->type != Yosys::AST::AST_INITIAL)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "System task `%s' outside initial block is unsupported.\n", ast_node->str.c_str());
-
-				log_file_error(ast_node->filename, ast_node->location.first_line, "System task `%s' executed.\n", ast_node->str.c_str());
-			}
-
-			if (ast_node->str == "\\$readmemh" || ast_node->str == "\\$readmemb")
-			{
-				if (GetSize(ast_node->children) < 2 || GetSize(ast_node->children) > 4)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "System function %s got %d arguments, expected 2-4.\n",
-							RTLIL::unescape_id(ast_node->str).c_str(), int(ast_node->children.size()));
-
-				Yosys::AST::AstNode *node_filename = ast_node->children[0]->clone();
-				while (simplify(node_filename, true, false, false, stage, width_hint, sign_hint, false)) { }
-				if (node_filename->type != Yosys::AST::AST_CONSTANT)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", ast_node->str.c_str());
-
-				Yosys::AST::AstNode *node_memory = ast_node->children[1]->clone();
-				while (simplify(node_memory, true, false, false, stage, width_hint, sign_hint, false)) { }
-				if (node_memory->type != Yosys::AST::AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != Yosys::AST::AST_MEMORY)
-					log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system function `%s' with non-memory 2nd argument.\n", ast_node->str.c_str());
-
-				int start_addr = -1, finish_addr = -1;
-
-				if (GetSize(ast_node->children) > 2) {
-					Yosys::AST::AstNode *node_addr = ast_node->children[2]->clone();
-					while (simplify(node_addr, true, false, false, stage, width_hint, sign_hint, false)) { }
-					if (node_addr->type != Yosys::AST::AST_CONSTANT)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system function `%s' with non-constant 3rd argument.\n", ast_node->str.c_str());
-					start_addr = int(node_addr->asInt(false));
-				}
-
-				if (GetSize(ast_node->children) > 3) {
-					Yosys::AST::AstNode *node_addr = ast_node->children[3]->clone();
-					while (simplify(node_addr, true, false, false, stage, width_hint, sign_hint, false)) { }
-					if (node_addr->type != Yosys::AST::AST_CONSTANT)
-						log_file_error(ast_node->filename, ast_node->location.first_line, "Failed to evaluate system function `%s' with non-constant 4th argument.\n", ast_node->str.c_str());
-					finish_addr = int(node_addr->asInt(false));
-				}
-
-				bool unconditional_init = false;
-				if (current_always->type == Yosys::AST::AST_INITIAL) {
-					pool<Yosys::AST::AstNode*> queue;
-					log_assert(current_always->children[0]->type == Yosys::AST::AST_BLOCK);
-					queue.insert(current_always->children[0]);
-					while (!unconditional_init && !queue.empty()) {
-						pool<Yosys::AST::AstNode*> next_queue;
-						for (auto n : queue)
-						for (auto c : n->children) {
-							if (c == ast_node)
-								unconditional_init = true;
-							next_queue.insert(c);
-						}
-						next_queue.swap(queue);
-					}
-				}
-
-				newNode = ast_node->readmem(ast_node->str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init);
-				delete node_filename;
-				delete node_memory;
-				goto apply_newNode;
-			}
-
-			if (current_scope.count(ast_node->str) == 0)
-				ast_node->str = ast_node->try_pop_module_prefix();
-			if (current_scope.count(ast_node->str) == 0 || current_scope[ast_node->str]->type != Yosys::AST::AST_TASK)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Can't resolve task name `%s'.\n", ast_node->str.c_str());
-		}
-
-
-		std::stringstream sstr;
-		sstr << ast_node->str << "$func$" << encode_filename(ast_node->filename) << ":" << ast_node->location.first_line << "$" << (autoidx++) << '.';
-		std::string prefix = sstr.str();
-
-		Yosys::AST::AstNode *decl = current_scope[ast_node->str];
-		if (unevaluated_tern_branch && decl->is_recursive_function())
-			goto replace_fcall_later;
-		decl = decl->clone();
-		decl->replace_result_wire_name_in_function(ast_node->str, "$result"); // enables recursion
-		decl->expand_genblock(prefix);
-
-		if (decl->type == Yosys::AST::AST_FUNCTION && !decl->attributes.count(ID::via_celltype))
-		{
-			bool require_const_eval = decl->has_const_only_constructs();
-			bool all_args_const = true;
-			for (auto child : ast_node->children) {
-				while (simplify(child, true, false, false, 1, -1, false, true)) { }
-				if (child->type != Yosys::AST::AST_CONSTANT && child->type != Yosys::AST::AST_REALVALUE)
-					all_args_const = false;
-			}
-
-			if (all_args_const) {
-				Yosys::AST::AstNode *func_workspace = decl->clone();
-				func_workspace->str = prefix_id(prefix, "$result");
-				newNode = func_workspace->eval_const_function(ast_node, in_param || require_const_eval);
-				delete func_workspace;
-				if (newNode) {
-					delete decl;
-					goto apply_newNode;
-				}
-			}
-
-			if (in_param)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Non-constant function call in constant expression.\n");
-			if (require_const_eval)
-				log_file_error(ast_node->filename, ast_node->location.first_line, "Function %s can only be called with constant arguments.\n", ast_node->str.c_str());
-		}
-
-		size_t arg_count = 0;
-		dict<std::string, Yosys::AST::AstNode*> wire_cache;
-		vector<Yosys::AST::AstNode*> new_stmts;
-		vector<Yosys::AST::AstNode*> output_assignments;
-
-		if (current_block == NULL)
-		{
-			log_assert(ast_node->type == Yosys::AST::AST_FCALL);
-
-			Yosys::AST::AstNode *wire = NULL;
-			std::string res_name = prefix_id(prefix, "$result");
-			for (auto child : decl->children)
-				if (child->type == Yosys::AST::AST_WIRE && child->str == res_name)
-					wire = child->clone();
-			log_assert(wire != NULL);
-
-			wire->port_id = 0;
-			wire->is_input = false;
-			wire->is_output = false;
-
-			current_scope[wire->str] = wire;
-			current_ast_mod->children.push_back(wire);
-			while (simplify(wire, true, false, false, 1, -1, false, false)) { }
-
-			Yosys::AST::AstNode *lvalue = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-			lvalue->str = wire->str;
-
-			Yosys::AST::AstNode *always = new Yosys::AST::AstNode(Yosys::AST::AST_ALWAYS, new Yosys::AST::AstNode(Yosys::AST::AST_BLOCK,
-					new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, lvalue, ast_node->clone())));
-			always->children[0]->children[0]->was_checked = true;
-
-			current_ast_mod->children.push_back(always);
-
-			goto replace_fcall_with_id;
-		}
-
-		if (decl->attributes.count(ID::via_celltype))
-		{
-			std::string celltype = decl->attributes.at(ID::via_celltype)->asAttrConst().decode_string();
-			std::string outport = ast_node->str;
-
-			if (celltype.find(' ') != std::string::npos) {
-				int pos = celltype.find(' ');
-				outport = RTLIL::escape_id(celltype.substr(pos+1));
-				celltype = RTLIL::escape_id(celltype.substr(0, pos));
-			} else
-				celltype = RTLIL::escape_id(celltype);
-
-			Yosys::AST::AstNode *cell = new Yosys::AST::AstNode(Yosys::AST::AST_CELL, new Yosys::AST::AstNode(Yosys::AST::AST_CELLTYPE));
-			cell->str = prefix.substr(0, GetSize(prefix)-1);
-			cell->children[0]->str = celltype;
-
-			for (auto attr : decl->attributes)
-				if (attr.first.str().rfind("\\via_celltype_defparam_", 0) == 0)
-				{
-					Yosys::AST::AstNode *cell_arg = new Yosys::AST::AstNode(Yosys::AST::AST_PARASET, attr.second->clone());
-					cell_arg->str = RTLIL::escape_id(attr.first.substr(strlen("\\via_celltype_defparam_")));
-					cell->children.push_back(cell_arg);
-				}
-
-			for (auto child : decl->children)
-				if (child->type == Yosys::AST::AST_WIRE && (child->is_input || child->is_output || (ast_node->type == Yosys::AST::AST_FCALL && child->str == ast_node->str)))
-				{
-					Yosys::AST::AstNode *wire = child->clone();
-					wire->port_id = 0;
-					wire->is_input = false;
-					wire->is_output = false;
-					current_ast_mod->children.push_back(wire);
-					while (simplify(wire, true, false, false, 1, -1, false, false)) { }
-
-					Yosys::AST::AstNode *wire_id = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-					wire_id->str = wire->str;
-
-					if ((child->is_input || child->is_output) && arg_count < ast_node->children.size())
-					{
-						Yosys::AST::AstNode *arg = ast_node->children[arg_count++]->clone();
-						Yosys::AST::AstNode *assign = child->is_input ?
-								new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, wire_id->clone(), arg) :
-								new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, arg, wire_id->clone());
-						assign->children[0]->was_checked = true;
-
-						for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
-							if (*it != current_block_child)
-								continue;
-							current_block->children.insert(it, assign);
-							break;
-						}
-					}
-
-					Yosys::AST::AstNode *cell_arg = new Yosys::AST::AstNode(Yosys::AST::AST_ARGUMENT, wire_id);
-					cell_arg->str = child->str == ast_node->str ? outport : child->str;
-					cell->children.push_back(cell_arg);
-				}
-
-			current_ast_mod->children.push_back(cell);
-			goto replace_fcall_with_id;
-		}
-
-		for (auto child : decl->children)
-			if (child->type == Yosys::AST::AST_WIRE || child->type == Yosys::AST::AST_MEMORY || child->type == Yosys::AST::AST_PARAMETER || child->type == Yosys::AST::AST_LOCALPARAM || child->type == Yosys::AST::AST_ENUM_ITEM)
-			{
-				Yosys::AST::AstNode *wire = nullptr;
-
-				if (wire_cache.count(child->str))
-				{
-					wire = wire_cache.at(child->str);
-					bool contains_value = wire->type == Yosys::AST::AST_LOCALPARAM;
-					if (wire->children.size() == contains_value) {
-						for (auto c : child->children)
-							wire->children.push_back(c->clone());
-					} else if (!child->children.empty()) {
-						while (simplify(child, true, false, false, stage, -1, false, false)) { }
-						if (GetSize(child->children) == GetSize(wire->children) - contains_value) {
-							for (int i = 0; i < GetSize(child->children); i++)
-								if (*child->children.at(i) != *wire->children.at(i + contains_value))
-									goto tcall_incompatible_wires;
-						} else {
-					tcall_incompatible_wires:
-							log_file_error(ast_node->filename, ast_node->location.first_line, "Incompatible re-declaration of wire %s.\n", child->str.c_str());
-						}
-					}
-				}
-				else
-				{
-					wire = child->clone();
-					wire->port_id = 0;
-					wire->is_input = false;
-					wire->is_output = false;
-					wire->is_reg = true;
-					wire->attributes[ID::nosync] = Yosys::AST::AstNode::mkconst_int(1, false);
-					if (child->type == Yosys::AST::AST_ENUM_ITEM)
-						wire->attributes[ID::enum_base_type] = child->attributes[ID::enum_base_type];
-
-					wire_cache[child->str] = wire;
-
-					current_scope[wire->str] = wire;
-					current_ast_mod->children.push_back(wire);
-				}
-
-				while (simplify(wire, true, false, false, 1, -1, false, false)) { }
-
-				if ((child->is_input || child->is_output) && arg_count < ast_node->children.size())
-				{
-					Yosys::AST::AstNode *arg = ast_node->children[arg_count++]->clone();
-					// convert purely constant arguments into localparams
-					if (child->is_input && child->type == Yosys::AST::AST_WIRE && arg->type == Yosys::AST::AST_CONSTANT && node_contains_assignment_to(decl, child)) {
-						wire->type = Yosys::AST::AST_LOCALPARAM;
-						if (wire->attributes.count(ID::nosync))
-							delete wire->attributes.at(ID::nosync);
-						wire->attributes.erase(ID::nosync);
-						wire->children.insert(wire->children.begin(), arg->clone());
-						// args without a range implicitly have width 1
-						if (wire->children.back()->type != Yosys::AST::AST_RANGE) {
-							// check if this wire is redeclared with an explicit size
-							bool uses_explicit_size = false;
-							for (const Yosys::AST::AstNode *other_child : decl->children)
-								if (other_child->type == Yosys::AST::AST_WIRE && child->str == other_child->str
-										&& !other_child->children.empty()
-										&& other_child->children.back()->type == Yosys::AST::AST_RANGE) {
-									uses_explicit_size = true;
-									break;
-								}
-							if (!uses_explicit_size) {
-								Yosys::AST::AstNode* range = new Yosys::AST::AstNode();
-								range->type = Yosys::AST::AST_RANGE;
-								wire->children.push_back(range);
-								range->children.push_back(Yosys::AST::AstNode::mkconst_int(0, true));
-								range->children.push_back(Yosys::AST::AstNode::mkconst_int(0, true));
-							}
-						}
-						// updates the sizing
-						while (simplify(wire, true, false, false, 1, -1, false, false)) { }
-						delete arg;
-						continue;
-					}
-					Yosys::AST::AstNode *wire_id = new Yosys::AST::AstNode(Yosys::AST::AST_IDENTIFIER);
-					wire_id->str = wire->str;
-					Yosys::AST::AstNode *assign = child->is_input ?
-							new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, wire_id, arg) :
-							new Yosys::AST::AstNode(Yosys::AST::AST_ASSIGN_EQ, arg, wire_id);
-					assign->children[0]->was_checked = true;
-					if (child->is_input)
-						new_stmts.push_back(assign);
-					else
-						output_assignments.push_back(assign);
-				}
-			}
-
-		for (auto child : decl->children)
-			if (child->type != Yosys::AST::AST_WIRE && child->type != Yosys::AST::AST_MEMORY && child->type != Yosys::AST::AST_PARAMETER && child->type != Yosys::AST::AST_LOCALPARAM)
-				new_stmts.push_back(child->clone());
-
-		new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end());
-
-		for (auto it = current_block->children.begin(); ; it++) {
-			log_assert(it != current_block->children.end());
-			if (*it == current_block_child) {
-				current_block->children.insert(it, new_stmts.begin(), new_stmts.end());
-				break;
-			}
-		}
-
-	replace_fcall_with_id:
-		delete decl;
-		if (ast_node->type == Yosys::AST::AST_FCALL) {
-			ast_node->delete_children();
-			ast_node->type = Yosys::AST::AST_IDENTIFIER;
-			ast_node->str = prefix_id(prefix, "$result");
-		}
-		if (ast_node->type == Yosys::AST::AST_TCALL)
-			ast_node->str = "";
-		did_something = true;
-	}
-
-replace_fcall_later:;
-
-	// perform const folding when activated
-	if (const_fold)
-	{
-		bool string_op;
-		std::vector<RTLIL::State> tmp_bits;
-		RTLIL::Const (*const_func)(const RTLIL::Const&, const RTLIL::Const&, bool, bool, ys_size_type);
-		RTLIL::Const dummy_arg;
-
-		switch (ast_node->type)
-		{
-		case Yosys::AST::AST_IDENTIFIER:
-			if (current_scope.count(ast_node->str) > 0 && (current_scope[ast_node->str]->type == Yosys::AST::AST_PARAMETER || current_scope[ast_node->str]->type == Yosys::AST::AST_LOCALPARAM || current_scope[ast_node->str]->type == Yosys::AST::AST_ENUM_ITEM)) {
-				if (current_scope[ast_node->str]->children[0]->type == Yosys::AST::AST_CONSTANT) {
-					if (ast_node->children.size() != 0 && ast_node->children[0]->type == Yosys::AST::AST_RANGE && ast_node->children[0]->range_valid) {
-						std::vector<RTLIL::State> data;
-						bool param_upto = current_scope[ast_node->str]->range_valid && current_scope[ast_node->str]->range_swapped;
-						int param_offset = current_scope[ast_node->str]->range_valid ? current_scope[ast_node->str]->range_right : 0;
-						int param_width = current_scope[ast_node->str]->range_valid ? current_scope[ast_node->str]->range_left - current_scope[ast_node->str]->range_right + 1 :
-								GetSize(current_scope[ast_node->str]->children[0]->bits);
-						int tmp_range_left = ast_node->children[0]->range_left, tmp_range_right = ast_node->children[0]->range_right;
-						if (param_upto) {
-							tmp_range_left = (param_width + 2*param_offset) - ast_node->children[0]->range_right - 1;
-							tmp_range_right = (param_width + 2*param_offset) - ast_node->children[0]->range_left - 1;
-						}
-						Yosys::AST::AstNode *member_node = systemverilog_plugin::get_struct_member(ast_node);
-						int chunk_offset = member_node ? member_node->range_right : 0;
-						log_assert(!(chunk_offset && param_upto));
-						for (int i = tmp_range_right; i <= tmp_range_left; i++) {
-							int index = i - param_offset;
-							if (0 <= index && index < param_width)
-								data.push_back(current_scope[ast_node->str]->children[0]->bits[chunk_offset + index]);
-							else
-								data.push_back(RTLIL::State::Sx);
-						}
-						newNode = Yosys::AST::AstNode::mkconst_bits(data, false);
-					} else
-					if (ast_node->children.size() == 0)
-						newNode = current_scope[ast_node->str]->children[0]->clone();
-				} else
-				if (current_scope[ast_node->str]->children[0]->isConst())
-					newNode = current_scope[ast_node->str]->children[0]->clone();
-			}
-			else if (at_zero && current_scope.count(ast_node->str) > 0) {
-				Yosys::AST::AstNode *node = current_scope[ast_node->str];
-				if (node->type == Yosys::AST::AST_WIRE || node->type == Yosys::AST::AST_AUTOWIRE || node->type == Yosys::AST::AST_MEMORY)
-					newNode = node->mkconst_int(0, sign_hint, width_hint);
-			}
-			break;
-		case Yosys::AST::AST_MEMRD:
-			if (at_zero) {
-				newNode = Yosys::AST::AstNode::mkconst_int(0, sign_hint, width_hint);
-			}
-			break;
-		case Yosys::AST::AST_BIT_NOT:
-			if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT) {
-				RTLIL::Const y = RTLIL::const_not(ast_node->children[0]->bitsAsConst(width_hint, sign_hint), dummy_arg, sign_hint, false, width_hint);
-				newNode = Yosys::AST::AstNode::mkconst_bits(y.bits, sign_hint);
-			}
-			break;
-		case Yosys::AST::AST_TO_SIGNED:
-		case Yosys::AST::AST_TO_UNSIGNED:
-			if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT) {
-				RTLIL::Const y = ast_node->children[0]->bitsAsConst(width_hint, sign_hint);
-				newNode = Yosys::AST::AstNode::mkconst_bits(y.bits, ast_node->type == Yosys::AST::AST_TO_SIGNED);
-			}
-			break;
-		if (0) { case Yosys::AST::AST_BIT_AND:  const_func = RTLIL::const_and;  }
-		if (0) { case Yosys::AST::AST_BIT_OR:   const_func = RTLIL::const_or;   }
-		if (0) { case Yosys::AST::AST_BIT_XOR:  const_func = RTLIL::const_xor;  }
-		if (0) { case Yosys::AST::AST_BIT_XNOR: const_func = RTLIL::const_xnor; }
-			if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT && ast_node->children[1]->type == Yosys::AST::AST_CONSTANT) {
-				RTLIL::Const y = const_func(ast_node->children[0]->bitsAsConst(width_hint, sign_hint),
-						ast_node->children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint);
-				newNode = Yosys::AST::AstNode::mkconst_bits(y.bits, sign_hint);
-			}
-			break;
-		if (0) { case Yosys::AST::AST_REDUCE_AND:  const_func = RTLIL::const_reduce_and;  }
-		if (0) { case Yosys::AST::AST_REDUCE_OR:   const_func = RTLIL::const_reduce_or;   }
-		if (0) { case Yosys::AST::AST_REDUCE_XOR:  const_func = RTLIL::const_reduce_xor;  }
-		if (0) { case Yosys::AST::AST_REDUCE_XNOR: const_func = RTLIL::const_reduce_xnor; }
-		if (0) { case Yosys::AST::AST_REDUCE_BOOL: const_func = RTLIL::const_reduce_bool; }
-			if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT) {
-				RTLIL::Const y = const_func(RTLIL::Const(ast_node->children[0]->bits), dummy_arg, false, false, -1);
-				newNode = Yosys::AST::AstNode::mkconst_bits(y.bits, false);
-			}
-			break;
-		case Yosys::AST::AST_LOGIC_NOT:
-			if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT) {
-				RTLIL::Const y = RTLIL::const_logic_not(RTLIL::Const(ast_node->children[0]->bits), dummy_arg, ast_node->children[0]->is_signed, false, -1);
-				newNode = Yosys::AST::AstNode::mkconst_bits(y.bits, false);
-			} else
-			if (ast_node->children[0]->isConst()) {
-				newNode = Yosys::AST::AstNode::mkconst_int(ast_node->children[0]->asReal(sign_hint) == 0, false, 1);
-			}
-			break;
-		if (0) { case Yosys::AST::AST_LOGIC_AND: const_func = RTLIL::const_logic_and; }
-		if (0) { case Yosys::AST::AST_LOGIC_OR:  const_func = RTLIL::const_logic_or;  }
-			if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT && ast_node->children[1]->type == Yosys::AST::AST_CONSTANT) {
-				RTLIL::Const y = const_func(RTLIL::Const(ast_node->children[0]->bits), RTLIL::Const(ast_node->children[1]->bits),
-						ast_node->children[0]->is_signed, ast_node->children[1]->is_signed, -1);
-				newNode = Yosys::AST::AstNode::mkconst_bits(y.bits, false);
-			} else
-			if (ast_node->children[0]->isConst() && ast_node->children[1]->isConst()) {
-				if (ast_node->type == Yosys::AST::AST_LOGIC_AND)
-					newNode = Yosys::AST::AstNode::mkconst_int((ast_node->children[0]->asReal(sign_hint) != 0) && (ast_node->children[1]->asReal(sign_hint) != 0), false, 1);
-				else
-					newNode = Yosys::AST::AstNode::mkconst_int((ast_node->children[0]->asReal(sign_hint) != 0) || (ast_node->children[1]->asReal(sign_hint) != 0), false, 1);
-			}
-			break;
-		if (0) { case Yosys::AST::AST_SHIFT_LEFT:   const_func = RTLIL::const_shl;  }
-		if (0) { case Yosys::AST::AST_SHIFT_RIGHT:  const_func = RTLIL::const_shr;  }
-		if (0) { case Yosys::AST::AST_SHIFT_SLEFT:  const_func = RTLIL::const_sshl; }
-		if (0) { case Yosys::AST::AST_SHIFT_SRIGHT: const_func = RTLIL::const_sshr; }
-		if (0) { case Yosys::AST::AST_POW:          const_func = RTLIL::const_pow; }
-			if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT && ast_node->children[1]->type == Yosys::AST::AST_CONSTANT) {
-				RTLIL::Const y = const_func(ast_node->children[0]->bitsAsConst(width_hint, sign_hint),
-						RTLIL::Const(ast_node->children[1]->bits), sign_hint, ast_node->type == Yosys::AST::AST_POW ? ast_node->children[1]->is_signed : false, width_hint);
-				newNode = Yosys::AST::AstNode::mkconst_bits(y.bits, sign_hint);
-			} else
-			if (ast_node->type == Yosys::AST::AST_POW && ast_node->children[0]->isConst() && ast_node->children[1]->isConst()) {
-				newNode = new Yosys::AST::AstNode(Yosys::AST::AST_REALVALUE);
-				newNode->realvalue = pow(ast_node->children[0]->asReal(sign_hint), ast_node->children[1]->asReal(sign_hint));
-			}
-			break;
-		if (0) { case Yosys::AST::AST_LT:  const_func = RTLIL::const_lt; }
-		if (0) { case Yosys::AST::AST_LE:  const_func = RTLIL::const_le; }
-		if (0) { case Yosys::AST::AST_EQ:  const_func = RTLIL::const_eq; }
-		if (0) { case Yosys::AST::AST_NE:  const_func = RTLIL::const_ne; }
-		if (0) { case Yosys::AST::AST_EQX: const_func = RTLIL::const_eqx; }
-		if (0) { case Yosys::AST::AST_NEX: const_func = RTLIL::const_nex; }
-		if (0) { case Yosys::AST::AST_GE:  const_func = RTLIL::const_ge; }
-		if (0) { case Yosys::AST::AST_GT:  const_func = RTLIL::const_gt; }
-			if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT && ast_node->children[1]->type == Yosys::AST::AST_CONSTANT) {
-				int cmp_width = max(ast_node->children[0]->bits.size(), ast_node->children[1]->bits.size());
-				bool cmp_signed = ast_node->children[0]->is_signed && ast_node->children[1]->is_signed;
-				RTLIL::Const y = const_func(ast_node->children[0]->bitsAsConst(cmp_width, cmp_signed),
-						ast_node->children[1]->bitsAsConst(cmp_width, cmp_signed), cmp_signed, cmp_signed, 1);
-				newNode = Yosys::AST::AstNode::mkconst_bits(y.bits, false);
-			} else
-			if (ast_node->children[0]->isConst() && ast_node->children[1]->isConst()) {
-				bool cmp_signed = (ast_node->children[0]->type == Yosys::AST::AST_REALVALUE || ast_node->children[0]->is_signed) && (ast_node->children[1]->type == Yosys::AST::AST_REALVALUE || ast_node->children[1]->is_signed);
-				switch (ast_node->type) {
-				case Yosys::AST::AST_LT:  newNode = Yosys::AST::AstNode::mkconst_int(ast_node->children[0]->asReal(cmp_signed) <  ast_node->children[1]->asReal(cmp_signed), false, 1); break;
-				case Yosys::AST::AST_LE:  newNode = Yosys::AST::AstNode::mkconst_int(ast_node->children[0]->asReal(cmp_signed) <= ast_node->children[1]->asReal(cmp_signed), false, 1); break;
-				case Yosys::AST::AST_EQ:  newNode = Yosys::AST::AstNode::mkconst_int(ast_node->children[0]->asReal(cmp_signed) == ast_node->children[1]->asReal(cmp_signed), false, 1); break;
-				case Yosys::AST::AST_NE:  newNode = Yosys::AST::AstNode::mkconst_int(ast_node->children[0]->asReal(cmp_signed) != ast_node->children[1]->asReal(cmp_signed), false, 1); break;
-				case Yosys::AST::AST_EQX: newNode = Yosys::AST::AstNode::mkconst_int(ast_node->children[0]->asReal(cmp_signed) == ast_node->children[1]->asReal(cmp_signed), false, 1); break;
-				case Yosys::AST::AST_NEX: newNode = Yosys::AST::AstNode::mkconst_int(ast_node->children[0]->asReal(cmp_signed) != ast_node->children[1]->asReal(cmp_signed), false, 1); break;
-				case Yosys::AST::AST_GE:  newNode = Yosys::AST::AstNode::mkconst_int(ast_node->children[0]->asReal(cmp_signed) >= ast_node->children[1]->asReal(cmp_signed), false, 1); break;
-				case Yosys::AST::AST_GT:  newNode = Yosys::AST::AstNode::mkconst_int(ast_node->children[0]->asReal(cmp_signed) >  ast_node->children[1]->asReal(cmp_signed), false, 1); break;
-				default: log_abort();
-				}
-			}
-			break;
-		if (0) { case Yosys::AST::AST_ADD: const_func = RTLIL::const_add; }
-		if (0) { case Yosys::AST::AST_SUB: const_func = RTLIL::const_sub; }
-		if (0) { case Yosys::AST::AST_MUL: const_func = RTLIL::const_mul; }
-		if (0) { case Yosys::AST::AST_DIV: const_func = RTLIL::const_div; }
-		if (0) { case Yosys::AST::AST_MOD: const_func = RTLIL::const_mod; }
-			if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT && ast_node->children[1]->type == Yosys::AST::AST_CONSTANT) {
-				RTLIL::Const y = const_func(ast_node->children[0]->bitsAsConst(width_hint, sign_hint),
-						ast_node->children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint);
-				newNode = Yosys::AST::AstNode::mkconst_bits(y.bits, sign_hint);
-			} else
-			if (ast_node->children[0]->isConst() && ast_node->children[1]->isConst()) {
-				newNode = new Yosys::AST::AstNode(Yosys::AST::AST_REALVALUE);
-				switch (ast_node->type) {
-				case Yosys::AST::AST_ADD: newNode->realvalue = ast_node->children[0]->asReal(sign_hint) + ast_node->children[1]->asReal(sign_hint); break;
-				case Yosys::AST::AST_SUB: newNode->realvalue = ast_node->children[0]->asReal(sign_hint) - ast_node->children[1]->asReal(sign_hint); break;
-				case Yosys::AST::AST_MUL: newNode->realvalue = ast_node->children[0]->asReal(sign_hint) * ast_node->children[1]->asReal(sign_hint); break;
-				case Yosys::AST::AST_DIV: newNode->realvalue = ast_node->children[0]->asReal(sign_hint) / ast_node->children[1]->asReal(sign_hint); break;
-				case Yosys::AST::AST_MOD: newNode->realvalue = fmod(ast_node->children[0]->asReal(sign_hint), ast_node->children[1]->asReal(sign_hint)); break;
-				default: log_abort();
-				}
-			}
-			break;
-		if (0) { case Yosys::AST::AST_SELFSZ: const_func = RTLIL::const_pos; }
-		if (0) { case Yosys::AST::AST_POS: const_func = RTLIL::const_pos; }
-		if (0) { case Yosys::AST::AST_NEG: const_func = RTLIL::const_neg; }
-			if (ast_node->children[0]->type == Yosys::AST::AST_CONSTANT) {
-				RTLIL::Const y = const_func(ast_node->children[0]->bitsAsConst(width_hint, sign_hint), dummy_arg, sign_hint, false, width_hint);
-				newNode = Yosys::AST::AstNode::mkconst_bits(y.bits, sign_hint);
-			} else
-			if (ast_node->children[0]->isConst()) {
-				newNode = new Yosys::AST::AstNode(Yosys::AST::AST_REALVALUE);
-				if (ast_node->type == Yosys::AST::AST_NEG)
-					newNode->realvalue = -ast_node->children[0]->asReal(sign_hint);
-				else
-					newNode->realvalue = +ast_node->children[0]->asReal(sign_hint);
-			}
-			break;
-		case Yosys::AST::AST_TERNARY:
-			if (ast_node->children[0]->isConst())
-			{
-				auto pair = ast_node->get_tern_choice();
-				Yosys::AST::AstNode *choice = pair.first;
-				Yosys::AST::AstNode *not_choice = pair.second;
-
-				if (choice != NULL) {
-					if (choice->type == Yosys::AST::AST_CONSTANT) {
-						int other_width_hint = width_hint;
-						bool other_sign_hint = sign_hint, other_real = false;
-						not_choice->detectSignWidth(other_width_hint, other_sign_hint, &other_real);
-						if (other_real) {
-							newNode = new Yosys::AST::AstNode(Yosys::AST::AST_REALVALUE);
-							choice->detectSignWidth(width_hint, sign_hint);
-							newNode->realvalue = choice->asReal(sign_hint);
-						} else {
-							RTLIL::Const y = choice->bitsAsConst(width_hint, sign_hint);
-							if (choice->is_string && y.bits.size() % 8 == 0 && sign_hint == false)
-								newNode = Yosys::AST::AstNode::mkconst_str(y.bits);
-							else
-								newNode = Yosys::AST::AstNode::mkconst_bits(y.bits, sign_hint);
-						}
-					} else
-					if (choice->isConst()) {
-						newNode = choice->clone();
-					}
-				} else if (ast_node->children[1]->type == Yosys::AST::AST_CONSTANT && ast_node->children[2]->type == Yosys::AST::AST_CONSTANT) {
-					RTLIL::Const a = ast_node->children[1]->bitsAsConst(width_hint, sign_hint);
-					RTLIL::Const b = ast_node->children[2]->bitsAsConst(width_hint, sign_hint);
-					log_assert(a.bits.size() == b.bits.size());
-					for (size_t i = 0; i < a.bits.size(); i++)
-						if (a.bits[i] != b.bits[i])
-							a.bits[i] = RTLIL::State::Sx;
-					newNode = Yosys::AST::AstNode::mkconst_bits(a.bits, sign_hint);
-				} else if (ast_node->children[1]->isConst() && ast_node->children[2]->isConst()) {
-					newNode = new Yosys::AST::AstNode(Yosys::AST::AST_REALVALUE);
-					if (ast_node->children[1]->asReal(sign_hint) == ast_node->children[2]->asReal(sign_hint))
-						newNode->realvalue = ast_node->children[1]->asReal(sign_hint);
-					else
-						// IEEE Std 1800-2012 Sec. 11.4.11 states that the entry in Table 7-1 for
-						// the data type in question should be returned if the ?: is ambiguous. The
-						// value in Table 7-1 for the 'real' type is 0.0.
-						newNode->realvalue = 0.0;
-				}
-			}
-			break;
-		case Yosys::AST::AST_CAST_SIZE:
-			if (ast_node->children.at(0)->type == Yosys::AST::AST_CONSTANT && ast_node->children.at(1)->type == Yosys::AST::AST_CONSTANT) {
-				int width = ast_node->children[0]->bitsAsConst().as_int();
-				RTLIL::Const val;
-				if (ast_node->children[1]->is_unsized)
-					val = ast_node->children[1]->bitsAsUnsizedConst(width);
-				else
-					val = ast_node->children[1]->bitsAsConst(width);
-				newNode = Yosys::AST::AstNode::mkconst_bits(val.bits, ast_node->children[1]->is_signed);
-			}
-			break;
-		case Yosys::AST::AST_CONCAT:
-			string_op = !ast_node->children.empty();
-			for (auto it = ast_node->children.begin(); it != ast_node->children.end(); it++) {
-				if ((*it)->type != Yosys::AST::AST_CONSTANT)
-					goto not_const;
-				if (!(*it)->is_string)
-					string_op = false;
-				tmp_bits.insert(tmp_bits.end(), (*it)->bits.begin(), (*it)->bits.end());
-			}
-			newNode = string_op ? Yosys::AST::AstNode::mkconst_str(tmp_bits) : Yosys::AST::AstNode::mkconst_bits(tmp_bits, false);
-			break;
-		case Yosys::AST::AST_REPLICATE:
-			if (ast_node->children.at(0)->type != Yosys::AST::AST_CONSTANT || ast_node->children.at(1)->type != Yosys::AST::AST_CONSTANT)
-				goto not_const;
-			for (int i = 0; i < ast_node->children[0]->bitsAsConst().as_int(); i++)
-				tmp_bits.insert(tmp_bits.end(), ast_node->children.at(1)->bits.begin(), ast_node->children.at(1)->bits.end());
-			newNode = ast_node->children.at(1)->is_string ? Yosys::AST::AstNode::mkconst_str(tmp_bits) : Yosys::AST::AstNode::mkconst_bits(tmp_bits, false);
-			break;
-		default:
-		not_const:
-			break;
-		}
-	}
-
-	// if any of the above set 'newNode' -> use 'newNode' as template to update 'ast_node'
-	if (newNode) {
-apply_newNode:
-		// fprintf(stderr, "----\n");
-		// dumpAst(stderr, "- ");
-		// newNode->dumpAst(stderr, "+ ");
-		log_assert(newNode != NULL);
-		newNode->filename = ast_node->filename;
-		newNode->location = ast_node->location;
-		newNode->cloneInto(ast_node);
-		delete newNode;
-		did_something = true;
-	}
-
-	if (!did_something)
-		ast_node->basic_prep = true;
-
-	recursion_counter--;
-	return did_something;
-}
-
-} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/third_party/yosys/simplify.h b/systemverilog-plugin/third_party/yosys/simplify.h
deleted file mode 100644
index 69cd4f4..0000000
--- a/systemverilog-plugin/third_party/yosys/simplify.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "frontends/ast/ast.h"
-
-namespace systemverilog_plugin
-{
-    using ys_size_type = int;  // Makes it easy to change if changed upstream.
-    bool simplify(Yosys::AST::AstNode *ast_node, bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);
-}
diff --git a/systemverilog-plugin/uhdmastfrontend.cc b/systemverilog-plugin/uhdmastfrontend.cc
deleted file mode 100644
index 58bd36e..0000000
--- a/systemverilog-plugin/uhdmastfrontend.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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
- *
- */
-
-#include "uhdm/uhdm-version.h" // UHDM_VERSION define
-#include "uhdm/vpi_visitor.h"  // visit_object
-#include "uhdmcommonfrontend.h"
-
-namespace systemverilog_plugin
-{
-
-using namespace ::Yosys;
-
-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");
-        log("    read_uhdm [options] [filename]\n");
-        log("\n");
-        log("Load design from a UHDM file into the current design\n");
-        log("\n");
-        this->print_read_options();
-    }
-    AST::AstNode *parse(std::string filename) override
-    {
-        UHDM::Serializer serializer;
-
-        std::vector<vpiHandle> restoredDesigns = serializer.Restore(filename);
-        UHDM::SynthSubset *synthSubset =
-          make_new_object_with_optional_extra_true_arg<UHDM::SynthSubset>(&serializer, this->shared.nonSynthesizableObjects, false);
-        synthSubset->listenDesigns(restoredDesigns);
-        delete synthSubset;
-        UhdmAst uhdm_ast(this->shared);
-        AST::AstNode *current_ast = uhdm_ast.visit_designs(restoredDesigns);
-        for (auto design : restoredDesigns)
-            vpi_release_handle(design);
-
-        serializer.Purge();
-        return current_ast;
-    }
-    void call_log_header(RTLIL::Design *design) override { log_header(design, "Executing UHDM frontend.\n"); }
-} UhdmAstFrontend;
-
-} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmastshared.h b/systemverilog-plugin/uhdmastshared.h
deleted file mode 100644
index 1dcd260..0000000
--- a/systemverilog-plugin/uhdmastshared.h
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef _UHDM_AST_SHARED_H_
-#define _UHDM_AST_SHARED_H_ 1
-
-#include "frontends/ast/ast.h"
-
-// Yosys defines a 'cover' macro in implicitly included kernel/log.h
-// that clashes with cover-class in UHDM
-#undef cover
-
-#include <string>
-#include <uhdm/uhdm.h>
-#include <uhdm/vpi_user.h>
-#include <unordered_map>
-
-namespace systemverilog_plugin
-{
-
-class UhdmAstShared
-{
-  private:
-    // Used for generating enum names
-    unsigned enum_count = 0;
-
-    // Used for generating port IDS
-    unsigned port_count = 0;
-
-    // Used for generating loop names
-    unsigned loop_count = 0;
-
-    // Used for generating unique names for anonymous types used as parameters.
-    unsigned anonymous_type_count = 0;
-
-    // Used to generate unique names for anonymous enum typedefs
-    unsigned anonymous_enum_typedef_count = 0;
-
-  public:
-    ~UhdmAstShared()
-    {
-        for (const auto &param : param_types)
-            delete param.second;
-        param_types.clear();
-    }
-
-    // Generate the next enum ID (starting with 0)
-    unsigned next_enum_id() { return enum_count++; }
-
-    // Generate the next port ID (starting with 1)
-    unsigned next_port_id() { return ++port_count; }
-
-    // Generate the next loop ID (starting with 0)
-    unsigned next_loop_id() { return loop_count++; }
-
-    // Generate the next anonymous type ID (starting with 0).
-    unsigned next_anonymous_type_id() { return anonymous_type_count++; }
-
-    // Generate the next anonymous enum typedef ID (starting with 0).
-    unsigned next_anonymous_enum_typedef_id() { return anonymous_enum_typedef_count++; }
-
-    // Flag that determines whether debug info should be printed
-    bool debug_flag = false;
-
-    // Flag that determines whether we should ignore assert() statements
-    bool no_assert = false;
-
-    // Flag that determines whether errors should be fatal
-    bool stop_on_error = true;
-
-    // Flag that determines whether we should only parse the design
-    // applies only to read_systemverilog command
-    bool parse_only = false;
-
-    // Flag that determines whether we should defer the elaboration
-    // applies only to read_systemverilog command
-    bool defer = false;
-
-    // Flag that determines whether we should perform the elaboration now
-    // applies only to read_systemverilog command
-    bool link = false;
-
-    // Flag equivalent to read_verilog -formal
-    // Defines FORMAL, undefines SYNTHESIS
-    // Allows verification constructs in Surelog
-    bool formal = false;
-
-    // Top nodes of the design (modules, interfaces)
-    std::unordered_map<std::string, ::Yosys::AST::AstNode *> top_nodes;
-
-    // Map from AST param nodes to their types (used for params with struct types)
-    std::unordered_map<std::string, ::Yosys::AST::AstNode *> param_types;
-
-    ::Yosys::AST::AstNode *current_top_node = nullptr;
-
-    // Currently processed UHDM module instance.
-    // Used as a fallback when obj->Instance() and obj->vpiParent() are not available.
-    const UHDM::any *current_instance = nullptr;
-
-    // Set of non-synthesizable objects to skip in current design;
-    std::set<const UHDM::BaseClass *> nonSynthesizableObjects;
-
-    // Map of anonymous enum types to generated typedefs
-    std::unordered_map<std::string, std::unordered_map<const UHDM::enum_typespec *, std::string>> anonymous_enums;
-};
-
-} // namespace systemverilog_plugin
-
-#endif
diff --git a/systemverilog-plugin/uhdmcommonfrontend.cc b/systemverilog-plugin/uhdmcommonfrontend.cc
deleted file mode 100644
index da7ac31..0000000
--- a/systemverilog-plugin/uhdmcommonfrontend.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * 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
- *
- */
-
-#include "uhdmcommonfrontend.h"
-
-namespace systemverilog_plugin
-{
-
-using namespace ::Yosys;
-
-/* 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("        alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2\n");
-    log("\n");
-    log("    -dump_ast1\n");
-    log("        dump abstract syntax tree (before simplification)\n");
-    log("\n");
-    log("    -dump_ast2\n");
-    log("        dump abstract syntax tree (after simplification)\n");
-    log("\n");
-    log("    -no_dump_ptr\n");
-    log("        do not include hex memory addresses in dump (easier to diff dumps)\n");
-    log("\n");
-    log("    -dump_vlog1\n");
-    log("        dump ast as Verilog code (before simplification)\n");
-    log("\n");
-    log("    -dump_vlog2\n");
-    log("        dump ast as Verilog code (after simplification)\n");
-    log("\n");
-    log("    -dump_rtlil\n");
-    log("        dump generated RTLIL netlist\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("        Needs to be followed by read_systemverilog -link after reading\n");
-    log("        all files.\n");
-    log("\n");
-    log("    -link\n");
-    log("        performs linking and elaboration of the files read with -defer\n");
-    log("\n");
-    log("    -parse-only\n");
-    log("        this parameter only applies to read_systemverilog command,\n");
-    log("        it runs only Surelog to parse design, but doesn't load generated\n");
-    log("        tree into Yosys.\n");
-    log("\n");
-    log("    -formal\n");
-    log("        enable support for SystemVerilog assertions and some Yosys extensions\n");
-    log("        replace the implicit -D SYNTHESIS with -D FORMAL\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;
-    bool dump_ast1 = false;
-    bool dump_ast2 = false;
-    bool dump_vlog1 = false;
-    bool dump_vlog2 = false;
-    bool no_dump_ptr = false;
-    bool dump_rtlil = false;
-    std::vector<std::string> unhandled_args;
-
-    for (size_t i = 0; i < args.size(); i++) {
-        if (args[i] == "-debug") {
-            dump_ast1 = true;
-            dump_ast2 = true;
-            dump_vlog1 = true;
-            dump_vlog2 = true;
-            this->shared.debug_flag = true;
-        } else if (args[i] == "-noassert") {
-            this->shared.no_assert = true;
-        } else if (args[i] == "-defer") {
-            this->shared.defer = true;
-        } else if (args[i] == "-dump_ast1") {
-            dump_ast1 = true;
-        } else if (args[i] == "-dump_ast2") {
-            dump_ast2 = true;
-        } else if (args[i] == "-dump_vlog1") {
-            dump_vlog1 = true;
-        } else if (args[i] == "-dump_vlog2") {
-            dump_vlog2 = true;
-        } else if (args[i] == "-no_dump_ptr") {
-            no_dump_ptr = true;
-        } else if (args[i] == "-dump_rtlil") {
-            dump_rtlil = true;
-        } else if (args[i] == "-parse-only") {
-            this->shared.parse_only = true;
-        } else if (args[i] == "-link") {
-            this->shared.link = true;
-            // Surelog needs it in the command line to link correctly
-            unhandled_args.push_back(args[i]);
-        } else if (args[i] == "-formal") {
-            this->shared.formal = true;
-            // Surelog needs it in the command line to annotate UHDM
-            unhandled_args.push_back(args[i]);
-        } else {
-            unhandled_args.push_back(args[i]);
-        }
-    }
-    // Yosys gets confused when extra_args are passed with -link or no option
-    // It's done fully by Surelog, so skip it in this case
-    if (!this->shared.link)
-        extra_args(f, filename, args, args.size() - 1);
-    // pass only unhandled args to Surelog
-    // unhandled args starts with command name,
-    // but Surelog expects args[0] to be program name
-    // and skips it
-    this->args = unhandled_args;
-
-    AST::current_filename = filename;
-    AST::set_line_num = &set_line_num;
-    AST::get_line_num = &get_line_num;
-
-    bool dont_redefine = false;
-    bool default_nettype_wire = true;
-
-    AST::AstNode *current_ast = parse(filename);
-
-    if (current_ast) {
-        AST::process(design, current_ast, dump_ast1, dump_ast2, no_dump_ptr, dump_vlog1, dump_vlog2, dump_rtlil, false, false, false, false, false,
-                     false, false, false, false, false, dont_redefine, false, defer, default_nettype_wire);
-        delete current_ast;
-    }
-}
-
-} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmcommonfrontend.h b/systemverilog-plugin/uhdmcommonfrontend.h
deleted file mode 100644
index 324cada..0000000
--- a/systemverilog-plugin/uhdmcommonfrontend.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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
- *
- */
-
-#include "UhdmAst.h"
-#include "frontends/ast/ast.h"
-#include "kernel/yosys.h"
-#include "uhdm/SynthSubset.h"
-#include "uhdm/VpiListener.h"
-#include <string>
-#include <type_traits>
-#include <vector>
-
-namespace systemverilog_plugin
-{
-
-// FIXME (mglb): temporary fix to support UHDM both before and after the following change:
-// https://github.com/chipsalliance/UHDM/commit/d78d094448bd94926644e48adea4df293b82f101
-// The commit introducing this code should to be reverted after Surelog is bumped to recent versions in all our repositories.
-template <typename ObjT, typename... ArgN, std::enable_if_t<std::is_constructible_v<ObjT, ArgN...>, bool> = true>
-static inline ObjT *make_new_object_with_optional_extra_true_arg(ArgN &&... arg_n)
-{
-    // Older UHDM version
-    return new ObjT(std::forward<ArgN>(arg_n)...);
-}
-
-template <typename ObjT, typename... ArgN, std::enable_if_t<!std::is_constructible_v<ObjT, ArgN...>, bool> = true>
-static inline ObjT *make_new_object_with_optional_extra_true_arg(ArgN &&... arg_n)
-{
-    // Newer UHDM version
-    return new ObjT(std::forward<ArgN>(arg_n)..., true);
-}
-
-struct UhdmCommonFrontend : public ::Yosys::Frontend {
-    UhdmAstShared shared;
-    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 ::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);
-};
-
-} // namespace systemverilog_plugin
diff --git a/systemverilog-plugin/uhdmsurelogastfrontend.cc b/systemverilog-plugin/uhdmsurelogastfrontend.cc
deleted file mode 100644
index 40d7a37..0000000
--- a/systemverilog-plugin/uhdmsurelogastfrontend.cc
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * 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
- *
- */
-
-#include "UhdmAst.h"
-#include "frontends/ast/ast.h"
-#include "kernel/yosys.h"
-#include "uhdmcommonfrontend.h"
-
-#if defined(_MSC_VER)
-#include <direct.h>
-#include <process.h>
-#else
-#include <sys/param.h>
-#include <unistd.h>
-#endif
-#include <memory>
-
-#include <list>
-
-#include "Surelog/API/Surelog.h"
-#include "Surelog/CommandLine/CommandLineParser.h"
-#include "Surelog/ErrorReporting/ErrorContainer.h"
-#include "Surelog/SourceCompile/SymbolTable.h"
-#include "uhdm/uhdm-version.h" // UHDM_VERSION define
-#include "uhdm/vpi_visitor.h"  // visit_object
-
-namespace systemverilog_plugin
-{
-
-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;
-        if (codedReturn) {
-            log_error("Error when parsing design. Aborting!\n");
-        }
-
-        this->clp = std::move(clp);
-        this->errors = std::move(errors);
-
-        return this->designs;
-    }
-
-  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) {}
-    UhdmSurelogAstFrontend() : UhdmCommonFrontend("verilog_with_uhdm", "generate/read UHDM file") {}
-
-    void help() override
-    {
-        //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
-        log("\n");
-        log("    read_verilog_with_uhdm [options] [filenames]\n");
-        log("\n");
-        log("Read SystemVerilog files using Surelog into the current design\n");
-        log("\n");
-        this->print_read_options();
-    }
-
-    AST::AstNode *parse(std::string filename) override
-    {
-        std::vector<const char *> cstrings;
-        bool link = false;
-        if (this->shared.formal) {
-            systemverilog_defines.push_back("-DFORMAL=1");
-        } else {
-            systemverilog_defines.push_back("-DSYNTHESIS=1");
-        }
-        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;
-        }
-
-        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");
-        }
-        // Force -parse flag settings even if it wasn't specified
-        clp->setwritePpOutput(true);
-        clp->setParse(true);
-        clp->fullSVMode(true);
-        clp->setCacheAllowed(true);
-        clp->setReportNonSynthesizable(true);
-        if (this->shared.defer) {
-            clp->setCompile(false);
-            clp->setElaborate(false);
-            clp->setSepComp(true);
-        } else {
-            clp->setCompile(true);
-            clp->setElaborate(true);
-            clp->setElabUhdm(true);
-        }
-        if (this->shared.link) {
-            clp->setLink(true);
-        }
-
-        Compiler compiler;
-        const auto &uhdm_designs = compiler.execute(std::move(errors), std::move(clp));
-
-        // on parse_only mode, don't try to load design
-        // into yosys
-        if (this->shared.parse_only)
-            return nullptr;
-
-        if (this->shared.defer && !this->shared.link)
-            return nullptr;
-
-        // FIXME: SynthSubset annotation is incompatible with separate compilation
-        // `-defer` turns elaboration off, so check for it
-        // Should be called 1. for normal flow 2. after finishing with `-link`
-        if (!this->shared.defer) {
-            UHDM::Serializer serializer;
-            UHDM::SynthSubset *synthSubset =
-              make_new_object_with_optional_extra_true_arg<UHDM::SynthSubset>(&serializer, this->shared.nonSynthesizableObjects, false);
-            synthSubset->listenDesigns(uhdm_designs);
-            delete synthSubset;
-        }
-
-        UhdmAst uhdm_ast(this->shared);
-        AST::AstNode *current_ast = uhdm_ast.visit_designs(uhdm_designs);
-
-        // 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"); }
-} UhdmSurelogAstFrontend;
-
-struct UhdmSystemVerilogFrontend : public UhdmSurelogAstFrontend {
-    UhdmSystemVerilogFrontend() : UhdmSurelogAstFrontend("systemverilog", "read SystemVerilog files") {}
-    void help() override
-    {
-        //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
-        log("\n");
-        log("    read_systemverilog [options] [filenames]\n");
-        log("\n");
-        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;
-
-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
diff --git a/systemverilog-plugin/utils/memory.h b/systemverilog-plugin/utils/memory.h
deleted file mode 100644
index 6cd43c0..0000000
--- a/systemverilog-plugin/utils/memory.h
+++ /dev/null
@@ -1,195 +0,0 @@
-#ifndef SYSTEMVERILOG_PLUGIN_UTILS_MEMORY_H_
-#define SYSTEMVERILOG_PLUGIN_UTILS_MEMORY_H_
-
-#include <cassert>
-#include <utility>
-
-namespace systemverilog_plugin
-{
-
-// `std::default_delete` equivalent for any range of pointers, e.g. `std::vector<Object *>`.
-template <class Range> struct default_delete_ptr_range {
-    void operator()(Range &range) const
-    {
-        for (auto *ptr : range)
-            delete ptr;
-    }
-};
-
-// Functor that takes a reference and does nothing. Useful as no-op deleter.
-struct noop_delete {
-    template <class T> void operator()(T &) const {}
-};
-
-namespace utils_memory_internal
-{
-
-// Unique type for detecting invalid (missing) default_resource_deleter.
-struct missing_type {
-};
-
-// Provider of default deleter functor for resource of type `R` used by `unique_resource`.
-template <class R, class AlwaysVoid_ = void> struct default_resource_deleter {
-    using type = missing_type;
-};
-
-// Type trait for detecting whether type `R` is any range of pointers.
-template <class R, class ValueType_ = std::remove_reference_t<decltype(*std::begin(std::declval<R>()))>>
-using is_range_of_pointers_t = std::enable_if_t<std::is_pointer_v<ValueType_> && !std::is_array_v<ValueType_>>;
-
-// Overload for any range of pointers.
-template <class R> struct default_resource_deleter<R, is_range_of_pointers_t<R>> {
-    using type = default_delete_ptr_range<R>;
-};
-
-// Convenience alias.
-template <class R> using default_resource_deleter_t = typename default_resource_deleter<R>::type;
-
-// Type trait for checking whether type `R` is a valid deleter of type `D`.
-template <class R, class D, class = void> struct is_valid_resource_deleter : std::false_type {
-};
-template <class R, class D> struct is_valid_resource_deleter<R, D, std::void_t<decltype(std::declval<D>()(std::declval<R &>()))>> : std::true_type {
-};
-
-// Convenience alias.
-template <class R, class D> inline constexpr bool is_valid_resource_deleter_v = is_valid_resource_deleter<R, D>::value;
-
-} // namespace utils_memory_internal
-
-// Wrapper that holds and manages resource of type `Resource`. Equivalent of `unique_ptr` for non-pointer types.
-//
-// `unique_resource` tracks initialization status of its resource. The `Destructor` is called only when the resource is in initialized state.
-// `unique_resource` constructed using default constructor is in uninitialized state. It becomes initialized when a valid resource is moved into it.
-// Moving resource out or releasing it switches state to uninitialized.
-//
-// The API is based on unique_ptr rather than `unique_resource` from Library Fundamentals TS3.
-template <class Resource, class Deleter = utils_memory_internal::default_resource_deleter_t<Resource>> class unique_resource
-{
-    // Check for errors in template parameters.
-    // Use of intermediate constexprs results in nicer error messages.
-    static constexpr bool deleter_for_resource_exists = !std::is_same_v<Deleter, utils_memory_internal::missing_type>;
-    static_assert(deleter_for_resource_exists, "'Deleter' has not been specified and no default deleter exists for type 'Resource'.");
-    static constexpr bool deleter_is_callable_with_resource_ref = utils_memory_internal::is_valid_resource_deleter_v<Resource, Deleter>;
-    static_assert(deleter_is_callable_with_resource_ref, "Object of type 'Deleter' must be callable with argument of type 'Resource &'.");
-    static constexpr bool resource_type_is_not_cvref = std::is_same_v<Resource, std::remove_cv_t<std::remove_reference_t<Resource>>>;
-    static_assert(resource_type_is_not_cvref, "'Resource' must not be a reference or have const or volatile qualifier.");
-
-    // Data members.
-
-    Resource resource = {};
-    bool initialized = false;
-
-  public:
-    // Initialize
-
-    unique_resource() = default;
-
-    template <class OtherResource> unique_resource(OtherResource &&other) : resource(std::forward<OtherResource>(other)), initialized(true) {}
-
-    // Copy
-
-    unique_resource(const unique_resource &) = delete;
-
-    unique_resource &operator=(const unique_resource &) = delete;
-
-    // Move
-
-    template <class OtherDeleter>
-    unique_resource(unique_resource<Resource, OtherDeleter> &&other) : resource(std::move(other.resource)), initialized(other.initialized)
-    {
-        other.initialized = false;
-    }
-
-    template <class OtherDeleter> unique_resource &operator=(unique_resource<Resource, OtherDeleter> &&other)
-    {
-        resource = std::move(other.resource);
-        initialized = other.initialized;
-        other.initialized = false;
-    };
-
-    // Destroy
-
-    ~unique_resource()
-    {
-        if (initialized) {
-            Deleter{}(resource);
-        }
-    }
-
-    // Data access
-
-    Resource &get()
-    {
-        assert(initialized);
-        return resource;
-    }
-
-    const Resource &get() const
-    {
-        assert(initialized);
-        return resource;
-    }
-
-    Resource &operator*()
-    {
-        assert(initialized);
-        return resource;
-    }
-
-    const Resource &operator*() const
-    {
-        assert(initialized);
-        return resource;
-    }
-
-    Resource *operator->()
-    {
-        assert(initialized);
-        return &resource;
-    }
-
-    const Resource *operator->() const
-    {
-        assert(initialized);
-        return &resource;
-    }
-
-    operator bool() const { return initialized; }
-
-    // Operations
-
-    Resource release()
-    {
-        Resource r = std::move(resource);
-        initialized = false;
-        return r;
-    }
-
-    void reset()
-    {
-        if (initialized) {
-            Deleter{}(resource);
-            initialized = false;
-        }
-    }
-
-    template <class OtherResource> void reset(OtherResource &&other)
-    {
-        if (initialized) {
-            Deleter{}(resource);
-        }
-        resource = std::forward<OtherResource>(other);
-        initialized = true;
-    }
-};
-
-// Creates `unique_resource<Resource, Deleter>` and initializes it with a resource constructed using specified arguments.
-template <class Resource, class Deleter = utils_memory_internal::default_resource_deleter_t<Resource>, class... Tn>
-inline unique_resource<Resource, Deleter> make_unique_resource(Tn &&... arg_n)
-{
-    return unique_resource<Resource, Deleter>(Resource(std::forward<Tn>(arg_n)...));
-}
-
-} // namespace systemverilog_plugin
-
-#endif // SYSTEMVERILOG_PLUGIN_UTILS_MEMORY_H_
diff --git a/uhdm-plugin/Makefile b/uhdm-plugin/Makefile
deleted file mode 100644
index 4f67830..0000000
--- a/uhdm-plugin/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-# 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
-
-PLUGIN_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
-
-NAME = uhdm
-SOURCES = uhdm.cc
-include ../Makefile_plugin.common
diff --git a/uhdm-plugin/README.md b/uhdm-plugin/README.md
deleted file mode 100644
index cecd427..0000000
--- a/uhdm-plugin/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# UHDM Plugin
-
-The UHDM plugin has been renamed to [SystemVerilog](../systemverilog-plugin/).
-
-It is kept here for backwards compatibility reasons.
-When loaded, it shows a warning and loads the `SystemVerilog` plugin (if available).
diff --git a/uhdm-plugin/tests/Makefile b/uhdm-plugin/tests/Makefile
deleted file mode 100644
index 1c6f1d8..0000000
--- a/uhdm-plugin/tests/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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
-
-include $(shell pwd)/../../Makefile_test.common
diff --git a/uhdm-plugin/uhdm.cc b/uhdm-plugin/uhdm.cc
deleted file mode 100644
index 9fde149..0000000
--- a/uhdm-plugin/uhdm.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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
- */
-#include "kernel/log.h"
-
-USING_YOSYS_NAMESPACE
-
-PRIVATE_NAMESPACE_BEGIN
-
-struct UhdmDummy {
-    UhdmDummy()
-    {
-        log("\n");
-        log("!! DEPRECATION WARNING !!\n");
-        log("\n");
-        log("The uhdm plugin has been renamed to systemverilog.\n");
-        log("Loading the systemverilog plugin...\n");
-
-        std::vector<std::string> plugin_aliases;
-        load_plugin("systemverilog", plugin_aliases);
-    }
-} UhdmDummy;
-
-PRIVATE_NAMESPACE_END