aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/calc.cc60
-rw-r--r--kernel/constids.inc1
-rw-r--r--kernel/ff.h486
-rw-r--r--kernel/ffinit.h141
-rw-r--r--kernel/log.cc10
-rw-r--r--kernel/mem.cc436
-rw-r--r--kernel/mem.h78
-rw-r--r--kernel/rtlil.cc10
-rw-r--r--kernel/rtlil.h2
-rw-r--r--kernel/satgen.cc63
-rw-r--r--kernel/satgen.h12
-rw-r--r--kernel/yosys.cc78
-rw-r--r--kernel/yosys.h3
13 files changed, 1309 insertions, 71 deletions
diff --git a/kernel/calc.cc b/kernel/calc.cc
index ae18809d3..d54ccbc10 100644
--- a/kernel/calc.cc
+++ b/kernel/calc.cc
@@ -275,10 +275,15 @@ RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const
return result;
}
-static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len)
+// Shift `arg1` by `arg2` bits.
+// If `direction` is +1, `arg1` is shifted right by `arg2` bits; if `direction` is -1, `arg1` is shifted left by `arg2` bits.
+// If `signed2` is true, `arg2` is interpreted as a signed integer; a negative `arg2` will cause a shift in the opposite direction.
+// Any required bits outside the bounds of `arg1` are padded with `vacant_bits` unless `sign_ext` is true, in which case any bits outside the left
+// bounds are filled with the leftmost bit of `arg1` (arithmetic shift).
+static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, bool signed2, int direction, int result_len, RTLIL::State vacant_bits = RTLIL::State::S0)
{
int undef_bit_pos = -1;
- BigInteger offset = const2big(arg2, false, undef_bit_pos) * direction;
+ BigInteger offset = const2big(arg2, signed2, undef_bit_pos) * direction;
if (result_len < 0)
result_len = arg1.bits.size();
@@ -290,9 +295,9 @@ static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Co
for (int i = 0; i < result_len; i++) {
BigInteger pos = BigInteger(i) + offset;
if (pos < 0)
- result.bits[i] = RTLIL::State::S0;
+ result.bits[i] = vacant_bits;
else if (pos >= BigInteger(int(arg1.bits.size())))
- result.bits[i] = sign_ext ? arg1.bits.back() : RTLIL::State::S0;
+ result.bits[i] = sign_ext ? arg1.bits.back() : vacant_bits;
else
result.bits[i] = arg1.bits[pos.toInt()];
}
@@ -304,61 +309,36 @@ RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2
{
RTLIL::Const arg1_ext = arg1;
extend_u0(arg1_ext, result_len, signed1);
- return const_shift_worker(arg1_ext, arg2, false, -1, result_len);
+ return const_shift_worker(arg1_ext, arg2, false, false, -1, result_len);
}
RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
extend_u0(arg1_ext, max(result_len, GetSize(arg1)), signed1);
- return const_shift_worker(arg1_ext, arg2, false, +1, result_len);
-}
-
-RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
-{
- if (!signed1)
- return const_shl(arg1, arg2, signed1, signed2, result_len);
- return const_shift_worker(arg1, arg2, true, -1, result_len);
+ return const_shift_worker(arg1_ext, arg2, false, false, +1, result_len);
}
-RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
- if (!signed1)
- return const_shr(arg1, arg2, signed1, signed2, result_len);
- return const_shift_worker(arg1, arg2, true, +1, result_len);
+ return const_shift_worker(arg1, arg2, signed1, false, -1, result_len);
}
-static RTLIL::Const const_shift_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool signed2, int result_len, RTLIL::State other_bits)
+RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
- int undef_bit_pos = -1;
- BigInteger offset = const2big(arg2, signed2, undef_bit_pos);
-
- if (result_len < 0)
- result_len = arg1.bits.size();
-
- RTLIL::Const result(RTLIL::State::Sx, result_len);
- if (undef_bit_pos >= 0)
- return result;
-
- for (int i = 0; i < result_len; i++) {
- BigInteger pos = BigInteger(i) + offset;
- if (pos < 0 || pos >= BigInteger(int(arg1.bits.size())))
- result.bits[i] = other_bits;
- else
- result.bits[i] = arg1.bits[pos.toInt()];
- }
-
- return result;
+ return const_shift_worker(arg1, arg2, signed1, false, +1, result_len);
}
RTLIL::Const RTLIL::const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
- return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::S0);
+ RTLIL::Const arg1_ext = arg1;
+ extend_u0(arg1_ext, max(result_len, GetSize(arg1)), signed1);
+ return const_shift_worker(arg1_ext, arg2, false, signed2, +1, result_len);
}
-RTLIL::Const RTLIL::const_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+RTLIL::Const RTLIL::const_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool signed2, int result_len)
{
- return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::Sx);
+ return const_shift_worker(arg1, arg2, false, signed2, +1, result_len, RTLIL::State::Sx);
}
RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
diff --git a/kernel/constids.inc b/kernel/constids.inc
index 69bc06d2c..3c2ff9beb 100644
--- a/kernel/constids.inc
+++ b/kernel/constids.inc
@@ -172,6 +172,7 @@ X(T)
X(TABLE)
X(techmap_autopurge)
X(_TECHMAP_BITS_CONNMAP_)
+X(_TECHMAP_CELLNAME_)
X(_TECHMAP_CELLTYPE_)
X(techmap_celltype)
X(_TECHMAP_FAIL_)
diff --git a/kernel/ff.h b/kernel/ff.h
new file mode 100644
index 000000000..0aecbaa2a
--- /dev/null
+++ b/kernel/ff.h
@@ -0,0 +1,486 @@
+/*
+ * 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;
+ }
+
+ void unmap_ce(Module *module) {
+ if (!has_en)
+ return;
+ log_assert(has_clk);
+ if (has_srst && ce_over_srst)
+ unmap_srst(module);
+
+ if (!is_fine) {
+ if (pol_en)
+ sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_en);
+ else
+ sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_en);
+ } else {
+ if (pol_en)
+ sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_en);
+ else
+ sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_en);
+ }
+ has_en = false;
+ }
+
+ void unmap_srst(Module *module) {
+ if (!has_srst)
+ return;
+ if (has_en && !ce_over_srst)
+ unmap_ce(module);
+
+ 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(Module *module) {
+ unmap_ce(module);
+ unmap_srst(module);
+ }
+
+ 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
diff --git a/kernel/ffinit.h b/kernel/ffinit.h
new file mode 100644
index 000000000..025b0c862
--- /dev/null
+++ b/kernel/ffinit.h
@@ -0,0 +1,141 @@
+/*
+ * 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 FFINIT_H
+#define FFINIT_H
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct FfInitVals
+{
+ const SigMap *sigmap;
+ RTLIL::Module *module;
+ dict<SigBit, std::pair<State,SigBit>> initbits;
+
+ void set(const SigMap *sigmap_, RTLIL::Module *module)
+ {
+ sigmap = sigmap_;
+ initbits.clear();
+ for (auto wire : module->wires())
+ {
+ if (wire->attributes.count(ID::init) == 0)
+ continue;
+
+ SigSpec wirebits = (*sigmap)(wire);
+ Const initval = wire->attributes.at(ID::init);
+
+ for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)
+ {
+ SigBit bit = wirebits[i];
+ State val = initval[i];
+
+ if (val != State::S0 && val != State::S1 && bit.wire != nullptr)
+ continue;
+
+ if (initbits.count(bit)) {
+ if (initbits.at(bit).first != val)
+ log_error("Conflicting init values for signal %s (%s = %s != %s).\n",
+ log_signal(bit), log_signal(SigBit(wire, i)),
+ log_signal(val), log_signal(initbits.at(bit).first));
+ continue;
+ }
+
+ initbits[bit] = std::make_pair(val,SigBit(wire,i));
+ }
+ }
+ }
+
+ RTLIL::State operator()(RTLIL::SigBit bit) const
+ {
+ auto it = initbits.find((*sigmap)(bit));
+ if (it != initbits.end())
+ return it->second.first;
+ else
+ return State::Sx;
+ }
+
+ RTLIL::Const operator()(const RTLIL::SigSpec &sig) const
+ {
+ RTLIL::Const res;
+ for (auto bit : sig)
+ res.bits.push_back((*this)(bit));
+ return res;
+ }
+
+ void set_init(RTLIL::SigBit bit, RTLIL::State val)
+ {
+ SigBit mbit = (*sigmap)(bit);
+ SigBit abit = bit;
+ auto it = initbits.find(mbit);
+ if (it != initbits.end())
+ abit = it->second.second;
+ else if (val == State::Sx)
+ return;
+ log_assert(abit.wire);
+ initbits[mbit] = std::make_pair(val,abit);
+ auto it2 = abit.wire->attributes.find(ID::init);
+ if (it2 != abit.wire->attributes.end()) {
+ it2->second[abit.offset] = val;
+ if (it2->second.is_fully_undef())
+ abit.wire->attributes.erase(it2);
+ } else if (val != State::Sx) {
+ Const cval(State::Sx, GetSize(abit.wire));
+ cval[abit.offset] = val;
+ abit.wire->attributes[ID::init] = cval;
+ }
+ }
+
+ void set_init(const RTLIL::SigSpec &sig, RTLIL::Const val)
+ {
+ log_assert(GetSize(sig) == GetSize(val));
+ for (int i = 0; i < GetSize(sig); i++)
+ set_init(sig[i], val[i]);
+ }
+
+ void remove_init(RTLIL::SigBit bit)
+ {
+ set_init(bit, State::Sx);
+ }
+
+ void remove_init(const RTLIL::SigSpec &sig)
+ {
+ for (auto bit : sig)
+ remove_init(bit);
+ }
+
+ void clear()
+ {
+ initbits.clear();
+ }
+
+ FfInitVals (const SigMap *sigmap, RTLIL::Module *module)
+ {
+ set(sigmap, module);
+ }
+
+ FfInitVals () {}
+};
+
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/kernel/log.cc b/kernel/log.cc
index 1c1d0182e..c7ae873bc 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -19,7 +19,7 @@
#include "kernel/yosys.h"
#include "libs/sha1/sha1.h"
-#include "backends/ilang/ilang_backend.h"
+#include "backends/rtlil/rtlil_backend.h"
#if !defined(_WIN32) || defined(__MINGW32__)
# include <sys/time.h>
@@ -600,7 +600,7 @@ void log_dump_val_worker(RTLIL::State v) {
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
{
std::stringstream buf;
- ILANG_BACKEND::dump_sigspec(buf, sig, autoint);
+ RTLIL_BACKEND::dump_sigspec(buf, sig, autoint);
if (string_buf.size() < 100) {
string_buf.push_back(buf.str());
@@ -647,21 +647,21 @@ const char *log_id(RTLIL::IdString str)
void log_module(RTLIL::Module *module, std::string indent)
{
std::stringstream buf;
- ILANG_BACKEND::dump_module(buf, indent, module, module->design, false);
+ RTLIL_BACKEND::dump_module(buf, indent, module, module->design, false);
log("%s", buf.str().c_str());
}
void log_cell(RTLIL::Cell *cell, std::string indent)
{
std::stringstream buf;
- ILANG_BACKEND::dump_cell(buf, indent, cell);
+ RTLIL_BACKEND::dump_cell(buf, indent, cell);
log("%s", buf.str().c_str());
}
void log_wire(RTLIL::Wire *wire, std::string indent)
{
std::stringstream buf;
- ILANG_BACKEND::dump_wire(buf, indent, wire);
+ RTLIL_BACKEND::dump_wire(buf, indent, wire);
log("%s", buf.str().c_str());
}
diff --git a/kernel/mem.cc b/kernel/mem.cc
new file mode 100644
index 000000000..0301a913c
--- /dev/null
+++ b/kernel/mem.cc
@@ -0,0 +1,436 @@
+/*
+ * 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/mem.h"
+
+USING_YOSYS_NAMESPACE
+
+void Mem::remove() {
+ if (cell) {
+ module->remove(cell);
+ cell = nullptr;
+ }
+ if (mem) {
+ module->memories.erase(mem->name);
+ delete mem;
+ mem = nullptr;
+ }
+ for (auto &port : rd_ports) {
+ if (port.cell) {
+ module->remove(port.cell);
+ port.cell = nullptr;
+ }
+ }
+ for (auto &port : wr_ports) {
+ if (port.cell) {
+ module->remove(port.cell);
+ port.cell = nullptr;
+ }
+ }
+ for (auto &init : inits) {
+ if (init.cell) {
+ module->remove(init.cell);
+ init.cell = nullptr;
+ }
+ }
+}
+
+void Mem::emit() {
+ if (packed) {
+ if (mem) {
+ module->memories.erase(mem->name);
+ delete mem;
+ mem = nullptr;
+ }
+ if (!cell) {
+ if (memid.empty())
+ memid = NEW_ID;
+ cell = module->addCell(memid, ID($mem));
+ }
+ cell->attributes = attributes;
+ cell->parameters[ID::MEMID] = Const(memid.str());
+ cell->parameters[ID::WIDTH] = Const(width);
+ cell->parameters[ID::OFFSET] = Const(start_offset);
+ cell->parameters[ID::SIZE] = Const(size);
+ cell->parameters[ID::RD_PORTS] = Const(GetSize(rd_ports));
+ cell->parameters[ID::WR_PORTS] = Const(GetSize(wr_ports));
+ Const rd_clk_enable, rd_clk_polarity, rd_transparent;
+ Const wr_clk_enable, wr_clk_polarity;
+ SigSpec rd_clk, rd_en, rd_addr, rd_data;
+ SigSpec wr_clk, wr_en, wr_addr, wr_data;
+ int abits = 0;
+ for (auto &port : rd_ports)
+ abits = std::max(abits, GetSize(port.addr));
+ for (auto &port : wr_ports)
+ abits = std::max(abits, GetSize(port.addr));
+ cell->parameters[ID::ABITS] = Const(abits);
+ for (auto &port : rd_ports) {
+ if (port.cell) {
+ module->remove(port.cell);
+ port.cell = nullptr;
+ }
+ rd_clk_enable.bits.push_back(State(port.clk_enable));
+ rd_clk_polarity.bits.push_back(State(port.clk_polarity));
+ rd_transparent.bits.push_back(State(port.transparent));
+ rd_clk.append(port.clk);
+ log_assert(GetSize(port.clk) == 1);
+ rd_en.append(port.en);
+ log_assert(GetSize(port.en) == 1);
+ SigSpec addr = port.addr;
+ addr.extend_u0(abits, false);
+ rd_addr.append(addr);
+ log_assert(GetSize(addr) == abits);
+ rd_data.append(port.data);
+ log_assert(GetSize(port.data) == width);
+ }
+ if (rd_ports.empty()) {
+ rd_clk_enable = State::S0;
+ rd_clk_polarity = State::S0;
+ rd_transparent = State::S0;
+ }
+ cell->parameters[ID::RD_CLK_ENABLE] = rd_clk_enable;
+ cell->parameters[ID::RD_CLK_POLARITY] = rd_clk_polarity;
+ cell->parameters[ID::RD_TRANSPARENT] = rd_transparent;
+ cell->setPort(ID::RD_CLK, rd_clk);
+ cell->setPort(ID::RD_EN, rd_en);
+ cell->setPort(ID::RD_ADDR, rd_addr);
+ cell->setPort(ID::RD_DATA, rd_data);
+ for (auto &port : wr_ports) {
+ if (port.cell) {
+ module->remove(port.cell);
+ port.cell = nullptr;
+ }
+ wr_clk_enable.bits.push_back(State(port.clk_enable));
+ wr_clk_polarity.bits.push_back(State(port.clk_polarity));
+ wr_clk.append(port.clk);
+ log_assert(GetSize(port.clk) == 1);
+ wr_en.append(port.en);
+ log_assert(GetSize(port.en) == width);
+ SigSpec addr = port.addr;
+ addr.extend_u0(abits, false);
+ wr_addr.append(addr);
+ log_assert(GetSize(addr) == abits);
+ wr_data.append(port.data);
+ log_assert(GetSize(port.data) == width);
+ }
+ if (wr_ports.empty()) {
+ wr_clk_enable = State::S0;
+ wr_clk_polarity = State::S0;
+ }
+ cell->parameters[ID::WR_CLK_ENABLE] = wr_clk_enable;
+ cell->parameters[ID::WR_CLK_POLARITY] = wr_clk_polarity;
+ cell->setPort(ID::WR_CLK, wr_clk);
+ cell->setPort(ID::WR_EN, wr_en);
+ cell->setPort(ID::WR_ADDR, wr_addr);
+ cell->setPort(ID::WR_DATA, wr_data);
+ for (auto &init : inits) {
+ if (init.cell) {
+ module->remove(init.cell);
+ init.cell = nullptr;
+ }
+ }
+ cell->parameters[ID::INIT] = get_init_data();
+ } else {
+ if (cell) {
+ module->remove(cell);
+ cell = nullptr;
+ }
+ if (!mem) {
+ if (memid.empty())
+ memid = NEW_ID;
+ mem = new RTLIL::Memory;
+ mem->name = memid;
+ module->memories[memid] = mem;
+ }
+ mem->width = width;
+ mem->start_offset = start_offset;
+ mem->size = size;
+ for (auto &port : rd_ports) {
+ if (!port.cell)
+ port.cell = module->addCell(NEW_ID, ID($memrd));
+ port.cell->parameters[ID::MEMID] = memid.str();
+ port.cell->parameters[ID::ABITS] = GetSize(port.addr);
+ port.cell->parameters[ID::WIDTH] = width;
+ port.cell->parameters[ID::CLK_ENABLE] = port.clk_enable;
+ port.cell->parameters[ID::CLK_POLARITY] = port.clk_polarity;
+ port.cell->parameters[ID::TRANSPARENT] = port.transparent;
+ port.cell->setPort(ID::CLK, port.clk);
+ port.cell->setPort(ID::EN, port.en);
+ port.cell->setPort(ID::ADDR, port.addr);
+ port.cell->setPort(ID::DATA, port.data);
+ }
+ int idx = 0;
+ for (auto &port : wr_ports) {
+ if (!port.cell)
+ port.cell = module->addCell(NEW_ID, ID($memwr));
+ port.cell->parameters[ID::MEMID] = memid.str();
+ port.cell->parameters[ID::ABITS] = GetSize(port.addr);
+ port.cell->parameters[ID::WIDTH] = width;
+ port.cell->parameters[ID::CLK_ENABLE] = port.clk_enable;
+ port.cell->parameters[ID::CLK_POLARITY] = port.clk_polarity;
+ port.cell->parameters[ID::PRIORITY] = idx++;
+ port.cell->setPort(ID::CLK, port.clk);
+ port.cell->setPort(ID::EN, port.en);
+ port.cell->setPort(ID::ADDR, port.addr);
+ port.cell->setPort(ID::DATA, port.data);
+ }
+ idx = 0;
+ for (auto &init : inits) {
+ if (!init.cell)
+ init.cell = module->addCell(NEW_ID, ID($meminit));
+ init.cell->parameters[ID::MEMID] = memid.str();
+ init.cell->parameters[ID::ABITS] = GetSize(init.addr);
+ init.cell->parameters[ID::WIDTH] = width;
+ init.cell->parameters[ID::WORDS] = GetSize(init.data) / width;
+ init.cell->parameters[ID::PRIORITY] = idx++;
+ init.cell->setPort(ID::ADDR, init.addr);
+ init.cell->setPort(ID::DATA, init.data);
+ }
+ }
+}
+
+void Mem::remove_wr_port(int idx) {
+ if (wr_ports[idx].cell) {
+ module->remove(wr_ports[idx].cell);
+ }
+ wr_ports.erase(wr_ports.begin() + idx);
+}
+
+void Mem::remove_rd_port(int idx) {
+ if (rd_ports[idx].cell) {
+ module->remove(rd_ports[idx].cell);
+ }
+ rd_ports.erase(rd_ports.begin() + idx);
+}
+
+void Mem::clear_inits() {
+ for (auto &init : inits)
+ if (init.cell)
+ module->remove(init.cell);
+ inits.clear();
+}
+
+Const Mem::get_init_data() const {
+ Const init_data(State::Sx, width * size);
+ for (auto &init : inits) {
+ int offset = (init.addr.as_int() - start_offset) * width;
+ for (int i = 0; i < GetSize(init.data); i++)
+ if (0 <= i+offset && i+offset < GetSize(init_data))
+ init_data.bits[i+offset] = init.data.bits[i];
+ }
+ return init_data;
+}
+
+namespace {
+
+ struct MemIndex {
+ dict<IdString, pool<Cell *>> rd_ports;
+ dict<IdString, pool<Cell *>> wr_ports;
+ dict<IdString, pool<Cell *>> inits;
+ MemIndex (Module *module) {
+ for (auto cell: module->cells()) {
+ if (cell->type == ID($memwr))
+ wr_ports[cell->parameters.at(ID::MEMID).decode_string()].insert(cell);
+ else if (cell->type == ID($memrd))
+ rd_ports[cell->parameters.at(ID::MEMID).decode_string()].insert(cell);
+ else if (cell->type == ID($meminit))
+ inits[cell->parameters.at(ID::MEMID).decode_string()].insert(cell);
+ }
+ }
+ };
+
+ Mem mem_from_memory(Module *module, RTLIL::Memory *mem, const MemIndex &index) {
+ Mem res(module, mem->name, mem->width, mem->start_offset, mem->size);
+ res.packed = false;
+ res.mem = mem;
+ res.attributes = mem->attributes;
+ if (index.rd_ports.count(mem->name)) {
+ for (auto cell : index.rd_ports.at(mem->name)) {
+ MemRd mrd;
+ mrd.cell = cell;
+ mrd.attributes = cell->attributes;
+ mrd.clk_enable = cell->parameters.at(ID::CLK_ENABLE).as_bool();
+ mrd.clk_polarity = cell->parameters.at(ID::CLK_POLARITY).as_bool();
+ mrd.transparent = cell->parameters.at(ID::TRANSPARENT).as_bool();
+ mrd.clk = cell->getPort(ID::CLK);
+ mrd.en = cell->getPort(ID::EN);
+ mrd.addr = cell->getPort(ID::ADDR);
+ mrd.data = cell->getPort(ID::DATA);
+ res.rd_ports.push_back(mrd);
+ }
+ }
+ if (index.wr_ports.count(mem->name)) {
+ std::vector<std::pair<int, MemWr>> ports;
+ for (auto cell : index.wr_ports.at(mem->name)) {
+ MemWr mwr;
+ mwr.cell = cell;
+ mwr.attributes = cell->attributes;
+ mwr.clk_enable = cell->parameters.at(ID::CLK_ENABLE).as_bool();
+ mwr.clk_polarity = cell->parameters.at(ID::CLK_POLARITY).as_bool();
+ mwr.clk = cell->getPort(ID::CLK);
+ mwr.en = cell->getPort(ID::EN);
+ mwr.addr = cell->getPort(ID::ADDR);
+ mwr.data = cell->getPort(ID::DATA);
+ ports.push_back(std::make_pair(cell->parameters.at(ID::PRIORITY).as_int(), mwr));
+ }
+ std::sort(ports.begin(), ports.end(), [](const std::pair<int, MemWr> &a, const std::pair<int, MemWr> &b) { return a.first < b.first; });
+ for (auto &it : ports)
+ res.wr_ports.push_back(it.second);
+ }
+ if (index.inits.count(mem->name)) {
+ std::vector<std::pair<int, MemInit>> inits;
+ for (auto cell : index.inits.at(mem->name)) {
+ MemInit init;
+ init.cell = cell;
+ init.attributes = cell->attributes;
+ auto addr = cell->getPort(ID::ADDR);
+ auto data = cell->getPort(ID::DATA);
+ if (!addr.is_fully_const())
+ log_error("Non-constant address %s in memory initialization %s.\n", log_signal(addr), log_id(cell));
+ if (!data.is_fully_const())
+ log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data), log_id(cell));
+ init.addr = addr.as_const();
+ init.data = data.as_const();
+ inits.push_back(std::make_pair(cell->parameters.at(ID::PRIORITY).as_int(), init));
+ }
+ std::sort(inits.begin(), inits.end(), [](const std::pair<int, MemInit> &a, const std::pair<int, MemInit> &b) { return a.first < b.first; });
+ for (auto &it : inits)
+ res.inits.push_back(it.second);
+ }
+ return res;
+ }
+
+ Mem mem_from_cell(Cell *cell) {
+ Mem res(cell->module, cell->parameters.at(ID::MEMID).decode_string(),
+ cell->parameters.at(ID::WIDTH).as_int(),
+ cell->parameters.at(ID::OFFSET).as_int(),
+ cell->parameters.at(ID::SIZE).as_int()
+ );
+ int abits = cell->parameters.at(ID::ABITS).as_int();
+ res.packed = true;
+ res.cell = cell;
+ res.attributes = cell->attributes;
+ Const &init = cell->parameters.at(ID::INIT);
+ if (!init.is_fully_undef()) {
+ int pos = 0;
+ while (pos < res.size) {
+ Const word = init.extract(pos * res.width, res.width, State::Sx);
+ if (word.is_fully_undef()) {
+ pos++;
+ } else {
+ int epos;
+ for (epos = pos; epos < res.size; epos++) {
+ Const eword = init.extract(epos * res.width, res.width, State::Sx);
+ if (eword.is_fully_undef())
+ break;
+ }
+ MemInit minit;
+ minit.addr = res.start_offset + pos;
+ minit.data = init.extract(pos * res.width, (epos - pos) * res.width, State::Sx);
+ res.inits.push_back(minit);
+ pos = epos;
+ }
+ }
+ }
+ for (int i = 0; i < cell->parameters.at(ID::RD_PORTS).as_int(); i++) {
+ MemRd mrd;
+ mrd.clk_enable = cell->parameters.at(ID::RD_CLK_ENABLE).extract(i, 1).as_bool();
+ mrd.clk_polarity = cell->parameters.at(ID::RD_CLK_POLARITY).extract(i, 1).as_bool();
+ mrd.transparent = cell->parameters.at(ID::RD_TRANSPARENT).extract(i, 1).as_bool();
+ mrd.clk = cell->getPort(ID::RD_CLK).extract(i, 1);
+ mrd.en = cell->getPort(ID::RD_EN).extract(i, 1);
+ mrd.addr = cell->getPort(ID::RD_ADDR).extract(i * abits, abits);
+ mrd.data = cell->getPort(ID::RD_DATA).extract(i * res.width, res.width);
+ res.rd_ports.push_back(mrd);
+ }
+ for (int i = 0; i < cell->parameters.at(ID::WR_PORTS).as_int(); i++) {
+ MemWr mwr;
+ mwr.clk_enable = cell->parameters.at(ID::WR_CLK_ENABLE).extract(i, 1).as_bool();
+ mwr.clk_polarity = cell->parameters.at(ID::WR_CLK_POLARITY).extract(i, 1).as_bool();
+ mwr.clk = cell->getPort(ID::WR_CLK).extract(i, 1);
+ mwr.en = cell->getPort(ID::WR_EN).extract(i * res.width, res.width);
+ mwr.addr = cell->getPort(ID::WR_ADDR).extract(i * abits, abits);
+ mwr.data = cell->getPort(ID::WR_DATA).extract(i * res.width, res.width);
+ res.wr_ports.push_back(mwr);
+ }
+ return res;
+ }
+
+}
+
+std::vector<Mem> Mem::get_all_memories(Module *module) {
+ std::vector<Mem> res;
+ MemIndex index(module);
+ for (auto it: module->memories) {
+ res.push_back(mem_from_memory(module, it.second, index));
+ }
+ for (auto cell: module->cells()) {
+ if (cell->type == ID($mem))
+ res.push_back(mem_from_cell(cell));
+ }
+ return res;
+}
+
+std::vector<Mem> Mem::get_selected_memories(Module *module) {
+ std::vector<Mem> res;
+ MemIndex index(module);
+ for (auto it: module->memories) {
+ if (module->design->selected(module, it.second))
+ res.push_back(mem_from_memory(module, it.second, index));
+ }
+ for (auto cell: module->selected_cells()) {
+ if (cell->type == ID($mem))
+ res.push_back(mem_from_cell(cell));
+ }
+ return res;
+}
+
+Cell *Mem::extract_rdff(int idx) {
+ MemRd &port = rd_ports[idx];
+
+ if (!port.clk_enable)
+ return nullptr;
+
+ Cell *c;
+
+ if (port.transparent)
+ {
+ SigSpec sig_q = module->addWire(stringf("%s$rdreg[%d]$q", memid.c_str(), idx), GetSize(port.addr));
+ SigSpec sig_d = port.addr;
+ port.addr = sig_q;
+ c = module->addDffe(stringf("%s$rdreg[%d]", memid.c_str(), idx), port.clk, port.en, sig_d, sig_q, port.clk_polarity, true);
+ }
+ else
+ {
+ SigSpec sig_d = module->addWire(stringf("%s$rdreg[%d]$d", memid.c_str(), idx), width);
+ SigSpec sig_q = port.data;
+ port.data = sig_d;
+ c = module->addDffe(stringf("%s$rdreg[%d]", memid.c_str(), idx), port.clk, port.en, sig_d, sig_q, port.clk_polarity, true);
+ }
+
+ log("Extracted %s FF from read port %d of %s.%s: %s\n", port.transparent ? "addr" : "data",
+ idx, log_id(module), log_id(memid), log_id(c));
+
+ port.en = State::S1;
+ port.clk = State::S0;
+ port.clk_enable = false;
+ port.clk_polarity = true;
+
+ return c;
+}
diff --git a/kernel/mem.h b/kernel/mem.h
new file mode 100644
index 000000000..6d727e71d
--- /dev/null
+++ b/kernel/mem.h
@@ -0,0 +1,78 @@
+/*
+ * 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 MEM_H
+#define MEM_H
+
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct MemRd {
+ dict<IdString, Const> attributes;
+ Cell *cell;
+ bool clk_enable, clk_polarity;
+ bool transparent;
+ SigSpec clk, en, addr, data;
+ MemRd() : cell(nullptr) {}
+};
+
+struct MemWr {
+ dict<IdString, Const> attributes;
+ Cell *cell;
+ bool clk_enable, clk_polarity;
+ SigSpec clk, en, addr, data;
+ MemWr() : cell(nullptr) {}
+};
+
+struct MemInit {
+ dict<IdString, Const> attributes;
+ Cell *cell;
+ Const addr;
+ Const data;
+ MemInit() : cell(nullptr) {}
+};
+
+struct Mem {
+ Module *module;
+ IdString memid;
+ dict<IdString, Const> attributes;
+ bool packed;
+ RTLIL::Memory *mem;
+ Cell *cell;
+ int width, start_offset, size;
+ std::vector<MemInit> inits;
+ std::vector<MemRd> rd_ports;
+ std::vector<MemWr> wr_ports;
+
+ void remove();
+ void emit();
+ void remove_wr_port(int idx);
+ void remove_rd_port(int idx);
+ void clear_inits();
+ Const get_init_data() const;
+ static std::vector<Mem> get_all_memories(Module *module);
+ static std::vector<Mem> get_selected_memories(Module *module);
+ Cell *extract_rdff(int idx);
+ Mem(Module *module, IdString memid, int width, int start_offset, int size) : module(module), memid(memid), packed(false), mem(nullptr), cell(nullptr), width(width), start_offset(start_offset), size(size) {}
+};
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index d7d226942..a9f585616 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -22,7 +22,7 @@
#include "kernel/celltypes.h"
#include "frontends/verilog/verilog_frontend.h"
#include "frontends/verilog/preproc.h"
-#include "backends/ilang/ilang_backend.h"
+#include "backends/rtlil/rtlil_backend.h"
#include <string.h>
#include <algorithm>
@@ -923,7 +923,7 @@ namespace {
void error(int linenr)
{
std::stringstream buf;
- ILANG_BACKEND::dump_cell(buf, " ", cell);
+ RTLIL_BACKEND::dump_cell(buf, " ", cell);
log_error("Found error in internal cell %s%s%s (%s) at %s:%d:\n%s",
module ? module->name.c_str() : "", module ? "." : "",
@@ -1035,7 +1035,11 @@ namespace {
}
if (cell->type.in(ID($shift), ID($shiftx))) {
- param_bool(ID::A_SIGNED);
+ if (cell->type == ID($shiftx)) {
+ param_bool(ID::A_SIGNED, /*expected=*/false);
+ } else {
+ param_bool(ID::A_SIGNED);
+ }
param_bool(ID::B_SIGNED);
port(ID::A, param(ID::A_WIDTH));
port(ID::B, param(ID::B_WIDTH));
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 6c561cb85..a03e8933c 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -375,6 +375,8 @@ namespace RTLIL
bool in(const char *rhs) const { return *this == rhs; }
bool in(const std::string &rhs) const { return *this == rhs; }
bool in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; }
+
+ bool isPublic() { return begins_with("\\"); }
};
namespace ID {
diff --git a/kernel/satgen.cc b/kernel/satgen.cc
index b90b43fb7..2a54e78ec 100644
--- a/kernel/satgen.cc
+++ b/kernel/satgen.cc
@@ -18,6 +18,7 @@
*/
#include "kernel/satgen.h"
+#include "kernel/ff.h"
USING_YOSYS_NAMESPACE
@@ -521,7 +522,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
int extend_bit = ez->CONST_FALSE;
- if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID::A_SIGNED].as_bool())
+ if (cell->parameters[ID::A_SIGNED].as_bool())
extend_bit = a.back();
while (y.size() < a.size())
@@ -554,7 +555,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
std::vector<int> undef_a_shifted;
extend_bit = cell->type == ID($shiftx) ? ez->CONST_TRUE : ez->CONST_FALSE;
- if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID::A_SIGNED].as_bool())
+ if (cell->parameters[ID::A_SIGNED].as_bool())
extend_bit = undef_a.back();
while (undef_y.size() < undef_a.size())
@@ -1075,8 +1076,14 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
return true;
}
- if (timestep > 0 && cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_N_), ID($_DFF_P_)))
+ if (timestep > 0 && RTLIL::builtin_ff_cell_types().count(cell->type))
{
+ FfData ff(nullptr, cell);
+
+ // Latches and FFs with async inputs are not supported — use clk2fflogic or async2sync first.
+ if (!ff.has_d || ff.has_arst || ff.has_sr || (ff.has_en && !ff.has_clk))
+ return false;
+
if (timestep == 1)
{
initial_state.add((*sigmap)(cell->getPort(ID::Q)));
@@ -1084,6 +1091,51 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
else
{
std::vector<int> d = importDefSigSpec(cell->getPort(ID::D), timestep-1);
+ std::vector<int> undef_d;
+ if (model_undef)
+ undef_d = importUndefSigSpec(cell->getPort(ID::D), timestep-1);
+ if (ff.has_srst && ff.has_en && ff.ce_over_srst) {
+ int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0);
+ std::vector<int> rval = importDefSigSpec(ff.val_srst, timestep-1);
+ int undef_srst;
+ std::vector<int> undef_rval;
+ if (model_undef) {
+ undef_srst = importUndefSigSpec(ff.sig_srst, timestep-1).at(0);
+ undef_rval = importUndefSigSpec(ff.val_srst, timestep-1);
+ }
+ if (ff.pol_srst)
+ std::tie(d, undef_d) = mux(srst, undef_srst, d, undef_d, rval, undef_rval);
+ else
+ std::tie(d, undef_d) = mux(srst, undef_srst, rval, undef_rval, d, undef_d);
+ }
+ if (ff.has_en) {
+ int en = importDefSigSpec(ff.sig_en, timestep-1).at(0);
+ std::vector<int> old_q = importDefSigSpec(ff.sig_q, timestep-1);
+ int undef_en;
+ std::vector<int> undef_old_q;
+ if (model_undef) {
+ undef_en = importUndefSigSpec(ff.sig_en, timestep-1).at(0);
+ undef_old_q = importUndefSigSpec(ff.sig_q, timestep-1);
+ }
+ if (ff.pol_en)
+ std::tie(d, undef_d) = mux(en, undef_en, old_q, undef_old_q, d, undef_d);
+ else
+ std::tie(d, undef_d) = mux(en, undef_en, d, undef_d, old_q, undef_old_q);
+ }
+ if (ff.has_srst && !(ff.has_en && ff.ce_over_srst)) {
+ int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0);
+ std::vector<int> rval = importDefSigSpec(ff.val_srst, timestep-1);
+ int undef_srst;
+ std::vector<int> undef_rval;
+ if (model_undef) {
+ undef_srst = importUndefSigSpec(ff.sig_srst, timestep-1).at(0);
+ undef_rval = importUndefSigSpec(ff.val_srst, timestep-1);
+ }
+ if (ff.pol_srst)
+ std::tie(d, undef_d) = mux(srst, undef_srst, d, undef_d, rval, undef_rval);
+ else
+ std::tie(d, undef_d) = mux(srst, undef_srst, rval, undef_rval, d, undef_d);
+ }
std::vector<int> q = importDefSigSpec(cell->getPort(ID::Q), timestep);
std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q;
@@ -1091,7 +1143,6 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
if (model_undef)
{
- std::vector<int> undef_d = importUndefSigSpec(cell->getPort(ID::D), timestep-1);
std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID::Q), timestep);
ez->assume(ez->vec_eq(undef_d, undef_q));
@@ -1182,7 +1233,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
return true;
}
- // Unsupported internal cell types: $pow $lut
- // .. and all sequential cells except $dff and $_DFF_[NP]_
+ // Unsupported internal cell types: $pow $fsm $mem*
+ // .. and all sequential cells with asynchronous inputs
return false;
}
diff --git a/kernel/satgen.h b/kernel/satgen.h
index bd6259ba1..cf2db733f 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -262,6 +262,18 @@ struct SatGen
}
}
+ std::pair<std::vector<int>, std::vector<int>> mux(int s, int undef_s, const std::vector<int> &a, const std::vector<int> &undef_a, const std::vector<int> &b, const std::vector<int> &undef_b) {
+ std::vector<int> res;
+ std::vector<int> undef_res;
+ res = ez->vec_ite(s, b, a);
+ if (model_undef) {
+ std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a, b));
+ std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b));
+ undef_res = ez->vec_ite(undef_s, undef_ab, ez->vec_ite(s, undef_b, undef_a));
+ }
+ return std::make_pair(res, undef_res);
+ }
+
void undefGating(int y, int yy, int undef)
{
ez->assume(ez->OR(undef, ez->IFF(y, yy)));
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 8986c8091..dcaf364e9 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -89,6 +89,12 @@ bool memhasher_active = false;
uint32_t memhasher_rng = 123456;
std::vector<void*> memhasher_store;
+std::string yosys_share_dirname;
+std::string yosys_abc_executable;
+
+void init_share_dirname();
+void init_abc_executable_name();
+
void memhasher_on()
{
#if defined(__linux__) || defined(__FreeBSD__)
@@ -523,6 +529,8 @@ void yosys_setup()
if(already_setup)
return;
already_setup = true;
+ init_share_dirname();
+ init_abc_executable_name();
#define X(_id) RTLIL::ID::_id = "\\" # _id;
#include "kernel/constids.inc"
@@ -825,38 +833,74 @@ std::string proc_self_dirname()
#endif
#if defined(EMSCRIPTEN) || defined(__wasm)
-std::string proc_share_dirname()
+void init_share_dirname()
{
- return "/share/";
+ yosys_share_dirname = "/share/";
}
#else
-std::string proc_share_dirname()
+void init_share_dirname()
{
std::string proc_self_path = proc_self_dirname();
# if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR)
std::string proc_share_path = proc_self_path + "share\\";
- if (check_file_exists(proc_share_path, true))
- return proc_share_path;
+ if (check_file_exists(proc_share_path, true)) {
+ yosys_share_dirname = proc_share_path;
+ return;
+ }
proc_share_path = proc_self_path + "..\\share\\";
- if (check_file_exists(proc_share_path, true))
- return proc_share_path;
+ if (check_file_exists(proc_share_path, true)) {
+ yosys_share_dirname = proc_share_path;
+ return;
+ }
# else
std::string proc_share_path = proc_self_path + "share/";
- if (check_file_exists(proc_share_path, true))
- return proc_share_path;
+ if (check_file_exists(proc_share_path, true)) {
+ yosys_share_dirname = proc_share_path;
+ return;
+ }
proc_share_path = proc_self_path + "../share/" + proc_program_prefix()+ "yosys/";
- if (check_file_exists(proc_share_path, true))
- return proc_share_path;
+ if (check_file_exists(proc_share_path, true)) {
+ yosys_share_dirname = proc_share_path;
+ return;
+ }
# ifdef YOSYS_DATDIR
proc_share_path = YOSYS_DATDIR "/";
- if (check_file_exists(proc_share_path, true))
- return proc_share_path;
+ if (check_file_exists(proc_share_path, true)) {
+ yosys_share_dirname = proc_share_path;
+ return;
+ }
# endif
# endif
- log_error("proc_share_dirname: unable to determine share/ directory!\n");
}
#endif
+void init_abc_executable_name()
+{
+#ifdef ABCEXTERNAL
+ std::string exe_file;
+ if (std::getenv("ABC")) {
+ yosys_abc_executable = std::getenv("ABC");
+ } else {
+ yosys_abc_executable = ABCEXTERNAL;
+ }
+#else
+ yosys_abc_executable = proc_self_dirname() + proc_program_prefix()+ "yosys-abc";
+#endif
+#ifdef _WIN32
+#ifndef ABCEXTERNAL
+ if (!check_file_exists(yosys_abc_executable + ".exe") && check_file_exists(proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc.exe"))
+ yosys_abc_executable = proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc";
+#endif
+#endif
+}
+
+std::string proc_share_dirname()
+{
+ if (yosys_share_dirname.empty())
+ log_error("init_share_dirname: unable to determine share/ directory!\n");
+ return yosys_share_dirname;
+}
+
std::string proc_program_prefix()
{
std::string program_prefix;
@@ -930,7 +974,7 @@ void run_frontend(std::string filename, std::string command, std::string *backen
else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".json") == 0)
command = "json";
else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".il") == 0)
- command = "ilang";
+ command = "rtlil";
else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".ys") == 0)
command = "script";
else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".tcl") == 0)
@@ -1053,7 +1097,7 @@ void run_backend(std::string filename, std::string command, RTLIL::Design *desig
else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".sv") == 0)
command = "verilog -sv";
else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0)
- command = "ilang";
+ command = "rtlil";
else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".cc") == 0)
command = "cxxrtl";
else if (filename.size() > 4 && filename.compare(filename.size()-4, std::string::npos, ".aig") == 0)
@@ -1065,7 +1109,7 @@ void run_backend(std::string filename, std::string command, RTLIL::Design *desig
else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".json") == 0)
command = "json";
else if (filename == "-")
- command = "ilang";
+ command = "rtlil";
else if (filename.empty())
return;
else
diff --git a/kernel/yosys.h b/kernel/yosys.h
index f1646d6bc..ab6eb5f8c 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -366,6 +366,9 @@ extern std::map<std::string, void*> loaded_python_plugins;
extern std::map<std::string, std::string> loaded_plugin_aliases;
void load_plugin(std::string filename, std::vector<std::string> aliases);
+extern std::string yosys_share_dirname;
+extern std::string yosys_abc_executable;
+
YOSYS_NAMESPACE_END
#endif