FfData: some refactoring.
authorMarcelina Kościelnicka <mwk@0x04.net>
Wed, 6 Oct 2021 20:16:55 +0000 (22:16 +0200)
committerMarcelina Kościelnicka <mwk@0x04.net>
Thu, 7 Oct 2021 02:24:06 +0000 (04:24 +0200)
- FfData now keeps track of the module and underlying cell, if any (so
  calling emit on FfData created from a cell will replace the existing cell)
- FfData implementation is split off to its own .cc file for faster
  compilation
- the "flip FF data sense by inserting inverters in front and after"
  functionality that zinit uses is moved onto FfData class and beefed up
  to have dffsr support, to support more use cases

14 files changed:
Makefile
kernel/ff.cc [new file with mode: 0644]
kernel/ff.h
kernel/ffmerge.cc
kernel/mem.cc
passes/memory/memory_dff.cc
passes/opt/opt_dff.cc
passes/sat/async2sync.cc
passes/sat/clk2fflogic.cc
passes/techmap/dffunmap.cc
passes/techmap/simplemap.cc
passes/techmap/zinit.cc
tests/arch/xilinx/fsm.ys
tests/techmap/zinit.ys

index eec70dfaa2420178272653fb9f6201131c1f5d1b..a2cad5dce045bd527303b065d6b6833765e2773a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -608,7 +608,7 @@ ifneq ($(ABCEXTERNAL),)
 kernel/yosys.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
 endif
 endif
-OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o
+OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o
 
 kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"'
 kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"'
