aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG2
-rw-r--r--README.md7
-rw-r--r--passes/pmgen/Makefile.inc6
-rw-r--r--passes/pmgen/xilinx_srl.cc237
-rw-r--r--passes/pmgen/xilinx_srl.pmg211
-rw-r--r--passes/sat/sat.cc2
-rw-r--r--passes/techmap/shregmap.cc179
-rw-r--r--techlibs/ecp5/cells_sim.v15
-rw-r--r--techlibs/ice40/cells_sim.v6
-rw-r--r--techlibs/xilinx/cells_sim.v24
-rw-r--r--techlibs/xilinx/synth_xilinx.cc28
-rw-r--r--tests/sat/initval.v4
-rw-r--r--tests/sat/initval.ys2
-rw-r--r--tests/various/shregmap.ys33
14 files changed, 524 insertions, 232 deletions
diff --git a/CHANGELOG b/CHANGELOG
index dd94c76ed..b4b3005d4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -28,6 +28,8 @@ Yosys 0.9 .. Yosys 0.9-dev
- Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping
- Removed "ice40_unlut"
- Improvements in pmgen: slices, choices, define, generate
+ - Added "xilinx_srl" for Xilinx shift register extraction
+ - Removed "shregmap -tech xilinx"
Yosys 0.8 .. Yosys 0.8-dev
--------------------------
diff --git a/README.md b/README.md
index a31bd6c37..606c4942e 100644
--- a/README.md
+++ b/README.md
@@ -69,11 +69,14 @@ prerequisites for building yosys:
graphviz xdot pkg-config python3 libboost-system-dev \
libboost-python-dev libboost-filesystem-dev zlib1g-dev
-Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies:
+Similarily, on Mac OS X Homebrew can be used to install dependencies:
$ brew tap Homebrew/bundle && brew bundle
+
+or MacPorts:
+
$ sudo port install bison flex readline gawk libffi \
- git graphviz pkgconfig python36 boost zlib
+ git graphviz pkgconfig python36 boost zlib tcl
On FreeBSD use the following command to install all prerequisites:
diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc
index 8e0cbdca8..e73a7b1c9 100644
--- a/passes/pmgen/Makefile.inc
+++ b/passes/pmgen/Makefile.inc
@@ -30,3 +30,9 @@ PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^)
+
+# --------------------------------------
+
+OBJS += passes/pmgen/xilinx_srl.o
+passes/pmgen/xilinx_srl.o: passes/pmgen/xilinx_srl_pm.h
+$(eval $(call add_extra_objs,passes/pmgen/xilinx_srl_pm.h))
diff --git a/passes/pmgen/xilinx_srl.cc b/passes/pmgen/xilinx_srl.cc
new file mode 100644
index 000000000..22fb93e18
--- /dev/null
+++ b/passes/pmgen/xilinx_srl.cc
@@ -0,0 +1,237 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * (C) 2019 Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+// for peepopt_pm
+bool did_something;
+
+#include "passes/pmgen/xilinx_srl_pm.h"
+#include "passes/pmgen/ice40_dsp_pm.h"
+#include "passes/pmgen/peepopt_pm.h"
+
+void run_fixed(xilinx_srl_pm &pm)
+{
+ auto &st = pm.st_fixed;
+ auto &ud = pm.ud_fixed;
+ auto param_def = [&ud](Cell *cell, IdString param) {
+ auto def = ud.default_params.at(std::make_pair(cell->type,param));
+ return cell->parameters.at(param, def);
+ };
+
+ log("Found fixed chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type));
+
+ auto last_cell = ud.longest_chain.back();
+
+ SigSpec initval;
+ for (auto cell : ud.longest_chain) {
+ log_debug(" %s\n", log_id(cell));
+ if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) {
+ SigBit Q = cell->getPort(ID(Q));
+ log_assert(Q.wire);
+ auto it = Q.wire->attributes.find(ID(init));
+ if (it != Q.wire->attributes.end()) {
+ initval.append(it->second[Q.offset]);
+ }
+ else
+ initval.append(State::Sx);
+ }
+ else if (cell->type.in(ID(FDRE), ID(FDRE_1)))
+ initval.append(param_def(cell, ID(INIT)));
+ else
+ log_abort();
+ if (cell != last_cell)
+ pm.autoremove(cell);
+ }
+
+ Cell *c = last_cell;
+ SigBit Q = st.first->getPort(ID(Q));
+ c->setPort(ID(Q), Q);
+
+ if (c->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID(FDRE), ID(FDRE_1))) {
+ c->parameters.clear();
+ c->setParam(ID(DEPTH), GetSize(ud.longest_chain));
+ c->setParam(ID(INIT), initval.as_const());
+ if (c->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
+ c->setParam(ID(CLKPOL), 1);
+ else if (c->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1)))
+ c->setParam(ID(CLKPOL), 0);
+ else if (c->type.in(ID(FDRE)))
+ c->setParam(ID(CLKPOL), param_def(c, ID(IS_C_INVERTED)).as_bool() ? 0 : 1);
+ else
+ log_abort();
+ if (c->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
+ c->setParam(ID(ENPOL), 1);
+ else if (c->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
+ c->setParam(ID(ENPOL), 0);
+ else
+ c->setParam(ID(ENPOL), 2);
+ if (c->type.in(ID($_DFF_N_), ID($_DFF_P_)))
+ c->setPort(ID(E), State::S1);
+ c->setPort(ID(L), GetSize(ud.longest_chain)-1);
+ c->type = ID($__XILINX_SHREG_);
+ }
+ else
+ log_abort();
+
+ log(" -> %s (%s)\n", log_id(c), log_id(c->type));
+}
+
+void run_variable(xilinx_srl_pm &pm)
+{
+ auto &st = pm.st_variable;
+ auto &ud = pm.ud_variable;
+
+ log("Found variable chain of length %d (%s):\n", GetSize(ud.chain), log_id(st.first->type));
+
+ auto last_cell = ud.chain.back();
+
+ SigSpec initval;
+ for (auto cell : ud.chain) {
+ log_debug(" %s\n", log_id(cell));
+ if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) {
+ SigBit Q = cell->getPort(ID(Q));
+ log_assert(Q.wire);
+ auto it = Q.wire->attributes.find(ID(init));
+ if (it != Q.wire->attributes.end()) {
+ initval.append(it->second[Q.offset]);
+ }
+ else
+ initval.append(State::Sx);
+ }
+ else
+ log_abort();
+ if (cell != last_cell)
+ pm.autoremove(cell);
+ }
+ pm.autoremove(st.shiftx);
+
+ Cell *c = last_cell;
+ SigBit Q = st.first->getPort(ID(Q));
+ c->setPort(ID(Q), Q);
+
+ if (c->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) {
+ c->parameters.clear();
+ c->setParam(ID(DEPTH), GetSize(ud.chain));
+ c->setParam(ID(INIT), initval.as_const());
+ if (c->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
+ c->setParam(ID(CLKPOL), 1);
+ else if (c->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1)))
+ c->setParam(ID(CLKPOL), 0);
+ else
+ log_abort();
+ if (c->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
+ c->setParam(ID(ENPOL), 1);
+ else if (c->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
+ c->setParam(ID(ENPOL), 0);
+ else
+ c->setParam(ID(ENPOL), 2);
+ if (c->type.in(ID($_DFF_N_), ID($_DFF_P_)))
+ c->setPort(ID(E), State::S1);
+ c->setPort(ID(L), st.shiftx->getPort(ID(B)));
+ c->setPort(ID(Q), st.shiftx->getPort(ID(Y)));
+ c->type = ID($__XILINX_SHREG_);
+ }
+ else
+ log_abort();
+
+ log(" -> %s (%s)\n", log_id(c), log_id(c->type));
+
+}
+
+struct XilinxSrlPass : public Pass {
+ XilinxSrlPass() : Pass("xilinx_srl", "Xilinx shift register extraction") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" xilinx_srl [options] [selection]\n");
+ log("\n");
+ log("This pass converts chains of built-in flops ($_DFF_[NP]_, $_DFFE_*) as well as\n");
+ log("Xilinx flops (FDRE, FDRE_1) into a $__XILINX_SHREG cell. Chains must be of the\n");
+ log("same type, clock, clock polarity, enable, enable polarity (when relevant).\n");
+ log("Flops with resets cannot be mapped to Xilinx devices and will not be inferred.");
+ log("\n");
+ log(" -minlen N\n");
+ log(" min length of shift register (default = 3)\n");
+ log("\n");
+ log(" -fixed\n");
+ log(" infer fixed-length shift registers.\n");
+ log("\n");
+ log(" -variable\n");
+ log(" infer variable-length shift registers (i.e. fixed-length shifts where\n");
+ log(" each element also fans-out to a $shiftx cell.\n");
+ log("\n");
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing XILINX_SRL pass (Xilinx shift register extraction).\n");
+
+ bool fixed = false;
+ bool variable = false;
+ int minlen = 3;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-minlen" && argidx+1 < args.size()) {
+ minlen = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-fixed") {
+ fixed = true;
+ continue;
+ }
+ if (args[argidx] == "-variable") {
+ variable = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!fixed && !variable)
+ log_cmd_error("'-fixed' and/or '-variable' must be specified.\n");
+
+ for (auto module : design->selected_modules()) {
+ auto pm = xilinx_srl_pm(module, module->selected_cells());
+ pm.ud_fixed.minlen = minlen;
+ pm.ud_variable.minlen = minlen;
+
+ if (fixed) {
+ // TODO: How to get these automatically?
+ pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(INIT))] = State::S0;
+ pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(IS_C_INVERTED))] = State::S0;
+ pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(IS_D_INVERTED))] = State::S0;
+ pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(IS_R_INVERTED))] = State::S0;
+ pm.run_fixed(run_fixed);
+ }
+ if (variable)
+ pm.run_variable(run_variable);
+ }
+ }
+} XilinxSrlPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/pmgen/xilinx_srl.pmg b/passes/pmgen/xilinx_srl.pmg
new file mode 100644
index 000000000..0cc551e92
--- /dev/null
+++ b/passes/pmgen/xilinx_srl.pmg
@@ -0,0 +1,211 @@
+pattern fixed
+
+udata <vector<Cell*>> chain longest_chain
+udata <pool<Cell*>> non_first_cells
+udata <int> minlen
+udata <dict<std::pair<IdString,IdString>,Const>> default_params
+
+code
+ non_first_cells.clear();
+ subpattern(setup);
+endcode
+
+match first
+ select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
+ select !first->has_keep_attr()
+ filter !non_first_cells.count(first)
+//generate
+// SigSpec A = module->addWire(NEW_ID);
+// SigSpec B = module->addWire(NEW_ID);
+// SigSpec Y = module->addWire(NEW_ID);
+// switch (rng(3))
+// {
+// case 0:
+// module->addAndGate(NEW_ID, A, B, Y);
+// break;
+// case 1:
+// module->addOrGate(NEW_ID, A, B, Y);
+// break;
+// case 2:
+// module->addXorGate(NEW_ID, A, B, Y);
+// break;
+// }
+endmatch
+
+code
+ longest_chain.clear();
+ chain.push_back(first);
+ subpattern(tail);
+finally
+ chain.pop_back();
+ log_assert(chain.empty());
+ if (GetSize(longest_chain) >= minlen)
+ accept;
+endcode
+
+// ------------------------------------------------------------------
+
+subpattern setup
+
+match first
+ select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
+ select !first->has_keep_attr()
+endmatch
+
+code
+ if (first->type.in(\FDRE, \FDRE_1)) {
+ SigBit R = port(first, \R);
+ if (first->type == \FDRE) {
+ auto inverted = first->parameters.at(\IS_R_INVERTED, default_params.at(std::make_pair(first->type,\IS_R_INVERTED))).as_bool();
+ if (!inverted && R != State::S0)
+ reject;
+ if (inverted && R != State::S1)
+ reject;
+ }
+ else if (first->type == \FDRE_1) {
+ if (R == State::S0)
+ reject;
+ }
+ else log_abort();
+ }
+endcode
+
+match next
+ select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
+ select !next->has_keep_attr()
+ select !port(next, \D)[0].wire->get_bool_attribute(\keep)
+ select nusers(port(next, \Q)) == 2
+ index <IdString> next->type === first->type
+ index <SigBit> port(next, \Q) === port(first, \D)
+endmatch
+
+code
+ if (next->type.in(\FDRE, \FDRE_1)) {
+ for (auto p : { \R })
+ if (port(next, p) != port(first, p))
+ reject;
+
+ if (next->type == \FDRE) {
+ for (auto p : { \IS_C_INVERTED, \IS_D_INVERTED, \IS_R_INVERTED }) {
+ auto n = next->parameters.at(p, default_params.at(std::make_pair(next->type,p)));
+ auto f = first->parameters.at(p, default_params.at(std::make_pair(first->type,p)));
+ if (n != f)
+ reject;
+ }
+ }
+ }
+ non_first_cells.insert(next);
+endcode
+
+// ------------------------------------------------------------------
+
+subpattern tail
+arg first
+
+match next
+ semioptional
+ select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
+ select !next->has_keep_attr()
+ select !port(next, \D)[0].wire->get_bool_attribute(\keep)
+ select nusers(port(next, \Q)) == 2
+ index <IdString> next->type === chain.back()->type
+ index <SigBit> port(next, \Q) === port(chain.back(), \D)
+//generate 10
+// SigSpec A = module->addWire(NEW_ID);
+// SigSpec B = module->addWire(NEW_ID);
+// SigSpec Y = port(chain.back().first, chain.back().second);
+// Cell *c = module->addAndGate(NEW_ID, A, B, Y);
+// c->type = chain.back().first->type;
+endmatch
+
+code
+ if (next) {
+ if (next->type.in(\FDRE, \FDRE_1)) {
+ for (auto p : { \R })
+ if (port(next, p) != port(first, p))
+ reject;
+
+ if (next->type == \FDRE) {
+ for (auto p : { \IS_C_INVERTED, \IS_D_INVERTED, \IS_R_INVERTED }) {
+ auto n = next->parameters.at(p, default_params.at(std::make_pair(next->type,p)));
+ auto f = first->parameters.at(p, default_params.at(std::make_pair(first->type,p)));
+ if (n != f)
+ reject;
+ }
+ }
+ }
+
+ chain.push_back(next);
+ subpattern(tail);
+ } else {
+ if (GetSize(chain) > GetSize(longest_chain))
+ longest_chain = chain;
+ }
+finally
+ if (next)
+ chain.pop_back();
+endcode
+
+// -----------
+
+pattern variable
+
+state <int> shiftx_width
+udata <int> minlen
+udata <vector<Cell*>> chain
+
+match shiftx
+ select shiftx->type.in($shiftx)
+ select !shiftx->has_keep_attr()
+ select param(shiftx, \Y_WIDTH).as_int() == 1
+ filter param(shiftx, \A_WIDTH).as_int() >= minlen
+endmatch
+
+code shiftx_width
+ shiftx_width = param(shiftx, \A_WIDTH).as_int();
+endcode
+
+match first
+ select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)
+ select nusers(port(first, \Q)) == 2
+ index <SigBit> port(first, \Q) === port(shiftx, \A)[shiftx_width-1]
+endmatch
+
+code
+ chain.push_back(first);
+ subpattern(tail);
+finally
+ if (GetSize(chain) == shiftx_width)
+ accept;
+ chain.clear();
+endcode
+
+// ------------------------------------------------------------------
+
+subpattern tail
+arg shiftx
+arg shiftx_width
+
+match next
+ semioptional
+ select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)
+ select !next->has_keep_attr()
+ select !port(next, \D)[0].wire->get_bool_attribute(\keep)
+ select nusers(port(next, \Q)) == 3
+ index <IdString> next->type === chain.back()->type
+ index <SigBit> port(next, \Q) === port(chain.back(), \D)
+ index <SigBit> port(next, \Q) === port(shiftx, \A)[shiftx_width-1-GetSize(chain)]
+endmatch
+
+code
+ if (next) {
+ auto sig = port(next, \Q);
+ log_warning("nusers of '%s'\n", log_signal(sig));
+ for (auto bit : sigmap(sig))
+ for (auto user : sigusers[bit])
+ log_warning("\t%s\n", log_id(user));
+ chain.push_back(next);
+ if (GetSize(chain) < shiftx_width)
+ subpattern(tail);
+ }
+endcode
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index dd56d8c71..bcc690fa3 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -268,6 +268,8 @@ struct SatHelper
RTLIL::SigSpec removed_bits;
for (int i = 0; i < lhs.size(); i++) {
RTLIL::SigSpec bit = lhs.extract(i, 1);
+ if (bit.is_fully_const() && rhs[i] == State::Sx)
+ rhs[i] = bit;
if (!satgen.initial_state.check_all(bit)) {
removed_bits.append(bit);
lhs.remove(i, 1);
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index 5e298d8dd..9da69e8ba 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -26,9 +26,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ShregmapTech
{
virtual ~ShregmapTech() { }
- virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {}
- virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {}
- virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) = 0;
+ virtual bool analyze(vector<int> &taps) = 0;
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
};
@@ -56,7 +54,7 @@ struct ShregmapOptions
struct ShregmapTechGreenpak4 : ShregmapTech
{
- bool analyze(vector<int> &taps, const vector<SigBit> &/*qbits*/)
+ bool analyze(vector<int> &taps)
{
if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
taps.clear();
@@ -93,155 +91,6 @@ struct ShregmapTechGreenpak4 : ShregmapTech
}
};
-struct ShregmapTechXilinx7 : ShregmapTech
-{
- dict<SigBit, std::tuple<Cell*,int,int>> sigbit_to_shiftx_offset;
- const ShregmapOptions &opts;
-
- ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {}
-
- virtual void init(const Module* module, const SigMap &sigmap) override
- {
- for (const auto &i : module->cells_) {
- auto cell = i.second;
- if (cell->type == ID($shiftx)) {
- if (cell->getParam(ID(Y_WIDTH)) != 1) continue;
- int j = 0;
- for (auto bit : sigmap(cell->getPort(ID::A)))
- sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0);
- log_assert(j == cell->getParam(ID(A_WIDTH)).as_int());
- }
- else if (cell->type == ID($mux)) {
- int j = 0;
- for (auto bit : sigmap(cell->getPort(ID::A)))
- sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
- j = 0;
- for (auto bit : sigmap(cell->getPort(ID::B)))
- sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++);
- }
- }
- }
-
- virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override
- {
- auto it = sigbit_to_shiftx_offset.find(bit);
- if (it == sigbit_to_shiftx_offset.end())
- return;
- if (cell) {
- if (cell->type == ID($shiftx) && port == ID::A)
- return;
- if (cell->type == ID($mux) && port.in(ID::A, ID::B))
- return;
- }
- sigbit_to_shiftx_offset.erase(it);
- }
-
- virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) override
- {
- if (GetSize(taps) == 1)
- return taps[0] >= opts.minlen-1 && sigbit_to_shiftx_offset.count(qbits[0]);
-
- if (taps.back() < opts.minlen-1)
- return false;
-
- Cell *shiftx = nullptr;
- int group = 0;
- for (int i = 0; i < GetSize(taps); ++i) {
- auto it = sigbit_to_shiftx_offset.find(qbits[i]);
- if (it == sigbit_to_shiftx_offset.end())
- return false;
-
- // Check taps are sequential
- if (i != taps[i])
- return false;
- // Check taps are not connected to a shift register,
- // or sequential to the same shift register
- if (i == 0) {
- int offset;
- std::tie(shiftx,offset,group) = it->second;
- if (offset != i)
- return false;
- }
- else {
- Cell *shiftx_ = std::get<0>(it->second);
- if (shiftx_ != shiftx)
- return false;
- int offset = std::get<1>(it->second);
- if (offset != i)
- return false;
- int group_ = std::get<2>(it->second);
- if (group_ != group)
- return false;
- }
- }
- log_assert(shiftx);
-
- // Only map if $shiftx exclusively covers the shift register
- if (shiftx->type == ID($shiftx)) {
- if (GetSize(taps) > shiftx->getParam(ID(A_WIDTH)).as_int())
- return false;
- // Due to padding the most significant bits of A may be 1'bx,
- // and if so, discount them
- if (GetSize(taps) < shiftx->getParam(ID(A_WIDTH)).as_int()) {
- const SigSpec A = shiftx->getPort(ID::A);
- const int A_width = shiftx->getParam(ID(A_WIDTH)).as_int();
- for (int i = GetSize(taps); i < A_width; ++i)
- if (A[i] != RTLIL::Sx) return false;
- }
- else if (GetSize(taps) != shiftx->getParam(ID(A_WIDTH)).as_int())
- return false;
- }
- else if (shiftx->type == ID($mux)) {
- if (GetSize(taps) != 2)
- return false;
- }
- else log_abort();
-
- return true;
- }
-
- virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) override
- {
- const auto &tap = *taps.begin();
- auto bit = tap.second;
-
- auto it = sigbit_to_shiftx_offset.find(bit);
- log_assert(it != sigbit_to_shiftx_offset.end());
-
- auto newcell = cell->module->addCell(NEW_ID, ID($__XILINX_SHREG_));
- newcell->set_src_attribute(cell->get_src_attribute());
- newcell->setParam(ID(DEPTH), cell->getParam(ID(DEPTH)));
- newcell->setParam(ID(INIT), cell->getParam(ID(INIT)));
- newcell->setParam(ID(CLKPOL), cell->getParam(ID(CLKPOL)));
- newcell->setParam(ID(ENPOL), cell->getParam(ID(ENPOL)));
-
- newcell->setPort(ID(C), cell->getPort(ID(C)));
- newcell->setPort(ID(D), cell->getPort(ID(D)));
- if (cell->hasPort(ID(E)))
- newcell->setPort(ID(E), cell->getPort(ID(E)));
-
- Cell* shiftx = std::get<0>(it->second);
- RTLIL::SigSpec l_wire, q_wire;
- if (shiftx->type == ID($shiftx)) {
- l_wire = shiftx->getPort(ID::B);
- q_wire = shiftx->getPort(ID::Y);
- shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
- }
- else if (shiftx->type == ID($mux)) {
- l_wire = shiftx->getPort(ID(S));
- q_wire = shiftx->getPort(ID::Y);
- shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
- }
- else log_abort();
-
- newcell->setPort(ID(Q), q_wire);
- newcell->setPort(ID(L), l_wire);
-
- return false;
- }
-};
-
-
struct ShregmapWorker
{
Module *module;
@@ -264,10 +113,8 @@ struct ShregmapWorker
for (auto wire : module->wires())
{
if (wire->port_output || wire->get_bool_attribute(ID::keep)) {
- for (auto bit : sigmap(wire)) {
+ for (auto bit : sigmap(wire))
sigbit_with_non_chain_users.insert(bit);
- if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {});
- }
}
if (wire->attributes.count(ID(init))) {
@@ -317,10 +164,8 @@ struct ShregmapWorker
for (auto conn : cell->connections())
if (cell->input(conn.first))
- for (auto bit : sigmap(conn.second)) {
+ for (auto bit : sigmap(conn.second))
sigbit_with_non_chain_users.insert(bit);
- if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first);
- }
}
}
@@ -425,7 +270,7 @@ struct ShregmapWorker
if (taps.empty() || taps.back() < depth-1)
taps.push_back(depth-1);
- if (opts.tech->analyze(taps, qbits))
+ if (opts.tech->analyze(taps))
break;
taps.pop_back();
@@ -544,9 +389,6 @@ struct ShregmapWorker
ShregmapWorker(Module *module, const ShregmapOptions &opts) :
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
{
- if (opts.tech)
- opts.tech->init(module, sigmap);
-
make_sigbit_chain_next_prev();
find_chain_start_cells();
@@ -617,11 +459,6 @@ struct ShregmapPass : public Pass {
log("\n");
log(" -tech greenpak4\n");
log(" map to greenpak4 shift registers.\n");
- log(" this option also implies -clkpol pos -zinit\n");
- log("\n");
- log(" -tech xilinx\n");
- log(" map to xilinx dynamic-length shift registers.\n");
- log(" this option also implies -params -init\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -676,12 +513,6 @@ struct ShregmapPass : public Pass {
clkpol = "pos";
opts.zinit = true;
opts.tech = new ShregmapTechGreenpak4;
- }
- else if (tech == "xilinx") {
- opts.init = true;
- opts.params = true;
- enpol = "any_or_none";
- opts.tech = new ShregmapTechXilinx7(opts);
} else {
argidx--;
break;
diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v
index 2fcb0369e..dc8334acb 100644
--- a/techlibs/ecp5/cells_sim.v
+++ b/techlibs/ecp5/cells_sim.v
@@ -17,10 +17,12 @@ endmodule
// ---------------------------------------
(* abc_box_id=1, lib_whitebox *)
module CCU2C(
- (* abc_carry *) input CIN,
+ (* abc_carry *)
+ input CIN,
input A0, B0, C0, D0, A1, B1, C1, D1,
output S0, S1,
- (* abc_carry *) output COUT
+ (* abc_carry *)
+ output COUT
);
parameter [15:0] INIT0 = 16'h0000;
parameter [15:0] INIT1 = 16'h0000;
@@ -109,9 +111,12 @@ endmodule
// ---------------------------------------
//(* abc_box_id=2 *)
module TRELLIS_DPR16X4 (
- (* abc_scc_break *) input [3:0] DI,
- (* abc_scc_break *) input [3:0] WAD,
- (* abc_scc_break *) input WRE,
+ (* abc_scc_break *)
+ input [3:0] DI,
+ (* abc_scc_break *)
+ input [3:0] WAD,
+ (* abc_scc_break *)
+ input WRE,
input WCK,
input [3:0] RAD,
output [3:0] DO
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index ab04808f4..c7f3bdad2 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -143,11 +143,13 @@ endmodule
(* abc_box_id = 1, lib_whitebox *)
module \$__ICE40_FULL_ADDER (
- (* abc_carry *) output CO,
+ (* abc_carry *)
+ output CO,
output O,
input A,
input B,
- (* abc_carry *) input CI
+ (* abc_carry *)
+ input CI
);
SB_CARRY carry (
.I0(A),
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index bec9ea1a0..3ad96d7fb 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -183,9 +183,11 @@ endmodule
(* abc_box_id = 4, lib_whitebox *)
module CARRY4(
- (* abc_carry *) output [3:0] CO,
+ (* abc_carry *)
+ output [3:0] CO,
output [3:0] O,
- (* abc_carry *) input CI,
+ (* abc_carry *)
+ input CI,
input CYINIT,
input [3:0] DI, S
);
@@ -298,9 +300,11 @@ endmodule
(* abc_box_id = 5 *)
module RAM32X1D (
output DPO, SPO,
- (* abc_scc_break *) input D,
+ (* abc_scc_break *)
+ input D,
input WCLK,
- (* abc_scc_break *) input WE,
+ (* abc_scc_break *)
+ input WE,
input A0, A1, A2, A3, A4,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
);
@@ -318,9 +322,11 @@ endmodule
(* abc_box_id = 6 *)
module RAM64X1D (
output DPO, SPO,
- (* abc_scc_break *) input D,
+ (* abc_scc_break *)
+ input D,
input WCLK,
- (* abc_scc_break *) input WE,
+ (* abc_scc_break *)
+ input WE,
input A0, A1, A2, A3, A4, A5,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
);
@@ -338,9 +344,11 @@ endmodule
(* abc_box_id = 7 *)
module RAM128X1D (
output DPO, SPO,
- (* abc_scc_break *) input D,
+ (* abc_scc_break *)
+ input D,
input WCLK,
- (* abc_scc_break *) input WE,
+ (* abc_scc_break *)
+ input WE,
input [6:0] A, DPRA
);
parameter INIT = 128'h0;
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 7ba67409b..8bf43bf97 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -352,9 +352,8 @@ struct SynthXilinxPass : public ScriptPass
if (!nosrl || help_mode) {
// shregmap operates on bit-level flops, not word-level,
// so break those down here
- run("simplemap t:$dff t:$dffe", " (skip if '-nosrl')");
- // shregmap with '-tech xilinx' infers variable length shift regs
- run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
+ run("simplemap t:$dff t:$dffe", " (skip if '-nosrl')");
+ run("xilinx_srl -variable -minlen 3", "(skip if '-nosrl')");
}
std::string techmap_args = " -map +/techmap.v";
@@ -383,6 +382,14 @@ struct SynthXilinxPass : public ScriptPass
run("clean");
}
+ if (check_label("map_ffs")) {
+ if (abc9 || help_mode) {
+ run("techmap -map +/xilinx/ff_map.v", "('-abc9' only)");
+ run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
+ "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT", "('-abc9' only)");
+ }
+ }
+
if (check_label("map_luts")) {
run("opt_expr -mux_undef");
if (help_mode)
@@ -406,10 +413,17 @@ struct SynthXilinxPass : public ScriptPass
// This shregmap call infers fixed length shift registers after abc
// has performed any necessary retiming
if (!nosrl || help_mode)
- run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
- run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
- run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
- "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
+ run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')");
+
+ std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v";
+ if (help_mode)
+ techmap_args += " [-map +/xilinx/ff_map.v]";
+ else if (!abc9)
+ techmap_args += " -map +/xilinx/ff_map.v";
+ run("techmap " + techmap_args);
+ if (!abc9)
+ run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
+ "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT", "(without '-abc9' only)");
run("clean");
}
diff --git a/tests/sat/initval.v b/tests/sat/initval.v
index 5b661f8d6..d46ccae48 100644
--- a/tests/sat/initval.v
+++ b/tests/sat/initval.v
@@ -1,6 +1,7 @@
module test(input clk, input [3:0] bar, output [3:0] foo);
reg [3:0] foo = 0;
reg [3:0] last_bar = 0;
+ reg [3:0] asdf = 4'b1xxx;
always @*
foo[1:0] <= bar[1:0];
@@ -11,5 +12,8 @@ module test(input clk, input [3:0] bar, output [3:0] foo);
always @(posedge clk)
last_bar <= bar;
+ always @*
+ asdf[2:0] <= 3'b111;
+
assert property (foo == {last_bar[3:2], bar[1:0]});
endmodule
diff --git a/tests/sat/initval.ys b/tests/sat/initval.ys
index 2079d2f34..3d88aa971 100644
--- a/tests/sat/initval.ys
+++ b/tests/sat/initval.ys
@@ -1,4 +1,4 @@
read_verilog -sv initval.v
-proc;;
+proc;
sat -seq 10 -prove-asserts
diff --git a/tests/various/shregmap.ys b/tests/various/shregmap.ys
index 0e5fe882b..16e5f40e1 100644
--- a/tests/various/shregmap.ys
+++ b/tests/various/shregmap.ys
@@ -31,36 +31,3 @@ sat -verify -prove-asserts -show-ports -seq 5 miter
#design -load gate
#stat
-
-##########
-
-design -load read
-design -copy-to model $__XILINX_SHREG_
-hierarchy -top shregmap_variable_test
-prep
-design -save gold
-
-simplemap t:$dff t:$dffe
-shregmap -tech xilinx
-
-#stat
-# show -width
-# write_verilog -noexpr -norename
-select -assert-count 1 t:$_DFF_P_
-select -assert-count 2 t:$__XILINX_SHREG_
-
-design -stash gate
-
-design -import gold -as gold
-design -import gate -as gate
-design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_
-prep
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -verify -prove-asserts -show-ports -seq 5 miter
-
-# design -load gold
-# stat
-
-# design -load gate
-# stat