rtlil: Make Process handling more uniform with Cell and Wire.
[yosys.git] / kernel / rtlil.cc
index 397edc4e7e966d84e040485d474d7ebb203c60c7..21ee15ac548a6cd23ba16ee31d8f204ec0ad2573 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  yosys -- Yosys Open SYnthesis Suite
  *
- *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  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
@@ -22,7 +22,7 @@
 #include "kernel/celltypes.h"
 #include "frontends/verilog/verilog_frontend.h"
 #include "frontends/verilog/preproc.h"
-#include "backends/ilang/ilang_backend.h"
+#include "backends/rtlil/rtlil_backend.h"
 
 #include <string.h>
 #include <algorithm>
@@ -54,8 +54,14 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
                ID($dff),
                ID($dffe),
                ID($dffsr),
+               ID($dffsre),
                ID($adff),
+               ID($adffe),
+               ID($sdff),
+               ID($sdffe),
+               ID($sdffce),
                ID($dlatch),
+               ID($adlatch),
                ID($dlatchsr),
                ID($_DFFE_NN_),
                ID($_DFFE_NP_),
@@ -69,16 +75,102 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
                ID($_DFFSR_PNP_),
                ID($_DFFSR_PPN_),
                ID($_DFFSR_PPP_),
+               ID($_DFFSRE_NNNN_),
+               ID($_DFFSRE_NNNP_),
+               ID($_DFFSRE_NNPN_),
+               ID($_DFFSRE_NNPP_),
+               ID($_DFFSRE_NPNN_),
+               ID($_DFFSRE_NPNP_),
+               ID($_DFFSRE_NPPN_),
+               ID($_DFFSRE_NPPP_),
+               ID($_DFFSRE_PNNN_),
+               ID($_DFFSRE_PNNP_),
+               ID($_DFFSRE_PNPN_),
+               ID($_DFFSRE_PNPP_),
+               ID($_DFFSRE_PPNN_),
+               ID($_DFFSRE_PPNP_),
+               ID($_DFFSRE_PPPN_),
+               ID($_DFFSRE_PPPP_),
+               ID($_DFF_N_),
+               ID($_DFF_P_),
                ID($_DFF_NN0_),
                ID($_DFF_NN1_),
                ID($_DFF_NP0_),
                ID($_DFF_NP1_),
-               ID($_DFF_N_),
                ID($_DFF_PN0_),
                ID($_DFF_PN1_),
                ID($_DFF_PP0_),
                ID($_DFF_PP1_),
-               ID($_DFF_P_),
+               ID($_DFFE_NN0N_),
+               ID($_DFFE_NN0P_),
+               ID($_DFFE_NN1N_),
+               ID($_DFFE_NN1P_),
+               ID($_DFFE_NP0N_),
+               ID($_DFFE_NP0P_),
+               ID($_DFFE_NP1N_),
+               ID($_DFFE_NP1P_),
+               ID($_DFFE_PN0N_),
+               ID($_DFFE_PN0P_),
+               ID($_DFFE_PN1N_),
+               ID($_DFFE_PN1P_),
+               ID($_DFFE_PP0N_),
+               ID($_DFFE_PP0P_),
+               ID($_DFFE_PP1N_),
+               ID($_DFFE_PP1P_),
+               ID($_SDFF_NN0_),
+               ID($_SDFF_NN1_),
+               ID($_SDFF_NP0_),
+               ID($_SDFF_NP1_),
+               ID($_SDFF_PN0_),
+               ID($_SDFF_PN1_),
+               ID($_SDFF_PP0_),
+               ID($_SDFF_PP1_),
+               ID($_SDFFE_NN0N_),
+               ID($_SDFFE_NN0P_),
+               ID($_SDFFE_NN1N_),
+               ID($_SDFFE_NN1P_),
+               ID($_SDFFE_NP0N_),
+               ID($_SDFFE_NP0P_),
+               ID($_SDFFE_NP1N_),
+               ID($_SDFFE_NP1P_),
+               ID($_SDFFE_PN0N_),
+               ID($_SDFFE_PN0P_),
+               ID($_SDFFE_PN1N_),
+               ID($_SDFFE_PN1P_),
+               ID($_SDFFE_PP0N_),
+               ID($_SDFFE_PP0P_),
+               ID($_SDFFE_PP1N_),
+               ID($_SDFFE_PP1P_),
+               ID($_SDFFCE_NN0N_),
+               ID($_SDFFCE_NN0P_),
+               ID($_SDFFCE_NN1N_),
+               ID($_SDFFCE_NN1P_),
+               ID($_SDFFCE_NP0N_),
+               ID($_SDFFCE_NP0P_),
+               ID($_SDFFCE_NP1N_),
+               ID($_SDFFCE_NP1P_),
+               ID($_SDFFCE_PN0N_),
+               ID($_SDFFCE_PN0P_),
+               ID($_SDFFCE_PN1N_),
+               ID($_SDFFCE_PN1P_),
+               ID($_SDFFCE_PP0N_),
+               ID($_SDFFCE_PP0P_),
+               ID($_SDFFCE_PP1N_),
+               ID($_SDFFCE_PP1P_),
+               ID($_SR_NN_),
+               ID($_SR_NP_),
+               ID($_SR_PN_),
+               ID($_SR_PP_),
+               ID($_DLATCH_N_),
+               ID($_DLATCH_P_),
+               ID($_DLATCH_NN0_),
+               ID($_DLATCH_NN1_),
+               ID($_DLATCH_NP0_),
+               ID($_DLATCH_NP1_),
+               ID($_DLATCH_PN0_),
+               ID($_DLATCH_PN1_),
+               ID($_DLATCH_PP0_),
+               ID($_DLATCH_PP1_),
                ID($_DLATCHSR_NNN_),
                ID($_DLATCHSR_NNP_),
                ID($_DLATCHSR_NPN_),