diff --git a/kernel/ff.cc b/kernel/ff.cc
new file mode 100644 (file)
index 0000000..c2f1a75
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2020  Marcelina Kościelnicka <mwk@0x04.net>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/ff.h"
+
+USING_YOSYS_NAMESPACE
+
+FfData::FfData(FfInitVals *initvals, Cell *cell_) : FfData(cell_->module, initvals, cell_->name)
+{
+       cell = cell_;
+       sig_q = cell->getPort(ID::Q);
+       width = GetSize(sig_q);
+       attributes = cell->attributes;
+
+       if (initvals)
+               val_init = (*initvals)(sig_q);
+
+       std::string type_str = cell->type.str();
+
+       if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
+               if (cell->type == ID($ff)) {
+                       has_gclk = true;
+                       sig_d = cell->getPort(ID::D);
+               } else if (cell->type == ID($sr)) {
+                       // No data input at all.
+               } else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
+                       has_aload = true;
+                       sig_aload = cell->getPort(ID::EN);
+                       pol_aload = cell->getParam(ID::EN_POLARITY).as_bool();
+                       sig_ad = cell->getPort(ID::D);
+               } else {
+                       has_clk = true;
+                       sig_clk = cell->getPort(ID::CLK);
+                       pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
+                       sig_d = cell->getPort(ID::D);
+               }
+               if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($aldffe), ID($sdffe), ID($sdffce))) {
+                       has_ce = true;
+                       sig_ce = cell->getPort(ID::EN);
+                       pol_ce = cell->getParam(ID::EN_POLARITY).as_bool();
+               }
+               if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) {
+                       has_sr = true;
+                       sig_clr = cell->getPort(ID::CLR);
+                       sig_set = cell->getPort(ID::SET);
+                       pol_clr = cell->getParam(ID::CLR_POLARITY).as_bool();
+                       pol_set = cell->getParam(ID::SET_POLARITY).as_bool();
+               }
+               if (cell->type.in(ID($aldff), ID($aldffe))) {
+                       has_aload = true;
+                       sig_aload = cell->getPort(ID::ALOAD);
+                       pol_aload = cell->getParam(ID::ALOAD_POLARITY).as_bool();
+                       sig_ad = cell->getPort(ID::AD);
+               }
+               if (cell->type.in(ID($adff), ID($adffe), ID($adlatch))) {
+                       has_arst = true;
+                       sig_arst = cell->getPort(ID::ARST);
+                       pol_arst = cell->getParam(ID::ARST_POLARITY).as_bool();
+                       val_arst = cell->getParam(ID::ARST_VALUE);
+               }
+               if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
+                       has_srst = true;
+                       sig_srst = cell->getPort(ID::SRST);
+                       pol_srst = cell->getParam(ID::SRST_POLARITY).as_bool();
+                       val_srst = cell->getParam(ID::SRST_VALUE);
+                       ce_over_srst = cell->type == ID($sdffce);
+               }
+       } else if (cell->type == ID($_FF_)) {
+               is_fine = true;
+               has_gclk = true;
+               sig_d = cell->getPort(ID::D);
+       } else if (type_str.substr(0, 5) == "$_SR_") {
+               is_fine = true;
+               has_sr = true;
+               pol_set = type_str[5] == 'P';
+               pol_clr = type_str[6] == 'P';
+               sig_set = cell->getPort(ID::S);
+               sig_clr = cell->getPort(ID::R);
+       } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
+               is_fine = true;
+               sig_d = cell->getPort(ID::D);
+               has_clk = true;
+               pol_clk = type_str[6] == 'P';
+               sig_clk = cell->getPort(ID::C);
+       } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
+               is_fine = true;
+               sig_d = cell->getPort(ID::D);
+               has_clk = true;
+               pol_clk = type_str[7] == 'P';
+               sig_clk = cell->getPort(ID::C);
+               has_ce = true;
+               pol_ce = type_str[8] == 'P';
+               sig_ce = cell->getPort(ID::E);
+       } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
+               is_fine = true;
+               sig_d = cell->getPort(ID::D);
+               has_clk = true;
+               pol_clk = type_str[6] == 'P';
+               sig_clk = cell->getPort(ID::C);
+               has_arst = true;
+               pol_arst = type_str[7] == 'P';
+               sig_arst = cell->getPort(ID::R);
+               val_arst = type_str[8] == '1' ? State::S1 : State::S0;
+       } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
+               is_fine = true;
+               sig_d = cell->getPort(ID::D);
+               has_clk = true;
+               pol_clk = type_str[7] == 'P';
+               sig_clk = cell->getPort(ID::C);
+               has_arst = true;
+               pol_arst = type_str[8] == 'P';
+               sig_arst = cell->getPort(ID::R);
+               val_arst = type_str[9] == '1' ? State::S1 : State::S0;
+               has_ce = true;
+               pol_ce = type_str[10] == 'P';
+               sig_ce = cell->getPort(ID::E);
+       } else if (type_str.substr(0, 8) == "$_ALDFF_" && type_str.size() == 11) {
+               is_fine = true;
+               sig_d = cell->getPort(ID::D);
+               has_clk = true;
+               pol_clk = type_str[8] == 'P';
+               sig_clk = cell->getPort(ID::C);
+               has_aload = true;
+               pol_aload = type_str[9] == 'P';
+               sig_aload = cell->getPort(ID::L);
+               sig_ad = cell->getPort(ID::AD);
+       } else if (type_str.substr(0, 9) == "$_ALDFFE_" && type_str.size() == 13) {
+               is_fine = true;
+               sig_d = cell->getPort(ID::D);
+               has_clk = true;
+               pol_clk = type_str[9] == 'P';
+               sig_clk = cell->getPort(ID::C);
+               has_aload = true;
+               pol_aload = type_str[10] == 'P';
+               sig_aload = cell->getPort(ID::L);
+               sig_ad = cell->getPort(ID::AD);
+               has_ce = true;
+               pol_ce = type_str[11] == 'P';
+               sig_ce = cell->getPort(ID::E);
+       } else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
+               is_fine = true;
+               sig_d = cell->getPort(ID::D);
+               has_clk = true;
+               pol_clk = type_str[8] == 'P';
+               sig_clk = cell->getPort(ID::C);
+               has_sr = true;
+               pol_set = type_str[9] == 'P';
+               pol_clr = type_str[10] == 'P';
+               sig_set = cell->getPort(ID::S);
+               sig_clr = cell->getPort(ID::R);
+       } else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
+               is_fine = true;
+               sig_d = cell->getPort(ID::D);
+               has_clk = true;
+               pol_clk = type_str[9] == 'P';
+               sig_clk = cell->getPort(ID::C);
+               has_sr = true;
+               pol_set = type_str[10] == 'P';
+               pol_clr = type_str[11] == 'P';
+               sig_set = cell->getPort(ID::S);
+               sig_clr = cell->getPort(ID::R);
+               has_ce = true;
+               pol_ce = type_str[12] == 'P';
+               sig_ce = cell->getPort(ID::E);
+       } else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
+               is_fine = true;
+               sig_d = cell->getPort(ID::D);
+               has_clk = true;
+               pol_clk = type_str[7] == 'P';
+               sig_clk = cell->getPort(ID::C);
+               has_srst = true;
+               pol_srst = type_str[8] == 'P';
+               sig_srst = cell->getPort(ID::R);
+               val_srst = type_str[9] == '1' ? State::S1 : State::S0;
+       } else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
+               is_fine = true;
+               sig_d = cell->getPort(ID::D);
+               has_clk = true;
+               pol_clk = type_str[8] == 'P';
+               sig_clk = cell->getPort(ID::C);
+               has_srst = true;
+               pol_srst = type_str[9] == 'P';
+               sig_srst = cell->getPort(ID::R);
+               val_srst = type_str[10] == '1' ? State::S1 : State::S0;
+               has_ce = true;
+               pol_ce = type_str[11] == 'P';
+               sig_ce = cell->getPort(ID::E);
+       } else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
+               is_fine = true;
+               sig_d = cell->getPort(ID::D);
+               has_clk = true;
+               pol_clk = type_str[9] == 'P';
+               sig_clk = cell->getPort(ID::C);
+               has_srst = true;
+               pol_srst = type_str[10] == 'P';
+               sig_srst = cell->getPort(ID::R);
+               val_srst = type_str[11] == '1' ? State::S1 : State::S0;
+               has_ce = true;
+               pol_ce = type_str[12] == 'P';
+               sig_ce = cell->getPort(ID::E);
+               ce_over_srst = true;
+       } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
+               is_fine = true;
+               has_aload = true;
+               sig_ad = cell->getPort(ID::D);
+               has_aload = true;
+               pol_aload = type_str[9] == 'P';
+               sig_aload = cell->getPort(ID::E);
+       } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
+               is_fine = true;
+               has_aload = true;
+               sig_ad = cell->getPort(ID::D);
+               has_aload = true;
+               pol_aload = type_str[9] == 'P';
+               sig_aload = cell->getPort(ID::E);
+               has_arst = true;
+               pol_arst = type_str[10] == 'P';
+               sig_arst = cell->getPort(ID::R);
+               val_arst = type_str[11] == '1' ? State::S1 : State::S0;
+       } else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
+               is_fine = true;
+               has_aload = true;
+               sig_ad = cell->getPort(ID::D);
+               has_aload = true;
+               pol_aload = type_str[11] == 'P';
+               sig_aload = cell->getPort(ID::E);
+               has_sr = true;
+               pol_set = type_str[12] == 'P';
+               pol_clr = type_str[13] == 'P';
+               sig_set = cell->getPort(ID::S);
+               sig_clr = cell->getPort(ID::R);
+       } else {
+               log_assert(0);
+       }
+       if (has_aload && !has_clk && !has_sr && !has_arst && sig_ad.is_fully_const()) {
+               // Plain D latches with const D treated specially.
+               has_aload = false;
+               has_arst = true;
+               sig_arst = sig_aload;
+               pol_arst = pol_aload;
+               val_arst = sig_ad.as_const();
+       }
+}
+
+FfData FfData::slice(const std::vector<int> &bits) {
+       FfData res(module, initvals, NEW_ID);
+       res.sig_clk = sig_clk;
+       res.sig_ce = sig_ce;
+       res.sig_aload = sig_aload;
+       res.sig_arst = sig_arst;
+       res.sig_srst = sig_srst;
+       res.has_clk = has_clk;
+       res.has_gclk = has_gclk;
+       res.has_ce = has_ce;
+       res.has_aload = has_aload;
+       res.has_arst = has_arst;
+       res.has_srst = has_srst;
+       res.has_sr = has_sr;
+       res.ce_over_srst = ce_over_srst;
+       res.is_fine = is_fine;
+       res.pol_clk = pol_clk;
+       res.pol_ce = pol_ce;
+       res.pol_aload = pol_aload;
+       res.pol_arst = pol_arst;
+       res.pol_srst = pol_srst;
+       res.pol_clr = pol_clr;
+       res.pol_set = pol_set;
+       res.attributes = attributes;
+       for (int i : bits) {
+               res.sig_q.append(sig_q[i]);
+               if (has_clk || has_gclk)
+                       res.sig_d.append(sig_d[i]);
+               if (has_aload)
+                       res.sig_ad.append(sig_ad[i]);
+               if (has_sr) {
+                       res.sig_clr.append(sig_clr[i]);
+                       res.sig_set.append(sig_set[i]);
+               }
+               if (has_arst)
+                       res.val_arst.bits.push_back(val_arst[i]);
+               if (has_srst)
+                       res.val_srst.bits.push_back(val_srst[i]);
+               if (initvals)
+                       res.val_init.bits.push_back(val_init[i]);
+       }
+       res.width = GetSize(res.sig_q);
+       return res;
+}
+
+void FfData::unmap_ce() {
+       if (!has_ce)
+               return;
+       log_assert(has_clk);
+       if (has_srst && ce_over_srst)
+               unmap_srst();
+
+       if (!is_fine) {
+               if (pol_ce)
+                       sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_ce);
+               else
+                       sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_ce);
+       } else {
+               if (pol_ce)
+                       sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_ce);
+               else
+                       sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_ce);
+       }
+       has_ce = false;
+}
+
+void FfData::unmap_srst() {
+       if (!has_srst)
+               return;
+       if (has_ce && !ce_over_srst)
+               unmap_ce();
+
+       if (!is_fine) {
+               if (pol_srst)
+                       sig_d = module->Mux(NEW_ID, sig_d, val_srst, sig_srst);
+               else
+                       sig_d = module->Mux(NEW_ID, val_srst, sig_d, sig_srst);
+       } else {
+               if (pol_srst)
+                       sig_d = module->MuxGate(NEW_ID, sig_d, val_srst[0], sig_srst);
+               else
+                       sig_d = module->MuxGate(NEW_ID, val_srst[0], sig_d, sig_srst);
+       }
+       has_srst = false;
+}
+
+Cell *FfData::emit() {
+       remove();
+       if (!width)
+               return nullptr;
+       if (!has_aload && !has_clk && !has_gclk && !has_sr) {
+               if (has_arst) {
+                       // Convert this case to a D latch.
+                       has_aload = true;
+                       has_arst = false;
+                       sig_ad = val_arst;
+                       sig_aload = sig_arst;
+                       pol_aload = pol_arst;
+               } else {
+                       // No control inputs left.  Turn into a const driver.
+                       module->connect(sig_q, val_init);
+                       return nullptr;
+               }
+       }
+       if (initvals)
+               initvals->set_init(sig_q, val_init);
+       if (!is_fine) {
+               if (has_gclk) {
+                       log_assert(!has_clk);
+                       log_assert(!has_ce);
+                       log_assert(!has_aload);
+                       log_assert(!has_arst);
+                       log_assert(!has_srst);
+                       log_assert(!has_sr);
+                       cell = module->addFf(name, sig_d, sig_q);
+               } else if (!has_aload && !has_clk) {
+                       log_assert(has_sr);
+                       cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
+               } else if (!has_clk) {
+                       log_assert(!has_srst);
+                       if (has_sr)
+                               cell = module->addDlatchsr(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
+                       else if (has_arst)
+                               cell = module->addAdlatch(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst, pol_aload, pol_arst);
+                       else
+                               cell = module->addDlatch(name, sig_aload, sig_ad, sig_q, pol_aload);
+               } else {
+                       if (has_sr) {
+                               if (has_ce)
+                                       cell = module->addDffsre(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
+                               else
+                                       cell = module->addDffsr(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
+                       } else if (has_arst) {
+                               if (has_ce)
+                                       cell = module->addAdffe(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_ce, pol_arst);
+                               else
+                                       cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst);
+                       } else if (has_aload) {
+                               if (has_ce)
+                                       cell = module->addAldffe(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload);
+                               else
+                                       cell = module->addAldff(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload);
+                       } else if (has_srst) {
+                               if (has_ce)
+                                       if (ce_over_srst)
+                                               cell = module->addSdffce(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
+                                       else
+                                               cell = module->addSdffe(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
+                               else
+                                       cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst);
+                       } else {
+                               if (has_ce)
+                                       cell = module->addDffe(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
+                               else
+                                       cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk);
+                       }
+               }
+       } else {
+               if (has_gclk) {
+                       log_assert(!has_clk);
+                       log_assert(!has_ce);
+                       log_assert(!has_aload);
+                       log_assert(!has_arst);
+                       log_assert(!has_srst);
+                       log_assert(!has_sr);
+                       cell = module->addFfGate(name, sig_d, sig_q);
+               } else if (!has_aload && !has_clk) {
+                       log_assert(has_sr);
+                       cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
+               } else if (!has_clk) {
+                       log_assert(!has_srst);
+                       if (has_sr)
+                               cell = module->addDlatchsrGate(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
+                       else if (has_arst)
+                               cell = module->addAdlatchGate(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst.as_bool(), pol_aload, pol_arst);
+                       else
+                               cell = module->addDlatchGate(name, sig_aload, sig_ad, sig_q, pol_aload);
+               } else {
+                       if (has_sr) {
+                               if (has_ce)
+                                       cell = module->addDffsreGate(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
+                               else
+                                       cell = module->addDffsrGate(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
+                       } else if (has_arst) {
+                               if (has_ce)
+                                       cell = module->addAdffeGate(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_ce, pol_arst);
+                               else
+                                       cell = module->addAdffGate(name, sig_clk, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_arst);
+                       } else if (has_aload) {
+                               if (has_ce)
+                                       cell = module->addAldffeGate(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload);
+                               else
+                                       cell = module->addAldffGate(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload);
+                       } else if (has_srst) {
+                               if (has_ce)
+                                       if (ce_over_srst)
+                                               cell = module->addSdffceGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
+                                       else
+                                               cell = module->addSdffeGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
+                               else
+                                       cell = module->addSdffGate(name, sig_clk, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_srst);
+                       } else {
+                               if (has_ce)
+                                       cell = module->addDffeGate(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
+                               else
+                                       cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk);
+                       }
+               }
+       }
+       cell->attributes = attributes;
+       return cell;
+}
+
+void FfData::remove() {
+       if (cell) {
+               remove_init();
+               module->remove(cell);
+               cell = nullptr;
+       }
+}
+
+namespace {
+       State invert(State s) {
+               switch (s) {
+                       case State::S0: return State::S1;
+                       case State::S1: return State::S0;
+                       default: return s;
+               }
+       }
+}
+
+void FfData::flip_bits(const pool<int> &bits) {
+       if (!bits.size())
+               return;
+
+       remove_init();
+
+       Wire *new_q = module->addWire(NEW_ID, width);
+
+       for (auto bit: bits) {
+               if (has_arst)
+                       val_arst[bit] = invert(val_arst[bit]);
+               if (has_srst)
+                       val_srst[bit] = invert(val_srst[bit]);
+               val_init[bit] = invert(val_init[bit]);
+       }
+
+       if (has_sr && cell) {
+               log_warning("Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s].", log_id(module->name), log_id(cell->name), log_id(cell->type));
+       }
+
+       if (is_fine) {
+               if (has_sr) {
+                       bool new_pol_clr = pol_set;
+                       SigSpec new_sig_clr;
+                       if (pol_set) {
+                               if (pol_clr) {
+                                       new_sig_clr = module->AndnotGate(NEW_ID, sig_set, sig_clr);
+                               } else {
+                                       new_sig_clr = module->AndGate(NEW_ID, sig_set, sig_clr);
+                               }
+                       } else {
+                               if (pol_clr) {
+                                       new_sig_clr = module->OrGate(NEW_ID, sig_set, sig_clr);
+                               } else {
+                                       new_sig_clr = module->OrnotGate(NEW_ID, sig_set, sig_clr);
+                               }
+                       }
+                       pol_set = pol_clr;
+                       sig_set = sig_clr;
+                       pol_clr = new_pol_clr;
+                       sig_clr = new_sig_clr;
+               }
+               if (has_clk || has_gclk)
+                       sig_d = module->NotGate(NEW_ID, sig_d);
+               if (has_aload)
+                       sig_ad = module->NotGate(NEW_ID, sig_ad);
+               module->addNotGate(NEW_ID, new_q, sig_q);
+       }
+       else
+       {
+               if (has_sr) {
+                       SigSpec not_clr;
+                       if (!pol_clr) {
+                               not_clr = sig_clr;
+                               sig_clr = module->Not(NEW_ID, sig_clr);
+                               pol_clr = true;
+                       } else {
+                               not_clr = module->Not(NEW_ID, sig_clr);
+                       }
+                       if (!pol_set) {
+                               sig_set = module->Not(NEW_ID, sig_set);
+                               pol_set = true;
+                       }
+
+                       SigSpec masked_set = module->And(NEW_ID, sig_set, not_clr);
+                       for (auto bit: bits) {
+                               sig_set[bit] = sig_clr[bit];
+                               sig_clr[bit] = masked_set[bit];
+                       }
+               }
+
+               Const mask = Const(State::S0, width);
+               for (auto bit: bits)
+                       mask.bits[bit] = State::S1;
+
+               if (has_clk || has_gclk)
+                       sig_d = module->Xor(NEW_ID, sig_d, mask);
+               if (has_aload)
+                       sig_ad = module->Xor(NEW_ID, sig_ad, mask);
+               module->addXor(NEW_ID, new_q, mask, sig_q);
+       }
+
+       sig_q = new_q;
+}
index 7f01b8a368d13a900d20610a4bfdfdca3f99cf75..3125f67c698fb4220542e9aaeace964d4e82b8f9 100644 (file)
@@ -76,7 +76,10 @@ YOSYS_NAMESPACE_BEGIN
 // - empty set [not a cell — will be emitted as a simple direct connection]
 
 struct FfData {
+       Module *module;
        FfInitVals *initvals;
+       Cell *cell;
+       IdString name;
        // The FF output.
        SigSpec sig_q;
        // The sync data input, present if has_clk or has_gclk.
@@ -142,7 +145,7 @@ struct FfData {
        int width;
        dict<IdString, Const> attributes;
 
-       FfData(FfInitVals *initvals = nullptr, Cell *cell = nullptr) : initvals(initvals) {
+       FfData(Module *module = nullptr, FfInitVals *initvals = nullptr, IdString name = IdString()) : module(module), initvals(initvals), cell(nullptr), name(name) {
                width = 0;
                has_clk = false;
                has_gclk = false;
@@ -160,464 +163,37 @@ struct FfData {
                pol_srst = false;
                pol_clr = false;
                pol_set = false;
-
-               if (!cell)
-                       return;
-
-               sig_q = cell->getPort(ID::Q);
-               width = GetSize(sig_q);
-               attributes = cell->attributes;
-
-               if (initvals)
-                       val_init = (*initvals)(sig_q);
-
-               std::string type_str = cell->type.str();
-
-               if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
-                       if (cell->type == ID($ff)) {
-                               has_gclk = true;
-                               sig_d = cell->getPort(ID::D);
-                       } else if (cell->type == ID($sr)) {
-                               // No data input at all.
-                       } else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
-                               has_aload = true;
-                               sig_aload = cell->getPort(ID::EN);
-                               pol_aload = cell->getParam(ID::EN_POLARITY).as_bool();
-                               sig_ad = cell->getPort(ID::D);
-                       } else {
-                               has_clk = true;
-                               sig_clk = cell->getPort(ID::CLK);
-                               pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
-                               sig_d = cell->getPort(ID::D);
-                       }
-                       if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($aldffe), ID($sdffe), ID($sdffce))) {
-                               has_ce = true;
-                               sig_ce = cell->getPort(ID::EN);
-                               pol_ce = cell->getParam(ID::EN_POLARITY).as_bool();
-                       }
-                       if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) {
-                               has_sr = true;
-                               sig_clr = cell->getPort(ID::CLR);
-                               sig_set = cell->getPort(ID::SET);
-                               pol_clr = cell->getParam(ID::CLR_POLARITY).as_bool();
-                               pol_set = cell->getParam(ID::SET_POLARITY).as_bool();
-                       }
-                       if (cell->type.in(ID($aldff), ID($aldffe))) {
-                               has_aload = true;
-                               sig_aload = cell->getPort(ID::ALOAD);
-                               pol_aload = cell->getParam(ID::ALOAD_POLARITY).as_bool();
-                               sig_ad = cell->getPort(ID::AD);
-                       }
-                       if (cell->type.in(ID($adff), ID($adffe), ID($adlatch))) {
-                               has_arst = true;
-                               sig_arst = cell->getPort(ID::ARST);
-                               pol_arst = cell->getParam(ID::ARST_POLARITY).as_bool();
-                               val_arst = cell->getParam(ID::ARST_VALUE);
-                       }
-                       if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
-                               has_srst = true;
-                               sig_srst = cell->getPort(ID::SRST);
-                               pol_srst = cell->getParam(ID::SRST_POLARITY).as_bool();
-                               val_srst = cell->getParam(ID::SRST_VALUE);
-                               ce_over_srst = cell->type == ID($sdffce);
-                       }
-               } else if (cell->type == ID($_FF_)) {
-                       is_fine = true;
-                       has_gclk = true;
-                       sig_d = cell->getPort(ID::D);
-               } else if (type_str.substr(0, 5) == "$_SR_") {
-                       is_fine = true;
-                       has_sr = true;
-                       pol_set = type_str[5] == 'P';
-                       pol_clr = type_str[6] == 'P';
-                       sig_set = cell->getPort(ID::S);
-                       sig_clr = cell->getPort(ID::R);
-               } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
-                       is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_clk = true;
-                       pol_clk = type_str[6] == 'P';
-                       sig_clk = cell->getPort(ID::C);
-               } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
-                       is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_clk = true;
-                       pol_clk = type_str[7] == 'P';
-                       sig_clk = cell->getPort(ID::C);
-                       has_ce = true;
-                       pol_ce = type_str[8] == 'P';
-                       sig_ce = cell->getPort(ID::E);
-               } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
-                       is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_clk = true;
-                       pol_clk = type_str[6] == 'P';
-                       sig_clk = cell->getPort(ID::C);
-                       has_arst = true;
-                       pol_arst = type_str[7] == 'P';
-                       sig_arst = cell->getPort(ID::R);
-                       val_arst = type_str[8] == '1' ? State::S1 : State::S0;
-               } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
-                       is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_clk = true;
-                       pol_clk = type_str[7] == 'P';
-                       sig_clk = cell->getPort(ID::C);
-                       has_arst = true;
-                       pol_arst = type_str[8] == 'P';
-                       sig_arst = cell->getPort(ID::R);
-                       val_arst = type_str[9] == '1' ? State::S1 : State::S0;
-                       has_ce = true;
-                       pol_ce = type_str[10] == 'P';
-                       sig_ce = cell->getPort(ID::E);
-               } else if (type_str.substr(0, 8) == "$_ALDFF_" && type_str.size() == 11) {
-                       is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_clk = true;
-                       pol_clk = type_str[8] == 'P';
-                       sig_clk = cell->getPort(ID::C);
-                       has_aload = true;
-                       pol_aload = type_str[9] == 'P';
-                       sig_aload = cell->getPort(ID::L);
-                       sig_ad = cell->getPort(ID::AD);
-               } else if (type_str.substr(0, 9) == "$_ALDFFE_" && type_str.size() == 13) {
-                       is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_clk = true;
-                       pol_clk = type_str[9] == 'P';
-                       sig_clk = cell->getPort(ID::C);
-                       has_aload = true;
-                       pol_aload = type_str[10] == 'P';
-                       sig_aload = cell->getPort(ID::L);
-                       sig_ad = cell->getPort(ID::AD);
-                       has_ce = true;
-                       pol_ce = type_str[11] == 'P';
-                       sig_ce = cell->getPort(ID::E);
-               } else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
-                       is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_clk = true;
-                       pol_clk = type_str[8] == 'P';
-                       sig_clk = cell->getPort(ID::C);
-                       has_sr = true;
-                       pol_set = type_str[9] == 'P';
-                       pol_clr = type_str[10] == 'P';
-                       sig_set = cell->getPort(ID::S);
-                       sig_clr = cell->getPort(ID::R);
-               } else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
-                       is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_clk = true;
-                       pol_clk = type_str[9] == 'P';
-                       sig_clk = cell->getPort(ID::C);
-                       has_sr = true;
-                       pol_set = type_str[10] == 'P';
-                       pol_clr = type_str[11] == 'P';
-                       sig_set = cell->getPort(ID::S);
-                       sig_clr = cell->getPort(ID::R);
-                       has_ce = true;
-                       pol_ce = type_str[12] == 'P';
-                       sig_ce = cell->getPort(ID::E);
-               } else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
-                       is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_clk = true;
-                       pol_clk = type_str[7] == 'P';
-                       sig_clk = cell->getPort(ID::C);
-                       has_srst = true;
-                       pol_srst = type_str[8] == 'P';
-                       sig_srst = cell->getPort(ID::R);
-                       val_srst = type_str[9] == '1' ? State::S1 : State::S0;
-               } else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
-                       is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_clk = true;
-                       pol_clk = type_str[8] == 'P';
-                       sig_clk = cell->getPort(ID::C);
-                       has_srst = true;
-                       pol_srst = type_str[9] == 'P';
-                       sig_srst = cell->getPort(ID::R);
-                       val_srst = type_str[10] == '1' ? State::S1 : State::S0;
-                       has_ce = true;
-                       pol_ce = type_str[11] == 'P';
-                       sig_ce = cell->getPort(ID::E);
-               } else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
-                       is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_clk = true;
-                       pol_clk = type_str[9] == 'P';
-                       sig_clk = cell->getPort(ID::C);
-                       has_srst = true;
-                       pol_srst = type_str[10] == 'P';
-                       sig_srst = cell->getPort(ID::R);
-                       val_srst = type_str[11] == '1' ? State::S1 : State::S0;
-                       has_ce = true;
-                       pol_ce = type_str[12] == 'P';
-                       sig_ce = cell->getPort(ID::E);
-                       ce_over_srst = true;
-               } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
-                       is_fine = true;
-                       has_aload = true;
-                       sig_ad = cell->getPort(ID::D);
-                       has_aload = true;
-                       pol_aload = type_str[9] == 'P';
-                       sig_aload = cell->getPort(ID::E);
-               } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
-                       is_fine = true;
-                       has_aload = true;
-                       sig_ad = cell->getPort(ID::D);
-                       has_aload = true;
-                       pol_aload = type_str[9] == 'P';
-                       sig_aload = cell->getPort(ID::E);
-                       has_arst = true;
-                       pol_arst = type_str[10] == 'P';
-                       sig_arst = cell->getPort(ID::R);
-                       val_arst = type_str[11] == '1' ? State::S1 : State::S0;
-               } else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
-                       is_fine = true;
-                       has_aload = true;
-                       sig_ad = cell->getPort(ID::D);
-                       has_aload = true;
-                       pol_aload = type_str[11] == 'P';
-                       sig_aload = cell->getPort(ID::E);
-                       has_sr = true;
-                       pol_set = type_str[12] == 'P';
-                       pol_clr = type_str[13] == 'P';
-                       sig_set = cell->getPort(ID::S);
-                       sig_clr = cell->getPort(ID::R);
-               } else {
-                       log_assert(0);
-               }
-               if (has_aload && !has_clk && !has_sr && !has_arst && sig_ad.is_fully_const()) {
-                       // Plain D latches with const D treated specially.
-                       has_aload = false;
-                       has_arst = true;
-                       sig_arst = sig_aload;
-                       pol_arst = pol_aload;
-                       val_arst = sig_ad.as_const();
-               }
        }
 
