aboutsummaryrefslogtreecommitdiffstats
path: root/passes
diff options
context:
space:
mode:
Diffstat (limited to 'passes')
-rw-r--r--passes/cmds/add.cc2
-rw-r--r--passes/cmds/bugpoint.cc8
-rw-r--r--passes/cmds/setattr.cc39
-rw-r--r--passes/cmds/show.cc4
-rw-r--r--passes/equiv/equiv_opt.cc2
-rw-r--r--passes/hierarchy/hierarchy.cc10
-rw-r--r--passes/hierarchy/uniquify.cc2
-rw-r--r--passes/proc/proc_mux.cc50
-rw-r--r--passes/proc/proc_rmdead.cc18
-rw-r--r--passes/sat/miter.cc8
-rw-r--r--passes/techmap/Makefile.inc1
-rw-r--r--passes/techmap/dfflibmap.cc2
-rw-r--r--passes/techmap/pmux2shiftx.cc81
-rw-r--r--passes/techmap/shregmap.cc216
-rw-r--r--passes/techmap/simplemap.cc2
-rw-r--r--passes/techmap/techmap.cc33
16 files changed, 442 insertions, 36 deletions
diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc
index cfccca966..af6f7043d 100644
--- a/passes/cmds/add.cc
+++ b/passes/cmds/add.cc
@@ -71,7 +71,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
RTLIL::Module *mod = design->modules_.at(it.second->type);
if (!design->selected_whole_module(mod->name))
continue;
- if (mod->get_bool_attribute("\\blackbox"))
+ if (mod->get_blackbox_attribute())
continue;
if (it.second->hasPort(name))
continue;
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc
index 606276e64..4b22f6d2d 100644
--- a/passes/cmds/bugpoint.cc
+++ b/passes/cmds/bugpoint.cc
@@ -128,7 +128,7 @@ struct BugpointPass : public Pass {
{
for (auto &it : design_copy->modules_)
{
- if (it.second->get_bool_attribute("\\blackbox"))
+ if (it.second->get_blackbox_attribute())
continue;
if (index++ == seed)
@@ -143,7 +143,7 @@ struct BugpointPass : public Pass {
{
for (auto mod : design_copy->modules())
{
- if (mod->get_bool_attribute("\\blackbox"))
+ if (mod->get_blackbox_attribute())
continue;
for (auto wire : mod->wires())
@@ -168,7 +168,7 @@ struct BugpointPass : public Pass {
{
for (auto mod : design_copy->modules())
{
- if (mod->get_bool_attribute("\\blackbox"))
+ if (mod->get_blackbox_attribute())
continue;
for (auto &it : mod->cells_)
@@ -186,7 +186,7 @@ struct BugpointPass : public Pass {
{
for (auto mod : design_copy->modules())
{
- if (mod->get_bool_attribute("\\blackbox"))
+ if (mod->get_blackbox_attribute())
continue;
for (auto cell : mod->cells())
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index d38a6b3da..b9fcc3e7a 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -128,6 +128,45 @@ struct SetattrPass : public Pass {
}
} SetattrPass;
+struct WbflipPass : public Pass {
+ WbflipPass() : Pass("wbflip", "flip the whitebox attribute") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" wbflip [selection]\n");
+ log("\n");
+ log("Flip the whitebox attribute on selected cells. I.e. if it's set, unset it, and\n");
+ log("vice-versa. Blackbox cells are not effected by this command.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+ // if (arg == "-mod") {
+ // flag_mod = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (Module *module : design->modules())
+ {
+ if (!design->selected(module))
+ continue;
+
+ if (module->get_bool_attribute("\\blackbox"))
+ continue;
+
+ module->set_bool_attribute("\\whitebox", !module->get_bool_attribute("\\whitebox"));
+ }
+ }
+} WbflipPass;
+
struct SetparamPass : public Pass {
SetparamPass() : Pass("setparam", "set/unset parameters on objects") { }
void help() YS_OVERRIDE
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index 0eadd904a..cf729215f 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -574,7 +574,7 @@ struct ShowWorker
if (!design->selected_module(module->name))
continue;
if (design->selected_whole_module(module->name)) {
- if (module->get_bool_attribute("\\blackbox")) {
+ if (module->get_blackbox_attribute()) {
// log("Skipping blackbox module %s.\n", id2cstr(module->name));
continue;
} else
@@ -790,7 +790,7 @@ struct ShowPass : public Pass {
if (format != "ps" && format != "dot") {
int modcount = 0;
for (auto &mod_it : design->modules_) {
- if (mod_it.second->get_bool_attribute("\\blackbox"))
+ if (mod_it.second->get_blackbox_attribute())
continue;
if (mod_it.second->cells_.empty() && mod_it.second->connections().empty())
continue;
diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc
index 86550a69b..e5dda9c24 100644
--- a/passes/equiv/equiv_opt.cc
+++ b/passes/equiv/equiv_opt.cc
@@ -134,7 +134,7 @@ struct EquivOptPass:public ScriptPass
opts = " -map <filename> ...";
else
opts = techmap_opts;
- run("techmap -D EQUIV -autoproc" + opts);
+ run("techmap -wb -D EQUIV -autoproc" + opts);
}
if (check_label("prove")) {
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 88c339e8c..b8ff99884 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -346,9 +346,9 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
}
RTLIL::Module *mod = design->modules_[cell->type];
- if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
+ if (design->modules_.at(cell->type)->get_blackbox_attribute()) {
if (flag_simcheck)
- log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n",
+ log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n",
cell->type.c_str(), module->name.c_str(), cell->name.c_str());
continue;
}
@@ -451,7 +451,7 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::
if (indent == 0)
log("Top module: %s\n", mod->name.c_str());
- else if (!mod->get_bool_attribute("\\blackbox"))
+ else if (!mod->get_blackbox_attribute())
log("Used module: %*s%s\n", indent, "", mod->name.c_str());
used.insert(mod);
@@ -491,7 +491,7 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
int del_counter = 0;
for (auto mod : del_modules) {
- if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
+ if (!purge_lib && mod->get_blackbox_attribute())
continue;
log("Removing unused module `%s'.\n", mod->name.c_str());
design->modules_.erase(mod->name);
@@ -910,7 +910,7 @@ struct HierarchyPass : public Pass {
if (m == nullptr)
continue;
- if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
+ if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
IdString new_m_name = m->derive(design, cell->parameters, true);
if (new_m_name.empty())
continue;
diff --git a/passes/hierarchy/uniquify.cc b/passes/hierarchy/uniquify.cc
index e6154e94f..ad3220918 100644
--- a/passes/hierarchy/uniquify.cc
+++ b/passes/hierarchy/uniquify.cc
@@ -75,7 +75,7 @@ struct UniquifyPass : public Pass {
if (tmod == nullptr)
continue;
- if (tmod->get_bool_attribute("\\blackbox"))
+ if (tmod->get_blackbox_attribute())
continue;
if (tmod->get_bool_attribute("\\unique") && newname == tmod->name)
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index 1329c1fef..aac0b121c 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -108,6 +108,7 @@ struct SigSnippets
struct SnippetSwCache
{
+ dict<RTLIL::SwitchRule*, pool<RTLIL::SigBit>, hash_ptr_ops> full_case_bits_cache;
dict<RTLIL::SwitchRule*, pool<int>, hash_ptr_ops> cache;
const SigSnippets *snippets;
int current_snippet;
@@ -268,6 +269,49 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve
last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size();
}
+const pool<SigBit> &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRule *sw)
+{
+ if (!swcache.full_case_bits_cache.count(sw))
+ {
+ pool<SigBit> bits;
+
+ if (sw->get_bool_attribute("\\full_case"))
+ {
+ bool first_case = true;
+
+ for (auto cs : sw->cases)
+ {
+ pool<SigBit> case_bits;
+
+ for (auto it : cs->actions) {
+ for (auto bit : it.first)
+ case_bits.insert(bit);
+ }
+
+ for (auto it : cs->switches) {
+ for (auto bit : get_full_case_bits(swcache, it))
+ case_bits.insert(bit);
+ }
+
+ if (first_case) {
+ first_case = false;
+ bits = case_bits;
+ } else {
+ pool<SigBit> new_bits;
+ for (auto bit : bits)
+ if (case_bits.count(bit))
+ new_bits.insert(bit);
+ bits.swap(new_bits);
+ }
+ }
+ }
+
+ bits.swap(swcache.full_case_bits_cache[sw]);
+ }
+
+ return swcache.full_case_bits_cache.at(sw);
+}
+
RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara,
RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode)
{
@@ -337,6 +381,12 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
}
}
+ // mask default bits that are irrelevant because the output is driven by a full case
+ const pool<SigBit> &full_case_bits = get_full_case_bits(swcache, sw);
+ for (int i = 0; i < GetSize(sig); i++)
+ if (full_case_bits.count(sig[i]))
+ result[i] = State::Sx;
+
// evaluate in reverse order to give the first entry the top priority
RTLIL::SigSpec initial_val = result;
RTLIL::Cell *last_mux_cell = NULL;
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
index 7c334e661..4f40be446 100644
--- a/passes/proc/proc_rmdead.cc
+++ b/passes/proc/proc_rmdead.cc
@@ -28,7 +28,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
+void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
{
BitPatternPool pool(sw->signal);
@@ -56,11 +56,16 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
}
for (auto switch_it : sw->cases[i]->switches)
- proc_rmdead(switch_it, counter);
+ proc_rmdead(switch_it, counter, full_case_counter);
if (is_default)
pool.take_all();
}
+
+ if (pool.empty() && !sw->get_bool_attribute("\\full_case")) {
+ sw->set_bool_attribute("\\full_case");
+ full_case_counter++;
+ }
}
struct ProcRmdeadPass : public Pass {
@@ -87,12 +92,15 @@ struct ProcRmdeadPass : public Pass {
for (auto &proc_it : mod->processes) {
if (!design->selected(mod, proc_it.second))
continue;
- int counter = 0;
+ int counter = 0, full_case_counter = 0;
for (auto switch_it : proc_it.second->root_case.switches)
- proc_rmdead(switch_it, counter);
+ proc_rmdead(switch_it, counter, full_case_counter);
if (counter > 0)
log("Removed %d dead cases from process %s in module %s.\n", counter,
- proc_it.first.c_str(), log_id(mod));
+ log_id(proc_it.first), log_id(mod));
+ if (full_case_counter > 0)
+ log("Marked %d switch rules as full_case in process %s in module %s.\n",
+ full_case_counter, log_id(proc_it.first), log_id(mod));
total_counter += counter;
}
}
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index d37f1b126..1a886af70 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -254,7 +254,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL:
if (flag_flatten) {
log_push();
- Pass::call_on_module(design, miter_module, "flatten; opt_expr -keepdc -undriven;;");
+ Pass::call_on_module(design, miter_module, "flatten -wb; opt_expr -keepdc -undriven;;");
log_pop();
}
}
@@ -308,7 +308,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
if (flag_flatten) {
log_push();
- Pass::call_on_module(design, module, "flatten;;");
+ Pass::call_on_module(design, module, "flatten -wb;;");
log_pop();
}
@@ -385,7 +385,7 @@ struct MiterPass : public Pass {
log(" also create an 'assert' cell that checks if trigger is always low.\n");
log("\n");
log(" -flatten\n");
- log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
+ log(" call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n");
log("\n");
log(" miter -assert [options] module [miter_name]\n");
@@ -399,7 +399,7 @@ struct MiterPass : public Pass {
log(" keep module output ports.\n");
log("\n");
log(" -flatten\n");
- log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
+ log(" call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index cf9e198ad..81df499da 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -37,6 +37,7 @@ OBJS += passes/techmap/attrmap.o
OBJS += passes/techmap/zinit.o
OBJS += passes/techmap/dff2dffs.o
OBJS += passes/techmap/flowmap.o
+OBJS += passes/techmap/pmux2shiftx.o
endif
GENFILES += passes/techmap/techmap.inc
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index 274177a68..b5c0498d0 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -664,7 +664,7 @@ struct DfflibmapPass : public Pass {
logmap_all();
for (auto &it : design->modules_)
- if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox"))
+ if (design->selected(it.second) && !it.second->get_blackbox_attribute())
dfflibmap(design, it.second, prepare_mode);
cell_mappings.clear();
diff --git a/passes/techmap/pmux2shiftx.cc b/passes/techmap/pmux2shiftx.cc
new file mode 100644
index 000000000..6ffc27a4c
--- /dev/null
+++ b/passes/techmap/pmux2shiftx.cc
@@ -0,0 +1,81 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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
+
+struct Pmux2ShiftxPass : public Pass {
+ Pmux2ShiftxPass() : Pass("pmux2shiftx", "transform $pmux cells to $shiftx cells") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" pmux2shiftx [selection]\n");
+ log("\n");
+ log("This pass transforms $pmux cells to $shiftx cells.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing PMUX2SHIFTX pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type != "$pmux")
+ continue;
+
+ // Create a new encoder, out of a $pmux, that takes
+ // the existing pmux's 'S' input and transforms it
+ // back into a binary value
+ RTLIL::SigSpec shiftx_a;
+ RTLIL::SigSpec pmux_s;
+
+ int s_width = cell->getParam("\\S_WIDTH").as_int();
+ if (!cell->getPort("\\A").is_fully_undef()) {
+ ++s_width;
+ shiftx_a.append(cell->getPort("\\A"));
+ pmux_s.append(module->Not(NEW_ID, module->ReduceOr(NEW_ID, cell->getPort("\\S"))));
+ }
+ const int clog2width = ceil(log2(s_width));
+
+ RTLIL::SigSpec pmux_b;
+ for (int i = s_width-1; i >= 0; i--)
+ pmux_b.append(RTLIL::Const(i, clog2width));
+ shiftx_a.append(cell->getPort("\\B"));
+ pmux_s.append(cell->getPort("\\S"));
+
+ RTLIL::SigSpec pmux_y = module->addWire(NEW_ID, clog2width);
+ module->addPmux(NEW_ID, RTLIL::Const(RTLIL::Sx, clog2width), pmux_b, pmux_s, pmux_y);
+ module->addShiftx(NEW_ID, shiftx_a, pmux_y, cell->getPort("\\Y"));
+ module->remove(cell);
+ }
+ }
+} Pmux2ShiftxPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index f20863ba0..ec43b5654 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -26,7 +26,9 @@ PRIVATE_NAMESPACE_BEGIN
struct ShregmapTech
{
virtual ~ShregmapTech() { }
- virtual bool analyze(vector<int> &taps) = 0;
+ 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 fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
};
@@ -54,7 +56,7 @@ struct ShregmapOptions
struct ShregmapTechGreenpak4 : ShregmapTech
{
- bool analyze(vector<int> &taps)
+ bool analyze(vector<int> &taps, const vector<SigBit> &/*qbits*/)
{
if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
taps.clear();
@@ -91,6 +93,197 @@ struct ShregmapTechGreenpak4 : ShregmapTech
}
};
+struct ShregmapTechXilinx7 : ShregmapTech
+{
+ dict<SigBit, std::tuple<Cell*,int,int>> sigbit_to_shiftx_offset;
+ dict<SigBit, SigSpec> sigbit_to_eq_input;
+ 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 == "$shiftx") {
+ if (cell->getParam("\\Y_WIDTH") != 1) continue;
+ int j = 0;
+ for (auto bit : sigmap(cell->getPort("\\A")))
+ sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0);
+ log_assert(j == cell->getParam("\\A_WIDTH").as_int());
+ }
+ else if (cell->type == "$mux") {
+ int j = 0;
+ for (auto bit : sigmap(cell->getPort("\\A")))
+ sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
+ j = 0;
+ for (auto bit : sigmap(cell->getPort("\\B")))
+ sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++);
+ }
+ else if (cell->type == "$pmux") {
+ if (!cell->get_bool_attribute("\\shiftx_compatible")) continue;
+ int width = cell->getParam("\\WIDTH").as_int();
+ int j = 0;
+ for (auto bit : sigmap(cell->getPort("\\A")))
+ sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
+ j = cell->getParam("\\S_WIDTH").as_int();
+ int k = 0;
+ for (auto bit : sigmap(cell->getPort("\\B"))) {
+ sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j, k++);
+ if (k == width) {
+ k = 0;
+ --j;
+ }
+ }
+ log_assert(j == 0);
+ }
+ else if (cell->type == "$eq") {
+ auto b_wire = cell->getPort("\\B");
+ // Keep track of $eq cells that compare against the value 1
+ // in anticipation that they drive the select (S) port of a $pmux
+ if (b_wire.is_fully_const() && b_wire.as_int() == 1) {
+ auto y_wire = sigmap(cell->getPort("\\Y").as_bit());
+ sigbit_to_eq_input[y_wire] = cell->getPort("\\A");
+ }
+ }
+ }
+ }
+
+ 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 == "$shiftx" && port == "\\A")
+ return;
+ if (cell->type == "$pmux" && (port == "\\A" || port == "\\B"))
+ return;
+ if (cell->type == "$mux" && (port == "\\A" || port == "\\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 == "$shiftx") {
+ if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int())
+ return false;
+ }
+ else if (shiftx->type == "$pmux") {
+ if (GetSize(taps) != shiftx->getParam("\\S_WIDTH").as_int() + 1)
+ return false;
+ }
+ else if (shiftx->type == "$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, "$__XILINX_SHREG_");
+ newcell->set_src_attribute(cell->get_src_attribute());
+ newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH"));
+ newcell->setParam("\\INIT", cell->getParam("\\INIT"));
+ newcell->setParam("\\CLKPOL", cell->getParam("\\CLKPOL"));
+ newcell->setParam("\\ENPOL", cell->getParam("\\ENPOL"));
+
+ newcell->setPort("\\C", cell->getPort("\\C"));
+ newcell->setPort("\\D", cell->getPort("\\D"));
+ if (cell->hasPort("\\E"))
+ newcell->setPort("\\E", cell->getPort("\\E"));
+
+ Cell* shiftx = std::get<0>(it->second);
+ RTLIL::SigSpec l_wire, q_wire;
+ if (shiftx->type == "$shiftx") {
+ l_wire = shiftx->getPort("\\B");
+ q_wire = shiftx->getPort("\\Y");
+ shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
+ }
+ else if (shiftx->type == "$pmux") {
+ // If the 'A' port is fully undef, then opt_expr -mux_undef
+ // has not been applied, so find the second-to-last bit of
+ // the 'S' port (corresponding to $eq cell comparing for 1)
+ // otherwise use the last bit of 'S'
+ const auto& s_wire_bits = shiftx->getPort("\\S").bits();
+ SigBit s1;
+ if (shiftx->getPort("\\A").is_fully_undef())
+ s1 = s_wire_bits[s_wire_bits.size() - 2];
+ else
+ s1 = s_wire_bits[s_wire_bits.size() - 1];
+ RTLIL::SigSpec y_wire = shiftx->getPort("\\Y");
+ l_wire = sigbit_to_eq_input.at(s1);
+ log_assert(l_wire.size() == ceil(log2(taps.size())));
+ int group = std::get<2>(it->second);
+ q_wire = y_wire[group];
+ y_wire[group] = cell->module->addWire(NEW_ID);
+ shiftx->setPort("\\Y", y_wire);
+ }
+ else if (shiftx->type == "$mux") {
+ l_wire = shiftx->getPort("\\S");
+ q_wire = shiftx->getPort("\\Y");
+ shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
+ }
+ else log_abort();
+
+ newcell->setPort("\\Q", q_wire);
+ newcell->setPort("\\L", l_wire);
+
+ return false;
+ }
+};
+
+
struct ShregmapWorker
{
Module *module;
@@ -113,8 +306,10 @@ struct ShregmapWorker
for (auto wire : module->wires())
{
if (wire->port_output || wire->get_bool_attribute("\\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("\\init")) {
@@ -152,8 +347,10 @@ 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);
+ }
}
}
@@ -258,7 +455,7 @@ struct ShregmapWorker
if (taps.empty() || taps.back() < depth-1)
taps.push_back(depth-1);
- if (opts.tech->analyze(taps))
+ if (opts.tech->analyze(taps, qbits))
break;
taps.pop_back();
@@ -377,6 +574,9 @@ 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();
@@ -501,6 +701,12 @@ 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/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index 660b60601..f3da80c66 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -599,7 +599,7 @@ struct SimplemapPass : public Pass {
simplemap_get_mappers(mappers);
for (auto mod : design->modules()) {
- if (!design->selected(mod))
+ if (!design->selected(mod) || mod->get_blackbox_attribute())
continue;
std::vector<RTLIL::Cell*> cells = mod->cells();
for (auto cell : cells) {
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index d0e5e2236..ee319b6e6 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -84,6 +84,7 @@ struct TechmapWorker
bool flatten_mode;
bool recursive_mode;
bool autoproc_mode;
+ bool ignore_wb;
TechmapWorker()
{
@@ -92,6 +93,7 @@ struct TechmapWorker
flatten_mode = false;
recursive_mode = false;
autoproc_mode = false;
+ ignore_wb = false;
}
std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose)
@@ -383,7 +385,7 @@ struct TechmapWorker
{
std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping";
- if (!design->selected(module))
+ if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb))
return false;
bool log_continue = false;
@@ -472,7 +474,7 @@ struct TechmapWorker
RTLIL::Module *tpl = map->modules_[tpl_name];
std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end());
- if (tpl->get_bool_attribute("\\blackbox"))
+ if (tpl->get_blackbox_attribute(ignore_wb))
continue;
if (!flatten_mode)
@@ -925,6 +927,9 @@ struct TechmapPass : public Pass {
log(" -autoproc\n");
log(" Automatically call \"proc\" on implementations that contain processes.\n");
log("\n");
+ log(" -wb\n");
+ log(" Ignore the 'whitebox' attribute on cell implementations.\n");
+ log("\n");
log(" -assert\n");
log(" this option will cause techmap to exit with an error if it can't map\n");
log(" a selected cell. only cell types that end on an underscore are accepted\n");
@@ -1068,6 +1073,10 @@ struct TechmapPass : public Pass {
worker.autoproc_mode = true;
continue;
}
+ if (args[argidx] == "-wb") {
+ worker.ignore_wb = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -1145,7 +1154,7 @@ struct FlattenPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" flatten [selection]\n");
+ log(" flatten [options] [selection]\n");
log("\n");
log("This pass flattens the design by replacing cells by their implementation. This\n");
log("pass is very similar to the 'techmap' pass. The only difference is that this\n");
@@ -1154,17 +1163,29 @@ struct FlattenPass : public Pass {
log("Cells and/or modules with the 'keep_hierarchy' attribute set will not be\n");
log("flattened by this command.\n");
log("\n");
+ log(" -wb\n");
+ log(" Ignore the 'whitebox' attribute on cell implementations.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FLATTEN pass (flatten design).\n");
log_push();
- extra_args(args, 1, design);
-
TechmapWorker worker;
worker.flatten_mode = true;
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-wb") {
+ worker.ignore_wb = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+
std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
for (auto module : design->modules())
celltypeMap[module->name].insert(module->name);
@@ -1209,7 +1230,7 @@ struct FlattenPass : public Pass {
dict<RTLIL::IdString, RTLIL::Module*> new_modules;
for (auto mod : vector<Module*>(design->modules()))
- if (used_modules[mod->name] || mod->get_bool_attribute("\\blackbox")) {
+ if (used_modules[mod->name] || mod->get_blackbox_attribute(worker.ignore_wb)) {
new_modules[mod->name] = mod;
} else {
log("Deleting now unused module %s.\n", log_id(mod));