@@ -87,8 +179,6 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
                ID($_DLATCHSR_PNP_),
                ID($_DLATCHSR_PPN_),
                ID($_DLATCHSR_PPP_),
-               ID($_DLATCH_N_),
-               ID($_DLATCH_P_),
                ID($_FF_),
        };
        return res;
@@ -273,6 +363,26 @@ bool RTLIL::Const::is_fully_undef() const
        return true;
 }
 
+bool RTLIL::Const::is_onehot(int *pos) const
+{
+       cover("kernel.rtlil.const.is_onehot");
+
+       bool found = false;
+       for (int i = 0; i < GetSize(*this); i++) {
+               auto &bit = bits[i];
+               if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1)
+                       return false;
+               if (bit == RTLIL::State::S1) {
+                       if (found)
+                               return false;
+                       if (pos)
+                               *pos = i;
+                       found = true;
+               }
+       }
+       return found;
+}
+
 bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const
 {
        return attributes.count(id);
@@ -319,7 +429,7 @@ void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<str
                        attrval += "|";
                attrval += s;
        }
-       attributes[id] = RTLIL::Const(attrval);
+       set_string_attribute(id, attrval);
 }
 
 void RTLIL::AttrObject::add_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
@@ -334,11 +444,27 @@ pool<string> RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const
 {
        pool<string> data;
        if (attributes.count(id) != 0)
-               for (auto s : split_tokens(attributes.at(id).decode_string(), "|"))
+               for (auto s : split_tokens(get_string_attribute(id), "|"))
                        data.insert(s);
        return data;
 }
 
+void RTLIL::AttrObject::set_hdlname_attribute(const vector<string> &hierarchy)
+{
+       string attrval;
+       for (const auto &ident : hierarchy) {
+               if (!attrval.empty())
+                       attrval += " ";
+               attrval += ident;
+       }
+       set_string_attribute(ID::hdlname, attrval);
+}
+
+vector<string> RTLIL::AttrObject::get_hdlname_attribute() const
+{
+       return split_tokens(get_string_attribute(ID::hdlname), " ");
+}
+
 bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const
 {
        if (full_selection)
@@ -445,8 +571,8 @@ RTLIL::Design::Design()
 
 RTLIL::Design::~Design()
 {
-       for (auto it = modules_.begin(); it != modules_.end(); ++it)
-               delete it->second;
+       for (auto &pr : modules_)
+               delete pr.second;
        for (auto n : verilog_packages)
                delete n;
        for (auto n : verilog_globals)
@@ -474,6 +600,11 @@ RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name)
        return modules_.count(name) ? modules_.at(name) : NULL;
 }
 
+const RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) const
+{
+       return modules_.count(name) ? modules_.at(name) : NULL;
+}
+
 RTLIL::Module *RTLIL::Design::top_module()
 {
        RTLIL::Module *module = nullptr;
@@ -507,7 +638,8 @@ void RTLIL::Design::add(RTLIL::Module *module)
 
 RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name)
 {
-       log_assert(modules_.count(name) == 0);
+       if (modules_.count(name) != 0)
+               log_error("Attempted to add new module named '%s', but a module by that name already exists\n", name.c_str());
        log_assert(refcount_modules_ == 0);
 
        RTLIL::Module *module = new RTLIL::Module;
@@ -701,12 +833,12 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const
        return result;
 }
 