-       // Returns a FF identical to this one, but only keeping bit indices from the argument.
-       FfData slice(const std::vector<int> &bits) {
-               FfData res(initvals);
-               res.sig_clk = sig_clk;
-               res.sig_ce = sig_ce;
-               res.sig_aload = sig_aload;
-               res.sig_arst = sig_arst;
-               res.sig_srst = sig_srst;
-               res.has_clk = has_clk;
-               res.has_gclk = has_gclk;
-               res.has_ce = has_ce;
-               res.has_aload = has_aload;
-               res.has_arst = has_arst;
-               res.has_srst = has_srst;
-               res.has_sr = has_sr;
-               res.ce_over_srst = ce_over_srst;
-               res.is_fine = is_fine;
-               res.pol_clk = pol_clk;
-               res.pol_ce = pol_ce;
-               res.pol_aload = pol_aload;
-               res.pol_arst = pol_arst;
-               res.pol_srst = pol_srst;
-               res.pol_clr = pol_clr;
-               res.pol_set = pol_set;
-               res.attributes = attributes;
-               for (int i : bits) {
-                       res.sig_q.append(sig_q[i]);
-                       if (has_clk || has_gclk)
-                               res.sig_d.append(sig_d[i]);
-                       if (has_aload)
-                               res.sig_ad.append(sig_ad[i]);
-                       if (has_sr) {
-                               res.sig_clr.append(sig_clr[i]);
-                               res.sig_set.append(sig_set[i]);
-                       }
-                       if (has_arst)
-                               res.val_arst.bits.push_back(val_arst[i]);
-                       if (has_srst)
-                               res.val_srst.bits.push_back(val_srst[i]);
-                       if (initvals)
-                               res.val_init.bits.push_back(val_init[i]);
-               }
-               res.width = GetSize(res.sig_q);
-               return res;
-       }
+       FfData(FfInitVals *initvals, Cell *cell_);
 
