Add utility module for representing flip-flops.
authorMarcelina Kościelnicka <mwk@0x04.net>
Sun, 19 Jul 2020 01:51:05 +0000 (03:51 +0200)
committerMarcelina Kościelnicka <mwk@0x04.net>
Thu, 23 Jul 2020 21:39:46 +0000 (23:39 +0200)
Makefile
kernel/ff.h [new file with mode: 0644]

index 90f8fee05d1dc1637397485e23f72a2d433ffb33..d6b421920dd590558ef2f71182345b7f86ca8e05 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -585,6 +585,7 @@ $(eval $(call add_include_file,kernel/modtools.h))
 $(eval $(call add_include_file,kernel/macc.h))
 $(eval $(call add_include_file,kernel/utils.h))
 $(eval $(call add_include_file,kernel/satgen.h))
+$(eval $(call add_include_file,kernel/ff.h))
 $(eval $(call add_include_file,kernel/ffinit.h))
 $(eval $(call add_include_file,libs/ezsat/ezsat.h))
 $(eval $(call add_include_file,libs/ezsat/ezminisat.h))
diff --git a/kernel/ff.h b/kernel/ff.h
new file mode 100644 (file)
index 0000000..8dc83eb
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ *  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.
+ *
+ */
+
+#ifndef FF_H
+#define FF_H
+
+#include "kernel/yosys.h"
+#include "kernel/ffinit.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct FfData {
+       FfInitVals *initvals;
+       SigSpec sig_q;
+       SigSpec sig_d;
+       SigSpec sig_clk;
+       SigSpec sig_en;
+       SigSpec sig_arst;
+       SigSpec sig_srst;
+       SigSpec sig_clr;
+       SigSpec sig_set;
+       bool has_d;
+       bool has_clk;
+       bool has_en;
+       bool has_srst;
+       bool has_arst;
+       bool has_sr;
+       bool ce_over_srst;
+       bool is_fine;
+       bool pol_clk;
+       bool pol_en;
+       bool pol_arst;
+       bool pol_srst;
+       bool pol_clr;
+       bool pol_set;
+       Const val_arst;
+       Const val_srst;
+       Const val_init;
+       Const val_d;
+       bool d_is_const;
+       int width;
+       dict<IdString, Const> attributes;
+
+       FfData(FfInitVals *initvals, Cell *cell = nullptr) : initvals(initvals) {
+               width = 0;
+               has_d = true;
+               has_clk = false;
+               has_en = false;
+               has_srst = false;
+               has_arst = false;
+               has_sr = false;
+               ce_over_srst = false;
+               is_fine = false;
+               pol_clk = false;
+               pol_en = false;
+               pol_arst = false;
+               pol_srst = false;
+               pol_clr = false;
+               pol_set = false;
+               d_is_const = 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($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
+                       if (cell->type == ID($sr)) {
+                               has_d = false;
+                       } else {
+                               sig_d = cell->getPort(ID::D);
+                       }
+                       if (!cell->type.in(ID($ff), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
+                               has_clk = true;
+                               sig_clk = cell->getPort(ID::CLK);
+                               pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
+                       }
+                       if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr))) {
+                               has_en = true;
+                               sig_en = cell->getPort(ID::EN);
+                               pol_en = 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($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;
+                       sig_d = cell->getPort(ID::D);
+               } else if (type_str.substr(0, 5) == "$_SR_") {
+                       is_fine = true;
+                       has_d = false;
+                       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_en = true;
+                       pol_en = type_str[8] == 'P';
+                       sig_en = 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_en = true;
+                       pol_en = type_str[10] == 'P';
+                       sig_en = 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_en = true;
+                       pol_en = type_str[12] == 'P';
+                       sig_en = 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_en = true;
+                       pol_en = type_str[11] == 'P';
+                       sig_en = 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_en = true;
+                       pol_en = type_str[12] == 'P';
+                       sig_en = cell->getPort(ID::E);
+                       ce_over_srst = true;
+               } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
+                       is_fine = true;
+                       sig_d = cell->getPort(ID::D);
+                       has_en = true;
+                       pol_en = type_str[9] == 'P';
+                       sig_en = cell->getPort(ID::E);
+               } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
+                       is_fine = true;
+                       sig_d = cell->getPort(ID::D);
+                       has_en = true;
+                       pol_en = type_str[9] == 'P';
+                       sig_en = 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;
+                       sig_d = cell->getPort(ID::D);
+                       has_en = true;
+                       pol_en = type_str[11] == 'P';
+                       sig_en = 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_d && sig_d.is_fully_const()) {
+                       d_is_const = true;
+                       val_d = sig_d.as_const();
+                       if (has_en && !has_clk && !has_sr && !has_arst) {
+                               // Plain D latches with const D treated specially.
+                               has_en = has_d = false;
+                               has_arst = true;
+                               sig_arst = sig_en;
+                               pol_arst = pol_en;
+                               val_arst = val_d;
+                       }
+               }
+       }
+
+       // 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_en = sig_en;
+               res.sig_arst = sig_arst;
+               res.sig_srst = sig_srst;
+               res.has_d = has_d;
+               res.has_clk = has_clk;
+               res.has_en = has_en;
+               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_en = pol_en;
+               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_d)
+                               res.sig_d.append(sig_d[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]);
+                       res.val_init.bits.push_back(val_init[i]);
+               }
+               res.width = GetSize(res.sig_q);
+               // Slicing bits out may cause D to become const.
+               if (has_d && res.sig_d.is_fully_const()) {
+                       res.d_is_const = true;
+                       res.val_d = res.sig_d.as_const();
+               }
+               return res;
+       }
+
+       Cell *emit(Module *module, IdString name) {
+               if (!width)
+                       return nullptr;
+               if (!has_d && !has_sr) {
+                       if (has_arst) {
+                               // Convert this case to a D latch.
+                               has_d = has_en = true;
+                               has_arst = false;
+                               sig_d = val_arst;
+                               sig_en = sig_arst;
+                               pol_en = pol_arst;
+                       } else {
+                               // No control inputs left.  Turn into a const driver.
+                               initvals->remove_init(sig_q);
+                               module->connect(sig_q, val_init);
+                               return nullptr;
+                       }
+               }
+               initvals->set_init(sig_q, val_init);
+               Cell *cell;
+               if (!is_fine) {
+                       if (!has_d) {
+                               log_assert(has_sr);
+                               cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
+                       } else if (!has_clk && !has_en) {
+                               log_assert(!has_arst);
+                               log_assert(!has_srst);
+                               log_assert(!has_sr);
+                               cell = module->addFf(name, sig_d, sig_q);
+                       } else if (!has_clk) {
+                               log_assert(!has_srst);
+                               if (has_sr)
+                                       cell = module->addDlatchsr(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
+                               else if (has_arst)
+                                       cell = module->addAdlatch(name, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_en, pol_arst);
+                               else
+                                       cell = module->addDlatch(name, sig_en, sig_d, sig_q, pol_en);
+                       } else {
+                               if (has_sr) {
+                                       if (has_en)
+                                               cell = module->addDffsre(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, 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_en)
+                                               cell = module->addAdffe(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_en, pol_arst);
+                                       else
+                                               cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst);
+                               } else if (has_srst) {
+                                       if (has_en)
+                                               if (ce_over_srst)
+                                                       cell = module->addSdffce(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
+                                               else
+                                                       cell = module->addSdffe(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
+                                       else
+                                               cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst);
+                               } else {
+                                       if (has_en)
+                                               cell = module->addDffe(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
+                                       else
+                                               cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk);
+                               }
+                       }
+               } else {
+                       if (!has_d) {
+                               log_assert(has_sr);
+                               cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
+                       } else if (!has_clk && !has_en) {
+                               log_assert(!has_arst);
+                               log_assert(!has_srst);
+                               log_assert(!has_sr);
+                               cell = module->addFfGate(name, sig_d, sig_q);
+                       } else if (!has_clk) {
+                               log_assert(!has_srst);
+                               if (has_sr)
+                                       cell = module->addDlatchsrGate(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
+                               else if (has_arst)
+                                       cell = module->addAdlatchGate(name, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_en, pol_arst);
+                               else
+                                       cell = module->addDlatchGate(name, sig_en, sig_d, sig_q, pol_en);
+                       } else {
+                               if (has_sr) {
+                                       if (has_en)
+                                               cell = module->addDffsreGate(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, 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_en)
+                                               cell = module->addAdffeGate(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_en, 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_srst) {
+                                       if (has_en)
+                                               if (ce_over_srst)
+                                                       cell = module->addSdffceGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, pol_srst);
+                                               else
+                                                       cell = module->addSdffeGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, 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_en)
+                                               cell = module->addDffeGate(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
+                                       else
+                                               cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk);
+                               }
+                       }
+               }
+               cell->attributes = attributes;
+               return cell;
+       }
+};
+
+YOSYS_NAMESPACE_END
+
+#endif