-std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const
+std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn(bool include_wb) const
 {
        std::vector<RTLIL::Module*> result;
        result.reserve(modules_.size());
        for (auto &it : modules_)
-               if (it.second->get_blackbox_attribute())
+               if (it.second->get_blackbox_attribute(include_wb))
                        continue;
                else if (selected_whole_module(it.first))
                        result.push_back(it.second);
@@ -732,14 +864,14 @@ RTLIL::Module::Module()
 
 RTLIL::Module::~Module()
 {
-       for (auto it = wires_.begin(); it != wires_.end(); ++it)
-               delete it->second;
-       for (auto it = memories.begin(); it != memories.end(); ++it)
-               delete it->second;
-       for (auto it = cells_.begin(); it != cells_.end(); ++it)
-               delete it->second;
-       for (auto it = processes.begin(); it != processes.end(); ++it)
-               delete it->second;
+       for (auto &pr : wires_)
+               delete pr.second;
+       for (auto &pr : memories)
+               delete pr.second;
+       for (auto &pr : cells_)
+               delete pr.second;
+       for (auto &pr : processes)
+               delete pr.second;
 #ifdef WITH_PYTHON
        RTLIL::Module::get_all_modules()->erase(hashidx_);
 #endif
@@ -817,7 +949,7 @@ namespace {
                void error(int linenr)
                {
                        std::stringstream buf;
-                       ILANG_BACKEND::dump_cell(buf, "  ", cell);
+                       RTLIL_BACKEND::dump_cell(buf, "  ", cell);
 
                        log_error("Found error in internal cell %s%s%s (%s) at %s:%d:\n%s",
                                        module ? module->name.c_str() : "", module ? "." : "",
@@ -929,7 +1061,11 @@ namespace {
                        }
 
                        if (cell->type.in(ID($shift), ID($shiftx))) {
-                               param_bool(ID::A_SIGNED);
+                               if (cell->type == ID($shiftx)) {
+                                       param_bool(ID::A_SIGNED, /*expected=*/false);
+                               } else {
+                                       param_bool(ID::A_SIGNED);
+                               }
                                param_bool(ID::B_SIGNED);
                                port(ID::A, param(ID::A_WIDTH));
                                port(ID::B, param(ID::B_WIDTH));
@@ -1123,6 +1259,21 @@ namespace {
                                return;
                        }
 
+                       if (cell->type == ID($dffsre)) {
+                               param_bool(ID::CLK_POLARITY);
+                               param_bool(ID::SET_POLARITY);
+                               param_bool(ID::CLR_POLARITY);
+                               param_bool(ID::EN_POLARITY);
+                               port(ID::CLK, 1);
+                               port(ID::EN, 1);
+                               port(ID::SET, param(ID::WIDTH));
+                               port(ID::CLR, param(ID::WIDTH));
+                               port(ID::D, param(ID::WIDTH));
+                               port(ID::Q, param(ID::WIDTH));
+                               check_expected();
+                               return;
+                       }
+
                        if (cell->type == ID($adff)) {
                                param_bool(ID::CLK_POLARITY);
                                param_bool(ID::ARST_POLARITY);
@@ -1135,6 +1286,46 @@ namespace {
                                return;
                        }
 
+                       if (cell->type == ID($sdff)) {
+                               param_bool(ID::CLK_POLARITY);
+                               param_bool(ID::SRST_POLARITY);
+                               param_bits(ID::SRST_VALUE, param(ID::WIDTH));
+                               port(ID::CLK, 1);
+                               port(ID::SRST, 1);
+                               port(ID::D, param(ID::WIDTH));
+                               port(ID::Q, param(ID::WIDTH));
+                               check_expected();
+                               return;
+                       }
+
+                       if (cell->type.in(ID($sdffe), ID($sdffce))) {
+                               param_bool(ID::CLK_POLARITY);
+                               param_bool(ID::EN_POLARITY);
+                               param_bool(ID::SRST_POLARITY);
+                               param_bits(ID::SRST_VALUE, param(ID::WIDTH));
+                               port(ID::CLK, 1);
+                               port(ID::EN, 1);
+                               port(ID::SRST, 1);
+                               port(ID::D, param(ID::WIDTH));
+                               port(ID::Q, param(ID::WIDTH));
+                               check_expected();
+                               return;
+                       }
+
+                       if (cell->type == ID($adffe)) {
+                               param_bool(ID::CLK_POLARITY);
+                               param_bool(ID::EN_POLARITY);
+                               param_bool(ID::ARST_POLARITY);
+                               param_bits(ID::ARST_VALUE, param(ID::WIDTH));
+                               port(ID::CLK, 1);
+                               port(ID::EN, 1);
+                               port(ID::ARST, 1);
+                               port(ID::D, param(ID::WIDTH));
+                               port(ID::Q, param(ID::WIDTH));
+                               check_expected();
+                               return;
+                       }
+
                        if (cell->type == ID($dlatch)) {
                                param_bool(ID::EN_POLARITY);
                                port(ID::EN, 1);
@@ -1144,6 +1335,18 @@ namespace {
                                return;
                        }
 
+                       if (cell->type == ID($adlatch)) {
+                               param_bool(ID::EN_POLARITY);
+                               param_bool(ID::ARST_POLARITY);
+                               param_bits(ID::ARST_VALUE, param(ID::WIDTH));
+                               port(ID::EN, 1);
+                               port(ID::ARST, 1);
+                               port(ID::D, param(ID::WIDTH));
+                               port(ID::Q, param(ID::WIDTH));
+                               check_expected();
+                               return;
+                       }
+
                        if (cell->type == ID($dlatchsr)) {
                                param_bool(ID::EN_POLARITY);
                                param_bool(ID::SET_POLARITY);
@@ -1335,49 +1538,69 @@ namespace {
                        if (cell->type == ID($_MUX8_))  { port(ID::A,1); port(ID::B,1); port(ID::C,1); port(ID::D,1); port(ID::E,1); port(ID::F,1); port(ID::G,1); port(ID::H,1); port(ID::S,1); port(ID::T,1); port(ID::U,1); port(ID::Y,1); check_expected(); return; }
                        if (cell->type == ID($_MUX16_)) { port(ID::A,1); port(ID::B,1); port(ID::C,1); port(ID::D,1); port(ID::E,1); port(ID::F,1); port(ID::G,1); port(ID::H,1); port(ID::I,1); port(ID::J,1); port(ID::K,1); port(ID::L,1); port(ID::M,1); port(ID::N,1); port(ID::O,1); port(ID::P,1); port(ID::S,1); port(ID::T,1); port(ID::U,1); port(ID::V,1); port(ID::Y,1); check_expected(); return; }
 
-                       if (cell->type == ID($_SR_NN_)) { port(ID::S,1); port(ID::R,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_SR_NP_)) { port(ID::S,1); port(ID::R,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_SR_PN_)) { port(ID::S,1); port(ID::R,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_SR_PP_)) { port(ID::S,1); port(ID::R,1); port(ID::Q,1); check_expected(); return; }
-
-                       if (cell->type == ID($_FF_))    { port(ID::D,1); port(ID::Q,1); check_expected();  return; }
-                       if (cell->type == ID($_DFF_N_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); check_expected(); return; }
-                       if (cell->type == ID($_DFF_P_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); check_expected(); return; }
-
-                       if (cell->type == ID($_DFFE_NN_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::E,1); check_expected(); return; }
-                       if (cell->type == ID($_DFFE_NP_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::E,1); check_expected(); return; }
-                       if (cell->type == ID($_DFFE_PN_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::E,1); check_expected(); return; }
-                       if (cell->type == ID($_DFFE_PP_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::E,1); check_expected(); return; }
-
-                       if (cell->type == ID($_DFF_NN0_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; }
-                       if (cell->type == ID($_DFF_NN1_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; }
-                       if (cell->type == ID($_DFF_NP0_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; }
-                       if (cell->type == ID($_DFF_NP1_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; }
-                       if (cell->type == ID($_DFF_PN0_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; }
-                       if (cell->type == ID($_DFF_PN1_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; }
-                       if (cell->type == ID($_DFF_PP0_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; }
-                       if (cell->type == ID($_DFF_PP1_)) { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; }
-
-                       if (cell->type == ID($_DFFSR_NNN_)) { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DFFSR_NNP_)) { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DFFSR_NPN_)) { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DFFSR_NPP_)) { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DFFSR_PNN_)) { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DFFSR_PNP_)) { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DFFSR_PPN_)) { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DFFSR_PPP_)) { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-
-                       if (cell->type == ID($_DLATCH_N_)) { port(ID::E,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DLATCH_P_)) { port(ID::E,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-
-                       if (cell->type == ID($_DLATCHSR_NNN_)) { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DLATCHSR_NNP_)) { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DLATCHSR_NPN_)) { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DLATCHSR_NPP_)) { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DLATCHSR_PNN_)) { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DLATCHSR_PNP_)) { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DLATCHSR_PPN_)) { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
-                       if (cell->type == ID($_DLATCHSR_PPP_)) { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
+                       if (cell->type.in(ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_)))
+                               { port(ID::S,1); port(ID::R,1); port(ID::Q,1); check_expected(); return; }
+
+                       if (cell->type == ID($_FF_)) { port(ID::D,1); port(ID::Q,1); check_expected();  return; }
+
+                       if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
+                               { port(ID::D,1); port(ID::Q,1); port(ID::C,1); check_expected(); return; }
+
+                       if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
+                               { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::E,1); check_expected(); return; }
+
+                       if (cell->type.in(
+                                       ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
+                                       ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_)))
+                               { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; }
+
+                       if (cell->type.in(
+                                       ID($_DFFE_NN0N_), ID($_DFFE_NN0P_), ID($_DFFE_NN1N_), ID($_DFFE_NN1P_),
+                                       ID($_DFFE_NP0N_), ID($_DFFE_NP0P_), ID($_DFFE_NP1N_), ID($_DFFE_NP1P_),
+                                       ID($_DFFE_PN0N_), ID($_DFFE_PN0P_), ID($_DFFE_PN1N_), ID($_DFFE_PN1P_),
+                                       ID($_DFFE_PP0N_), ID($_DFFE_PP0P_), ID($_DFFE_PP1N_), ID($_DFFE_PP1P_)))
+                               { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); port(ID::E,1); check_expected(); return; }
+
+                       if (cell->type.in(
+                                       ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
+                                       ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
+                               { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
+
+                       if (cell->type.in(
+                                       ID($_DFFSRE_NNNN_), ID($_DFFSRE_NNNP_), ID($_DFFSRE_NNPN_), ID($_DFFSRE_NNPP_),
+                                       ID($_DFFSRE_NPNN_), ID($_DFFSRE_NPNP_), ID($_DFFSRE_NPPN_), ID($_DFFSRE_NPPP_),
+                                       ID($_DFFSRE_PNNN_), ID($_DFFSRE_PNNP_), ID($_DFFSRE_PNPN_), ID($_DFFSRE_PNPP_),
+                                       ID($_DFFSRE_PPNN_), ID($_DFFSRE_PPNP_), ID($_DFFSRE_PPPN_), ID($_DFFSRE_PPPP_)))
+                               { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::E,1); port(ID::Q,1); check_expected(); return; }
+
+                       if (cell->type.in(
+                                       ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_),
+                                       ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_)))
+                               { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; }
+
+                       if (cell->type.in(
+                                       ID($_SDFFE_NN0N_), ID($_SDFFE_NN0P_), ID($_SDFFE_NN1N_), ID($_SDFFE_NN1P_),
+                                       ID($_SDFFE_NP0N_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1N_), ID($_SDFFE_NP1P_),
+                                       ID($_SDFFE_PN0N_), ID($_SDFFE_PN0P_), ID($_SDFFE_PN1N_), ID($_SDFFE_PN1P_),
+                                       ID($_SDFFE_PP0N_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1N_), ID($_SDFFE_PP1P_),
+                                       ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NN1P_),
+                                       ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1N_), ID($_SDFFCE_NP1P_),
+                                       ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PN1P_),
+                                       ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1N_), ID($_SDFFCE_PP1P_)))
+                               { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); port(ID::E,1); check_expected(); return; }
+
+                       if (cell->type.in(ID($_DLATCH_N_), ID($_DLATCH_P_)))
+                               { port(ID::E,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
+
+                       if (cell->type.in(
+                                       ID($_DLATCH_NN0_), ID($_DLATCH_NN1_), ID($_DLATCH_NP0_), ID($_DLATCH_NP1_),
+                                       ID($_DLATCH_PN0_), ID($_DLATCH_PN1_), ID($_DLATCH_PP0_), ID($_DLATCH_PP1_)))
+                               { port(ID::E,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
+
+                       if (cell->type.in(
+                                       ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_),
+                                       ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_)))
+                               { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; }
 
                        error(__LINE__);
                }
@@ -1520,13 +1743,13 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const
                new_mod->addWire(it.first, it.second);
 
        for (auto &it : memories)
-               new_mod->memories[it.first] = new RTLIL::Memory(*it.second);
+               new_mod->addMemory(it.first, it.second);
 
        for (auto &it : cells_)
                new_mod->addCell(it.first, it.second);
 
        for (auto &it : processes)
-               new_mod->processes[it.first] = it.second->clone();
+               new_mod->addProcess(it.first, it.second);
 
        struct RewriteSigSpecWorker
        {
@@ -1616,6 +1839,14 @@ void RTLIL::Module::add(RTLIL::Cell *cell)
        cell->module = this;
 }
 
+void RTLIL::Module::add(RTLIL::Process *process)
+{
+       log_assert(!process->name.empty());
+       log_assert(count_id(process->name) == 0);
+       processes[process->name] = process;
+       process->module = this;
+}
+
 void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
 {
        log_assert(refcount_wires_ == 0);
@@ -1629,7 +1860,7 @@ void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
                        sig.pack();
                        for (auto &c : sig.chunks_)
                                if (c.wire != NULL && wires_p->count(c.wire)) {
-                                       c.wire = module->addWire(NEW_ID, c.width);
+                                       c.wire = module->addWire(stringf("$delete_wire$%d", autoidx++), c.width);
                                        c.offset = 0;
                                }
                }
@@ -1672,6 +1903,13 @@ void RTLIL::Module::remove(RTLIL::Cell *cell)
        delete cell;
 }
 