-       void unmap_ce(Module *module) {
-               if (!has_ce)
-                       return;
-               log_assert(has_clk);
-               if (has_srst && ce_over_srst)
-                       unmap_srst(module);
+       // Returns a FF identical to this one, but only keeping bit indices from the argument.
+       FfData slice(const std::vector<int> &bits);
 
-               if (!is_fine) {
-                       if (pol_ce)
-                               sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_ce);
-                       else
-                               sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_ce);
-               } else {
-                       if (pol_ce)
-                               sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_ce);
-                       else
-                               sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_ce);
-               }
-               has_ce = false;
-       }
+       void unmap_ce();
 
-       void unmap_srst(Module *module) {
-               if (!has_srst)
-                       return;
-               if (has_ce && !ce_over_srst)
-                       unmap_ce(module);
+       void unmap_srst();
 
-               if (!is_fine) {
-                       if (pol_srst)
-                               sig_d = module->Mux(NEW_ID, sig_d, val_srst, sig_srst);
-                       else
-                               sig_d = module->Mux(NEW_ID, val_srst, sig_d, sig_srst);
-               } else {
-                       if (pol_srst)
-                               sig_d = module->MuxGate(NEW_ID, sig_d, val_srst[0], sig_srst);
-                       else
-                               sig_d = module->MuxGate(NEW_ID, val_srst[0], sig_d, sig_srst);
-               }
-               has_srst = false;
+       void unmap_ce_srst() {
+               unmap_ce();
+               unmap_srst();
        }
 
-       void unmap_ce_srst(Module *module) {
-               unmap_ce(module);
-               unmap_srst(module);
-       }
+       Cell *emit();
 
-       Cell *emit(Module *module, IdString name) {
-               if (!width)
-                       return nullptr;
-               if (!has_aload && !has_clk && !has_gclk && !has_sr) {
-                       if (has_arst) {
-                               // Convert this case to a D latch.
-                               has_aload = true;
-                               has_arst = false;
-                               sig_ad = val_arst;
-                               sig_aload = sig_arst;
-                               pol_aload = pol_arst;
-                       } else {
-                               // No control inputs left.  Turn into a const driver.
-                               if (initvals)
-                                       initvals->remove_init(sig_q);
-                               module->connect(sig_q, val_init);
-                               return nullptr;
-                       }
-               }
+       // Removes init attribute from the Q output, but keeps val_init unchanged.
+       // It will be automatically reattached on emit.  Use this before changing sig_q.
+       void remove_init() {
                if (initvals)
-                       initvals->set_init(sig_q, val_init);
-               Cell *cell;
-               if (!is_fine) {
-                       if (has_gclk) {
-                               log_assert(!has_clk);
-                               log_assert(!has_ce);
-                               log_assert(!has_aload);
-                               log_assert(!has_arst);
-                               log_assert(!has_srst);
-                               log_assert(!has_sr);
-                               cell = module->addFf(name, sig_d, sig_q);
-                       } else if (!has_aload && !has_clk) {
-                               log_assert(has_sr);
-                               cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
-                       } else if (!has_clk) {
-                               log_assert(!has_srst);
-                               if (has_sr)
-                                       cell = module->addDlatchsr(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
-                               else if (has_arst)
-                                       cell = module->addAdlatch(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst, pol_aload, pol_arst);
-                               else
-                                       cell = module->addDlatch(name, sig_aload, sig_ad, sig_q, pol_aload);
-                       } else {
-                               if (has_sr) {
-                                       if (has_ce)
-                                               cell = module->addDffsre(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
-                                       else
-                                               cell = module->addDffsr(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
-                               } else if (has_arst) {
-                                       if (has_ce)
-                                               cell = module->addAdffe(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_ce, pol_arst);
-                                       else
-                                               cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst);
-                               } else if (has_aload) {
-                                       if (has_ce)
-                                               cell = module->addAldffe(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload);
-                                       else
-                                               cell = module->addAldff(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload);
-                               } else if (has_srst) {
-                                       if (has_ce)
-                                               if (ce_over_srst)
-                                                       cell = module->addSdffce(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
-                                               else
-                                                       cell = module->addSdffe(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
-                                       else
-                                               cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst);
-                               } else {
-                                       if (has_ce)
-                                               cell = module->addDffe(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
-                                       else
-                                               cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk);
-                               }
-                       }
-               } else {
-                       if (has_gclk) {
-                               log_assert(!has_clk);
-                               log_assert(!has_ce);
-                               log_assert(!has_aload);
-                               log_assert(!has_arst);
-                               log_assert(!has_srst);
-                               log_assert(!has_sr);
-                               cell = module->addFfGate(name, sig_d, sig_q);
-                       } else if (!has_aload && !has_clk) {
-                               log_assert(has_sr);
-                               cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
-                       } else if (!has_clk) {
-                               log_assert(!has_srst);
-                               if (has_sr)
-                                       cell = module->addDlatchsrGate(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
-                               else if (has_arst)
-                                       cell = module->addAdlatchGate(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst.as_bool(), pol_aload, pol_arst);
-                               else
-                                       cell = module->addDlatchGate(name, sig_aload, sig_ad, sig_q, pol_aload);
-                       } else {
-                               if (has_sr) {
-                                       if (has_ce)
-                                               cell = module->addDffsreGate(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
-                                       else
-                                               cell = module->addDffsrGate(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
-                               } else if (has_arst) {
-                                       if (has_ce)
-                                               cell = module->addAdffeGate(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_ce, pol_arst);
-                                       else
-                                               cell = module->addAdffGate(name, sig_clk, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_arst);
-                               } else if (has_aload) {
-                                       if (has_ce)
-                                               cell = module->addAldffeGate(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload);
-                                       else
-                                               cell = module->addAldffGate(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload);
-                               } else if (has_srst) {
-                                       if (has_ce)
-                                               if (ce_over_srst)
-                                                       cell = module->addSdffceGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
-                                               else
-                                                       cell = module->addSdffeGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
-                                       else
-                                               cell = module->addSdffGate(name, sig_clk, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_srst);
-                               } else {
-                                       if (has_ce)
-                                               cell = module->addDffeGate(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
-                                       else
-                                               cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk);
-                               }
-                       }
-               }
-               cell->attributes = attributes;
-               return cell;
+                       initvals->remove_init(sig_q);
        }
+
+       void remove();
+
+       // Flip the sense of the given bit slices of the FF: insert inverters on data
+       // inputs and output, flip the corresponding init/reset bits, swap clr/set
+       // inputs with proper priority fix.
+       void flip_bits(const pool<int> &bits);
 };
 
 YOSYS_NAMESPACE_END
index 7d62a88cfc534f8629a1e24fb3cebf3aa2e250ee..4ca5bcbb4bbb71cf2a43bf63eb1bb7c1c2826f83 100644 (file)
@@ -29,7 +29,7 @@ bool FfMergeHelper::is_output_unused(RTLIL::SigSpec sig) {
 }
 
 bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits) {
-       ff = FfData();
+       ff = FfData(module, initvals, NEW_ID);
        sigmap->apply(sig);
 
        bool found = false;
index 40659b15b1bc64b6e52f0f6abacefba3890a063b..746f667ea77f6333d3edec14c127a0ef88768718 100644 (file)
@@ -955,7 +955,7 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
                }
 
                IdString name = stringf("$%s$rdreg[%d]", memid.c_str(), idx);
-               FfData ff(initvals);
+               FfData ff(module, initvals, name);
                ff.width = GetSize(port.data);
                ff.has_clk = true;
                ff.sig_clk = port.clk;
@@ -982,7 +982,7 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
                ff.sig_q = port.data;
                ff.val_init = port.init_value;
                port.data = async_d;
-               c = ff.emit(module, name);
+               c = ff.emit();
        }
 
        log("Extracted %s FF from read port %d of %s.%s: %s\n", trans_use_addr ? "addr" : "data",
@@ -1160,7 +1160,7 @@ void Mem::emulate_transparency(int widx, int ridx, FfInitVals *initvals) {
                        // The FF for storing the bypass enable signal must be carefully
                        // constructed to preserve the overall init/reset/enable behavior
                        // of the whole port.
-                       FfData ff(initvals);
+                       FfData ff(module, initvals, NEW_ID);
                        ff.width = 1;
                        ff.sig_q = cond_q;
                        ff.sig_d = cond;
@@ -1189,7 +1189,7 @@ void Mem::emulate_transparency(int widx, int ridx, FfInitVals *initvals) {
                                ff.val_init = State::S0;
                        else
                                ff.val_init = State::Sx;
-                       ff.emit(module, NEW_ID);
+                       ff.emit();
                        // And the final bypass mux.
                        SigSpec cur = rdata_a.extract(pos, epos-pos);
                        SigSpec other = wdata_q.extract(pos + wsub * width, epos-pos);
index b87ecdd9987224854028c4d6ad3f47aeb1918edc..91209d428765fdc532ea583275818604747e101d 100644 (file)
@@ -581,7 +581,7 @@ struct MemoryDffWorker
                // Now we're commited to merge it.
                merger.mark_input_ff(bits);
                // If the address FF has enable and/or sync reset, unmap it.
-               ff.unmap_ce_srst(module);
+               ff.unmap_ce_srst();
                port.clk = ff.sig_clk;
                port.en = State::S1;
                port.addr = ff.sig_d;
index 0e25484b8d3267b5881219f0f3abca9355bdb3d1..38faba15ab5ba9d12a3aad224a2d6d7b1164f53b 100644 (file)
@@ -275,7 +275,7 @@ struct OptDffWorker
                        bool changed = false;
 
                        if (!ff.width) {
-                               module->remove(cell);
+                               ff.remove();
                                did_something = true;
                                continue;
                        }
@@ -316,6 +316,7 @@ struct OptDffWorker
                                                continue;
                                        }
                                        ff = ff.slice(keep_bits);
+                                       ff.cell = cell;
                                        changed = true;
                                }
 
@@ -393,8 +394,7 @@ struct OptDffWorker
                                        // Always-active enable.  Make a comb circuit, nuke the FF/latch.
                                        log("Handling always-active async load on %s (%s) from module %s (changing to combinatorial circuit).\n",
                                                        log_id(cell), log_id(cell->type), log_id(module));
-                                       initvals.remove_init(ff.sig_q);
-                                       module->remove(cell);
+                                       ff.remove();
                                        if (ff.has_sr) {
                                                SigSpec tmp;
                                                if (ff.is_fine) {
@@ -456,8 +456,7 @@ struct OptDffWorker
                                        // Always-active async reset — change to const driver.
                                        log("Handling always-active ARST on %s (%s) from module %s (changing to const driver).\n",
                                                        log_id(cell), log_id(cell->type), log_id(module));
-                                       initvals.remove_init(ff.sig_q);
-                                       module->remove(cell);
+                                       ff.remove();
                                        module->connect(ff.sig_q, ff.val_arst);
                                        did_something = true;
                                        continue;
@@ -660,6 +659,7 @@ struct OptDffWorker
                                        continue;
                                }
                                ff = ff.slice(keep_bits);
+                               ff.cell = cell;
                                changed = true;
                        }
 
@@ -728,7 +728,7 @@ struct OptDffWorker
                                                new_ff.pol_srst = srst.second;
                                                if (new_ff.has_ce)
                                                        new_ff.ce_over_srst = true;
-                                               Cell *new_cell = new_ff.emit(module, NEW_ID);
+                                               Cell *new_cell = new_ff.emit();
                                                if (new_cell)
                                                        dff_cells.push_back(new_cell);
                                                log("Adding SRST signal on %s (%s) from module %s (D = %s, Q = %s, rval = %s).\n",
@@ -741,6 +741,7 @@ struct OptDffWorker
                                                continue;
                                        } else if (GetSize(remaining_indices) != ff.width) {
                                                ff = ff.slice(remaining_indices);
+                                               ff.cell = cell;
                                                changed = true;
                                        }
                                }
@@ -790,7 +791,7 @@ struct OptDffWorker
                                                new_ff.sig_ce = en.first;
                                                new_ff.pol_ce = en.second;
                                                new_ff.ce_over_srst = false;
-                                               Cell *new_cell = new_ff.emit(module, NEW_ID);
+                                               Cell *new_cell = new_ff.emit();
                                                if (new_cell)
                                                        dff_cells.push_back(new_cell);
                                                log("Adding EN signal on %s (%s) from module %s (D = %s, Q = %s).\n",
@@ -803,6 +804,7 @@ struct OptDffWorker
                                                continue;
                                        } else if (GetSize(remaining_indices) != ff.width) {
                                                ff = ff.slice(remaining_indices);
+                                               ff.cell = cell;
                                                changed = true;
                                        }
                                }
@@ -810,9 +812,7 @@ struct OptDffWorker
 
                        if (changed) {
                                // Rebuild the FF.
-                               IdString name = cell->name;
-                               module->remove(cell);
-                               ff.emit(module, name);
+                               ff.emit();
                                did_something = true;
                        }
                }
index f1b93d084727f1c3e15ff9980654893e7a38be48..46c76eba960daeafaede8c09c51e41abca507919 100644 (file)
@@ -78,7 +78,7 @@ struct Async2syncPass : public Pass {
                                if (ff.has_clk)
                                {
                                        if (ff.has_sr) {
-                                               ff.unmap_ce_srst(module);
+                                               ff.unmap_ce_srst();
 
                                                log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
                                                                log_id(module), log_id(cell), log_id(cell->type),
@@ -124,7 +124,7 @@ struct Async2syncPass : public Pass {
                                                ff.sig_q = new_q;
                                                ff.has_sr = false;
                                        } else if (ff.has_aload) {
-                                               ff.unmap_ce_srst(module);
+                                               ff.unmap_ce_srst();
 
                                                log("Replacing %s.%s (%s): ALOAD=%s, AD=%s, D=%s, Q=%s\n",
                                                                log_id(module), log_id(cell), log_id(cell->type),
@@ -157,7 +157,7 @@ struct Async2syncPass : public Pass {
                                                ff.sig_q = new_q;
                                                ff.has_aload = false;
                                        } else if (ff.has_arst) {
-                                               ff.unmap_srst(module);
+                                               ff.unmap_srst();
 
                                                log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
                                                                log_id(module), log_id(cell), log_id(cell->type),
@@ -267,10 +267,7 @@ struct Async2syncPass : public Pass {
                                        ff.has_sr = false;
                                        ff.has_gclk = true;
                                }
-
-                               IdString name = cell->name;
-                               module->remove(cell);
-                               ff.emit(module, name);
+                               ff.emit();
                        }
                }
        }
index d90206b465aaa325c85b12f9fd0590f6d248200d..a292941c8bf9ddd6cbcfbfc73fae32425ad22a7f 100644 (file)
@@ -153,6 +153,23 @@ struct Clk2fflogicPass : public Pass {
                                                continue;
                                        }
 
+                                       if (ff.has_clk) {
+                                               log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n",
+                                                               log_id(module), log_id(cell), log_id(cell->type),
+                                                               log_signal(ff.sig_clk), log_signal(ff.sig_d), log_signal(ff.sig_q));
+                                       } else if (ff.has_aload) {
+                                               log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
+                                                               log_id(module), log_id(cell), log_id(cell->type),
+                                                               log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_q));
+                                       } else {
+                                               // $sr.
+                                               log("Replacing %s.%s (%s): SET=%s, CLR=%s, Q=%s\n",
+                                                               log_id(module), log_id(cell), log_id(cell->type),
+                                                               log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_q));
+                                       }
+
+                                       ff.remove();
+
                                        Wire *past_q = module->addWire(NEW_ID, ff.width);
                                        if (!ff.is_fine) {
                                                module->addFf(NEW_ID, ff.sig_q, past_q);
@@ -163,7 +180,7 @@ struct Clk2fflogicPass : public Pass {
                                                initvals.set_init(past_q, ff.val_init);
 
                                        if (ff.has_clk) {
-                                               ff.unmap_ce_srst(module);
+                                               ff.unmap_ce_srst();
 
                                                Wire *past_clk = module->addWire(NEW_ID);
                                                initvals.set_init(past_clk, ff.pol_clk ? State::S1 : State::S0);
@@ -173,10 +190,6 @@ struct Clk2fflogicPass : public Pass {
                                                else
                                                        module->addFfGate(NEW_ID, ff.sig_clk, past_clk);
 
-                                               log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n",
-                                                               log_id(module), log_id(cell), log_id(cell->type),
-                                                               log_signal(ff.sig_clk), log_signal(ff.sig_d), log_signal(ff.sig_q));
-
                                                SigSpec clock_edge_pattern;
 
                                                if (ff.pol_clk) {
@@ -203,16 +216,6 @@ struct Clk2fflogicPass : public Pass {
                                                else
                                                        qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
                                        } else {
-                                               if (ff.has_aload) {
-                                                       log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
-                                                                       log_id(module), log_id(cell), log_id(cell->type),
-                                                                       log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_q));
-                                               } else {
-                                                       // $sr.
-                                                       log("Replacing %s.%s (%s): SET=%s, CLR=%s, Q=%s\n",
-                                                                       log_id(module), log_id(cell), log_id(cell->type),
-                                                                       log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_q));
-                                               }
                                                qval = past_q;
                                        }
 
@@ -246,10 +249,6 @@ struct Clk2fflogicPass : public Pass {
                                        } else {
                                                module->connect(ff.sig_q, qval);
                                        }
-
-                                       initvals.remove_init(ff.sig_q);
-                                       module->remove(cell);
-                                       continue;
                                }
                        }
                }
index 583185e75bc9e51f8868a89c9f65f3c2844b4e92..7312015f1e53becef533931505086d8537de5072 100644 (file)
@@ -86,19 +86,18 @@ struct DffunmapPass : public Pass {
                                if (ce_only) {
                                        if (!ff.has_ce)
                                                continue;
-                                       ff.unmap_ce(mod);
+                                       ff.unmap_ce();
                                } else if (srst_only) {
                                        if (!ff.has_srst)
                                                continue;
-                                       ff.unmap_srst(mod);
+                                       ff.unmap_srst();
                                } else {
                                        if (!ff.has_ce && !ff.has_srst)
                                                continue;
-                                       ff.unmap_ce_srst(mod);
+                                       ff.unmap_ce_srst();
                                }
 
-                               mod->remove(cell);
-                               ff.emit(mod, name);
+                               ff.emit();
                        }
                }
        }
index 04d7ec87471d9cb8a98efc9e5550fc1727d746b8..68f44cf6d7543865fd2cff2f989909c37dc60bc7 100644 (file)
@@ -368,13 +368,13 @@ void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
        module->connect(RTLIL::SigSig(sig_y, sig_ab));
 }
 
-void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_ff(RTLIL::Module *, RTLIL::Cell *cell)
 {
        FfData ff(nullptr, cell);
        for (int i = 0; i < ff.width; i++) {
                FfData fff = ff.slice({i});
                fff.is_fine = true;
-               fff.emit(module, NEW_ID);
+               fff.emit();
        }
 }
 