+void RTLIL::Module::remove(RTLIL::Process *process)
+{
+       log_assert(processes.count(process->name) != 0);
+       processes.erase(process->name);
+       delete process;
+}
+
 void RTLIL::Module::rename(RTLIL::Wire *wire, RTLIL::IdString new_name)
 {
        log_assert(wires_[wire->name] == wire);
@@ -1885,6 +2123,34 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth
        return cell;
 }
 
+RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memory *other)
+{
+       RTLIL::Memory *mem = new RTLIL::Memory;
+       mem->name = name;
+       mem->width = other->width;
+       mem->start_offset = other->start_offset;
+       mem->size = other->size;
+       mem->attributes = other->attributes;
+       memories[mem->name] = mem;
+       return mem;
+}
+
+RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name)
+{
+       RTLIL::Process *proc = new RTLIL::Process;
+       proc->name = name;
+       add(proc);
+       return proc;
+}
+
+RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Process *other)
+{
+       RTLIL::Process *proc = other->clone();
+       proc->name = name;
+       add(proc);
+       return proc;
+}
+
 #define DEF_METHOD(_func, _y_size, _type) \
        RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed, const std::string &src) { \
                RTLIL::Cell *cell = addCell(name, _type);           \
@@ -2263,6 +2529,25 @@ RTLIL::Cell* RTLIL::Module::addDffsr(RTLIL::IdString name, const RTLIL::SigSpec
        return cell;
 }
 
+RTLIL::Cell* RTLIL::Module::addDffsre(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,
+               RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, ID($dffsre));
+       cell->parameters[ID::CLK_POLARITY] = clk_polarity;
+       cell->parameters[ID::EN_POLARITY] = en_polarity;
+       cell->parameters[ID::SET_POLARITY] = set_polarity;
+       cell->parameters[ID::CLR_POLARITY] = clr_polarity;
+       cell->parameters[ID::WIDTH] = sig_q.size();
+       cell->setPort(ID::CLK, sig_clk);
+       cell->setPort(ID::EN, sig_en);
+       cell->setPort(ID::SET, sig_set);
+       cell->setPort(ID::CLR, sig_clr);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
 RTLIL::Cell* RTLIL::Module::addAdff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
                RTLIL::Const arst_value, bool clk_polarity, bool arst_polarity, const std::string &src)
 {
@@ -2279,6 +2564,76 @@ RTLIL::Cell* RTLIL::Module::addAdff(RTLIL::IdString name, const RTLIL::SigSpec &
        return cell;
 }
 
+RTLIL::Cell* RTLIL::Module::addAdffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
+               RTLIL::Const arst_value, bool clk_polarity, bool en_polarity, bool arst_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, ID($adffe));
+       cell->parameters[ID::CLK_POLARITY] = clk_polarity;
+       cell->parameters[ID::EN_POLARITY] = en_polarity;
+       cell->parameters[ID::ARST_POLARITY] = arst_polarity;
+       cell->parameters[ID::ARST_VALUE] = arst_value;
+       cell->parameters[ID::WIDTH] = sig_q.size();
+       cell->setPort(ID::CLK, sig_clk);
+       cell->setPort(ID::EN, sig_en);
+       cell->setPort(ID::ARST, sig_arst);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addSdff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
+               RTLIL::Const srst_value, bool clk_polarity, bool srst_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, ID($sdff));
+       cell->parameters[ID::CLK_POLARITY] = clk_polarity;
+       cell->parameters[ID::SRST_POLARITY] = srst_polarity;
+       cell->parameters[ID::SRST_VALUE] = srst_value;
+       cell->parameters[ID::WIDTH] = sig_q.size();
+       cell->setPort(ID::CLK, sig_clk);
+       cell->setPort(ID::SRST, sig_srst);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addSdffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
+               RTLIL::Const srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, ID($sdffe));
+       cell->parameters[ID::CLK_POLARITY] = clk_polarity;
+       cell->parameters[ID::EN_POLARITY] = en_polarity;
+       cell->parameters[ID::SRST_POLARITY] = srst_polarity;
+       cell->parameters[ID::SRST_VALUE] = srst_value;
+       cell->parameters[ID::WIDTH] = sig_q.size();
+       cell->setPort(ID::CLK, sig_clk);
+       cell->setPort(ID::EN, sig_en);
+       cell->setPort(ID::SRST, sig_srst);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addSdffce(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
+               RTLIL::Const srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, ID($sdffce));
+       cell->parameters[ID::CLK_POLARITY] = clk_polarity;
+       cell->parameters[ID::EN_POLARITY] = en_polarity;
+       cell->parameters[ID::SRST_POLARITY] = srst_polarity;
+       cell->parameters[ID::SRST_VALUE] = srst_value;
+       cell->parameters[ID::WIDTH] = sig_q.size();
+       cell->setPort(ID::CLK, sig_clk);
+       cell->setPort(ID::EN, sig_en);
+       cell->setPort(ID::SRST, sig_srst);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
 RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, const std::string &src)
 {
        RTLIL::Cell *cell = addCell(name, ID($dlatch));
@@ -2291,6 +2646,22 @@ RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, const RTLIL::SigSpec
        return cell;
 }
 