index 8fcc47570a56de74d67dea3fc92f1e07a58da47d..cc208c5169c0c5e45d5c56aef7635499fd4d7317 100644 (file)
 USING_YOSYS_NAMESPACE
 PRIVATE_NAMESPACE_BEGIN
 
-State invert(State s) {
-       switch (s) {
-               case State::S0: return State::S1;
-               case State::S1: return State::S0;
-               default: return s;
-       }
-}
-
 struct ZinitPass : public Pass {
        ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { }
        void help() override
@@ -75,45 +67,19 @@ struct ZinitPass : public Pass {
                                        continue;
 
                                FfData ff(&initvals, cell);
-                               if (!ff.width)
-                                       continue;
-
-                               // Supporting those would require a new cell type where S has priority over R.
-                               if (ff.has_sr)
-                                       continue;
-
-                               Wire *new_q = module->addWire(NEW_ID, ff.width);
 
                                log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type),
                                                log_signal(ff.sig_q), log_signal(ff.val_init));
 
-                               IdString name = cell->name;
-                               module->remove(cell);
-                               initvals.remove_init(ff.sig_q);
-
-                               for (int i = 0; i < ff.width; i++)
-                                       if (ff.val_init[i] == State::S1)
-                                       {
-                                               if (ff.has_clk || ff.has_gclk)
-                                                       ff.sig_d[i] = module->NotGate(NEW_ID, ff.sig_d[i]);
-                                               if (ff.has_aload)
-                                                       ff.sig_ad[i] = module->NotGate(NEW_ID, ff.sig_ad[i]);
-                                               if (ff.has_arst)
-                                                       ff.val_arst[i] = invert(ff.val_arst[i]);
-                                               if (ff.has_srst)
-                                                       ff.val_srst[i] = invert(ff.val_srst[i]);
-                                               module->addNotGate(NEW_ID, SigSpec(new_q, i), ff.sig_q[i]);
-                                               ff.val_init[i] = State::S0;
-                                       }
-                                       else
-                                       {
-                                               module->connect(ff.sig_q[i], SigSpec(new_q, i));
-                                               if (all_mode)
-                                                       ff.val_init[i] = State::S0;
-                                       }
-
-                               ff.sig_q = new_q;
-                               ff.emit(module, name);
+                               pool<int> bits;
+                               for (int i = 0; i < ff.width; i++) {
+                                       if (ff.val_init.bits[i] == State::S1)
+                                               bits.insert(i);
+                                       else if (ff.val_init.bits[i] != State::S0 && all_mode)
+                                               ff.val_init.bits[i] = State::S0;
+                               }
+                               ff.flip_bits(bits);
+                               ff.emit();
                        }
                }
        }
index ace646af48a5f83f9c00aa450c17342050e12f3c..3b19196270729b8a37d1cb609f1f2be995f45d1d 100644 (file)
@@ -31,6 +31,7 @@ stat
 select -assert-count 1 t:BUFG
 select -assert-count 6 t:FDRE
 select -assert-count 1 t:LUT1
-select -assert-count 8 t:LUT4
+select -assert-max 1 t:LUT3
+select -assert-max 8 t:LUT4
 select -assert-count 5 t:MUXF5
-select -assert-none t:BUFG t:FDRE t:LUT1 t:LUT4 t:MUXF5 %% t:* %D
+select -assert-none t:BUFG t:FDRE t:LUT1 t:LUT3 t:LUT4 t:MUXF5 %% t:* %D
index 1670573dd50387248b638092c1dc9771fd5ce1a5..bc07f40e6ce1957987282fcd2b41c2d7bc0104cc 100644 (file)
@@ -20,7 +20,8 @@ EOT
 equiv_opt -assert -multiclock zinit
 design -load postopt
 
-select -assert-count 20 t:$_NOT_
+select -assert-count 16 t:$_NOT_
+select -assert-count 4 t:$xor
 select -assert-count 1 w:unused a:init %i
 select -assert-count 1 w:Q a:init=13'bxxxx1xxxxxxxx %i
 select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$_DFF_??1_ %i
@@ -52,7 +53,7 @@ design -load postopt
 
 select -assert-count 0 t:$_NOT_
 select -assert-count 1 w:unused a:init %i
-select -assert-count 1 w:Q a:init=13'bxxxx1xxxxxxxx %i
+select -assert-count 1 w:Q a:init=13'bx00x100000000 %i
 select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$_DFF_??0_ %i
 select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$_DFF_??1_ %i
 
@@ -142,7 +143,7 @@ EOT
 zinit
 
 select -assert-count 0 t:$_NOT_
-select -assert-count 0 w:Q a:init %i
+select -assert-count 1 w:Q a:init=24'b0 %i
 select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$_DFFE_??0P_ %i
 select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$_DFFE_??1P_ %i
 select -assert-count 4 c:dff8 c:dff10 c:dff12 c:dff14 %% t:$_SDFF_??0_ %i