+RTLIL::Cell* RTLIL::Module::addAdlatch(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
+               RTLIL::Const arst_value, bool en_polarity, bool arst_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, ID($adlatch));
+       cell->parameters[ID::EN_POLARITY] = en_polarity;
+       cell->parameters[ID::ARST_POLARITY] = arst_polarity;
+       cell->parameters[ID::ARST_VALUE] = arst_value;
+       cell->parameters[ID::WIDTH] = sig_q.size();
+       cell->setPort(ID::EN, sig_en);
+       cell->setPort(ID::ARST, sig_arst);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
 RTLIL::Cell* RTLIL::Module::addDlatchsr(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,
                RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src)
 {
@@ -2308,6 +2679,17 @@ RTLIL::Cell* RTLIL::Module::addDlatchsr(RTLIL::IdString name, const RTLIL::SigSp
        return cell;
 }
 
+RTLIL::Cell* RTLIL::Module::addSrGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,
+               const RTLIL::SigSpec &sig_q, bool set_polarity, bool clr_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, stringf("$_SR_%c%c_", set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N'));
+       cell->setPort(ID::S, sig_set);
+       cell->setPort(ID::R, sig_clr);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
 RTLIL::Cell* RTLIL::Module::addFfGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src)
 {
        RTLIL::Cell *cell = addCell(name, ID($_FF_));
@@ -2351,6 +2733,20 @@ RTLIL::Cell* RTLIL::Module::addDffsrGate(RTLIL::IdString name, const RTLIL::SigS
        return cell;
 }
 
+RTLIL::Cell* RTLIL::Module::addDffsreGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,
+               RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, stringf("$_DFFSRE_%c%c%c%c_", clk_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
+       cell->setPort(ID::C, sig_clk);
+       cell->setPort(ID::S, sig_set);
+       cell->setPort(ID::R, sig_clr);
+       cell->setPort(ID::E, sig_en);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
 RTLIL::Cell* RTLIL::Module::addAdffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
                bool arst_value, bool clk_polarity, bool arst_polarity, const std::string &src)
 {
@@ -2363,6 +2759,57 @@ RTLIL::Cell* RTLIL::Module::addAdffGate(RTLIL::IdString name, const RTLIL::SigSp
        return cell;
 }
 
+RTLIL::Cell* RTLIL::Module::addAdffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
+               bool arst_value, bool clk_polarity, bool en_polarity, bool arst_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, stringf("$_DFFE_%c%c%c%c_", clk_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0', en_polarity ? 'P' : 'N'));
+       cell->setPort(ID::C, sig_clk);
+       cell->setPort(ID::R, sig_arst);
+       cell->setPort(ID::E, sig_en);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addSdffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
+               bool srst_value, bool clk_polarity, bool srst_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, stringf("$_SDFF_%c%c%c_", clk_polarity ? 'P' : 'N', srst_polarity ? 'P' : 'N', srst_value ? '1' : '0'));
+       cell->setPort(ID::C, sig_clk);
+       cell->setPort(ID::R, sig_srst);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addSdffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
+               bool srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, stringf("$_SDFFE_%c%c%c%c_", clk_polarity ? 'P' : 'N', srst_polarity ? 'P' : 'N', srst_value ? '1' : '0', en_polarity ? 'P' : 'N'));
+       cell->setPort(ID::C, sig_clk);
+       cell->setPort(ID::R, sig_srst);
+       cell->setPort(ID::E, sig_en);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addSdffceGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
+               bool srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, stringf("$_SDFFCE_%c%c%c%c_", clk_polarity ? 'P' : 'N', srst_polarity ? 'P' : 'N', srst_value ? '1' : '0', en_polarity ? 'P' : 'N'));
+       cell->setPort(ID::C, sig_clk);
+       cell->setPort(ID::R, sig_srst);
+       cell->setPort(ID::E, sig_en);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
 RTLIL::Cell* RTLIL::Module::addDlatchGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, const std::string &src)
 {
        RTLIL::Cell *cell = addCell(name, stringf("$_DLATCH_%c_", en_polarity ? 'P' : 'N'));
@@ -2373,6 +2820,18 @@ RTLIL::Cell* RTLIL::Module::addDlatchGate(RTLIL::IdString name, const RTLIL::Sig
        return cell;
 }
 
+RTLIL::Cell* RTLIL::Module::addAdlatchGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,
+               bool arst_value, bool en_polarity, bool arst_polarity, const std::string &src)
+{
+       RTLIL::Cell *cell = addCell(name, stringf("$_DLATCH_%c%c%c_", en_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0'));
+       cell->setPort(ID::E, sig_en);
+       cell->setPort(ID::R, sig_arst);
+       cell->setPort(ID::D, sig_d);
+       cell->setPort(ID::Q, sig_q);
+       cell->set_src_attribute(src);
+       return cell;
+}
+
 RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,
                RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src)
 {
@@ -2484,6 +2943,13 @@ RTLIL::Memory::Memory()
 #endif
 }
 
+RTLIL::Process::Process() : module(nullptr)
+{
+       static unsigned int hashidx_count = 123456789;
+       hashidx_count = mkhash_xorshift(hashidx_count);
+       hashidx_ = hashidx_count;
+}
+
 RTLIL::Cell::Cell() : module(nullptr)
 {
        static unsigned int hashidx_count = 123456789;
@@ -2709,6 +3175,16 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
        check();
 }
 
+bool RTLIL::Cell::has_memid() const
+{
+       return type.in(ID($memwr), ID($memrd), ID($meminit));
+}
+
+bool RTLIL::Cell::is_mem_cell() const
+{
+       return type == ID($mem) || has_memid();
+}
+
 RTLIL::SigChunk::SigChunk()
 {
        wire = NULL;
@@ -2865,8 +3341,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::Const &value)
 {
        cover("kernel.rtlil.sigspec.init.const");
 
-       chunks_.emplace_back(value);
-       width_ = chunks_.back().width;
+       if (GetSize(value) != 0) {
+               chunks_.emplace_back(value);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -2875,8 +3355,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk)
 {
        cover("kernel.rtlil.sigspec.init.chunk");
 
-       chunks_.emplace_back(chunk);
-       width_ = chunks_.back().width;
+       if (chunk.width != 0) {
+               chunks_.emplace_back(chunk);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -2885,8 +3369,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire)
 {
        cover("kernel.rtlil.sigspec.init.wire");
 
-       chunks_.emplace_back(wire);
-       width_ = chunks_.back().width;
+       if (wire->width != 0) {
+               chunks_.emplace_back(wire);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -2895,8 +3383,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width)
 {
        cover("kernel.rtlil.sigspec.init.wire_part");
 
-       chunks_.emplace_back(wire, offset, width);
-       width_ = chunks_.back().width;
+       if (width != 0) {
+               chunks_.emplace_back(wire, offset, width);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -2905,8 +3397,12 @@ RTLIL::SigSpec::SigSpec(const std::string &str)
 {
        cover("kernel.rtlil.sigspec.init.str");
 
-       chunks_.emplace_back(str);
-       width_ = chunks_.back().width;
+       if (str.size() != 0) {
+               chunks_.emplace_back(str);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -2915,7 +3411,8 @@ RTLIL::SigSpec::SigSpec(int val, int width)
 {
        cover("kernel.rtlil.sigspec.init.int");
 
-       chunks_.emplace_back(val, width);
+       if (width != 0)
+               chunks_.emplace_back(val, width);
        width_ = width;
        hash_ = 0;
        check();
@@ -2925,7 +3422,8 @@ RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width)
 {
        cover("kernel.rtlil.sigspec.init.state");
 
-       chunks_.emplace_back(bit, width);
+       if (width != 0)
+               chunks_.emplace_back(bit, width);
        width_ = width;
        hash_ = 0;
        check();
@@ -2935,11 +3433,13 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width)
 {
        cover("kernel.rtlil.sigspec.init.bit");
 
-       if (bit.wire == NULL)
-               chunks_.emplace_back(bit.data, width);
-       else
-               for (int i = 0; i < width; i++)
-                       chunks_.push_back(bit);
+       if (width != 0) {
+               if (bit.wire == NULL)
+                       chunks_.emplace_back(bit.data, width);
+               else
+                       for (int i = 0; i < width; i++)
+                               chunks_.push_back(bit);
+       }
        width_ = width;
        hash_ = 0;
        check();
@@ -3384,7 +3884,13 @@ void RTLIL::SigSpec::remove_const()
                width_ = 0;
                for (auto &chunk : chunks_)
                        if (chunk.wire != NULL) {
-                               new_chunks.push_back(chunk);
+                               if (!new_chunks.empty() &&
+                                       new_chunks.back().wire == chunk.wire &&
+                                       new_chunks.back().offset + new_chunks.back().width == chunk.offset) {
+                                       new_chunks.back().width += chunk.width;
+                               } else {
+                                       new_chunks.push_back(chunk);
+                               }
                                width_ += chunk.width;
                        }
 
@@ -3544,6 +4050,7 @@ void RTLIL::SigSpec::check() const
                int w = 0;
                for (size_t i = 0; i < chunks_.size(); i++) {
                        const RTLIL::SigChunk &chunk = chunks_[i];
+                       log_assert(chunk.width != 0);
                        if (chunk.wire == NULL) {
                                if (i > 0)
                                        log_assert(chunks_[i-1].wire != NULL);
@@ -3754,6 +4261,19 @@ bool RTLIL::SigSpec::has_marked_bits() const
        return false;
 }
 
+bool RTLIL::SigSpec::is_onehot(int *pos) const
+{
+       cover("kernel.rtlil.sigspec.is_onehot");
+
+       pack();
+       if (!is_fully_const())
+               return false;
+       log_assert(GetSize(chunks_) <= 1);
+       if (width_)
+               return RTLIL::Const(chunks_[0].data).is_onehot(pos);
+       return false;
+}
+
 bool RTLIL::SigSpec::as_bool() const
 {
        cover("kernel.rtlil.sigspec.as_bool");
@@ -4127,6 +4647,7 @@ RTLIL::SyncRule *RTLIL::SyncRule::clone() const
        new_syncrule->type = type;
        new_syncrule->signal = signal;
        new_syncrule->actions = actions;
+       new_syncrule->mem_write_actions = mem_write_actions;
        return new_syncrule;
 }