summaryrefslogtreecommitdiff
path: root/passes
diff options
context:
space:
mode:
Diffstat (limited to 'passes')
-rw-r--r--passes/cmds/Makefile.inc4
-rw-r--r--passes/cmds/add.cc4
-rw-r--r--passes/cmds/blackbox.cc81
-rw-r--r--passes/cmds/check.cc89
-rw-r--r--passes/cmds/chformal.cc282
-rw-r--r--passes/cmds/chtype.cc83
-rw-r--r--passes/cmds/connect.cc4
-rw-r--r--passes/cmds/connwrappers.cc6
-rw-r--r--passes/cmds/copy.cc4
-rw-r--r--passes/cmds/cover.cc6
-rw-r--r--passes/cmds/delete.cc4
-rw-r--r--passes/cmds/design.cc142
-rw-r--r--passes/cmds/edgetypes.cc4
-rw-r--r--passes/cmds/logcmd.cc4
-rw-r--r--passes/cmds/ltp.cc185
-rw-r--r--passes/cmds/plugin.cc4
-rw-r--r--passes/cmds/qwp.cc5
-rw-r--r--passes/cmds/rename.cc4
-rw-r--r--passes/cmds/scatter.cc4
-rw-r--r--passes/cmds/scc.cc78
-rw-r--r--passes/cmds/select.cc59
-rw-r--r--passes/cmds/setattr.cc12
-rw-r--r--passes/cmds/setundef.cc269
-rw-r--r--passes/cmds/show.cc36
-rw-r--r--passes/cmds/splice.cc4
-rw-r--r--passes/cmds/splitnets.cc14
-rw-r--r--passes/cmds/stat.cc15
-rw-r--r--passes/cmds/tee.cc5
-rw-r--r--passes/cmds/torder.cc4
-rw-r--r--passes/cmds/trace.cc17
-rw-r--r--passes/cmds/write_file.cc5
-rw-r--r--passes/equiv/equiv_add.cc4
-rw-r--r--passes/equiv/equiv_induct.cc4
-rw-r--r--passes/equiv/equiv_make.cc8
-rw-r--r--passes/equiv/equiv_mark.cc4
-rw-r--r--passes/equiv/equiv_miter.cc4
-rw-r--r--passes/equiv/equiv_purge.cc8
-rw-r--r--passes/equiv/equiv_remove.cc4
-rw-r--r--passes/equiv/equiv_simple.cc59
-rw-r--r--passes/equiv/equiv_status.cc4
-rw-r--r--passes/equiv/equiv_struct.cc4
-rw-r--r--passes/fsm/fsm.cc4
-rw-r--r--passes/fsm/fsm_detect.cc8
-rw-r--r--passes/fsm/fsm_expand.cc34
-rw-r--r--passes/fsm/fsm_export.cc4
-rw-r--r--passes/fsm/fsm_extract.cc4
-rw-r--r--passes/fsm/fsm_info.cc4
-rw-r--r--passes/fsm/fsm_map.cc7
-rw-r--r--passes/fsm/fsm_opt.cc4
-rw-r--r--passes/fsm/fsm_recode.cc4
-rw-r--r--passes/hierarchy/Makefile.inc2
-rw-r--r--passes/hierarchy/hierarchy.cc164
-rw-r--r--passes/hierarchy/submod.cc5
-rw-r--r--passes/hierarchy/uniquify.cc (renamed from passes/hierarchy/singleton.cc)43
-rw-r--r--passes/memory/Makefile.inc1
-rw-r--r--passes/memory/memory.cc4
-rw-r--r--passes/memory/memory_bram.cc4
-rw-r--r--passes/memory/memory_collect.cc4
-rw-r--r--passes/memory/memory_dff.cc24
-rw-r--r--passes/memory/memory_map.cc4
-rw-r--r--passes/memory/memory_memx.cc4
-rw-r--r--passes/memory/memory_nordff.cc121
-rw-r--r--passes/memory/memory_share.cc4
-rw-r--r--passes/memory/memory_unpack.cc4
-rw-r--r--passes/opt/Makefile.inc2
-rw-r--r--passes/opt/opt.cc4
-rw-r--r--passes/opt/opt_clean.cc107
-rw-r--r--passes/opt/opt_demorgan.cc202
-rw-r--r--passes/opt/opt_expr.cc315
-rw-r--r--passes/opt/opt_merge.cc19
-rw-r--r--passes/opt/opt_muxtree.cc4
-rw-r--r--passes/opt/opt_reduce.cc4
-rw-r--r--passes/opt/opt_rmdff.cc246
-rw-r--r--passes/opt/rmports.cc187
-rw-r--r--passes/opt/share.cc4
-rw-r--r--passes/opt/wreduce.cc4
-rw-r--r--passes/proc/proc.cc4
-rw-r--r--passes/proc/proc_arst.cc4
-rw-r--r--passes/proc/proc_clean.cc4
-rw-r--r--passes/proc/proc_dff.cc9
-rw-r--r--passes/proc/proc_dlatch.cc20
-rw-r--r--passes/proc/proc_init.cc4
-rw-r--r--passes/proc/proc_mux.cc4
-rw-r--r--passes/proc/proc_rmdead.cc4
-rw-r--r--passes/sat/Makefile.inc2
-rw-r--r--passes/sat/assertpmux.cc4
-rw-r--r--passes/sat/async2sync.cc147
-rw-r--r--passes/sat/clk2fflogic.cc114
-rw-r--r--passes/sat/eval.cc4
-rw-r--r--passes/sat/expose.cc55
-rw-r--r--passes/sat/freduce.cc7
-rw-r--r--passes/sat/miter.cc4
-rw-r--r--passes/sat/sat.cc5
-rw-r--r--passes/sat/sim.cc862
-rw-r--r--passes/techmap/Makefile.inc5
-rw-r--r--passes/techmap/abc.cc612
-rw-r--r--passes/techmap/aigmap.cc4
-rw-r--r--passes/techmap/alumacc.cc19
-rw-r--r--passes/techmap/attrmap.cc12
-rw-r--r--passes/techmap/attrmvcp.cc4
-rw-r--r--passes/techmap/deminout.cc36
-rw-r--r--passes/techmap/dff2dffe.cc18
-rw-r--r--passes/techmap/dff2dffs.cc142
-rw-r--r--passes/techmap/dffinit.cc24
-rw-r--r--passes/techmap/dfflibmap.cc12
-rw-r--r--passes/techmap/dffsr2dff.cc4
-rw-r--r--passes/techmap/extract.cc4
-rw-r--r--passes/techmap/extract_counter.cc651
-rw-r--r--passes/techmap/extract_fa.cc605
-rw-r--r--passes/techmap/extract_reduce.cc324
-rw-r--r--passes/techmap/hilomap.cc4
-rw-r--r--passes/techmap/insbuf.cc4
-rw-r--r--passes/techmap/iopadmap.cc61
-rw-r--r--passes/techmap/libparse.cc24
-rw-r--r--passes/techmap/lut2mux.cc4
-rw-r--r--passes/techmap/maccmap.cc4
-rw-r--r--passes/techmap/muxcover.cc4
-rw-r--r--passes/techmap/nlutmap.cc6
-rw-r--r--passes/techmap/pmuxtree.cc4
-rw-r--r--passes/techmap/shregmap.cc4
-rw-r--r--passes/techmap/simplemap.cc4
-rw-r--r--passes/techmap/techmap.cc45
-rw-r--r--passes/techmap/tribuf.cc4
-rw-r--r--passes/techmap/zinit.cc4
-rw-r--r--passes/tests/test_abcloop.cc4
-rw-r--r--passes/tests/test_autotb.cc4
-rw-r--r--passes/tests/test_cell.cc6
127 files changed, 6347 insertions, 675 deletions
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index 01ada773..44a83b2b 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -25,4 +25,8 @@ OBJS += passes/cmds/plugin.o
OBJS += passes/cmds/check.o
OBJS += passes/cmds/qwp.o
OBJS += passes/cmds/edgetypes.o
+OBJS += passes/cmds/chformal.o
+OBJS += passes/cmds/chtype.o
+OBJS += passes/cmds/blackbox.o
+OBJS += passes/cmds/ltp.o
diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc
index e698926f..cfccca96 100644
--- a/passes/cmds/add.cc
+++ b/passes/cmds/add.cc
@@ -83,7 +83,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
struct AddPass : public Pass {
AddPass() : Pass("add", "add objects to the design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -106,7 +106,7 @@ struct AddPass : public Pass {
log("selected modules.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string command;
std::string arg_name;
diff --git a/passes/cmds/blackbox.cc b/passes/cmds/blackbox.cc
new file mode 100644
index 00000000..6094f8f1
--- /dev/null
+++ b/passes/cmds/blackbox.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"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct BlackboxPass : public Pass {
+ BlackboxPass() : Pass("blackbox", "change type of cells in the design") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" blackbox [options] [selection]\n");
+ log("\n");
+ log("Convert modules into blackbox modules (remove contents and set the blackbox\n");
+ log("module attribute).\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++)
+ {
+ // if (args[argidx] == "-???") {
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_whole_modules_warn())
+ {
+ pool<Cell*> remove_cells;
+ pool<Wire*> remove_wires;
+
+ for (auto cell : module->cells())
+ remove_cells.insert(cell);
+
+ for (auto wire : module->wires())
+ if (wire->port_id == 0)
+ remove_wires.insert(wire);
+
+ for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
+ delete it->second;
+ module->memories.clear();
+
+ for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
+ delete it->second;
+ module->processes.clear();
+
+ module->new_connections(std::vector<RTLIL::SigSig>());
+
+ for (auto cell : remove_cells)
+ module->remove(cell);
+
+ module->remove(remove_wires);
+
+ module->set_bool_attribute("\\blackbox");
+ }
+ }
+} BlackboxPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc
index b3622cb1..64697c13 100644
--- a/passes/cmds/check.cc
+++ b/passes/cmds/check.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct CheckPass : public Pass {
CheckPass() : Pass("check", "check for obvious problems in the design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -44,14 +44,18 @@ struct CheckPass : public Pass {
log("When called with -noinit then this command also checks for wires which have\n");
log("the 'init' attribute set.\n");
log("\n");
+ log("When called with -initdrv then this command also checks for wires which have\n");
+ log("the 'init' attribute set and aren't driven by a FF cell type.\n");
+ log("\n");
log("When called with -assert then the command will produce an error if any\n");
log("problems are found in the current design.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
int counter = 0;
bool noinit = false;
+ bool initdrv = false;
bool assert_mode = false;
size_t argidx;
@@ -60,6 +64,10 @@ struct CheckPass : public Pass {
noinit = true;
continue;
}
+ if (args[argidx] == "-initdrv") {
+ initdrv = true;
+ continue;
+ }
if (args[argidx] == "-assert") {
assert_mode = true;
continue;
@@ -70,6 +78,49 @@ struct CheckPass : public Pass {
log_header(design, "Executing CHECK pass (checking for obvious problems).\n");
+ pool<IdString> fftypes;
+ fftypes.insert("$sr");
+ fftypes.insert("$ff");
+ fftypes.insert("$dff");
+ fftypes.insert("$dffe");
+ fftypes.insert("$dffsr");
+ fftypes.insert("$adff");
+ fftypes.insert("$dlatch");
+ fftypes.insert("$dlatchsr");
+ fftypes.insert("$_DFFE_NN_");
+ fftypes.insert("$_DFFE_NP_");
+ fftypes.insert("$_DFFE_PN_");
+ fftypes.insert("$_DFFE_PP_");
+ fftypes.insert("$_DFFSR_NNN_");
+ fftypes.insert("$_DFFSR_NNP_");
+ fftypes.insert("$_DFFSR_NPN_");
+ fftypes.insert("$_DFFSR_NPP_");
+ fftypes.insert("$_DFFSR_PNN_");
+ fftypes.insert("$_DFFSR_PNP_");
+ fftypes.insert("$_DFFSR_PPN_");
+ fftypes.insert("$_DFFSR_PPP_");
+ fftypes.insert("$_DFF_NN0_");
+ fftypes.insert("$_DFF_NN1_");
+ fftypes.insert("$_DFF_NP0_");
+ fftypes.insert("$_DFF_NP1_");
+ fftypes.insert("$_DFF_N_");
+ fftypes.insert("$_DFF_PN0_");
+ fftypes.insert("$_DFF_PN1_");
+ fftypes.insert("$_DFF_PP0_");
+ fftypes.insert("$_DFF_PP1_");
+ fftypes.insert("$_DFF_P_");
+ fftypes.insert("$_DLATCHSR_NNN_");
+ fftypes.insert("$_DLATCHSR_NNP_");
+ fftypes.insert("$_DLATCHSR_NPN_");
+ fftypes.insert("$_DLATCHSR_NPP_");
+ fftypes.insert("$_DLATCHSR_PNN_");
+ fftypes.insert("$_DLATCHSR_PNP_");
+ fftypes.insert("$_DLATCHSR_PPN_");
+ fftypes.insert("$_DLATCHSR_PPP_");
+ fftypes.insert("$_DLATCH_N_");
+ fftypes.insert("$_DLATCH_P_");
+ fftypes.insert("$_FF_");
+
for (auto module : design->selected_whole_modules_warn())
{
if (module->has_processes_warn())
@@ -109,6 +160,8 @@ struct CheckPass : public Pass {
if (bit.wire) wire_drivers_count[bit]++;
}
+ pool<SigBit> init_bits;
+
for (auto wire : module->wires()) {
if (wire->port_input) {
SigSpec sig = sigmap(wire);
@@ -121,9 +174,15 @@ struct CheckPass : public Pass {
if (wire->port_input && !wire->port_output)
for (auto bit : sigmap(wire))
if (bit.wire) wire_drivers_count[bit]++;
- if (noinit && wire->attributes.count("\\init")) {
- log_warning("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module), log_id(wire));
- counter++;
+ if (wire->attributes.count("\\init")) {
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ init_bits.insert(sigmap(SigBit(wire, i)));
+ if (noinit) {
+ log_warning("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module), log_id(wire));
+ counter++;
+ }
}
}
@@ -150,6 +209,26 @@ struct CheckPass : public Pass {
log_warning("%s", message.c_str());
counter++;
}
+
+ if (initdrv)
+ {
+ for (auto cell : module->cells())
+ {
+ if (fftypes.count(cell->type) == 0)
+ continue;
+
+ for (auto bit : sigmap(cell->getPort("\\Q")))
+ init_bits.erase(bit);
+ }
+
+ SigSpec init_sig(init_bits);
+ init_sig.sort_and_unify();
+
+ for (auto chunk : init_sig.chunks()) {
+ log_warning("Wire %s.%s has 'init' attribute and is not driven by an FF cell.\n", log_id(module), log_signal(chunk));
+ counter++;
+ }
+ }
}
log("found and reported %d problems.\n", counter);
diff --git a/passes/cmds/chformal.cc b/passes/cmds/chformal.cc
new file mode 100644
index 00000000..522758ea
--- /dev/null
+++ b/passes/cmds/chformal.cc
@@ -0,0 +1,282 @@
+/*
+ * 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 ChformalPass : public Pass {
+ ChformalPass() : Pass("chformal", "change formal constraints of the design") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" chformal [types] [mode] [options] [selection]\n");
+ log("\n");
+ log("Make changes to the formal constraints of the design. The [types] options\n");
+ log("the type of constraint to operate on. If none of the folling options is given,\n");
+ log("the command will operate on all constraint types:\n");
+ log("\n");
+ log(" -assert $assert cells, representing assert(...) constraints\n");
+ log(" -assume $assume cells, representing assume(...) constraints\n");
+ log(" -live $live cells, representing assert(s_eventually ...)\n");
+ log(" -fair $fair cells, representing assume(s_eventually ...)\n");
+ log(" -cover $cover cells, representing cover() statements\n");
+ log("\n");
+ log("Exactly one of the following modes must be specified:\n");
+ log("\n");
+ log(" -remove\n");
+ log(" remove the cells and thus constraints from the design\n");
+ log("\n");
+ log(" -early\n");
+ log(" bypass FFs that only delay the activation of a constraint\n");
+ log("\n");
+ log(" -delay <N>\n");
+ log(" delay activation of the constraint by <N> clock cycles\n");
+ log("\n");
+ log(" -skip <N>\n");
+ log(" ignore activation of the constraint in the first <N> clock cycles\n");
+ log("\n");
+ log(" -assert2assume\n");
+ log(" -assume2assert\n");
+ log(" -live2fair\n");
+ log(" -fair2live\n");
+ log(" change the roles of cells as indicated. this options can be combined\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool assert2assume = false;
+ bool assume2assert = false;
+ bool live2fair = false;
+ bool fair2live = false;
+
+ pool<IdString> constr_types;
+ char mode = 0;
+ int mode_arg = 0;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-assert") {
+ constr_types.insert("$assert");
+ continue;
+ }
+ if (args[argidx] == "-assume") {
+ constr_types.insert("$assume");
+ continue;
+ }
+ if (args[argidx] == "-live") {
+ constr_types.insert("$live");
+ continue;
+ }
+ if (args[argidx] == "-fair") {
+ constr_types.insert("$fair");
+ continue;
+ }
+ if (args[argidx] == "-cover") {
+ constr_types.insert("$cover");
+ continue;
+ }
+ if (mode == 0 && args[argidx] == "-remove") {
+ mode = 'r';
+ continue;
+ }
+ if (mode == 0 && args[argidx] == "-early") {
+ mode = 'e';
+ continue;
+ }
+ if (mode == 0 && args[argidx] == "-delay" && argidx+1 < args.size()) {
+ mode = 'd';
+ mode_arg = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (mode == 0 && args[argidx] == "-skip" && argidx+1 < args.size()) {
+ mode = 's';
+ mode_arg = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if ((mode == 0 || mode == 'c') && args[argidx] == "-assert2assume") {
+ assert2assume = true;
+ mode = 'c';
+ continue;
+ }
+ if ((mode == 0 || mode == 'c') && args[argidx] == "-assume2assert") {
+ assume2assert = true;
+ mode = 'c';
+ continue;
+ }
+ if ((mode == 0 || mode == 'c') && args[argidx] == "-live2fair") {
+ live2fair = true;
+ mode = 'c';
+ continue;
+ }
+ if ((mode == 0 || mode == 'c') && args[argidx] == "-fair2live") {
+ fair2live = true;
+ mode = 'c';
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (constr_types.empty()) {
+ constr_types.insert("$assert");
+ constr_types.insert("$assume");
+ constr_types.insert("$live");
+ constr_types.insert("$fair");
+ constr_types.insert("$cover");
+ }
+
+ if (mode == 0)
+ log_cmd_error("Mode option is missing.\n");
+
+ for (auto module : design->selected_modules())
+ {
+ vector<Cell*> constr_cells;
+
+ for (auto cell : module->selected_cells())
+ if (constr_types.count(cell->type))
+ constr_cells.push_back(cell);
+
+ if (mode == 'r')
+ {
+ for (auto cell : constr_cells)
+ module->remove(cell);
+ }
+ else
+ if (mode == 'e')
+ {
+ SigMap sigmap(module);
+ dict<SigBit, pair<SigBit, pair<SigBit, bool>>> ffmap;
+ pool<SigBit> init_zero, init_one;
+
+ for (auto wire : module->wires())
+ {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ SigSpec initsig = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+
+ for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) {
+ if (initval[i] == State::S0)
+ init_zero.insert(initsig[i]);
+ if (initval[i] == State::S1)
+ init_one.insert(initsig[i]);
+ }
+ }
+
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "$ff") {
+ SigSpec D = sigmap(cell->getPort("\\D"));
+ SigSpec Q = sigmap(cell->getPort("\\Q"));
+ for (int i = 0; i < GetSize(D); i++)
+ ffmap[Q[i]] = make_pair(D[i], make_pair(State::Sm, false));
+ }
+ if (cell->type == "$dff") {
+ SigSpec D = sigmap(cell->getPort("\\D"));
+ SigSpec Q = sigmap(cell->getPort("\\Q"));
+ SigSpec C = sigmap(cell->getPort("\\CLK"));
+ bool clockpol = cell->getParam("\\CLK_POLARITY").as_bool();
+ for (int i = 0; i < GetSize(D); i++)
+ ffmap[Q[i]] = make_pair(D[i], make_pair(C, clockpol));
+ }
+ }
+
+ for (auto cell : constr_cells)
+ while (true)
+ {
+ SigSpec A = sigmap(cell->getPort("\\A"));
+ SigSpec EN = sigmap(cell->getPort("\\EN"));
+
+ if (ffmap.count(A) == 0 || ffmap.count(EN) == 0)
+ break;
+
+ if (!init_zero.count(EN)) {
+ if (cell->type == "$cover") break;
+ if (cell->type.in("$assert", "$assume") && !init_one.count(A)) break;
+ }
+
+ const auto &A_map = ffmap.at(A);
+ const auto &EN_map = ffmap.at(EN);
+
+ if (A_map.second != EN_map.second)
+ break;
+
+ cell->setPort("\\A", A_map.first);
+ cell->setPort("\\EN", EN_map.first);
+ }
+ }
+ else
+ if (mode == 'd')
+ {
+ for (auto cell : constr_cells)
+ for (int i = 0; i < mode_arg; i++)
+ {
+ SigSpec orig_a = cell->getPort("\\A");
+ SigSpec orig_en = cell->getPort("\\EN");
+
+ Wire *new_a = module->addWire(NEW_ID);
+ Wire *new_en = module->addWire(NEW_ID);
+ new_en->attributes["\\init"] = State::S0;
+
+ module->addFf(NEW_ID, orig_a, new_a);
+ module->addFf(NEW_ID, orig_en, new_en);
+
+ cell->setPort("\\A", new_a);
+ cell->setPort("\\EN", new_en);
+ }
+ }
+ else
+ if (mode == 's')
+ {
+ SigSpec en = State::S1;
+
+ for (int i = 0; i < mode_arg; i++) {
+ Wire *w = module->addWire(NEW_ID);
+ w->attributes["\\init"] = State::S0;
+ module->addFf(NEW_ID, en, w);
+ en = w;
+ }
+
+ for (auto cell : constr_cells)
+ cell->setPort("\\EN", module->LogicAnd(NEW_ID, en, cell->getPort("\\EN")));
+ }
+ else
+ if (mode == 'c')
+ {
+ for (auto cell : constr_cells)
+ if (assert2assume && cell->type == "$assert")
+ cell->type = "$assume";
+ else if (assume2assert && cell->type == "$assume")
+ cell->type = "$assert";
+ else if (live2fair && cell->type == "$live")
+ cell->type = "$fair";
+ else if (fair2live && cell->type == "$fair")
+ cell->type = "$live";
+ }
+ }
+ }
+} ChformalPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/chtype.cc b/passes/cmds/chtype.cc
new file mode 100644
index 00000000..979aeadd
--- /dev/null
+++ b/passes/cmds/chtype.cc
@@ -0,0 +1,83 @@
+/*
+ * 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"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ChtypePass : public Pass {
+ ChtypePass() : Pass("chtype", "change type of cells in the design") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" chtype [options] [selection]\n");
+ log("\n");
+ log("Change the types of cells in the design.\n");
+ log("\n");
+ log(" -set <type>\n");
+ log(" set the cell type to the given type\n");
+ log("\n");
+ log(" -map <old_type> <new_type>\n");
+ log(" change cells types that match <old_type> to <new_type>\n");
+ log("\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ IdString set_type;
+ dict<IdString, IdString> map_types;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (set_type == IdString() && args[argidx] == "-set" && argidx+1 < args.size()) {
+ set_type = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-map" && argidx+2 < args.size()) {
+ IdString old_type = RTLIL::escape_id(args[++argidx]);
+ IdString new_type = RTLIL::escape_id(args[++argidx]);
+ map_types[old_type] = new_type;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ for (auto cell : module->selected_cells())
+ {
+ if (map_types.count(cell->type)) {
+ cell->type = map_types.at(cell->type);
+ continue;
+ }
+
+ if (set_type != IdString()) {
+ cell->type = set_type;
+ continue;
+ }
+ }
+ }
+ }
+} ChtypePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc
index 52611cf4..d480b79a 100644
--- a/passes/cmds/connect.cc
+++ b/passes/cmds/connect.cc
@@ -43,7 +43,7 @@ static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &
struct ConnectPass : public Pass {
ConnectPass() : Pass("connect", "create or remove connections") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -75,7 +75,7 @@ struct ConnectPass : public Pass {
log("This command does not operate on module with processes.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
RTLIL::Module *module = NULL;
for (auto &it : design->modules_) {
diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc
index c9ab226d..5a15cbba 100644
--- a/passes/cmds/connwrappers.cc
+++ b/passes/cmds/connwrappers.cc
@@ -149,8 +149,8 @@ struct ConnwrappersWorker
};
struct ConnwrappersPass : public Pass {
- ConnwrappersPass() : Pass("connwrappers", "replace undef values with defined constants") { }
- virtual void help()
+ ConnwrappersPass() : Pass("connwrappers", "match width of input-output port pairs") { }
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -172,7 +172,7 @@ struct ConnwrappersPass : public Pass {
log("The options -signed, -unsigned, and -port can be specified multiple times.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
ConnwrappersWorker worker;
diff --git a/passes/cmds/copy.cc b/passes/cmds/copy.cc
index fb863512..acd2dba5 100644
--- a/passes/cmds/copy.cc
+++ b/passes/cmds/copy.cc
@@ -26,7 +26,7 @@ PRIVATE_NAMESPACE_BEGIN
struct CopyPass : public Pass {
CopyPass() : Pass("copy", "copy modules in the design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -36,7 +36,7 @@ struct CopyPass : public Pass {
log("by this command.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
if (args.size() != 3)
log_cmd_error("Invalid number of arguments!\n");
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index 1475475c..0ec74767 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -35,7 +35,7 @@ PRIVATE_NAMESPACE_BEGIN
struct CoverPass : public Pass {
CoverPass() : Pass("cover", "print code coverage counters") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -83,7 +83,7 @@ struct CoverPass : public Pass {
log("Coverage counters are only available in Yosys for Linux.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<FILE*> out_files;
std::vector<std::string> patterns;
@@ -128,7 +128,7 @@ struct CoverPass : public Pass {
log("\n");
}
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
for (auto &it : get_coverage_data()) {
if (!patterns.empty()) {
for (auto &p : patterns)
diff --git a/passes/cmds/delete.cc b/passes/cmds/delete.cc
index 6d51d30e..f8d91ea4 100644
--- a/passes/cmds/delete.cc
+++ b/passes/cmds/delete.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct DeletePass : public Pass {
DeletePass() : Pass("delete", "delete objects in the design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -40,7 +40,7 @@ struct DeletePass : public Pass {
log("selected wires, thus 'deleting' module ports.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_input = false;
bool flag_output = false;
diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc
index e900e7b9..172addcc 100644
--- a/passes/cmds/design.cc
+++ b/passes/cmds/design.cc
@@ -17,10 +17,8 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/celltypes.h"
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+#include "frontends/ast/ast.h"
YOSYS_NAMESPACE_BEGIN
@@ -29,7 +27,7 @@ std::vector<RTLIL::Design*> pushed_designs;
struct DesignPass : public Pass {
DesignPass() : Pass("design", "save, restore and reset current design") { }
- virtual ~DesignPass() {
+ ~DesignPass() YS_OVERRIDE {
for (auto &it : saved_designs)
delete it.second;
saved_designs.clear();
@@ -37,7 +35,7 @@ struct DesignPass : public Pass {
delete it;
pushed_designs.clear();
}
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -82,13 +80,28 @@ struct DesignPass : public Pass {
log("\n");
log("Copy modules from the current design into the specified one.\n");
log("\n");
+ log("\n");
+ log(" design -import <name> [-as <new_top_name>] [selection]\n");
+ log("\n");
+ log("Import the specified design into the current design. The source design must\n");
+ log("either have a selected top module or the selection must contain exactly one\n");
+ log("module that is then used as top module for this command.\n");
+ log("\n");
+ log("\n");
+ log(" design -reset-vlog\n");
+ log("\n");
+ log("The Verilog front-end remembers defined macros and top-level declarations\n");
+ log("between calls to 'read_verilog'. This command resets this memory.\n");
+ log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool got_mode = false;
bool reset_mode = false;
+ bool reset_vlog_mode = false;
bool push_mode = false;
bool pop_mode = false;
+ bool import_mode = false;
RTLIL::Design *copy_from_design = NULL, *copy_to_design = NULL;
std::string save_name, load_name, as_name;
std::vector<RTLIL::Module*> copy_src_modules;
@@ -102,6 +115,11 @@ struct DesignPass : public Pass {
reset_mode = true;
continue;
}
+ if (!got_mode && args[argidx] == "-reset-vlog") {
+ got_mode = true;
+ reset_vlog_mode = true;
+ continue;
+ }
if (!got_mode && args[argidx] == "-push") {
got_mode = true;
push_mode = true;
@@ -146,8 +164,17 @@ struct DesignPass : public Pass {
copy_from_design = design;
continue;
}
- if (copy_from_design != NULL && args[argidx] == "-as" && argidx+1 < args.size()) {
+ if (!got_mode && args[argidx] == "-import" && argidx+1 < args.size()) {
got_mode = true;
+ import_mode = true;
+ if (saved_designs.count(args[++argidx]) == 0)
+ log_cmd_error("No saved design '%s' found!\n", args[argidx].c_str());
+ copy_from_design = saved_designs.at(args[argidx]);
+ copy_to_design = design;
+ as_name = args[argidx];
+ continue;
+ }
+ if (copy_from_design != NULL && args[argidx] == "-as" && argidx+1 < args.size()) {
as_name = args[++argidx];
continue;
}
@@ -156,10 +183,10 @@ struct DesignPass : public Pass {
if (copy_from_design != NULL)
{
- if (copy_from_design != design && argidx == args.size())
+ if (copy_from_design != design && argidx == args.size() && !import_mode)
cmd_error(args, argidx, "Missing selection.");
- RTLIL::Selection sel = design->selection_stack.back();
+ RTLIL::Selection sel;
if (argidx != args.size()) {
handle_extra_select_args(this, args, argidx, args.size(), copy_from_design);
sel = copy_from_design->selection_stack.back();
@@ -175,6 +202,17 @@ struct DesignPass : public Pass {
if (sel.selected_module(it.first))
log_cmd_error("Module %s is only partly selected.\n", RTLIL::id2cstr(it.first));
}
+
+ if (import_mode) {
+ for (auto module : copy_src_modules)
+ {
+ if (module->get_bool_attribute("\\top")) {
+ copy_src_modules.clear();
+ copy_src_modules.push_back(module);
+ break;
+ }
+ }
+ }
}
extra_args(args, argidx, design, false);
@@ -185,6 +223,68 @@ struct DesignPass : public Pass {
if (pop_mode && pushed_designs.empty())
log_cmd_error("No pushed designs.\n");
+ if (import_mode)
+ {
+ std::string prefix = RTLIL::escape_id(as_name);
+
+ pool<Module*> queue;
+ dict<IdString, IdString> done;
+
+ if (copy_to_design->modules_.count(prefix))
+ delete copy_to_design->modules_.at(prefix);
+
+ if (GetSize(copy_src_modules) != 1)
+ log_cmd_error("No top module found in source design.\n");
+
+ for (auto mod : copy_src_modules)
+ {
+ log("Importing %s as %s.\n", log_id(mod), log_id(prefix));
+
+ copy_to_design->modules_[prefix] = mod->clone();
+ copy_to_design->modules_[prefix]->name = prefix;
+ copy_to_design->modules_[prefix]->design = copy_to_design;
+ copy_to_design->modules_[prefix]->attributes.erase("\\top");
+
+ queue.insert(copy_to_design->modules_[prefix]);
+ done[mod->name] = prefix;
+ }
+
+ while (!queue.empty())
+ {
+ pool<Module*> old_queue;
+ old_queue.swap(queue);
+
+ for (auto mod : old_queue)
+ for (auto cell : mod->cells())
+ {
+ Module *fmod = copy_from_design->module(cell->type);
+
+ if (fmod == nullptr)
+ continue;
+
+ if (done.count(cell->type) == 0)
+ {
+ std::string trg_name = prefix + "." + (cell->type.c_str() + (*cell->type.c_str() == '\\'));
+
+ log("Importing %s as %s.\n", log_id(fmod), log_id(trg_name));
+
+ if (copy_to_design->modules_.count(trg_name))
+ delete copy_to_design->modules_.at(trg_name);
+
+ copy_to_design->modules_[trg_name] = fmod->clone();
+ copy_to_design->modules_[trg_name]->name = trg_name;
+ copy_to_design->modules_[trg_name]->design = copy_to_design;
+ copy_to_design->modules_[trg_name]->attributes.erase("\\top");
+
+ queue.insert(copy_to_design->modules_[trg_name]);
+ done[cell->type] = trg_name;
+ }
+
+ cell->type = done.at(cell->type);
+ }
+ }
+ }
+ else
if (copy_to_design != NULL)
{
if (!as_name.empty() && copy_src_modules.size() > 1)
@@ -196,6 +296,7 @@ struct DesignPass : public Pass {
if (copy_to_design->modules_.count(trg_name))
delete copy_to_design->modules_.at(trg_name);
+
copy_to_design->modules_[trg_name] = mod->clone();
copy_to_design->modules_[trg_name]->name = trg_name;
copy_to_design->modules_[trg_name]->design = copy_to_design;
@@ -235,19 +336,34 @@ struct DesignPass : public Pass {
design->selection_stack.push_back(RTLIL::Selection());
}
+ if (reset_mode || reset_vlog_mode || !load_name.empty() || push_mode || pop_mode)
+ {
+ for (auto node : design->verilog_packages)
+ delete node;
+ design->verilog_packages.clear();
+
+ for (auto node : design->verilog_globals)
+ delete node;
+ design->verilog_globals.clear();
+
+ design->verilog_defines.clear();
+ }
+
if (!load_name.empty() || pop_mode)
{
RTLIL::Design *saved_design = pop_mode ? pushed_designs.back() : saved_designs.at(load_name);
- if (pop_mode)
- pushed_designs.pop_back();
-
for (auto &it : saved_design->modules_)
design->add(it.second->clone());
design->selection_stack = saved_design->selection_stack;
design->selection_vars = saved_design->selection_vars;
design->selected_active_module = saved_design->selected_active_module;
+
+ if (pop_mode) {
+ delete saved_design;
+ pushed_designs.pop_back();
+ }
}
}
} DesignPass;
diff --git a/passes/cmds/edgetypes.cc b/passes/cmds/edgetypes.cc
index 7b75a009..58ed6457 100644
--- a/passes/cmds/edgetypes.cc
+++ b/passes/cmds/edgetypes.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EdgetypePass : public Pass {
EdgetypePass() : Pass("edgetypes", "list all types of edges in selection") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -35,7 +35,7 @@ struct EdgetypePass : public Pass {
log("is a 4-tuple of source and sink cell type and port name.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/cmds/logcmd.cc b/passes/cmds/logcmd.cc
index 85386f3d..522e1089 100644
--- a/passes/cmds/logcmd.cc
+++ b/passes/cmds/logcmd.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct LogPass : public Pass {
LogPass() : Pass("log", "print text and log files") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -52,7 +52,7 @@ struct LogPass : public Pass {
log(" do not append a newline\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
{
size_t argidx;
bool to_stdout = false;
diff --git a/passes/cmds/ltp.cc b/passes/cmds/ltp.cc
new file mode 100644
index 00000000..05701710
--- /dev/null
+++ b/passes/cmds/ltp.cc
@@ -0,0 +1,185 @@
+/*
+ * 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/celltypes.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct LtpWorker
+{
+ RTLIL::Design *design;
+ RTLIL::Module *module;
+ SigMap sigmap;
+
+ dict<SigBit, tuple<int, SigBit, Cell*>> bits;
+ dict<SigBit, dict<SigBit, Cell*>> bit2bits;
+ dict<SigBit, tuple<SigBit, Cell*>> bit2ff;
+
+ int maxlvl;
+ SigBit maxbit;
+ pool<SigBit> busy;
+
+ LtpWorker(RTLIL::Module *module, bool noff) : design(module->design), module(module), sigmap(module)
+ {
+ CellTypes ff_celltypes;
+
+ if (noff) {
+ ff_celltypes.setup_internals_mem();
+ ff_celltypes.setup_stdcells_mem();
+ }
+
+ for (auto wire : module->selected_wires())
+ for (auto bit : sigmap(wire))
+ bits[bit] = tuple<int, SigBit, Cell*>(-1, State::Sx, nullptr);
+
+ for (auto cell : module->selected_cells())
+ {
+ pool<SigBit> src_bits, dst_bits;
+
+ for (auto &conn : cell->connections())
+ for (auto bit : sigmap(conn.second)) {
+ if (cell->input(conn.first))
+ src_bits.insert(bit);
+ if (cell->output(conn.first))
+ dst_bits.insert(bit);
+ }
+
+ if (noff && ff_celltypes.cell_known(cell->type)) {
+ for (auto s : src_bits)
+ for (auto d : dst_bits) {
+ bit2ff[s] = tuple<SigBit, Cell*>(d, cell);
+ break;
+ }
+ continue;
+ }
+
+ for (auto s : src_bits)
+ for (auto d : dst_bits)
+ bit2bits[s][d] = cell;
+ }
+
+ maxlvl = -1;
+ maxbit = State::Sx;
+ }
+
+ void runner(SigBit bit, int level, SigBit from, Cell *via)
+ {
+ auto &bitinfo = bits.at(bit);
+
+ if (get<0>(bitinfo) >= level)
+ return;
+
+ if (busy.count(bit) > 0) {
+ log_warning("Detected loop at %s in %s\n", log_signal(bit), log_id(module));
+ return;
+ }
+
+ busy.insert(bit);
+ get<0>(bitinfo) = level;
+ get<1>(bitinfo) = from;
+ get<2>(bitinfo) = via;
+
+ if (level > maxlvl) {
+ maxlvl = level;
+ maxbit = bit;
+ }
+
+ if (bit2bits.count(bit)) {
+ for (auto &it : bit2bits.at(bit))
+ runner(it.first, level+1, bit, it.second);
+ }
+
+ busy.erase(bit);
+ }
+
+ void printpath(SigBit bit)
+ {
+ auto &bitinfo = bits.at(bit);
+ if (get<2>(bitinfo)) {
+ printpath(get<1>(bitinfo));
+ log("%5d: %s (via %s)\n", get<0>(bitinfo), log_signal(bit), log_id(get<2>(bitinfo)));
+ } else {
+ log("%5d: %s\n", get<0>(bitinfo), log_signal(bit));
+ }
+ }
+
+ void run()
+ {
+ for (auto &it : bits)
+ if (get<0>(it.second) < 0)
+ runner(it.first, 0, State::Sx, nullptr);
+
+ log("\n");
+ log("Longest topological path in %s (length=%d):\n", log_id(module), maxlvl);
+
+ if (maxlvl >= 0)
+ printpath(maxbit);
+
+ if (bit2ff.count(maxbit))
+ log("%5s: %s (via %s)\n", "ff", log_signal(get<0>(bit2ff.at(maxbit))), log_id(get<1>(bit2ff.at(maxbit))));
+ }
+};
+
+struct LtpPass : public Pass {
+ LtpPass() : Pass("ltp", "print longest topological path") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" ltp [options] [selection]\n");
+ log("\n");
+ log("This command prints the longest topological path in the design. (Only considers\n");
+ log("paths within a single module, so the design must be flattened.)\n");
+ log("\n");
+ log(" -noff\n");
+ log(" automatically exclude FF cell types\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool noff = false;
+
+ log_header(design, "Executing LTP pass (find longest path).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-noff") {
+ noff = true;
+ continue;
+ }
+ break;
+ }
+
+ extra_args(args, argidx, design);
+
+ for (Module *module : design->selected_modules())
+ {
+ if (module->has_processes_warn())
+ continue;
+
+ LtpWorker worker(module, noff);
+ worker.run();
+ }
+ }
+} LtpPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc
index 828c671d..aa6d5b6c 100644
--- a/passes/cmds/plugin.cc
+++ b/passes/cmds/plugin.cc
@@ -58,7 +58,7 @@ void load_plugin(std::string, std::vector<std::string>)
struct PluginPass : public Pass {
PluginPass() : Pass("plugin", "load and list loaded plugins") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -76,7 +76,7 @@ struct PluginPass : public Pass {
log(" List loaded plugins\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string plugin_filename;
std::vector<std::string> plugin_aliases;
diff --git a/passes/cmds/qwp.cc b/passes/cmds/qwp.cc
index 1b800b6d..1c64a7b7 100644
--- a/passes/cmds/qwp.cc
+++ b/passes/cmds/qwp.cc
@@ -778,7 +778,7 @@ struct QwpWorker
struct QwpPass : public Pass {
QwpPass() : Pass("qwp", "quadratic wirelength placer") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -808,7 +808,7 @@ struct QwpPass : public Pass {
log("dense matrix operations. It is only a toy-placer for small circuits.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
QwpConfig config;
xorshift32_state = 123456789;
@@ -835,6 +835,7 @@ struct QwpPass : public Pass {
}
if (args[argidx] == "-dump" && argidx+1 < args.size()) {
config.dump_file.open(args[++argidx], std::ofstream::trunc);
+ yosys_output_files.insert(args[argidx]);
continue;
}
break;
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index 6a002869..dce576fd 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -54,7 +54,7 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
struct RenamePass : public Pass {
RenamePass() : Pass("rename", "rename object in the design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -81,7 +81,7 @@ struct RenamePass : public Pass {
log("Rename top module.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string pattern_prefix = "_", pattern_suffix = "_";
bool flag_enumerate = false;
diff --git a/passes/cmds/scatter.cc b/passes/cmds/scatter.cc
index f083e1f6..7123ba9f 100644
--- a/passes/cmds/scatter.cc
+++ b/passes/cmds/scatter.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ScatterPass : public Pass {
ScatterPass() : Pass("scatter", "add additional intermediate nets") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -41,7 +41,7 @@ struct ScatterPass : public Pass {
log("Use the opt_clean command to get rid of the additional nets.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
CellTypes ct(design);
extra_args(args, 1, design);
diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc
index bb6d7447..99f4fbae 100644
--- a/passes/cmds/scc.cc
+++ b/passes/cmds/scc.cc
@@ -163,16 +163,8 @@ struct SccWorker
}
for (auto cell : workQueue)
- cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);
-
- labelCounter = 0;
- cellLabels.clear();
-
- while (workQueue.size() > 0)
{
- RTLIL::Cell *cell = *workQueue.begin();
- log_assert(cellStack.size() == 0);
- cellDepth.clear();
+ cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);
if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
log("Found an SCC:");
@@ -183,6 +175,16 @@ struct SccWorker
sccList.push_back(scc);
log("\n");
}
+ }
+
+ labelCounter = 0;
+ cellLabels.clear();
+
+ while (!workQueue.empty())
+ {
+ RTLIL::Cell *cell = *workQueue.begin();
+ log_assert(cellStack.size() == 0);
+ cellDepth.clear();
run(cell, 0, maxDepth);
}
@@ -216,7 +218,7 @@ struct SccWorker
struct SccPass : public Pass {
SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -244,20 +246,18 @@ struct SccPass : public Pass {
log(" are assumed to be bidirectional 'inout' ports.\n");
log("\n");
log(" -set_attr <name> <value>\n");
- log(" -set_cell_attr <name> <value>\n");
- log(" -set_wire_attr <name> <value>\n");
- log(" set the specified attribute on all cells and/or wires that are part of\n");
- log(" a logic loop. the special token {} in the value is replaced with a\n");
- log(" unique identifier for the logic loop.\n");
+ log(" set the specified attribute on all cells that are part of a logic\n");
+ log(" loop. the special token {} in the value is replaced with a unique\n");
+ log(" identifier for the logic loop.\n");
log("\n");
log(" -select\n");
log(" replace the current selection with a selection of all cells and wires\n");
log(" that are part of a found logic loop\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- std::map<std::string, std::string> setCellAttr, setWireAttr;
+ std::map<std::string, std::string> setAttr;
bool allCellTypes = false;
bool selectMode = false;
bool nofeedbackMode = false;
@@ -285,18 +285,7 @@ struct SccPass : public Pass {
continue;
}
if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
- setCellAttr[args[argidx+1]] = args[argidx+2];
- setWireAttr[args[argidx+1]] = args[argidx+2];
- argidx += 2;
- continue;
- }
- if (args[argidx] == "-set_cell_attr" && argidx+2 < args.size()) {
- setCellAttr[args[argidx+1]] = args[argidx+2];
- argidx += 2;
- continue;
- }
- if (args[argidx] == "-set_wire_attr" && argidx+2 < args.size()) {
- setWireAttr[args[argidx+1]] = args[argidx+2];
+ setAttr[args[argidx+1]] = args[argidx+2];
argidx += 2;
continue;
}
@@ -309,9 +298,6 @@ struct SccPass : public Pass {
int origSelectPos = design->selection_stack.size() - 1;
extra_args(args, argidx, design);
- if (setCellAttr.size() > 0 || setWireAttr.size() > 0)
- log_cmd_error("The -set*_attr options are not implemented at the moment!\n");
-
RTLIL::Selection newSelection(false);
int scc_counter = 0;
@@ -319,7 +305,33 @@ struct SccPass : public Pass {
if (design->selected(mod_it.second))
{
SccWorker worker(design, mod_it.second, nofeedbackMode, allCellTypes, maxDepth);
- scc_counter += GetSize(worker.sccList);
+
+ if (!setAttr.empty())
+ {
+ for (const auto &cells : worker.sccList)
+ {
+ for (auto attr : setAttr)
+ {
+ IdString attr_name(RTLIL::escape_id(attr.first));
+ string attr_valstr = attr.second;
+ string index = stringf("%d", scc_counter);
+
+ for (size_t pos = 0; (pos = attr_valstr.find("{}", pos)) != string::npos; pos += index.size())
+ attr_valstr.replace(pos, 2, index);
+
+ Const attr_value(attr_valstr);
+
+ for (auto cell : cells)
+ cell->attributes[attr_name] = attr_value;
+ }
+
+ scc_counter++;
+ }
+ }
+ else
+ {
+ scc_counter += GetSize(worker.sccList);
+ }
if (selectMode)
worker.select(newSelection);
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index d2e1a2e2..d97aa2b3 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -760,6 +760,9 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
if (!design->selected_active_module.empty()) {
arg_mod = design->selected_active_module;
arg_memb = arg;
+ } else
+ if (GetSize(arg) >= 2 && arg[0] >= 'a' && arg[0] <= 'z' && arg[1] == ':') {
+ arg_mod = "*", arg_memb = arg;
} else {
size_t pos = arg.find('/');
if (pos == std::string::npos) {
@@ -947,7 +950,7 @@ PRIVATE_NAMESPACE_BEGIN
struct SelectPass : public Pass {
SelectPass() : Pass("select", "modify and view the list of selected objects") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -961,7 +964,7 @@ struct SelectPass : public Pass {
log("list of selected objects.\n");
log("\n");
log("Note that many commands support an optional [selection] argument that can be\n");
- log("used to override the global selection for the command. The syntax of this\n");
+ log("used to YS_OVERRIDE the global selection for the command. The syntax of this\n");
log("optional argument is identical to the syntax of the <selection> argument\n");
log("described here.\n");
log("\n");
@@ -1164,7 +1167,7 @@ struct SelectPass : public Pass {
log(" select */t:SWITCH %%x:+[GATE] */t:SWITCH %%d\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool add_mode = false;
bool del_mode = false;
@@ -1263,6 +1266,7 @@ struct SelectPass : public Pass {
log_cmd_error("Option -read can not be combined with a selection expression.\n");
std::ifstream f(read_file);
+ yosys_input_files.insert(read_file);
if (f.fail())
log_error("Can't open '%s' for reading: %s\n", read_file.c_str(), strerror(errno));
@@ -1331,6 +1335,7 @@ struct SelectPass : public Pass {
FILE *f = NULL;
if (!write_file.empty()) {
f = fopen(write_file.c_str(), "w");
+ yosys_output_files.insert(write_file);
if (f == NULL)
log_error("Can't open '%s' for writing: %s\n", write_file.c_str(), strerror(errno));
}
@@ -1465,7 +1470,7 @@ struct SelectPass : public Pass {
struct CdPass : public Pass {
CdPass() : Pass("cd", "a shortcut for 'select -module <name>'") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1482,17 +1487,53 @@ struct CdPass : public Pass {
log("\n");
log(" cd ..\n");
log("\n");
+ log("Remove trailing substrings that start with '.' in current module name until\n");
+ log("the name of a module in the current design is generated, then switch to that\n");
+ log("module. Otherwise clear the current selection.\n");
+ log("\n");
+ log(" cd\n");
+ log("\n");
log("This is just a shortcut for 'select -clear'.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- if (args.size() != 2)
+ if (args.size() != 1 && args.size() != 2)
log_cmd_error("Invalid number of arguments.\n");
- if (args[1] == "..") {
+ if (args.size() == 1 || args[1] == "/") {
+ design->selection_stack.back() = RTLIL::Selection(true);
+ design->selected_active_module = std::string();
+ return;
+ }
+
+ if (args[1] == "..")
+ {
+ string modname = design->selected_active_module;
+
design->selection_stack.back() = RTLIL::Selection(true);
design->selected_active_module = std::string();
+
+ while (1)
+ {
+ size_t pos = modname.rfind('.');
+
+ if (pos == string::npos)
+ break;
+
+ modname = modname.substr(0, pos);
+ Module *mod = design->module(modname);
+
+ if (mod == nullptr)
+ continue;
+
+ design->selected_active_module = modname;
+ design->selection_stack.back() = RTLIL::Selection();
+ select_filter_active_mod(design, design->selection_stack.back());
+ design->selection_stack.back().optimize(design);
+ return;
+ }
+
return;
}
@@ -1537,7 +1578,7 @@ static void log_matches(const char *title, Module *module, T list)
struct LsPass : public Pass {
LsPass() : Pass("ls", "list modules or objects in modules") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1548,7 +1589,7 @@ struct LsPass : public Pass {
log("When an active module is selected, this prints a list of objects in the module.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx = 1;
extra_args(args, argidx, design);
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index 689e3148..d38a6b3d 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -56,7 +56,7 @@ static void do_setunset(dict<RTLIL::IdString, RTLIL::Const> &attrs, const std::v
struct SetattrPass : public Pass {
SetattrPass() : Pass("setattr", "set/unset attributes on objects") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -69,7 +69,7 @@ struct SetattrPass : public Pass {
log("instead of objects within modules.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<setunset_t> setunset_list;
bool flag_mod = false;
@@ -130,7 +130,7 @@ struct SetattrPass : public Pass {
struct SetparamPass : public Pass {
SetparamPass() : Pass("setparam", "set/unset parameters on objects") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -142,7 +142,7 @@ struct SetparamPass : public Pass {
log("The -type option can be used to change the cell type of the selected cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
vector<setunset_t> setunset_list;
string new_cell_type;
@@ -188,7 +188,7 @@ struct SetparamPass : public Pass {
struct ChparamPass : public Pass {
ChparamPass() : Pass("chparam", "re-evaluate modules with new parameters") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -203,7 +203,7 @@ struct ChparamPass : public Pass {
log("List the available parameters of the selected modules.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<setunset_t> setunset_list;
dict<RTLIL::IdString, RTLIL::Const> new_parameters;
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index 26b2eb87..a1dfa9b5 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -23,33 +23,82 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+#define MODE_ZERO 0
+#define MODE_ONE 1
+#define MODE_UNDEF 2
+#define MODE_RANDOM 3
+#define MODE_ANYSEQ 4
+#define MODE_ANYCONST 5
+
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
+static RTLIL::Wire * add_wire(RTLIL::Module *module, std::string name, int width, bool flag_input, bool flag_output)
+{
+ RTLIL::Wire *wire = NULL;
+ name = RTLIL::escape_id(name);
+
+ if (module->count_id(name) != 0)
+ {
+ log("Module %s already has such an object %s.\n", module->name.c_str(), name.c_str());
+ name += "$";
+ return add_wire(module, name, width, flag_input, flag_output);
+ }
+ else
+ {
+ wire = module->addWire(name, width);
+ wire->port_input = flag_input;
+ wire->port_output = flag_output;
+
+ if (flag_input || flag_output) {
+ wire->port_id = module->wires_.size();
+ module->fixup_ports();
+ }
+
+ log("Added wire %s to module %s.\n", name.c_str(), module->name.c_str());
+ }
+
+ return wire;
+}
+
struct SetundefWorker
{
int next_bit_mode;
uint32_t next_bit_state;
+ vector<SigSpec*> siglist;
RTLIL::State next_bit()
{
- if (next_bit_mode == 0)
+ if (next_bit_mode == MODE_ZERO)
return RTLIL::State::S0;
- if (next_bit_mode == 1)
+ if (next_bit_mode == MODE_ONE)
return RTLIL::State::S1;
- // xorshift32
- next_bit_state ^= next_bit_state << 13;
- next_bit_state ^= next_bit_state >> 17;
- next_bit_state ^= next_bit_state << 5;
- log_assert(next_bit_state != 0);
+ if (next_bit_mode == MODE_UNDEF)
+ return RTLIL::State::Sx;
+
+ if (next_bit_mode == MODE_RANDOM)
+ {
+ // xorshift32
+ next_bit_state ^= next_bit_state << 13;
+ next_bit_state ^= next_bit_state >> 17;
+ next_bit_state ^= next_bit_state << 5;
+ log_assert(next_bit_state != 0);
- return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1;
+ return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1;
+ }
+
+ log_abort();
}
void operator()(RTLIL::SigSpec &sig)
{
+ if (next_bit_mode == MODE_ANYSEQ || next_bit_mode == MODE_ANYCONST) {
+ siglist.push_back(&sig);
+ return;
+ }
+
for (auto &bit : sig)
if (bit.wire == NULL && bit.data > RTLIL::State::S1)
bit = next_bit();
@@ -58,23 +107,35 @@ struct SetundefWorker
struct SetundefPass : public Pass {
SetundefPass() : Pass("setundef", "replace undef values with defined constants") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" setundef [options] [selection]\n");
log("\n");
- log("This command replaced undef (x) constants with defined (0/1) constants.\n");
+ log("This command replaces undef (x) constants with defined (0/1) constants.\n");
log("\n");
log(" -undriven\n");
log(" also set undriven nets to constant values\n");
log("\n");
+ log(" -expose\n");
+ log(" also expose undriven nets as inputs (use with -undriven)\n");
+ log("\n");
log(" -zero\n");
log(" replace with bits cleared (0)\n");
log("\n");
log(" -one\n");
log(" replace with bits set (1)\n");
log("\n");
+ log(" -undef\n");
+ log(" replace with undef (x) bits, may be used with -undriven\n");
+ log("\n");
+ log(" -anyseq\n");
+ log(" replace with $anyseq drivers (for formal)\n");
+ log("\n");
+ log(" -anyconst\n");
+ log(" replace with $anyconst drivers (for formal)\n");
+ log("\n");
log(" -random <seed>\n");
log(" replace with random bits using the specified integer als seed\n");
log(" value for the random number generator.\n");
@@ -83,13 +144,16 @@ struct SetundefPass : public Pass {
log(" also create/update init values for flip-flops\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool got_value = false;
bool undriven_mode = false;
+ bool expose_mode = false;
bool init_mode = false;
SetundefWorker worker;
+ log_header(design, "Executing SETUNDEF pass (replace undef values with defined constants).\n");
+
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
@@ -97,14 +161,38 @@ struct SetundefPass : public Pass {
undriven_mode = true;
continue;
}
+ if (args[argidx] == "-expose") {
+ expose_mode = true;
+ continue;
+ }
if (args[argidx] == "-zero") {
got_value = true;
- worker.next_bit_mode = 0;
+ worker.next_bit_mode = MODE_ZERO;
+ worker.next_bit_state = 0;
continue;
}
if (args[argidx] == "-one") {
got_value = true;
- worker.next_bit_mode = 1;
+ worker.next_bit_mode = MODE_ONE;
+ worker.next_bit_state = 0;
+ continue;
+ }
+ if (args[argidx] == "-anyseq") {
+ got_value = true;
+ worker.next_bit_mode = MODE_ANYSEQ;
+ worker.next_bit_state = 0;
+ continue;
+ }
+ if (args[argidx] == "-anyconst") {
+ got_value = true;
+ worker.next_bit_mode = MODE_ANYCONST;
+ worker.next_bit_state = 0;
+ continue;
+ }
+ if (args[argidx] == "-undef") {
+ got_value = true;
+ worker.next_bit_mode = MODE_UNDEF;
+ worker.next_bit_state = 0;
continue;
}
if (args[argidx] == "-init") {
@@ -113,7 +201,7 @@ struct SetundefPass : public Pass {
}
if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
got_value = true;
- worker.next_bit_mode = 2;
+ worker.next_bit_mode = MODE_RANDOM;
worker.next_bit_state = atoi(args[++argidx].c_str()) + 1;
for (int i = 0; i < 10; i++)
worker.next_bit();
@@ -123,8 +211,20 @@ struct SetundefPass : public Pass {
}
extra_args(args, argidx, design);
+ if (!got_value && expose_mode) {
+ log("Using default as -undef with -expose.\n");
+ got_value = true;
+ worker.next_bit_mode = MODE_UNDEF;
+ worker.next_bit_state = 0;
+ }
+
+ if (expose_mode && !undriven_mode)
+ log_cmd_error("Option -expose must be used with option -undriven.\n");
if (!got_value)
- log_cmd_error("One of the options -zero, -one, or -random <seed> must be specified.\n");
+ log_cmd_error("One of the options -zero, -one, -anyseq, -anyconst, or -random <seed> must be specified.\n");
+
+ if (init_mode && (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST))
+ log_cmd_error("The options -init and -anyseq / -anyconst are exclusive.\n");
for (auto module : design->selected_modules())
{
@@ -133,25 +233,103 @@ struct SetundefPass : public Pass {
if (!module->processes.empty())
log_error("The 'setundef' command can't operate in -undriven mode on modules with processes. Run 'proc' first.\n");
- SigMap sigmap(module);
- SigPool undriven_signals;
+ if (expose_mode)
+ {
+ SigMap sigmap(module);
+ dict<SigBit, bool> wire_drivers;
+ pool<SigBit> used_wires;
+ SigPool undriven_signals;
+
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections()) {
+ SigSpec sig = sigmap(conn.second);
+ if (cell->input(conn.first))
+ for (auto bit : sig)
+ if (bit.wire)
+ used_wires.insert(bit);
+ if (cell->output(conn.first))
+ for (int i = 0; i < GetSize(sig); i++)
+ if (sig[i].wire)
+ wire_drivers[sig[i]] = true;
+ }
+
+ for (auto wire : module->wires()) {
+ if (wire->port_input) {
+ SigSpec sig = sigmap(wire);
+ for (int i = 0; i < GetSize(sig); i++)
+ wire_drivers[sig[i]] = true;
+ }
+ if (wire->port_output) {
+ SigSpec sig = sigmap(wire);
+ for (auto bit : sig)
+ if (bit.wire)
+ used_wires.insert(bit);
+ }
+ }
- for (auto &it : module->wires_)
- if (!it.second->port_input)
+ pool<RTLIL::Wire*> undriven_wires;
+ for (auto bit : used_wires)
+ if (!wire_drivers.count(bit))
+ undriven_wires.insert(bit.wire);
+
+ for (auto &it : undriven_wires)
+ undriven_signals.add(sigmap(it));
+
+ for (auto &it : undriven_wires)
+ if (it->port_input)
+ undriven_signals.del(sigmap(it));
+
+ CellTypes ct(design);
+ for (auto &it : module->cells_)
+ for (auto &conn : it.second->connections())
+ if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first))
+ undriven_signals.del(sigmap(conn.second));
+
+ RTLIL::SigSpec sig = undriven_signals.export_all();
+ for (auto &c : sig.chunks()) {
+ RTLIL::Wire * wire;
+ if (c.wire->width == c.width) {
+ wire = c.wire;
+ wire->port_input = true;
+ } else {
+ string name = c.wire->name.str() + "$[" + std::to_string(c.width + c.offset) + ":" + std::to_string(c.offset) + "]";
+ wire = add_wire(module, name, c.width, true, false);
+ module->connect(RTLIL::SigSig(c, wire));
+ }
+ log("Exposing undriven wire %s as input.\n", wire->name.c_str());
+ }
+ module->fixup_ports();
+ }
+ else
+ {
+ SigMap sigmap(module);
+ SigPool undriven_signals;
+
+ for (auto &it : module->wires_)
undriven_signals.add(sigmap(it.second));
- CellTypes ct(design);
- for (auto &it : module->cells_)
- for (auto &conn : it.second->connections())
- if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first))
- undriven_signals.del(sigmap(conn.second));
-
- RTLIL::SigSpec sig = undriven_signals.export_all();
- for (auto &c : sig.chunks()) {
- RTLIL::SigSpec bits;
- for (int i = 0; i < c.width; i++)
- bits.append(worker.next_bit());
- module->connect(RTLIL::SigSig(c, bits));
+ for (auto &it : module->wires_)
+ if (it.second->port_input)
+ undriven_signals.del(sigmap(it.second));
+
+ CellTypes ct(design);
+ for (auto &it : module->cells_)
+ for (auto &conn : it.second->connections())
+ if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first))
+ undriven_signals.del(sigmap(conn.second));
+
+ RTLIL::SigSpec sig = undriven_signals.export_all();
+ for (auto &c : sig.chunks()) {
+ RTLIL::SigSpec bits;
+ if (worker.next_bit_mode == MODE_ANYSEQ)
+ bits = module->Anyseq(NEW_ID, c.width);
+ else if (worker.next_bit_mode == MODE_ANYCONST)
+ bits = module->Anyconst(NEW_ID, c.width);
+ else
+ for (int i = 0; i < c.width; i++)
+ bits.append(worker.next_bit());
+ module->connect(RTLIL::SigSig(c, bits));
+ }
}
}
@@ -236,6 +414,35 @@ struct SetundefPass : public Pass {
}
module->rewrite_sigspecs(worker);
+
+ if (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST)
+ {
+ vector<SigSpec*> siglist;
+ siglist.swap(worker.siglist);
+
+ for (auto sigptr : siglist)
+ {
+ SigSpec &sig = *sigptr;
+ int cursor = 0;
+
+ while (cursor < GetSize(sig))
+ {
+ int width = 0;
+ while (cursor+width < GetSize(sig) && sig[cursor+width] == State::Sx)
+ width++;
+
+ if (width > 0) {
+ if (worker.next_bit_mode == MODE_ANYSEQ)
+ sig.replace(cursor, module->Anyseq(NEW_ID, width));
+ else
+ sig.replace(cursor, module->Anyconst(NEW_ID, width));
+ cursor += width;
+ } else {
+ cursor++;
+ }
+ }
+ }
+ }
}
}
} SetundefPass;
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index 3a3939a8..a4887324 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -30,6 +30,10 @@
# include <readline/readline.h>
#endif
+#ifdef YOSYS_ENABLE_EDITLINE
+# include <editline/readline.h>
+#endif
+
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -569,7 +573,7 @@ struct ShowWorker
struct ShowPass : public Pass {
ShowPass() : Pass("show", "generate schematics using graphviz") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -580,6 +584,7 @@ struct ShowPass : public Pass {
log("\n");
log(" -viewer <viewer>\n");
log(" Run the specified command with the graphics file as parameter.\n");
+ log(" On Windows, this pauses yosys until the viewer exits.\n");
log("\n");
log(" -format <format>\n");
log(" Generate a graphics file in the specified format. Use 'dot' to just\n");
@@ -641,7 +646,7 @@ struct ShowPass : public Pass {
log(" do not add the module name as graph title to the dot file\n");
log("\n");
log("When no <format> is specified, 'dot' is used. When no <format> and <viewer> is\n");
- log("specified, 'xdot' is used to display the schematic.\n");
+ log("specified, 'xdot' is used to display the schematic (POSIX systems only).\n");
log("\n");
log("The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',\n");
log("unless another prefix is specified using -prefix <prefix>.\n");
@@ -651,7 +656,7 @@ struct ShowPass : public Pass {
log("the 'show' command is executed.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Generating Graphviz representation of design.\n");
log_push();
@@ -677,6 +682,7 @@ struct ShowPass : public Pass {
bool flag_enum = false;
bool flag_abbreviate = true;
bool flag_notitle = false;
+ bool custom_prefix = false;
RTLIL::IdString colorattr;
size_t argidx;
@@ -693,6 +699,7 @@ struct ShowPass : public Pass {
}
if (arg == "-prefix" && argidx+1 < args.size()) {
prefix = args[++argidx];
+ custom_prefix = true;
continue;
}
if (arg == "-color" && argidx+2 < args.size()) {
@@ -778,6 +785,7 @@ struct ShowPass : public Pass {
for (auto filename : libfiles) {
std::ifstream f;
f.open(filename.c_str());
+ yosys_input_files.insert(filename);
if (f.fail())
log_error("Can't open lib file `%s'.\n", filename.c_str());
RTLIL::Design *lib = new RTLIL::Design;
@@ -793,6 +801,8 @@ struct ShowPass : public Pass {
log("Writing dot description to `%s'.\n", dot_file.c_str());
FILE *f = fopen(dot_file.c_str(), "w");
+ if (custom_prefix)
+ yosys_output_files.insert(dot_file);
if (f == NULL) {
for (auto lib : libs)
delete lib;
@@ -808,14 +818,30 @@ struct ShowPass : public Pass {
log_cmd_error("Nothing there to show.\n");
if (format != "dot" && !format.empty()) {
- std::string cmd = stringf("dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'", format.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str(), out_file.c_str());
+ #ifdef _WIN32
+ // system()/cmd.exe does not understand single quotes on Windows.
+ #define DOT_CMD "dot -T%s \"%s\" > \"%s.new\" && move \"%s.new\" \"%s\""
+ #else
+ #define DOT_CMD "dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'"
+ #endif
+ std::string cmd = stringf(DOT_CMD, format.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str(), out_file.c_str());
+ #undef DOT_CMD
log("Exec: %s\n", cmd.c_str());
if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
}
if (!viewer_exe.empty()) {
- std::string cmd = stringf("%s '%s' &", viewer_exe.c_str(), out_file.c_str());
+ #ifdef _WIN32
+ // system()/cmd.exe does not understand single quotes nor
+ // background tasks on Windows. So we have to pause yosys
+ // until the viewer exits.
+ #define VIEW_CMD "%s \"%s\""
+ #else
+ #define VIEW_CMD "%s '%s' &"
+ #endif
+ std::string cmd = stringf(VIEW_CMD, viewer_exe.c_str(), out_file.c_str());
+ #undef VIEW_CMD
log("Exec: %s\n", cmd.c_str());
if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc
index 7418ec4d..bafafca4 100644
--- a/passes/cmds/splice.cc
+++ b/passes/cmds/splice.cc
@@ -247,7 +247,7 @@ struct SpliceWorker
struct SplicePass : public Pass {
SplicePass() : Pass("splice", "create explicit splicing cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -288,7 +288,7 @@ struct SplicePass : public Pass {
log("by selected wires are rewired.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool sel_by_cell = false;
bool sel_by_wire = false;
diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc
index 14eeb066..f5a1f17b 100644
--- a/passes/cmds/splitnets.cc
+++ b/passes/cmds/splitnets.cc
@@ -37,14 +37,20 @@ struct SplitnetsWorker
new_wire_name += format.substr(0, 1);
if (width > 1) {
- new_wire_name += stringf("%d", offset+width-1);
+ if (wire->upto)
+ new_wire_name += stringf("%d", wire->start_offset+wire->width-(offset+width)-1);
+ else
+ new_wire_name += stringf("%d", wire->start_offset+offset+width-1);
if (format.size() > 2)
new_wire_name += format.substr(2, 1);
else
new_wire_name += ":";
}
- new_wire_name += stringf("%d", offset);
+ if (wire->upto)
+ new_wire_name += stringf("%d", wire->start_offset+wire->width-offset-1);
+ else
+ new_wire_name += stringf("%d", wire->start_offset+offset);
if (format.size() > 1)
new_wire_name += format.substr(1, 1);
@@ -81,7 +87,7 @@ struct SplitnetsWorker
struct SplitnetsPass : public Pass {
SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -103,7 +109,7 @@ struct SplitnetsPass : public Pass {
log(" and split nets so that no driver drives only part of a net.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_ports = false;
bool flag_driver = false;
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 362a0edf..54f4ea81 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -112,7 +112,7 @@ struct statdata_t
"$lut", "$and", "$or", "$xor", "$xnor",
"$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
"$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
- "$add", "$sub", "$mul", "$div", "$mod", "$pow")) {
+ "$add", "$sub", "$mul", "$div", "$mod", "$pow", "$alu")) {
int width_a = it.second->hasPort("\\A") ? GetSize(it.second->getPort("\\A")) : 0;
int width_b = it.second->hasPort("\\B") ? GetSize(it.second->getPort("\\B")) : 0;
int width_y = it.second->hasPort("\\Y") ? GetSize(it.second->getPort("\\Y")) : 0;
@@ -142,7 +142,7 @@ struct statdata_t
}
}
- void log_data()
+ void log_data(RTLIL::IdString mod_name, bool top_mod)
{
log(" Number of wires: %6d\n", num_wires);
log(" Number of wire bits: %6d\n", num_wire_bits);
@@ -163,7 +163,7 @@ struct statdata_t
if (area != 0) {
log("\n");
- log(" Chip area for this module: %f\n", area);
+ log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area);
}
}
};
@@ -190,6 +190,7 @@ void read_liberty_cellarea(dict<IdString, double> &cell_area, string liberty_fil
{
std::ifstream f;
f.open(liberty_file.c_str());
+ yosys_input_files.insert(liberty_file);
if (f.fail())
log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
LibertyParser libparser(f);
@@ -208,7 +209,7 @@ void read_liberty_cellarea(dict<IdString, double> &cell_area, string liberty_fil
struct StatPass : public Pass {
StatPass() : Pass("stat", "print some statistics") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -230,7 +231,7 @@ struct StatPass : public Pass {
log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Printing statistics.\n");
@@ -274,7 +275,7 @@ struct StatPass : public Pass {
log("\n");
log("=== %s%s ===\n", RTLIL::id2cstr(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)");
log("\n");
- data.log_data();
+ data.log_data(mod->name, false);
}
if (top_mod != NULL && GetSize(mod_stat) > 1)
@@ -287,7 +288,7 @@ struct StatPass : public Pass {
statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0);
log("\n");
- data.log_data();
+ data.log_data(top_mod->name, true);
}
log("\n");
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
index 3db2dbf0..ff80f385 100644
--- a/passes/cmds/tee.cc
+++ b/passes/cmds/tee.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct TeePass : public Pass {
TeePass() : Pass("tee", "redirect command output to file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -49,7 +49,7 @@ struct TeePass : public Pass {
log(" Add/subract INT from the -v setting for this command.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<FILE*> backup_log_files, files_to_close;
int backup_log_verbose_level = log_verbose_level;
@@ -65,6 +65,7 @@ struct TeePass : public Pass {
if ((args[argidx] == "-o" || args[argidx] == "-a") && argidx+1 < args.size()) {
const char *open_mode = args[argidx] == "-o" ? "w" : "a+";
FILE *f = fopen(args[++argidx].c_str(), open_mode);
+ yosys_input_files.insert(args[argidx]);
if (f == NULL) {
for (auto cf : files_to_close)
fclose(cf);
diff --git a/passes/cmds/torder.cc b/passes/cmds/torder.cc
index 56223610..3c0eac8d 100644
--- a/passes/cmds/torder.cc
+++ b/passes/cmds/torder.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct TorderPass : public Pass {
TorderPass() : Pass("torder", "print cells in topological order") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -43,7 +43,7 @@ struct TorderPass : public Pass {
log(" are not used in topological sorting. this option deactivates that.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool noautostop = false;
dict<IdString, pool<IdString>> stop_db;
diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc
index 1a5f873f..f5305cde 100644
--- a/passes/cmds/trace.cc
+++ b/passes/cmds/trace.cc
@@ -25,34 +25,34 @@ PRIVATE_NAMESPACE_BEGIN
struct TraceMonitor : public RTLIL::Monitor
{
- virtual void notify_module_add(RTLIL::Module *module) YS_OVERRIDE
+ void notify_module_add(RTLIL::Module *module) YS_OVERRIDE
{
log("#TRACE# Module add: %s\n", log_id(module));
}
- virtual void notify_module_del(RTLIL::Module *module) YS_OVERRIDE
+ void notify_module_del(RTLIL::Module *module) YS_OVERRIDE
{
log("#TRACE# Module delete: %s\n", log_id(module));
}
- virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE
+ void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE
{
log("#TRACE# Cell connect: %s.%s.%s = %s (was: %s)\n", log_id(cell->module), log_id(cell), log_id(port), log_signal(sig), log_signal(old_sig));
}
- virtual void notify_connect(RTLIL::Module *module, const RTLIL::SigSig &sigsig) YS_OVERRIDE
+ void notify_connect(RTLIL::Module *module, const RTLIL::SigSig &sigsig) YS_OVERRIDE
{
log("#TRACE# Connection in module %s: %s = %s\n", log_id(module), log_signal(sigsig.first), log_signal(sigsig.second));
}
- virtual void notify_connect(RTLIL::Module *module, const std::vector<RTLIL::SigSig> &sigsig_vec) YS_OVERRIDE
+ void notify_connect(RTLIL::Module *module, const std::vector<RTLIL::SigSig> &sigsig_vec) YS_OVERRIDE
{
log("#TRACE# New connections in module %s:\n", log_id(module));
for (auto &sigsig : sigsig_vec)
log("## %s = %s\n", log_signal(sigsig.first), log_signal(sigsig.second));
}
- virtual void notify_blackout(RTLIL::Module *module) YS_OVERRIDE
+ void notify_blackout(RTLIL::Module *module) YS_OVERRIDE
{
log("#TRACE# Blackout in module %s:\n", log_id(module));
}
@@ -60,7 +60,7 @@ struct TraceMonitor : public RTLIL::Monitor
struct TracePass : public Pass {
TracePass() : Pass("trace", "redirect command output to file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -70,7 +70,7 @@ struct TracePass : public Pass {
log("the design in real time.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -95,4 +95,3 @@ struct TracePass : public Pass {
} TracePass;
PRIVATE_NAMESPACE_END
-
diff --git a/passes/cmds/write_file.cc b/passes/cmds/write_file.cc
index b7826593..9613b462 100644
--- a/passes/cmds/write_file.cc
+++ b/passes/cmds/write_file.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct WriteFileFrontend : public Frontend {
WriteFileFrontend() : Frontend("=write_file", "write a text to a file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -44,7 +44,7 @@ struct WriteFileFrontend : public Frontend {
log(" EOT\n");
log("\n");
}
- virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design*)
+ void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
{
bool append_mode = false;
std::string output_filename;
@@ -67,6 +67,7 @@ struct WriteFileFrontend : public Frontend {
extra_args(f, filename, args, argidx);
FILE *of = fopen(output_filename.c_str(), append_mode ? "a" : "w");
+ yosys_output_files.insert(output_filename);
char buffer[64 * 1024];
int bytes;
diff --git a/passes/equiv/equiv_add.cc b/passes/equiv/equiv_add.cc
index 0494a724..71599f46 100644
--- a/passes/equiv/equiv_add.cc
+++ b/passes/equiv/equiv_add.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EquivAddPass : public Pass {
EquivAddPass() : Pass("equiv_add", "add a $equiv cell") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -39,7 +39,7 @@ struct EquivAddPass : public Pass {
log("This command adds $equiv cells for the ports of the specified cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
bool try_mode = false;
diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc
index c958c3de..bcc68d6d 100644
--- a/passes/equiv/equiv_induct.cc
+++ b/passes/equiv/equiv_induct.cc
@@ -162,7 +162,7 @@ struct EquivInductWorker
struct EquivInductPass : public Pass {
EquivInductPass() : Pass("equiv_induct", "proving $equiv cells using temporal induction") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -192,7 +192,7 @@ struct EquivInductPass : public Pass {
log("after reset.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
int success_counter = 0;
bool model_undef = false;
diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc
index 40ca4262..b1f88d55 100644
--- a/passes/equiv/equiv_make.cc
+++ b/passes/equiv/equiv_make.cc
@@ -260,11 +260,11 @@ struct EquivMakeWorker
for (int i = 0; i < wire->width; i++) {
if (undriven_bits.count(assign_map(SigBit(gold_wire, i)))) {
- log(" Skipping signal bit %d: undriven on gold side.\n", i);
+ log(" Skipping signal bit %s [%d]: undriven on gold side.\n", id2cstr(gold_wire->name), i);
continue;
}
if (undriven_bits.count(assign_map(SigBit(gate_wire, i)))) {
- log(" Skipping signal bit %d: undriven on gate side.\n", i);
+ log(" Skipping signal bit %s [%d]: undriven on gate side.\n", id2cstr(gate_wire->name), i);
continue;
}
equiv_mod->addEquiv(NEW_ID, SigSpec(gold_wire, i), SigSpec(gate_wire, i), SigSpec(wire, i));
@@ -390,7 +390,7 @@ struct EquivMakeWorker
struct EquivMakePass : public Pass {
EquivMakePass() : Pass("equiv_make", "prepare a circuit for equivalence checking") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -415,7 +415,7 @@ struct EquivMakePass : public Pass {
log("checking problem. Use 'miter -equiv' if you want to create a miter circuit.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
EquivMakeWorker worker;
worker.ct.setup(design);
diff --git a/passes/equiv/equiv_mark.cc b/passes/equiv/equiv_mark.cc
index 22c50176..135eaf14 100644
--- a/passes/equiv/equiv_mark.cc
+++ b/passes/equiv/equiv_mark.cc
@@ -204,7 +204,7 @@ struct EquivMarkWorker
struct EquivMarkPass : public Pass {
EquivMarkPass() : Pass("equiv_mark", "mark equivalence checking regions") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -216,7 +216,7 @@ struct EquivMarkPass : public Pass {
log("wires and cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
log_header(design, "Executing EQUIV_MARK pass.\n");
diff --git a/passes/equiv/equiv_miter.cc b/passes/equiv/equiv_miter.cc
index eb2e5a17..e06f9515 100644
--- a/passes/equiv/equiv_miter.cc
+++ b/passes/equiv/equiv_miter.cc
@@ -261,7 +261,7 @@ struct EquivMiterWorker
struct EquivMiterPass : public Pass {
EquivMiterPass() : Pass("equiv_miter", "extract miter from equiv circuit") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -282,7 +282,7 @@ struct EquivMiterPass : public Pass {
log(" Create compare logic that handles undefs correctly\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
EquivMiterWorker worker;
worker.ct.setup(design);
diff --git a/passes/equiv/equiv_purge.cc b/passes/equiv/equiv_purge.cc
index 163b1009..18b3e7d3 100644
--- a/passes/equiv/equiv_purge.cc
+++ b/passes/equiv/equiv_purge.cc
@@ -80,7 +80,7 @@ struct EquivPurgeWorker
Wire *wire = module->addWire(name, GetSize(sig));
wire->port_input = true;
module->connect(sig, wire);
- log(" Module input: %s\n", log_signal(wire));
+ log(" Module input: %s (%s)\n", log_signal(wire), log_signal(sig));
return module->addWire(NEW_ID, GetSize(sig));
}
}
@@ -142,7 +142,7 @@ struct EquivPurgeWorker
for (auto bit : queue)
visited.insert(bit);
-
+
for (auto bit : queue)
{
auto &cells = up_bit2cells[bit];
@@ -176,7 +176,7 @@ struct EquivPurgeWorker
struct EquivPurgePass : public Pass {
EquivPurgePass() : Pass("equiv_purge", "purge equivalence checking module") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -187,7 +187,7 @@ struct EquivPurgePass : public Pass {
log("ports as needed.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
log_header(design, "Executing EQUIV_PURGE pass.\n");
diff --git a/passes/equiv/equiv_remove.cc b/passes/equiv/equiv_remove.cc
index 770497a5..c5c28c7d 100644
--- a/passes/equiv/equiv_remove.cc
+++ b/passes/equiv/equiv_remove.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EquivRemovePass : public Pass {
EquivRemovePass() : Pass("equiv_remove", "remove $equiv cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -40,7 +40,7 @@ struct EquivRemovePass : public Pass {
log(" keep gate circuit\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
bool mode_gold = false;
bool mode_gate = false;
diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc
index 49963ed6..c2fab26f 100644
--- a/passes/equiv/equiv_simple.cc
+++ b/passes/equiv/equiv_simple.cc
@@ -35,13 +35,14 @@ struct EquivSimpleWorker
ezSatPtr ez;
SatGen satgen;
int max_seq;
+ bool short_cones;
bool verbose;
pool<pair<Cell*, int>> imported_cells_cache;
- EquivSimpleWorker(const vector<Cell*> &equiv_cells, SigMap &sigmap, dict<SigBit, Cell*> &bit2driver, int max_seq, bool verbose, bool model_undef) :
+ EquivSimpleWorker(const vector<Cell*> &equiv_cells, SigMap &sigmap, dict<SigBit, Cell*> &bit2driver, int max_seq, bool short_cones, bool verbose, bool model_undef) :
module(equiv_cells.front()->module), equiv_cells(equiv_cells), equiv_cell(nullptr),
- sigmap(sigmap), bit2driver(bit2driver), satgen(ez.get(), &sigmap), max_seq(max_seq), verbose(verbose)
+ sigmap(sigmap), bit2driver(bit2driver), satgen(ez.get(), &sigmap), max_seq(max_seq), short_cones(short_cones), verbose(verbose)
{
satgen.model_undef = model_undef;
}
@@ -59,7 +60,7 @@ struct EquivSimpleWorker
for (auto &conn : cell->connections())
if (yosys_celltypes.cell_input(cell->type, conn.first))
for (auto bit : sigmap(conn.second)) {
- if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_")) {
+ if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_", "$ff", "$_FF_")) {
if (!conn.first.in("\\CLK", "\\C"))
next_seed.insert(bit);
} else
@@ -142,22 +143,44 @@ struct EquivSimpleWorker
pool<SigBit> short_bits_cone_a, short_bits_cone_b;
pool<SigBit> input_bits;
- for (auto bit_a : seed_a)
- find_input_cone(next_seed_a, short_cells_cone_a, short_bits_cone_a, full_cells_cone_b, full_bits_cone_b, &input_bits, bit_a);
- next_seed_a.swap(seed_a);
+ if (short_cones)
+ {
+ for (auto bit_a : seed_a)
+ find_input_cone(next_seed_a, short_cells_cone_a, short_bits_cone_a, full_cells_cone_b, full_bits_cone_b, &input_bits, bit_a);
+ next_seed_a.swap(seed_a);
- for (auto bit_b : seed_b)
- find_input_cone(next_seed_b, short_cells_cone_b, short_bits_cone_b, full_cells_cone_a, full_bits_cone_a, &input_bits, bit_b);
- next_seed_b.swap(seed_b);
+ for (auto bit_b : seed_b)
+ find_input_cone(next_seed_b, short_cells_cone_b, short_bits_cone_b, full_cells_cone_a, full_bits_cone_a, &input_bits, bit_b);
+ next_seed_b.swap(seed_b);
+ }
+ else
+ {
+ short_cells_cone_a = full_cells_cone_a;
+ short_bits_cone_a = full_bits_cone_a;
+ next_seed_a.swap(seed_a);
+
+ short_cells_cone_b = full_cells_cone_b;
+ short_bits_cone_b = full_bits_cone_b;
+ next_seed_b.swap(seed_b);
+ }
pool<Cell*> problem_cells;
problem_cells.insert(short_cells_cone_a.begin(), short_cells_cone_a.end());
problem_cells.insert(short_cells_cone_b.begin(), short_cells_cone_b.end());
if (verbose)
+ {
log(" Adding %d new cells to the problem (%d A, %d B, %d shared).\n",
GetSize(problem_cells), GetSize(short_cells_cone_a), GetSize(short_cells_cone_b),
(GetSize(short_cells_cone_a) + GetSize(short_cells_cone_b)) - GetSize(problem_cells));
+ #if 0
+ for (auto cell : short_cells_cone_a)
+ log(" A-side cell: %s\n", log_id(cell));
+
+ for (auto cell : short_cells_cone_b)
+ log(" B-side cell: %s\n", log_id(cell));
+ #endif
+ }
for (auto cell : problem_cells) {
auto key = pair<Cell*, int>(cell, step+1);
@@ -250,7 +273,7 @@ struct EquivSimpleWorker
struct EquivSimplePass : public Pass {
EquivSimplePass() : Pass("equiv_simple", "try proving simple $equiv instances") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -264,6 +287,10 @@ struct EquivSimplePass : public Pass {
log(" -undef\n");
log(" enable modelling of undef states\n");
log("\n");
+ log(" -short\n");
+ log(" create shorter input cones that stop at shared nodes. This yields\n");
+ log(" simpler SAT problems but sometimes fails to prove equivalence.\n");
+ log("\n");
log(" -nogroup\n");
log(" disabling grouping of $equiv cells by output wire\n");
log("\n");
@@ -271,9 +298,9 @@ struct EquivSimplePass : public Pass {
log(" the max. number of time steps to be considered (default = 1)\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
- bool verbose = false, model_undef = false, nogroup = false;
+ bool verbose = false, short_cones = false, model_undef = false, nogroup = false;
int success_counter = 0;
int max_seq = 1;
@@ -285,6 +312,10 @@ struct EquivSimplePass : public Pass {
verbose = true;
continue;
}
+ if (args[argidx] == "-short") {
+ short_cones = true;
+ continue;
+ }
if (args[argidx] == "-undef") {
model_undef = true;
continue;
@@ -329,7 +360,7 @@ struct EquivSimplePass : public Pass {
unproven_cells_counter, GetSize(unproven_equiv_cells), log_id(module));
for (auto cell : module->cells()) {
- if (!ct.cell_known(cell->type) && !cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_"))
+ if (!ct.cell_known(cell->type) && !cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_", "$ff", "$_FF_"))
continue;
for (auto &conn : cell->connections())
if (yosys_celltypes.cell_output(cell->type, conn.first))
@@ -346,7 +377,7 @@ struct EquivSimplePass : public Pass {
for (auto it2 : it.second)
cells.push_back(it2.second);
- EquivSimpleWorker worker(cells, sigmap, bit2driver, max_seq, verbose, model_undef);
+ EquivSimpleWorker worker(cells, sigmap, bit2driver, max_seq, short_cones, verbose, model_undef);
success_counter += worker.run();
}
}
diff --git a/passes/equiv/equiv_status.cc b/passes/equiv/equiv_status.cc
index 7b9230b3..b4a93ccf 100644
--- a/passes/equiv/equiv_status.cc
+++ b/passes/equiv/equiv_status.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EquivStatusPass : public Pass {
EquivStatusPass() : Pass("equiv_status", "print status of equivalent checking module") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -36,7 +36,7 @@ struct EquivStatusPass : public Pass {
log(" produce an error if any unproven $equiv cell is found\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
bool assert_mode = false;
int unproven_count = 0;
diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc
index c4ced6a7..a7973fd0 100644
--- a/passes/equiv/equiv_struct.cc
+++ b/passes/equiv/equiv_struct.cc
@@ -283,7 +283,7 @@ struct EquivStructWorker
struct EquivStructPass : public Pass {
EquivStructPass() : Pass("equiv_struct", "structural equivalence checking") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -314,7 +314,7 @@ struct EquivStructPass : public Pass {
log(" maximum number of iterations to run before aborting\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
pool<IdString> fwonly_cells({ "$equiv" });
bool mode_icells = false;
diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc
index 997558b8..c5cb338a 100644
--- a/passes/fsm/fsm.cc
+++ b/passes/fsm/fsm.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct FsmPass : public Pass {
FsmPass() : Pass("fsm", "extract and optimize finite state machines") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -68,7 +68,7 @@ struct FsmPass : public Pass {
log(" passed through to fsm_recode pass\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_nomap = false;
bool flag_norecode = false;
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index 6a560f16..fc504e98 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -180,7 +180,7 @@ static void detect_fsm(RTLIL::Wire *wire)
for (auto &port_it : cell->connections())
if (cell->output(port_it.first)) {
SigSpec sig = assign_map(port_it.second);
- Const val(set_output ? State::S1 : State::S0, GetSize(sig));
+ Const val(set_output ? State::S1 : State::S0, GetSize(sig));
ce.set(sig, val);
}
}
@@ -215,7 +215,7 @@ static void detect_fsm(RTLIL::Wire *wire)
for (auto w : warnings) warnmsg += " " + w;
log_warning("%s", warnmsg.c_str());
} else {
- log("FSM state register %s.%s already has fsm_encoding attribute.\n", log_id(wire->module), log_id(wire));
+ log("FSM state register %s.%s already has fsm_encoding attribute.\n", log_id(wire->module), log_id(wire));
}
}
else
@@ -245,7 +245,7 @@ static void detect_fsm(RTLIL::Wire *wire)
struct FsmDetectPass : public Pass {
FsmDetectPass() : Pass("fsm_detect", "finding FSMs in design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -261,7 +261,7 @@ struct FsmDetectPass : public Pass {
log("'fsm_encoding' attribute to \"none\".\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FSM_DETECT pass (finding FSMs in design).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
index e7b9dcf9..c34d0c15 100644
--- a/passes/fsm/fsm_expand.cc
+++ b/passes/fsm/fsm_expand.cc
@@ -54,13 +54,27 @@ struct FsmExpand
if (cell->getPort("\\A").size() < 2)
return true;
+ int in_bits = 0;
RTLIL::SigSpec new_signals;
- if (cell->hasPort("\\A"))
+
+ if (cell->hasPort("\\A")) {
+ in_bits += GetSize(cell->getPort("\\A"));
new_signals.append(assign_map(cell->getPort("\\A")));
- if (cell->hasPort("\\B"))
+ }
+
+ if (cell->hasPort("\\B")) {
+ in_bits += GetSize(cell->getPort("\\B"));
new_signals.append(assign_map(cell->getPort("\\B")));
- if (cell->hasPort("\\S"))
+ }
+
+ if (cell->hasPort("\\S")) {
+ in_bits += GetSize(cell->getPort("\\S"));
new_signals.append(assign_map(cell->getPort("\\S")));
+ }
+
+ if (in_bits > 8)
+ return false;
+
if (cell->hasPort("\\Y"))
new_signals.append(assign_map(cell->getPort("\\Y")));
@@ -173,6 +187,16 @@ struct FsmExpand
new_ctrl_out.append(output_sig);
fsm_cell->setPort("\\CTRL_OUT", new_ctrl_out);
+ if (GetSize(input_sig) > 10)
+ log_warning("Cell %s.%s (%s) has %d input bits, merging into FSM %s.%s might be problematic.\n",
+ log_id(cell->module), log_id(cell), log_id(cell->type),
+ GetSize(input_sig), log_id(fsm_cell->module), log_id(fsm_cell));
+
+ if (GetSize(fsm_data.transition_table) > 10000)
+ log_warning("Transition table for FSM %s.%s already has %d rows, merging more cells "
+ "into this FSM might be problematic.\n", log_id(fsm_cell->module), log_id(fsm_cell),
+ GetSize(fsm_data.transition_table));
+
std::vector<FsmData::transition_t> new_transition_table;
for (auto &tr : fsm_data.transition_table) {
for (int i = 0; i < (1 << input_sig.size()); i++) {
@@ -241,7 +265,7 @@ struct FsmExpand
struct FsmExpandPass : public Pass {
FsmExpandPass() : Pass("fsm_expand", "expand FSM cells by merging logic into it") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -255,7 +279,7 @@ struct FsmExpandPass : public Pass {
log("word-wide cells. Call with -full to consider all cells for merging.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool full_mode = false;
diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc
index 1cbfcfae..8eb1872f 100644
--- a/passes/fsm/fsm_export.cc
+++ b/passes/fsm/fsm_export.cc
@@ -120,7 +120,7 @@ void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell, std::st
*/
struct FsmExportPass : public Pass {
FsmExportPass() : Pass("fsm_export", "exporting FSMs to KISS2 files") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -143,7 +143,7 @@ struct FsmExportPass : public Pass {
log(" use binary state encoding as state names instead of s0, s1, ...\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
dict<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
std::string arg;
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
index 8a4ee3f2..67551f67 100644
--- a/passes/fsm/fsm_extract.cc
+++ b/passes/fsm/fsm_extract.cc
@@ -401,7 +401,7 @@ static void extract_fsm(RTLIL::Wire *wire)
struct FsmExtractPass : public Pass {
FsmExtractPass() : Pass("fsm_extract", "extracting FSMs in design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -417,7 +417,7 @@ struct FsmExtractPass : public Pass {
log("'opt_clean' pass to eliminate this signal.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FSM_EXTRACT pass (extracting FSM from design).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc
index 2cc1a7d5..0548259e 100644
--- a/passes/fsm/fsm_info.cc
+++ b/passes/fsm/fsm_info.cc
@@ -30,7 +30,7 @@ PRIVATE_NAMESPACE_BEGIN
struct FsmInfoPass : public Pass {
FsmInfoPass() : Pass("fsm_info", "print information on finite state machines") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -41,7 +41,7 @@ struct FsmInfoPass : public Pass {
log("pass so that this information is included in the synthesis log file.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FSM_INFO pass (dumping all available information on FSM cells).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
index c4230375..90c95891 100644
--- a/passes/fsm/fsm_map.cc
+++ b/passes/fsm/fsm_map.cc
@@ -274,9 +274,6 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
{
RTLIL::SigSpec sig_a(RTLIL::State::Sx, next_state_wire->width);
RTLIL::SigSpec sig_b, sig_s;
- int reset_state = fsm_data.reset_state;
- if (reset_state < 0)
- reset_state = 0;
for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
RTLIL::Const state = fsm_data.state_table[i];
@@ -325,7 +322,7 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
struct FsmMapPass : public Pass {
FsmMapPass() : Pass("fsm_map", "mapping FSMs to basic logic") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -334,7 +331,7 @@ struct FsmMapPass : public Pass {
log("This pass translates FSM cells to flip-flops and logic.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FSM_MAP pass (mapping FSMs to basic logic).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index 5b1da44f..3a6ac274 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -323,7 +323,7 @@ PRIVATE_NAMESPACE_BEGIN
struct FsmOptPass : public Pass {
FsmOptPass() : Pass("fsm_opt", "optimize finite state machines") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -334,7 +334,7 @@ struct FsmOptPass : public Pass {
log("combination with the 'opt_clean' pass (see also 'help fsm').\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FSM_OPT pass (simple optimizations of FSMs).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
index e1bde728..fa1ff48c 100644
--- a/passes/fsm/fsm_recode.cc
+++ b/passes/fsm/fsm_recode.cc
@@ -126,7 +126,7 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
struct FsmRecodePass : public Pass {
FsmRecodePass() : Pass("fsm_recode", "recoding finite state machines") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -151,7 +151,7 @@ struct FsmRecodePass : public Pass {
log(" .map <old_bitpattern> <new_bitpattern>\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
FILE *fm_set_fsm_file = NULL;
FILE *encfile = NULL;
diff --git a/passes/hierarchy/Makefile.inc b/passes/hierarchy/Makefile.inc
index 1fb669c1..b3f139b7 100644
--- a/passes/hierarchy/Makefile.inc
+++ b/passes/hierarchy/Makefile.inc
@@ -1,5 +1,5 @@
OBJS += passes/hierarchy/hierarchy.o
-OBJS += passes/hierarchy/singleton.o
+OBJS += passes/hierarchy/uniquify.o
OBJS += passes/hierarchy/submod.o
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index e21a7a4e..5df69848 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -18,6 +18,7 @@
*/
#include "kernel/yosys.h"
+#include "frontends/verific/verific.h"
#include <stdlib.h>
#include <stdio.h>
#include <set>
@@ -138,7 +139,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
}
}
-bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
+bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs)
{
bool did_something = false;
std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
@@ -173,24 +174,24 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
for (auto &dir : libdirs)
{
- filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
- if (check_file_exists(filename)) {
- std::vector<std::string> args;
- args.push_back(filename);
- Frontend::frontend_call(design, NULL, filename, "verilog");
- goto loaded_module;
- }
-
- filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
- if (check_file_exists(filename)) {
- std::vector<std::string> args;
- args.push_back(filename);
- Frontend::frontend_call(design, NULL, filename, "ilang");
- goto loaded_module;
+ static const vector<pair<string, string>> extensions_list =
+ {
+ {".v", "verilog"},
+ {".sv", "verilog -sv"},
+ {".il", "ilang"}
+ };
+
+ for (auto &ext : extensions_list)
+ {
+ filename = dir + "/" + RTLIL::unescape_id(cell->type) + ext.first;
+ if (check_file_exists(filename)) {
+ Frontend::frontend_call(design, NULL, filename, ext.second);
+ goto loaded_module;
+ }
}
}
- if (flag_check && cell->type[0] != '$')
+ if ((flag_check || flag_simcheck) && cell->type[0] != '$')
log_error("Module `%s' referenced in module `%s' in cell `%s' is not part of the design.\n",
cell->type.c_str(), module->name.c_str(), cell->name.c_str());
continue;
@@ -200,7 +201,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str());
did_something = true;
} else
- if (flag_check)
+ if (flag_check || flag_simcheck)
{
RTLIL::Module *mod = design->module(cell->type);
for (auto &conn : cell->connections())
@@ -213,15 +214,19 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n",
log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first));
for (auto &param : cell->parameters)
- if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$')
+ if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$' && strchr(param.first.c_str(), '.') == NULL)
log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n",
log_id(cell->type), log_id(module), log_id(cell), log_id(param.first));
}
- if (cell->parameters.size() == 0)
+ if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
+ if (flag_simcheck)
+ log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n",
+ cell->type.c_str(), module->name.c_str(), cell->name.c_str());
continue;
+ }
- if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox"))
+ if (cell->parameters.size() == 0)
continue;
RTLIL::Module *mod = design->modules_[cell->type];
@@ -254,7 +259,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
if (mod->wires_.count(portname) == 0)
log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
int port_size = mod->wires_.at(portname)->width;
- if (conn_size == port_size)
+ if (conn_size == port_size || conn_size == 0)
continue;
if (conn_size != port_size*num)
log_error("Array cell `%s.%s' has invalid port vs. signal size for port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
@@ -317,7 +322,7 @@ bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
if (cache.count(mod) == 0)
for (auto c : mod->cells()) {
RTLIL::Module *m = mod->design->module(c->type);
- if ((m != nullptr && set_keep_assert(cache, m)) || c->type.in("$assert", "$assume"))
+ if ((m != nullptr && set_keep_assert(cache, m)) || c->type.in("$assert", "$assume", "$live", "$fair", "$cover"))
return cache[mod] = true;
}
return cache[mod];
@@ -338,7 +343,7 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
struct HierarchyPass : public Pass {
HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -354,6 +359,10 @@ struct HierarchyPass : public Pass {
log(" also check the design hierarchy. this generates an error when\n");
log(" an unknown module is used as cell type.\n");
log("\n");
+ log(" -simcheck\n");
+ log(" like -check, but also thow an error if blackbox modules are\n");
+ log(" instantiated, and throw an error if the design has no top module\n");
+ log("\n");
log(" -purge_lib\n");
log(" by default the hierarchy command will not remove library (blackbox)\n");
log(" modules. use this option to also remove unused blackbox modules.\n");
@@ -367,6 +376,11 @@ struct HierarchyPass : public Pass {
log(" per default this pass also converts positional arguments in cells\n");
log(" to arguments using port names. this option disables this behavior.\n");
log("\n");
+ log(" -keep_portwidths\n");
+ log(" per default this pass adjusts the port width on cells that are\n");
+ log(" module instances when the width does not match the module port. this\n");
+ log(" option disables this behavior.\n");
+ log("\n");
log(" -nokeep_asserts\n");
log(" per default this pass sets the \"keep\" attribute on all modules\n");
log(" that directly or indirectly contain one or more $assert cells. this\n");
@@ -400,18 +414,21 @@ struct HierarchyPass : public Pass {
log("in the current design.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n");
bool flag_check = false;
+ bool flag_simcheck = false;
bool purge_lib = false;
RTLIL::Module *top_mod = NULL;
+ std::string load_top_mod;
std::vector<std::string> libdirs;
bool auto_top_mode = false;
bool generate_mode = false;
bool keep_positionals = false;
+ bool keep_portwidths = false;
bool nokeep_asserts = false;
std::vector<std::string> generate_cells;
std::vector<generate_port_decl_t> generate_ports;
@@ -419,7 +436,7 @@ struct HierarchyPass : public Pass {
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
- if (args[argidx] == "-generate" && !flag_check && !top_mod) {
+ if (args[argidx] == "-generate" && !flag_check && !flag_simcheck && !top_mod) {
generate_mode = true;
log("Entering generate mode.\n");
while (++argidx < args.size()) {
@@ -462,6 +479,10 @@ struct HierarchyPass : public Pass {
flag_check = true;
continue;
}
+ if (args[argidx] == "-simcheck") {
+ flag_simcheck = true;
+ continue;
+ }
if (args[argidx] == "-purge_lib") {
purge_lib = true;
continue;
@@ -470,6 +491,10 @@ struct HierarchyPass : public Pass {
keep_positionals = true;
continue;
}
+ if (args[argidx] == "-keep_portwidths") {
+ keep_portwidths = true;
+ continue;
+ }
if (args[argidx] == "-nokeep_asserts") {
nokeep_asserts = true;
continue;
@@ -488,7 +513,7 @@ struct HierarchyPass : public Pass {
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
}
if (top_mod == NULL)
- log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
+ load_top_mod = args[argidx];
continue;
}
if (args[argidx] == "-auto-top") {
@@ -499,6 +524,22 @@ struct HierarchyPass : public Pass {
}
extra_args(args, argidx, design, false);
+ if (!load_top_mod.empty()) {
+#ifdef YOSYS_ENABLE_VERIFIC
+ if (verific_import_pending) {
+ verific_import(design, load_top_mod);
+ top_mod = design->module(RTLIL::escape_id(load_top_mod));
+ }
+#endif
+ if (top_mod == NULL)
+ log_cmd_error("Module `%s' not found!\n", load_top_mod.c_str());
+ } else {
+#ifdef YOSYS_ENABLE_VERIFIC
+ if (verific_import_pending)
+ verific_import(design);
+#endif
+ }
+
if (generate_mode) {
generate(design, generate_cells, generate_ports);
return;
@@ -524,6 +565,9 @@ struct HierarchyPass : public Pass {
log("Automatically selected %s as design top module.\n", log_id(top_mod));
}
+ if (flag_simcheck && top_mod == nullptr)
+ log_error("Design has no top module.\n");
+
bool did_something = true;
while (did_something)
{
@@ -539,7 +583,7 @@ struct HierarchyPass : public Pass {
}
for (auto module : used_modules) {
- if (expand_module(design, module, flag_check, libdirs))
+ if (expand_module(design, module, flag_check, flag_simcheck, libdirs))
did_something = true;
}
}
@@ -614,6 +658,72 @@ struct HierarchyPass : public Pass {
}
}
+ std::set<Module*> blackbox_derivatives;
+ std::vector<Module*> design_modules = design->modules();
+
+ for (auto module : design_modules)
+ for (auto cell : module->cells())
+ {
+ Module *m = design->module(cell->type);
+
+ if (m == nullptr)
+ continue;
+
+ if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty()) {
+ IdString new_m_name = m->derive(design, cell->parameters, true);
+ if (new_m_name.empty())
+ continue;
+ if (new_m_name != m->name) {
+ m = design->module(new_m_name);
+ blackbox_derivatives.insert(m);
+ }
+ }
+
+ for (auto &conn : cell->connections())
+ {
+ Wire *w = m->wire(conn.first);
+
+ if (w == nullptr || w->port_id == 0)
+ continue;
+
+ if (GetSize(conn.second) == 0)
+ continue;
+
+ SigSpec sig = conn.second;
+
+ if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
+ {
+ if (GetSize(w) < GetSize(conn.second))
+ {
+ int n = GetSize(conn.second) - GetSize(w);
+ if (!w->port_input && w->port_output)
+ module->connect(sig.extract(GetSize(w), n), Const(0, n));
+ sig.remove(GetSize(w), n);
+ }
+ else
+ {
+ int n = GetSize(w) - GetSize(conn.second);
+ if (w->port_input && !w->port_output)
+ sig.append(Const(0, n));
+ else
+ sig.append(module->addWire(NEW_ID, n));
+ }
+
+ if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
+ log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
+ log_id(conn.first), GetSize(conn.second), GetSize(sig));
+ cell->setPort(conn.first, sig);
+ }
+
+ if (w->port_output && !w->port_input && sig.has_const())
+ log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
+ log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
+ }
+ }
+
+ for (auto module : blackbox_derivatives)
+ design->remove(module);
+
log_pop();
}
} HierarchyPass;
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index 9f312f82..ec242aa1 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -169,6 +169,7 @@ struct SubmodWorker
}
new_mod->fixup_ports();
+ ct.setup_module(new_mod);
for (RTLIL::Cell *cell : submod.cells) {
RTLIL::Cell *new_cell = new_mod->addCell(cell->name, cell);
@@ -268,7 +269,7 @@ struct SubmodWorker
struct SubmodPass : public Pass {
SubmodPass() : Pass("submod", "moving part of a module to a new submodule") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -296,7 +297,7 @@ struct SubmodPass : public Pass {
log("with -copy to not modify the source module.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing SUBMOD pass (moving cells to submodules as requested).\n");
log_push();
diff --git a/passes/hierarchy/singleton.cc b/passes/hierarchy/uniquify.cc
index 03c365fb..c88ecd82 100644
--- a/passes/hierarchy/singleton.cc
+++ b/passes/hierarchy/uniquify.cc
@@ -22,28 +22,28 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-struct SingletonPass : public Pass {
- SingletonPass() : Pass("singleton", "create singleton modules") { }
- virtual void help()
+struct UniquifyPass : public Pass {
+ UniquifyPass() : Pass("uniquify", "create unique copies of modules") { }
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" singleton [selection]\n");
+ log(" uniquify [selection]\n");
log("\n");
log("By default, a module that is instantiated by several other modules is only\n");
log("kept once in the design. This preserves the original modularity of the design\n");
log("and reduces the overall size of the design in memory. But it prevents certain\n");
- log("optimizations and other operations on the design. This pass creates singleton\n");
+ log("optimizations and other operations on the design. This pass creates unique\n");
log("modules for all selected cells. The created modules are marked with the\n");
- log("'singleton' attribute.\n");
+ log("'unique' attribute.\n");
log("\n");
- log("This commands only operates on modules that by themself have the 'singleton'\n");
- log("attribute set (the 'top' module is a singleton implicitly).\n");
+ log("This commands only operates on modules that by themself have the 'unique'\n");
+ log("attribute set (the 'top' module is unique implicitly).\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- log_header(design, "Executing SINGLETON pass (creating singleton modules).\n");
+ log_header(design, "Executing UNIQUIFY pass (creating unique copies of modules).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -56,7 +56,7 @@ struct SingletonPass : public Pass {
extra_args(args, argidx, design);
bool did_something = true;
- int singleton_cnt = 0;
+ int count = 0;
while (did_something)
{
@@ -64,12 +64,13 @@ struct SingletonPass : public Pass {
for (auto module : design->selected_modules())
{
- if (!module->get_bool_attribute("\\singleton") && !module->get_bool_attribute("\\top"))
+ if (!module->get_bool_attribute("\\unique") && !module->get_bool_attribute("\\top"))
continue;
for (auto cell : module->selected_cells())
{
- auto tmod = design->module(cell->type);
+ Module *tmod = design->module(cell->type);
+ IdString newname = module->name.str() + "." + log_id(cell->name);
if (tmod == nullptr)
continue;
@@ -77,25 +78,25 @@ struct SingletonPass : public Pass {
if (tmod->get_bool_attribute("\\blackbox"))
continue;
- if (tmod->get_bool_attribute("\\singleton"))
+ if (tmod->get_bool_attribute("\\unique") && newname == tmod->name)
continue;
- cell->type = module->name.str() + "." + log_id(cell->name);
- log("Creating singleton '%s'.\n", log_id(cell->type));
+ log("Creating module %s from %s.\n", log_id(newname), log_id(tmod));
auto smod = tmod->clone();
- smod->name = cell->type;
- smod->set_bool_attribute("\\singleton");
+ smod->name = newname;
+ cell->type = newname;
+ smod->set_bool_attribute("\\unique");
design->add(smod);
did_something = true;
- singleton_cnt++;
+ count++;
}
}
}
- log("Created %d singleton modules.\n", singleton_cnt);
+ log("Created %d unique modules.\n", count);
}
-} SingletonPass;
+} UniquifyPass;
PRIVATE_NAMESPACE_END
diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc
index ad359c01..e468c3a0 100644
--- a/passes/memory/Makefile.inc
+++ b/passes/memory/Makefile.inc
@@ -7,4 +7,5 @@ OBJS += passes/memory/memory_unpack.o
OBJS += passes/memory/memory_bram.o
OBJS += passes/memory/memory_map.o
OBJS += passes/memory/memory_memx.o
+OBJS += passes/memory/memory_nordff.o
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
index 947d598b..712bc253 100644
--- a/passes/memory/memory.cc
+++ b/passes/memory/memory.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct MemoryPass : public Pass {
MemoryPass() : Pass("memory", "translate memories to basic cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -48,7 +48,7 @@ struct MemoryPass : public Pass {
log("or multiport memory blocks if called with the -nomap option.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_nomap = false;
bool flag_nordff = false;
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index a7f9cf38..e8552bbc 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -1120,7 +1120,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
struct MemoryBramPass : public Pass {
MemoryBramPass() : Pass("memory_bram", "map memories to block rams") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1210,7 +1210,7 @@ struct MemoryBramPass : public Pass {
log("the data bits to accommodate the enable pattern of port A.\n");
log("\n");
}
- virtual void execute(vector<string> args, Design *design)
+ void execute(vector<string> args, Design *design) YS_OVERRIDE
{
rules_t rules;
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index ab66e3fb..70d98713 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -246,7 +246,7 @@ static void handle_module(Design *design, Module *module)
struct MemoryCollectPass : public Pass {
MemoryCollectPass() : Pass("memory_collect", "creating multi-port memory cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -256,7 +256,7 @@ struct MemoryCollectPass : public Pass {
log("memory cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_COLLECT pass (generating $mem cells).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_)
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 40691d16..32df1917 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -33,8 +33,20 @@ struct MemoryDffWorker
dict<SigBit, int> sigbit_users_count;
dict<SigSpec, Cell*> mux_cells_a, mux_cells_b;
pool<Cell*> forward_merged_dffs, candidate_dffs;
+ pool<SigBit> init_bits;
- MemoryDffWorker(Module *module) : module(module), sigmap(module) { }
+ MemoryDffWorker(Module *module) : module(module), sigmap(module)
+ {
+ for (auto wire : module->wires()) {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+ SigSpec sig = sigmap(wire);
+ Const initval = wire->attributes.count("\\init");
+ for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ init_bits.insert(sig[i]);
+ }
+ }
bool find_sig_before_dff(RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
{
@@ -45,6 +57,9 @@ struct MemoryDffWorker
if (bit.wire == NULL)
continue;
+ if (!after && init_bits.count(sigmap(bit)))
+ return false;
+
for (auto cell : dff_cells)
{
if (after && forward_merged_dffs.count(cell))
@@ -72,6 +87,9 @@ struct MemoryDffWorker
if (d.size() != 1)
continue;
+ if (after && init_bits.count(d))
+ return false;
+
bit = d;
clk = this_clk;
clk_polarity = this_clk_polarity;
@@ -265,7 +283,7 @@ struct MemoryDffWorker
struct MemoryDffPass : public Pass {
MemoryDffPass() : Pass("memory_dff", "merge input/output DFFs into memories") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -279,7 +297,7 @@ struct MemoryDffPass : public Pass {
log(" do not merge registers on read ports\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_wr_only = false;
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index bffeec85..a0b808e5 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -352,7 +352,7 @@ struct MemoryMapWorker
struct MemoryMapPass : public Pass {
MemoryMapPass() : Pass("memory_map", "translate multiport memories to basic cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -362,7 +362,7 @@ struct MemoryMapPass : public Pass {
log("pass to word-wide DFFs and address decoders.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
extra_args(args, 1, design);
for (auto mod : design->selected_modules())
diff --git a/passes/memory/memory_memx.cc b/passes/memory/memory_memx.cc
index 2b02e249..95837016 100644
--- a/passes/memory/memory_memx.cc
+++ b/passes/memory/memory_memx.cc
@@ -28,7 +28,7 @@ PRIVATE_NAMESPACE_BEGIN
struct MemoryMemxPass : public Pass {
MemoryMemxPass() : Pass("memory_memx", "emulate vlog sim behavior for mem ports") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -38,7 +38,7 @@ struct MemoryMemxPass : public Pass {
log("behavior for out-of-bounds memory reads and writes.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_MEMX pass (converting $mem cells to logic and flip-flops).\n");
extra_args(args, 1, design);
diff --git a/passes/memory/memory_nordff.cc b/passes/memory/memory_nordff.cc
new file mode 100644
index 00000000..ba0361c0
--- /dev/null
+++ b/passes/memory/memory_nordff.cc
@@ -0,0 +1,121 @@
+/*
+ * 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 MemoryNordffPass : public Pass {
+ MemoryNordffPass() : Pass("memory_nordff", "extract read port FFs from memories") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" memory_nordff [options] [selection]\n");
+ log("\n");
+ log("This pass extracts FFs from memory read ports. This results in a netlist\n");
+ log("similar to what one would get from calling memory_dff with -nordff.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing MEMORY_NORDFF pass (extracting $dff cells from $mem).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ // if (args[argidx] == "-nordff" || args[argidx] == "-wr_only") {
+ // flag_wr_only = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ for (auto cell : vector<Cell*>(module->selected_cells()))
+ {
+ if (cell->type != "$mem")
+ continue;
+
+ int rd_ports = cell->getParam("\\RD_PORTS").as_int();
+ int abits = cell->getParam("\\ABITS").as_int();
+ int width = cell->getParam("\\WIDTH").as_int();
+
+ SigSpec rd_addr = cell->getPort("\\RD_ADDR");
+ SigSpec rd_data = cell->getPort("\\RD_DATA");
+ SigSpec rd_clk = cell->getPort("\\RD_CLK");
+ SigSpec rd_en = cell->getPort("\\RD_EN");
+ Const rd_clk_enable = cell->getParam("\\RD_CLK_ENABLE");
+ Const rd_clk_polarity = cell->getParam("\\RD_CLK_POLARITY");
+
+ for (int i = 0; i < rd_ports; i++)
+ {
+ bool clk_enable = rd_clk_enable[i] == State::S1;
+
+ if (clk_enable)
+ {
+ bool clk_polarity = cell->getParam("\\RD_CLK_POLARITY")[i] == State::S1;
+ bool transparent = cell->getParam("\\RD_TRANSPARENT")[i] == State::S1;
+
+ SigSpec clk = cell->getPort("\\RD_CLK")[i] ;
+ SigSpec en = cell->getPort("\\RD_EN")[i];
+ Cell *c;
+
+ if (transparent)
+ {
+ SigSpec sig_q = module->addWire(NEW_ID, abits);
+ SigSpec sig_d = rd_addr.extract(abits * i, abits);
+ rd_addr.replace(abits * i, sig_q);
+ if (en != State::S1)
+ sig_d = module->Mux(NEW_ID, sig_q, sig_d, en);
+ c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity);
+ }
+ else
+ {
+ SigSpec sig_d = module->addWire(NEW_ID, width);
+ SigSpec sig_q = rd_data.extract(width * i, width);
+ rd_data.replace(width *i, sig_d);
+ if (en != State::S1)
+ sig_d = module->Mux(NEW_ID, sig_q, sig_d, en);
+ c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity);
+ }
+
+ log("Extracted %s FF from read port %d of %s.%s: %s\n", transparent ? "addr" : "data",
+ i, log_id(module), log_id(cell), log_id(c));
+ }
+
+ rd_en[i] = State::S1;
+ rd_clk[i] = State::S0;
+ rd_clk_enable[i] = State::S0;
+ rd_clk_polarity[i] = State::S1;
+ }
+
+ cell->setPort("\\RD_ADDR", rd_addr);
+ cell->setPort("\\RD_DATA", rd_data);
+ cell->setPort("\\RD_CLK", rd_clk);
+ cell->setPort("\\RD_EN", rd_en);
+ cell->setParam("\\RD_CLK_ENABLE", rd_clk_enable);
+ cell->setParam("\\RD_CLK_POLARITY", rd_clk_polarity);
+ }
+ }
+} MemoryNordffPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
index ca09ac52..172afe0c 100644
--- a/passes/memory/memory_share.cc
+++ b/passes/memory/memory_share.cc
@@ -726,7 +726,7 @@ struct MemoryShareWorker
struct MemorySharePass : public Pass {
MemorySharePass() : Pass("memory_share", "consolidate memory ports") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -752,7 +752,7 @@ struct MemorySharePass : public Pass {
log("optimizations) such as \"share\" and \"opt_merge\".\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_SHARE pass (consolidating $memrd/$memwr cells).\n");
extra_args(args, 1, design);
for (auto module : design->selected_modules())
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index a0fc31b5..49ec6679 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -127,7 +127,7 @@ void handle_module(RTLIL::Design *design, RTLIL::Module *module)
struct MemoryUnpackPass : public Pass {
MemoryUnpackPass() : Pass("memory_unpack", "unpack multi-port memory cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -137,7 +137,7 @@ struct MemoryUnpackPass : public Pass {
log("$memwr cells. It is the counterpart to the memory_collect pass.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_)
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index a8b1537b..0d01e9d3 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -10,5 +10,7 @@ OBJS += passes/opt/opt_expr.o
ifneq ($(SMALL),1)
OBJS += passes/opt/share.o
OBJS += passes/opt/wreduce.o
+OBJS += passes/opt/opt_demorgan.o
+OBJS += passes/opt/rmports.o
endif
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index 021c1a03..a4aca2fe 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct OptPass : public Pass {
OptPass() : Pass("opt", "perform simple optimizations") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -63,7 +63,7 @@ struct OptPass : public Pass {
log("\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string opt_clean_args;
std::string opt_expr_args;
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 6600ffa2..c3b13aca 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -64,7 +64,7 @@ struct keep_cache_t
bool query(Cell *cell)
{
- if (cell->type.in("$memwr", "$meminit", "$assert", "$assume"))
+ if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover"))
return true;
if (cell->has_keep_attr())
@@ -91,9 +91,16 @@ void rmunused_module_cells(Module *module, bool verbose)
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first))
- for (auto bit : sigmap(it2.second))
+ for (auto raw_bit : it2.second) {
+ if (raw_bit.wire == nullptr)
+ continue;
+ auto bit = sigmap(raw_bit);
+ if (bit.wire == nullptr)
+ log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n",
+ log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module));
if (bit.wire != nullptr)
wire2driver[bit].insert(cell);
+ }
}
if (keep_cache.query(cell))
queue.insert(cell);
@@ -320,19 +327,89 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
if (check_public_name(wire->name) && verbose) {
log(" removing unused non-port wire %s.\n", wire->name.c_str());
- del_wires_count++;
}
del_wires.insert(wire);
+ del_wires_count++;
}
module->remove(del_wires);
- count_rm_wires += del_wires.size();;
+ count_rm_wires += del_wires.size();
- if (del_wires_count > 0)
+ if (verbose && del_wires_count > 0)
log(" removed %d unused temporary wires.\n", del_wires_count);
}
-void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
+bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
+{
+ bool did_something = false;
+ CellTypes fftypes;
+ fftypes.setup_internals_mem();
+
+ SigMap sigmap(module);
+ dict<SigBit, State> qbits;
+
+ for (auto cell : module->cells())
+ if (fftypes.cell_known(cell->type) && cell->hasPort("\\Q"))
+ {
+ SigSpec sig = cell->getPort("\\Q");
+
+ for (int i = 0; i < GetSize(sig); i++)
+ {
+ SigBit bit = sig[i];
+
+ if (bit.wire == nullptr || bit.wire->attributes.count("\\init") == 0)
+ continue;
+
+ Const init = bit.wire->attributes.at("\\init");
+
+ if (i >= GetSize(init) || init[i] == State::Sx || init[i] == State::Sz)
+ continue;
+
+ sigmap.add(bit);
+ qbits[bit] = init[i];
+ }
+ }
+
+ for (auto wire : module->wires())
+ {
+ if (!purge_mode && wire->name[0] == '\\')
+ continue;
+
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ Const init = wire->attributes.at("\\init");
+
+ for (int i = 0; i < GetSize(wire) && i < GetSize(init); i++)
+ {
+ if (init[i] == State::Sx || init[i] == State::Sz)
+ continue;
+
+ SigBit wire_bit = SigBit(wire, i);
+ SigBit mapped_wire_bit = sigmap(wire_bit);
+
+ if (wire_bit == mapped_wire_bit)
+ goto next_wire;
+
+ if (qbits.count(sigmap(SigBit(wire, i))) == 0)
+ goto next_wire;
+
+ if (qbits.at(sigmap(SigBit(wire, i))) != init[i])
+ goto next_wire;
+ }
+
+ if (verbose)
+ log(" removing redundant init attribute on %s.\n", log_id(wire));
+
+ wire->attributes.erase("\\init");
+ did_something = true;
+ next_wire:;
+ }
+
+ return did_something;
+}
+
+void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool rminit)
{
if (verbose)
log("Finding unused cells or wires in module %s..\n", module->name.c_str());
@@ -358,11 +435,14 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
rmunused_module_cells(module, verbose);
rmunused_module_signals(module, purge_mode, verbose);
+
+ if (rminit && rmunused_module_init(module, purge_mode, verbose))
+ rmunused_module_signals(module, purge_mode, verbose);
}
struct OptCleanPass : public Pass {
OptCleanPass() : Pass("opt_clean", "remove unused cells and wires") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -379,7 +459,7 @@ struct OptCleanPass : public Pass {
log(" also remove internal nets if they have a public name\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool purge_mode = false;
@@ -406,9 +486,12 @@ struct OptCleanPass : public Pass {
for (auto module : design->selected_whole_modules_warn()) {
if (module->has_processes_warn())
continue;
- rmunused_module(module, purge_mode, true);
+ rmunused_module(module, purge_mode, true, true);
}
+ if (count_rm_cells > 0 || count_rm_wires > 0)
+ log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires);
+
design->optimize();
design->sort();
design->check();
@@ -422,7 +505,7 @@ struct OptCleanPass : public Pass {
struct CleanPass : public Pass {
CleanPass() : Pass("clean", "remove unused cells and wires") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -437,7 +520,7 @@ struct CleanPass : public Pass {
log("in -purge mode between the commands.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool purge_mode = false;
@@ -465,7 +548,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) {
if (module->has_processes())
continue;
- rmunused_module(module, purge_mode, false);
+ rmunused_module(module, purge_mode, false, false);
}
if (count_rm_cells > 0 || count_rm_wires > 0)
diff --git a/passes/opt/opt_demorgan.cc b/passes/opt/opt_demorgan.cc
new file mode 100644
index 00000000..1699a645
--- /dev/null
+++ b/passes/opt/opt_demorgan.cc
@@ -0,0 +1,202 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2017 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"
+#include "kernel/modtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void demorgan_worker(
+ ModIndex& index,
+ Cell *cell,
+ unsigned int& cells_changed)
+{
+ SigMap& sigmap = index.sigmap;
+ auto m = cell->module;
+
+ //TODO: Add support for reduce_xor
+ //DeMorgan of XOR is either XOR (if even number of inputs) or XNOR (if odd number)
+
+ if( (cell->type != "$reduce_and") && (cell->type != "$reduce_or") )
+ return;
+
+ auto insig = sigmap(cell->getPort("\\A"));
+ log("Inspecting %s cell %s (%d inputs)\n", log_id(cell->type), log_id(cell->name), GetSize(insig));
+ int num_inverted = 0;
+ for(int i=0; i<GetSize(insig); i++)
+ {
+ auto b = insig[i];
+
+ //See if this bit is driven by a $not cell
+ //TODO: do other stuff like nor/nand?
+ pool<ModIndex::PortInfo> ports = index.query_ports(b);
+ bool inverted = false;
+ for(auto x : ports)
+ {
+ if(x.port == "\\Y" && x.cell->type == "$_NOT_")
+ {
+ inverted = true;
+ break;
+ }
+ }
+
+ if(inverted)
+ num_inverted ++;
+ }
+
+ //Stop if less than half of the inputs are inverted
+ if(num_inverted*2 < GetSize(insig))
+ {
+ log(" %d / %d inputs are inverted, not pushing\n", num_inverted, GetSize(insig));
+ return;
+ }
+
+ //More than half of the inputs are inverted! Push through
+ cells_changed ++;
+ log(" %d / %d inputs are inverted, pushing inverter through reduction\n", num_inverted, GetSize(insig));
+
+ //For each input, either add or remove the inverter as needed
+ //TODO: this duplicates the loop up above, can we refactor it?
+ for(int i=0; i<GetSize(insig); i++)
+ {
+ auto b = insig[i];
+
+ //See if this bit is driven by a $not cell
+ //TODO: do other stuff like nor/nand?
+ pool<ModIndex::PortInfo> ports = index.query_ports(b);
+ RTLIL::Cell* srcinv = NULL;
+ for(auto x : ports)
+ {
+ if(x.port == "\\Y" && x.cell->type == "$_NOT_")
+ {
+ srcinv = x.cell;
+ break;
+ }
+ }
+
+ //We are NOT inverted! Add an inverter
+ if(!srcinv)
+ {
+ auto inverted_b = m->addWire(NEW_ID);
+ m->addNot(NEW_ID, RTLIL::SigSpec(b), RTLIL::SigSpec(inverted_b));
+ insig[i] = inverted_b;
+ }
+
+ //We ARE inverted - bypass it
+ //Don't automatically delete the inverter since other stuff might still use it
+ else
+ insig[i] = srcinv->getPort("\\A");
+ }
+
+ //Cosmetic fixup: If our input is just a scrambled version of one bus, rearrange it
+ //Reductions are all commutative, so there's no point in having them in a weird order
+ bool same_signal = true;
+ RTLIL::Wire* srcwire = insig[0].wire;
+ dict<int, int> seen_bits;
+ for(int i=0; i<GetSize(insig); i++)
+ seen_bits[i] = 0;
+ for(int i=0; i<GetSize(insig); i++)
+ {
+ seen_bits[insig[i].offset] ++;
+ if(insig[i].wire != srcwire)
+ {
+ same_signal = false;
+ break;
+ }
+ }
+ if(same_signal)
+ {
+ //Make sure we've seen every bit exactly once
+ bool every_bit_once = true;
+ for(int i=0; i<GetSize(insig); i++)
+ {
+ if(seen_bits[i] != 1)
+ {
+ every_bit_once = false;
+ break;
+ }
+ }
+
+ //All good? Just use the whole wire as-is without any reordering
+ //We do have to swap MSB to LSB b/c that's the way the reduction cells seem to work?
+ //Unclear on why this isn't sorting properly
+ //TODO: can we do SigChunks instead of single bits if we have subsets of a bus?
+ if(every_bit_once && (GetSize(insig) == srcwire->width) )
+ {
+ log("Rearranging bits\n");
+ RTLIL::SigSpec newsig;
+ for(int i=0; i<GetSize(insig); i++)
+ newsig.append(RTLIL::SigBit(srcwire, GetSize(insig) - i - 1));
+ insig = newsig;
+ insig.sort();
+ }
+ }
+
+ //Push the new input signal back to the reduction (after bypassing/adding inverters)
+ cell->setPort("\\A", insig);
+
+ //Change the cell type
+ if(cell->type == "$reduce_and")
+ cell->type = "$reduce_or";
+ else if(cell->type == "$reduce_or")
+ cell->type = "$reduce_and";
+ //don't change XOR
+
+ //Add an inverter to the output
+ auto inverted_output = cell->getPort("\\Y");
+ auto uninverted_output = m->addWire(NEW_ID);
+ m->addNot(NEW_ID, RTLIL::SigSpec(uninverted_output), inverted_output);
+ cell->setPort("\\Y", uninverted_output);
+}
+
+struct OptDemorganPass : public Pass {
+ OptDemorganPass() : Pass("opt_demorgan", "Optimize reductions with DeMorgan equivalents") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" opt_demorgan [selection]\n");
+ log("\n");
+ log("This pass pushes inverters through $reduce_* cells if this will reduce the\n");
+ log("overall gate count of the circuit\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing OPT_DEMORGAN pass (push inverters through $reduce_* cells).\n");
+
+ int argidx = 0;
+ extra_args(args, argidx, design);
+
+ unsigned int cells_changed = 0;
+ for (auto module : design->selected_modules())
+ {
+ ModIndex index(module);
+ for (auto cell : module->selected_cells())
+ demorgan_worker(index, cell, cells_changed);
+ }
+
+ if(cells_changed)
+ log("Pushed inverters through %u reductions\n", cells_changed);
+ }
+} OptDemorganPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index b62eae28..0ba233c6 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -259,6 +259,29 @@ bool is_one_or_minus_one(const Const &value, bool is_signed, bool &is_negative)
return last_bit_one;
}
+// if the signal has only one bit set, return the index of that bit.
+// otherwise return -1
+int get_onehot_bit_index(RTLIL::SigSpec signal)
+{
+ int bit_index = -1;
+
+ for (int i = 0; i < GetSize(signal); i++)
+ {
+ if (signal[i] == RTLIL::State::S0)
+ continue;
+
+ if (signal[i] != RTLIL::State::S1)
+ return -1;
+
+ if (bit_index != -1)
+ return -1;
+
+ bit_index = i;
+ }
+
+ return bit_index;
+}
+
void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool clkinv)
{
if (!design->selected(module))
@@ -348,19 +371,20 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type.in("$reduce_and", "$_AND_"))
detect_const_and = true;
- if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1)
+ if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool())
detect_const_and = true;
if (cell->type.in("$reduce_or", "$reduce_bool", "$_OR_"))
detect_const_or = true;
- if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1)
+ if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool())
detect_const_or = true;
if (detect_const_and || detect_const_or)
{
pool<SigBit> input_bits = assign_map(cell->getPort("\\A")).to_sigbit_pool();
- bool found_zero = false, found_one = false, found_inv = false;
+ bool found_zero = false, found_one = false, found_undef = false, found_inv = false, many_conconst = false;
+ SigBit non_const_input = State::Sm;
if (cell->hasPort("\\B")) {
vector<SigBit> more_bits = assign_map(cell->getPort("\\B")).to_sigbit_vector();
@@ -368,12 +392,20 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
for (auto bit : input_bits) {
- if (bit == State::S0)
- found_zero = true;
- if (bit == State::S1)
- found_one = true;
- if (invert_map.count(bit) && input_bits.count(invert_map.at(bit)))
- found_inv = true;
+ if (bit.wire) {
+ if (invert_map.count(bit) && input_bits.count(invert_map.at(bit)))
+ found_inv = true;
+ if (non_const_input != State::Sm)
+ many_conconst = true;
+ non_const_input = many_conconst ? State::Sm : bit;
+ } else {
+ if (bit == State::S0)
+ found_zero = true;
+ else if (bit == State::S1)
+ found_one = true;
+ else
+ found_undef = true;
+ }
}
if (detect_const_and && (found_zero || found_inv)) {
@@ -387,6 +419,12 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
replace_cell(assign_map, module, cell, "const_or", "\\Y", RTLIL::State::S1);
goto next_cell;
}
+
+ if (non_const_input != State::Sm && !found_undef) {
+ cover("opt.opt_expr.and_or_buffer");
+ replace_cell(assign_map, module, cell, "and_or_buffer", "\\Y", non_const_input);
+ goto next_cell;
+ }
}
if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") &&
@@ -411,6 +449,53 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (group_cell_inputs(module, cell, true, assign_map))
goto next_cell;
+ if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" ||
+ cell->type == "$reduce_or" || cell->type == "$reduce_and" || cell->type == "$reduce_bool")
+ {
+ SigBit neutral_bit = cell->type == "$reduce_and" ? State::S1 : State::S0;
+
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec new_sig_a;
+
+ for (auto bit : sig_a)
+ if (bit != neutral_bit) new_sig_a.append(bit);
+
+ if (GetSize(new_sig_a) == 0)
+ new_sig_a.append(neutral_bit);
+
+ if (GetSize(new_sig_a) < GetSize(sig_a)) {
+ cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str());
+ log("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a));
+ cell->setPort("\\A", new_sig_a);
+ cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a);
+ did_something = true;
+ }
+ }
+
+ if (cell->type == "$logic_and" || cell->type == "$logic_or")
+ {
+ SigBit neutral_bit = State::S0;
+
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec new_sig_b;
+
+ for (auto bit : sig_b)
+ if (bit != neutral_bit) new_sig_b.append(bit);
+
+ if (GetSize(new_sig_b) == 0)
+ new_sig_b.append(neutral_bit);
+
+ if (GetSize(new_sig_b) < GetSize(sig_b)) {
+ cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str());
+ log("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b));
+ cell->setPort("\\B", new_sig_b);
+ cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b);
+ did_something = true;
+ }
+ }
+
if (cell->type == "$reduce_and")
{
RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
@@ -633,6 +718,23 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
+ if (cell->type == "$_TBUF_" || cell->type == "$tribuf") {
+ RTLIL::SigSpec input = cell->getPort(cell->type == "$_TBUF_" ? "\\E" : "\\EN");
+ RTLIL::SigSpec a = cell->getPort("\\A");
+ assign_map.apply(input);
+ assign_map.apply(a);
+ if (input == State::S1)
+ ACTION_DO("\\Y", cell->getPort("\\A"));
+ if (input == State::S0 && !a.is_fully_undef()) {
+ cover("opt.opt_expr.action_" S__LINE__);
+ log("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str());
+ cell->setPort("\\A", SigSpec(State::Sx, GetSize(a)));
+ did_something = true;
+ goto next_cell;
+ }
+ }
+
if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex")
{
RTLIL::SigSpec a = cell->getPort("\\A");
@@ -1167,6 +1269,197 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
+ // remove redundant pairs of bits in ==, ===, !=, and !==
+ // replace cell with const driver if inputs can't be equal
+ if (do_fine && cell->type.in("$eq", "$ne", "$eqx", "$nex"))
+ {
+ pool<pair<SigBit, SigBit>> redundant_cache;
+ mfp<SigBit> contradiction_cache;
+
+ contradiction_cache.promote(State::S0);
+ contradiction_cache.promote(State::S1);
+
+ int a_width = cell->getParam("\\A_WIDTH").as_int();
+ int b_width = cell->getParam("\\B_WIDTH").as_int();
+
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ int width = is_signed ? std::min(a_width, b_width) : std::max(a_width, b_width);
+
+ SigSpec sig_a = cell->getPort("\\A");
+ SigSpec sig_b = cell->getPort("\\B");
+
+ int redundant_bits = 0;
+
+ for (int i = width-1; i >= 0; i--)
+ {
+ SigBit bit_a = i < a_width ? assign_map(sig_a[i]) : State::S0;
+ SigBit bit_b = i < b_width ? assign_map(sig_b[i]) : State::S0;
+
+ if (bit_a != State::Sx && bit_a != State::Sz &&
+ bit_b != State::Sx && bit_b != State::Sz)
+ contradiction_cache.merge(bit_a, bit_b);
+
+ if (bit_b < bit_a)
+ std::swap(bit_a, bit_b);
+
+ pair<SigBit, SigBit> key(bit_a, bit_b);
+
+ if (redundant_cache.count(key)) {
+ if (i < a_width) sig_a.remove(i);
+ if (i < b_width) sig_b.remove(i);
+ redundant_bits++;
+ continue;
+ }
+
+ redundant_cache.insert(key);
+ }
+
+ if (contradiction_cache.find(State::S0) == contradiction_cache.find(State::S1))
+ {
+ SigSpec y_sig = cell->getPort("\\Y");
+ Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig));
+
+ log("Replacing cell `%s' in module `%s' with constant driver %s.\n",
+ log_id(cell), log_id(module), log_signal(y_value));
+
+ module->connect(y_sig, y_value);
+ module->remove(cell);
+
+ did_something = true;
+ goto next_cell;
+ }
+
+ if (redundant_bits)
+ {
+ log("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
+ redundant_bits, log_id(cell->type), log_id(cell), log_id(module));
+
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\B", sig_b);
+ cell->setParam("\\A_WIDTH", GetSize(sig_a));
+ cell->setParam("\\B_WIDTH", GetSize(sig_b));
+
+ did_something = true;
+ goto next_cell;
+ }
+ }
+
+ // replace a<0 or a>=0 with the top bit of a
+ if (do_fine && (cell->type == "$lt" || cell->type == "$ge" || cell->type == "$gt" || cell->type == "$le"))
+ {
+ //used to decide whether the signal needs to be negated
+ bool is_lt = false;
+
+ //references the variable signal in the comparison
+ RTLIL::SigSpec sigVar;
+
+ //references the constant signal in the comparison
+ RTLIL::SigSpec sigConst;
+
+ // note that this signal must be constant for the optimization
+ // to take place, but it is not checked beforehand.
+ // If new passes are added, this signal must be checked for const-ness
+
+ //width of the variable port
+ int width;
+ int const_width;
+
+ bool var_signed;
+
+ if (cell->type == "$lt" || cell->type == "$ge") {
+ is_lt = cell->type == "$lt" ? 1 : 0;
+ sigVar = cell->getPort("\\A");
+ sigConst = cell->getPort("\\B");
+ width = cell->parameters["\\A_WIDTH"].as_int();
+ const_width = cell->parameters["\\B_WIDTH"].as_int();
+ var_signed = cell->parameters["\\A_SIGNED"].as_bool();
+ } else
+ if (cell->type == "$gt" || cell->type == "$le") {
+ is_lt = cell->type == "$gt" ? 1 : 0;
+ sigVar = cell->getPort("\\B");
+ sigConst = cell->getPort("\\A");
+ width = cell->parameters["\\B_WIDTH"].as_int();
+ const_width = cell->parameters["\\A_WIDTH"].as_int();
+ var_signed = cell->parameters["\\B_SIGNED"].as_bool();
+ } else
+ log_abort();
+
+ // replace a(signed) < 0 with the high bit of a
+ if (sigConst.is_fully_const() && sigConst.is_fully_zero() && var_signed == true)
+ {
+ RTLIL::SigSpec a_prime(RTLIL::State::S0, cell->parameters["\\Y_WIDTH"].as_int());
+ a_prime[0] = sigVar[width - 1];
+ if (is_lt) {
+ log("Replacing %s cell `%s' (implementing X<0) with X[%d]: %s\n",
+ log_id(cell->type), log_id(cell), width-1, log_signal(a_prime));
+ module->connect(cell->getPort("\\Y"), a_prime);
+ module->remove(cell);
+ } else {
+ log("Replacing %s cell `%s' (implementing X>=0) with ~X[%d]: %s\n",
+ log_id(cell->type), log_id(cell), width-1, log_signal(a_prime));
+ module->addNot(NEW_ID, a_prime, cell->getPort("\\Y"));
+ module->remove(cell);
+ }
+ did_something = true;
+ goto next_cell;
+ } else
+ if (sigConst.is_fully_const() && sigConst.is_fully_def() && var_signed == false)
+ {
+ if (sigConst.is_fully_zero()) {
+ RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
+ if (is_lt) {
+ log("Replacing %s cell `%s' (implementing unsigned X<0) with constant false.\n",
+ log_id(cell->type), log_id(cell));
+ a_prime[0] = RTLIL::State::S0;
+ } else {
+ log("Replacing %s cell `%s' (implementing unsigned X>=0) with constant true.\n",
+ log_id(cell->type), log_id(cell));
+ a_prime[0] = RTLIL::State::S1;
+ }
+ module->connect(cell->getPort("\\Y"), a_prime);
+ module->remove(cell);
+ did_something = true;
+ goto next_cell;
+ }
+
+ int const_bit_set = get_onehot_bit_index(sigConst);
+ if (const_bit_set >= 0 && const_bit_set < width) {
+ int bit_set = const_bit_set;
+ RTLIL::SigSpec a_prime(RTLIL::State::S0, width - bit_set);
+ for (int i = bit_set; i < width; i++) {
+ a_prime[i - bit_set] = sigVar[i];
+ }
+ if (is_lt) {
+ log("Replacing %s cell `%s' (implementing unsigned X<%s) with !X[%d:%d]: %s.\n",
+ log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime));
+ module->addLogicNot(NEW_ID, a_prime, cell->getPort("\\Y"));
+ } else {
+ log("Replacing %s cell `%s' (implementing unsigned X>=%s) with |X[%d:%d]: %s.\n",
+ log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime));
+ module->addReduceOr(NEW_ID, a_prime, cell->getPort("\\Y"));
+ }
+ module->remove(cell);
+ did_something = true;
+ goto next_cell;
+ }
+ else if(const_bit_set >= width && const_bit_set >= 0){
+ RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
+ if(is_lt){
+ a_prime[0] = RTLIL::State::S1;
+ log("Replacing %s cell `%s' (implementing unsigned X[%d:0] < %s[%d:0]) with constant 0.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
+ }
+ else{
+ log("Replacing %s cell `%s' (implementing unsigned X[%d:0]>= %s[%d:0]) with constant 1.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
+ }
+ module->connect(cell->getPort("\\Y"), a_prime);
+ module->remove(cell);
+ did_something = true;
+ goto next_cell;
+
+ }
+ }
+ }
+
next_cell:;
#undef ACTION_DO
#undef ACTION_DO_Y
@@ -1177,7 +1470,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
struct OptExprPass : public Pass {
OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1211,7 +1504,7 @@ struct OptExprPass : public Pass {
log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool mux_undef = false;
bool mux_bool = false;
diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc
index 97989d27..eedf8890 100644
--- a/passes/opt/opt_merge.cc
+++ b/passes/opt/opt_merge.cc
@@ -275,13 +275,24 @@ struct OptMergeWorker
ct.cell_types.erase("$pmux");
}
+ ct.cell_types.erase("$tribuf");
+ ct.cell_types.erase("$_TBUF_");
+ ct.cell_types.erase("$anyseq");
+ ct.cell_types.erase("$anyconst");
+ ct.cell_types.erase("$allseq");
+ ct.cell_types.erase("$allconst");
+
log("Finding identical cells in module `%s'.\n", module->name.c_str());
assign_map.set(module);
dff_init_map.set(module);
for (auto &it : module->wires_)
- if (it.second->attributes.count("\\init") != 0)
- dff_init_map.add(it.second, it.second->attributes.at("\\init"));
+ if (it.second->attributes.count("\\init") != 0) {
+ Const initval = it.second->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initval) && i < GetSize(it.second); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ dff_init_map.add(SigBit(it.second, i), initval[i]);
+ }
bool did_something = true;
while (did_something)
@@ -330,7 +341,7 @@ struct OptMergeWorker
struct OptMergePass : public Pass {
OptMergePass() : Pass("opt_merge", "consolidate identical cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -346,7 +357,7 @@ struct OptMergePass : public Pass {
log(" Operate on all cell types, not just built-in types.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing OPT_MERGE pass (detect identical cells).\n");
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index f5ddc2af..87c7ce9b 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -449,7 +449,7 @@ struct OptMuxtreeWorker
struct OptMuxtreePass : public Pass {
OptMuxtreePass() : Pass("opt_muxtree", "eliminate dead trees in multiplexer trees") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -462,7 +462,7 @@ struct OptMuxtreePass : public Pass {
log("This pass only operates on completely selected modules without processes.\n");
log("\n");
}
- virtual void execute(vector<std::string> args, RTLIL::Design *design)
+ void execute(vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n");
extra_args(args, 1, design);
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index eb9d02ad..d99f1ca6 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -329,7 +329,7 @@ struct OptReduceWorker
struct OptReducePass : public Pass {
OptReducePass() : Pass("opt_reduce", "simplify large MUXes and AND/OR gates") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -350,7 +350,7 @@ struct OptReducePass : public Pass {
log(" alias for -fine\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool do_fine = false;
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index 922f086f..5880254c 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -39,11 +39,201 @@ void remove_init_attr(SigSpec sig)
wbit.wire->attributes.at("\\init")[wbit.offset] = State::Sx;
}
+bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
+{
+ SigSpec sig_set, sig_clr;
+ State pol_set, pol_clr;
+
+ if (cell->hasPort("\\S"))
+ sig_set = cell->getPort("\\S");
+
+ if (cell->hasPort("\\R"))
+ sig_clr = cell->getPort("\\R");
+
+ if (cell->hasPort("\\SET"))
+ sig_set = cell->getPort("\\SET");
+
+ if (cell->hasPort("\\CLR"))
+ sig_clr = cell->getPort("\\CLR");
+
+ log_assert(GetSize(sig_set) == GetSize(sig_clr));
+
+ if (cell->type.substr(0,8) == "$_DFFSR_") {
+ pol_set = cell->type[9] == 'P' ? State::S1 : State::S0;
+ pol_clr = cell->type[10] == 'P' ? State::S1 : State::S0;
+ } else
+ if (cell->type.substr(0,11) == "$_DLATCHSR_") {
+ pol_set = cell->type[12] == 'P' ? State::S1 : State::S0;
+ pol_clr = cell->type[13] == 'P' ? State::S1 : State::S0;
+ } else
+ if (cell->type == "$dffsr" || cell->type == "$dlatchsr") {
+ pol_set = cell->parameters["\\SET_POLARITY"].as_bool() ? State::S1 : State::S0;
+ pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool() ? State::S1 : State::S0;
+ } else
+ log_abort();
+
+ State npol_set = pol_set == State::S0 ? State::S1 : State::S0;
+ State npol_clr = pol_clr == State::S0 ? State::S1 : State::S0;
+
+ SigSpec sig_d = cell->getPort("\\D");
+ SigSpec sig_q = cell->getPort("\\Q");
+
+ bool did_something = false;
+ bool proper_sr = false;
+ bool used_pol_set = false;
+ bool used_pol_clr = false;
+ bool hasreset = false;
+ Const reset_val;
+ SigSpec sig_reset;
+
+ for (int i = 0; i < GetSize(sig_set); i++)
+ {
+ SigBit s = sig_set[i], c = sig_clr[i];
+
+ if (s != npol_set || c != npol_clr)
+ hasreset = true;
+
+ if (s == pol_set || c == pol_clr)
+ {
+ log("Constantly %s Q bit %s for SR cell %s (%s) from module %s.\n",
+ s == pol_set ? "set" : "cleared", log_signal(sig_q[i]),
+ log_id(cell), log_id(cell->type), log_id(mod));
+
+ remove_init_attr(sig_q[i]);
+ mod->connect(sig_q[i], s == pol_set ? State::S1 : State::S0);
+ sig_set.remove(i);
+ sig_clr.remove(i);
+ sig_d.remove(i);
+ sig_q.remove(i--);
+ did_something = true;
+ continue;
+ }
+ if (sig_reset.empty() && s.wire != nullptr) sig_reset = s;
+ if (sig_reset.empty() && c.wire != nullptr) sig_reset = c;
+
+ if (s.wire != nullptr && s != sig_reset) proper_sr = true;
+ if (c.wire != nullptr && c != sig_reset) proper_sr = true;
+
+ if ((s.wire == nullptr) != (c.wire == nullptr)) {
+ if (s.wire != nullptr) used_pol_set = true;
+ if (c.wire != nullptr) used_pol_clr = true;
+ reset_val.bits.push_back(c.wire == nullptr ? State::S1 : State::S0);
+ } else
+ proper_sr = true;
+ }
+
+ if (!hasreset)
+ proper_sr = false;
+
+ if (GetSize(sig_set) == 0)
+ {
+ log("Removing %s (%s) from module %s.\n", log_id(cell), log_id(cell->type), log_id(mod));
+ mod->remove(cell);
+ return true;
+ }
+
+ if (cell->type == "$dffsr" || cell->type == "$dlatchsr")
+ {
+ cell->setParam("\\WIDTH", GetSize(sig_d));
+ cell->setPort("\\SET", sig_set);
+ cell->setPort("\\CLR", sig_clr);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ }
+ else
+ {
+ cell->setPort("\\S", sig_set);
+ cell->setPort("\\R", sig_clr);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ }
+
+ if (proper_sr)
+ return did_something;
+
+ if (used_pol_set && used_pol_clr && pol_set != pol_clr)
+ return did_something;
+
+ if (cell->type == "$dlatchsr")
+ return did_something;
+
+ State unified_pol = used_pol_set ? pol_set : pol_clr;
+
+ if (cell->type == "$dffsr")
+ {
+ if (hasreset)
+ {
+ log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$adff", log_id(mod));
+
+ cell->type = "$adff";
+ cell->setParam("\\ARST_POLARITY", unified_pol);
+ cell->setParam("\\ARST_VALUE", reset_val);
+ cell->setPort("\\ARST", sig_reset);
+
+ cell->unsetParam("\\SET_POLARITY");
+ cell->unsetParam("\\CLR_POLARITY");
+ cell->unsetPort("\\SET");
+ cell->unsetPort("\\CLR");
+
+ return true;
+ }
+ else
+ {
+ log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$dff", log_id(mod));
+
+ cell->type = "$dff";
+ cell->unsetParam("\\SET_POLARITY");
+ cell->unsetParam("\\CLR_POLARITY");
+ cell->unsetPort("\\SET");
+ cell->unsetPort("\\CLR");
+
+ return true;
+ }
+ }
+ else
+ {
+ IdString new_type;
+
+ if (cell->type.substr(0,8) == "$_DFFSR_")
+ new_type = stringf("$_DFF_%c_", cell->type[8]);
+ else if (cell->type.substr(0,11) == "$_DLATCHSR_")
+ new_type = stringf("$_DLATCH_%c_", cell->type[11]);
+ else
+ log_abort();
+
+ log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), log_id(new_type), log_id(mod));
+
+ cell->type = new_type;
+ cell->unsetPort("\\S");
+ cell->unsetPort("\\R");
+
+ return did_something;
+ }
+}
+
bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
{
- SigSpec sig_e = dlatch->getPort("\\EN");
+ SigSpec sig_e;
+ State on_state, off_state;
+
+ if (dlatch->type == "$dlatch") {
+ sig_e = assign_map(dlatch->getPort("\\EN"));
+ on_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S1 : State::S0;
+ off_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S0 : State::S1;
+ } else
+ if (dlatch->type == "$_DLATCH_P_") {
+ sig_e = assign_map(dlatch->getPort("\\E"));
+ on_state = State::S1;
+ off_state = State::S0;
+ } else
+ if (dlatch->type == "$_DLATCH_N_") {
+ sig_e = assign_map(dlatch->getPort("\\E"));
+ on_state = State::S0;
+ off_state = State::S1;
+ } else
+ log_abort();
- if (sig_e == State::S0)
+ if (sig_e == off_state)
{
RTLIL::Const val_init;
for (auto bit : dff_init_map(dlatch->getPort("\\Q")))
@@ -52,7 +242,7 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
goto delete_dlatch;
}
- if (sig_e == State::S1)
+ if (sig_e == on_state)
{
mod->connect(dlatch->getPort("\\Q"), dlatch->getPort("\\D"));
goto delete_dlatch;
@@ -168,7 +358,7 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
goto delete_dff;
}
- if (sig_d == sig_q && (!sig_r.size() || !has_init || val_init == val_rv)) {
+ if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) {
if (sig_r.size())
mod->connect(sig_q, val_rv);
if (has_init)
@@ -176,6 +366,28 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
goto delete_dff;
}
+ if (!sig_r.empty() && sig_r.is_fully_const())
+ {
+ if (sig_r == val_rp || sig_r.is_fully_undef()) {
+ mod->connect(sig_q, val_rv);
+ goto delete_dff;
+ }
+
+ log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
+
+ if (dff->type == "$adff") {
+ dff->type = "$dff";
+ dff->unsetPort("\\ARST");
+ dff->unsetParam("\\ARST_POLARITY");
+ dff->unsetParam("\\ARST_VALUE");
+ return true;
+ }
+
+ log_assert(dff->type.substr(0,6) == "$_DFF_");
+ dff->type = stringf("$_DFF_%c_", + dff->type[6]);
+ dff->unsetPort("\\R");
+ }
+
return false;
delete_dff:
@@ -187,7 +399,7 @@ delete_dff:
struct OptRmdffPass : public Pass {
OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -197,7 +409,7 @@ struct OptRmdffPass : public Pass {
log("a constant driver.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
int total_count = 0, total_initdrv = 0;
log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
@@ -221,12 +433,16 @@ struct OptRmdffPass : public Pass {
assign_map.set(module);
dff_init_map.set(module);
+ mux_drivers.clear();
+ init_attributes.clear();
for (auto wire : module->wires())
{
if (wire->attributes.count("\\init") != 0) {
Const initval = wire->attributes.at("\\init");
- dff_init_map.add(wire, initval);
+ for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ dff_init_map.add(SigBit(wire, i), initval[i]);
for (int i = 0; i < GetSize(wire); i++) {
SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit);
if (mapped_bit.wire) {
@@ -245,6 +461,7 @@ struct OptRmdffPass : public Pass {
mux_drivers.clear();
std::vector<RTLIL::IdString> dff_list;
+ std::vector<RTLIL::IdString> dffsr_list;
std::vector<RTLIL::IdString> dlatch_list;
for (auto cell : module->cells())
{
@@ -262,16 +479,28 @@ struct OptRmdffPass : public Pass {
if (!design->selected(module, cell))
continue;
+ if (cell->type.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
+ "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_", "$dffsr",
+ "$_DLATCHSR_NNN_", "$_DLATCHSR_NNP_", "$_DLATCHSR_NPN_", "$_DLATCHSR_NPP_",
+ "$_DLATCHSR_PNN_", "$_DLATCHSR_PNP_", "$_DLATCHSR_PPN_", "$_DLATCHSR_PPP_", "$dlatchsr"))
+ dffsr_list.push_back(cell->name);
+
if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
"$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
"$ff", "$dff", "$adff"))
dff_list.push_back(cell->name);
- if (cell->type == "$dlatch")
+ if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
dlatch_list.push_back(cell->name);
}
+ for (auto &id : dffsr_list) {
+ if (module->cell(id) != nullptr &&
+ handle_dffsr(module, module->cells_[id]))
+ total_count++;
+ }
+
for (auto &id : dff_list) {
if (module->cell(id) != nullptr &&
handle_dff(module, module->cells_[id]))
@@ -310,6 +539,7 @@ struct OptRmdffPass : public Pass {
assign_map.clear();
mux_drivers.clear();
+ init_attributes.clear();
if (total_count || total_initdrv)
design->scratchpad_set_bool("opt.did_something", true);
diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc
new file mode 100644
index 00000000..fc1596eb
--- /dev/null
+++ b/passes/opt/rmports.cc
@@ -0,0 +1,187 @@
+/*
+ * 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/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct RmportsPassPass : public Pass {
+ RmportsPassPass() : Pass("rmports", "remove module ports with no connections") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" rmports [selection]\n");
+ log("\n");
+ log("This pass identifies ports in the selected modules which are not used or\n");
+ log("driven and removes them.\n");
+ log("\n");
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing RMPORTS pass (remove ports with no connections).\n");
+
+ size_t argidx = 1;
+ extra_args(args, argidx, design);
+
+ // The set of ports we removed
+ dict<IdString, pool<IdString>> removed_ports;
+
+ // Find all of the unused ports, and remove them from that module
+ auto modules = design->selected_modules();
+ for(auto mod : modules)
+ ScanModule(mod, removed_ports);
+
+ // Remove the unused ports from all instances of those modules
+ for(auto mod : modules)
+ CleanupModule(mod, removed_ports);
+ }
+
+ void CleanupModule(Module *module, dict<IdString, pool<IdString>> &removed_ports)
+ {
+ log("Removing now-unused cell ports in module %s\n", module->name.c_str());
+
+ auto cells = module->cells();
+ for(auto cell : cells)
+ {
+ if(removed_ports.find(cell->type) == removed_ports.end())
+ {
+ // log(" Not touching instance \"%s\" because we didn't remove any ports from module \"%s\"\n",
+ // cell->name.c_str(), cell->type.c_str());
+ continue;
+ }
+
+ auto ports_to_remove = removed_ports[cell->type];
+ for(auto p : ports_to_remove)
+ {
+ log(" Removing port \"%s\" from instance \"%s\"\n",
+ p.c_str(), cell->type.c_str());
+ cell->unsetPort(p);
+ }
+ }
+ }
+
+ void ScanModule(Module* module, dict<IdString, pool<IdString>> &removed_ports)
+ {
+ log("Finding unconnected ports in module %s\n", module->name.c_str());
+
+ pool<IdString> used_ports;
+
+ // See what wires are used.
+ // Start by checking connections between named wires
+ auto &conns = module->connections();
+ for(auto sigsig : conns)
+ {
+ auto s1 = sigsig.first;
+ auto s2 = sigsig.second;
+
+ int len1 = s1.size();
+ int len2 = s2.size();
+ int len = len1;
+ if(len2 < len1)
+ len = len2;
+
+ for(int i=0; i<len; i++)
+ {
+ auto w1 = s1[i].wire;
+ auto w2 = s2[i].wire;
+ if( (w1 == NULL) || (w2 == NULL) )
+ continue;
+
+ //log(" conn %s, %s\n", w1->name.c_str(), w2->name.c_str());
+
+ if( (w1->port_input || w1->port_output) && (used_ports.find(w1->name) == used_ports.end()) )
+ used_ports.insert(w1->name);
+
+ if( (w2->port_input || w2->port_output) && (used_ports.find(w2->name) == used_ports.end()) )
+ used_ports.insert(w2->name);
+ }
+ }
+
+ // Then check connections to cells
+ auto cells = module->cells();
+ for(auto cell : cells)
+ {
+ auto &cconns = cell->connections();
+ for(auto conn : cconns)
+ {
+ for(int i=0; i<conn.second.size(); i++)
+ {
+ auto sig = conn.second[i].wire;
+ if(sig == NULL)
+ continue;
+
+ // log(" sig %s\n", sig->name.c_str());
+ if( (sig->port_input || sig->port_output) && (used_ports.find(sig->name) == used_ports.end()) )
+ used_ports.insert(sig->name);
+ }
+ }
+ }
+
+ // Now that we know what IS used, get rid of anything that isn't in that list
+ pool<IdString> unused_ports;
+ for(auto port : module->ports)
+ {
+ if(used_ports.find(port) != used_ports.end())
+ continue;
+ unused_ports.insert(port);
+ }
+
+ // Print the ports out as we go through them
+ for(auto port : unused_ports)
+ {
+ log(" removing unused port %s\n", port.c_str());
+ removed_ports[module->name].insert(port);
+
+ // Remove from ports list
+ for(size_t i=0; i<module->ports.size(); i++)
+ {
+ if(module->ports[i] == port)
+ {
+ module->ports.erase(module->ports.begin() + i);
+ break;
+ }
+ }
+
+ // Mark the wire as no longer a port
+ auto wire = module->wire(port);
+ wire->port_input = false;
+ wire->port_output = false;
+ wire->port_id = 0;
+ }
+ log("Removed %zu unused ports.\n", unused_ports.size());
+
+ // Re-number all of the wires that DO have ports still on them
+ for(size_t i=0; i<module->ports.size(); i++)
+ {
+ auto port = module->ports[i];
+ auto wire = module->wire(port);
+ wire->port_id = i+1;
+ }
+ }
+
+} RmportsPassPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 22914eaa..b8028082 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -1421,7 +1421,7 @@ struct ShareWorker
struct SharePass : public Pass {
SharePass() : Pass("share", "perform sat-based resource sharing") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1453,7 +1453,7 @@ struct SharePass : public Pass {
log(" Only perform the first N merges, then stop. This is useful for debugging.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
ShareWorkerConfig config;
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 07503fbb..0164f58d 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -353,7 +353,7 @@ struct WreduceWorker
struct WreducePass : public Pass {
WreducePass() : Pass("wreduce", "reduce the word size of operations if possible") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -373,7 +373,7 @@ struct WreducePass : public Pass {
log(" flows that use the 'memory_memx' pass.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
WreduceConfig config;
bool opt_memx = false;
diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc
index d5366f26..ef7cb0f7 100644
--- a/passes/proc/proc.cc
+++ b/passes/proc/proc.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ProcPass : public Pass {
ProcPass() : Pass("proc", "translate processes to netlists") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -57,7 +57,7 @@ struct ProcPass : public Pass {
log(" executed in -ifx mode.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string global_arst;
bool ifxmode = false;
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index 216b00dd..b69eba3f 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -203,7 +203,7 @@ restart_proc_arst:
struct ProcArstPass : public Pass {
ProcArstPass() : Pass("proc_arst", "detect asynchronous resets") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -221,7 +221,7 @@ struct ProcArstPass : public Pass {
log(" in the 'init' attribute on the net.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string global_arst;
bool global_arst_neg = false;
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 7dbabc21..b9e43d1d 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -143,7 +143,7 @@ void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count)
struct ProcCleanPass : public Pass {
ProcCleanPass() : Pass("proc_clean", "remove empty parts of processes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -153,7 +153,7 @@ struct ProcCleanPass : public Pass {
log("if it contains only empty structures.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
int total_count = 0;
log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index 98653dc6..519d35cd 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -322,6 +322,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
}
}
+ SigSpec sig_q = sig;
ce.assign_map.apply(insig);
ce.assign_map.apply(rstval);
ce.assign_map.apply(sig);
@@ -350,13 +351,13 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
else if (!rstval.is_fully_const() && !ce.eval(rstval))
{
log_warning("Async reset value `%s' is not constant!\n", log_signal(rstval));
- gen_dffsr(mod, insig, rstval, sig,
+ gen_dffsr(mod, insig, rstval, sig_q,
sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
sync_edge->signal, sync_level->signal, proc);
}
else
- gen_dff(mod, insig, rstval.as_const(), sig,
+ gen_dff(mod, insig, rstval.as_const(), sig_q,
sync_edge && sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
sync_edge ? sync_edge->signal : SigSpec(),
@@ -369,7 +370,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
struct ProcDffPass : public Pass {
ProcDffPass() : Pass("proc_dff", "extract flip-flops from processes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -379,7 +380,7 @@ struct ProcDffPass : public Pass {
log("d-type flip-flop cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PROC_DFF pass (convert process syncs to FFs).\n");
diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc
index 6621afd3..d9d5dfbe 100644
--- a/passes/proc/proc_dlatch.cc
+++ b/passes/proc/proc_dlatch.cc
@@ -217,7 +217,7 @@ struct proc_dlatch_db_t
return make_inner(children);
}
- SigBit make_hold(int n)
+ SigBit make_hold(int n, string &src)
{
if (n == true_node)
return State::S1;
@@ -235,20 +235,20 @@ struct proc_dlatch_db_t
if (rule.match == State::S1)
and_bits.append(rule.signal);
else if (rule.match == State::S0)
- and_bits.append(module->Not(NEW_ID, rule.signal));
+ and_bits.append(module->Not(NEW_ID, rule.signal, false, src));
else
- and_bits.append(module->Eq(NEW_ID, rule.signal, rule.match));
+ and_bits.append(module->Eq(NEW_ID, rule.signal, rule.match, false, src));
}
if (!rule.children.empty()) {
SigSpec or_bits;
for (int k : rule.children)
- or_bits.append(make_hold(k));
- and_bits.append(module->ReduceOr(NEW_ID, or_bits));
+ or_bits.append(make_hold(k, src));
+ and_bits.append(module->ReduceOr(NEW_ID, or_bits, false, src));
}
if (GetSize(and_bits) == 2)
- and_bits = module->And(NEW_ID, and_bits[0], and_bits[1]);
+ and_bits = module->And(NEW_ID, and_bits[0], and_bits[1], false, src);
log_assert(GetSize(and_bits) == 1);
rules_sig[n] = and_bits[0];
@@ -340,6 +340,7 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
RTLIL::SigSig latches_bits, nolatches_bits;
dict<SigBit, SigBit> latches_out_in;
dict<SigBit, int> latches_hold;
+ std::string src = proc->get_src_attribute();
for (auto sr : proc->syncs)
{
@@ -405,7 +406,8 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
SigSpec lhs = latches_bits.first.extract(offset, width);
SigSpec rhs = latches_bits.second.extract(offset, width);
- Cell *cell = db.module->addDlatch(NEW_ID, db.module->Not(NEW_ID, db.make_hold(n)), rhs, lhs);
+ Cell *cell = db.module->addDlatch(NEW_ID, db.module->Not(NEW_ID, db.make_hold(n, src)), rhs, lhs);
+ cell->set_src_attribute(src);
db.generated_dlatches.insert(cell);
log("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n",
@@ -420,7 +422,7 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
struct ProcDlatchPass : public Pass {
ProcDlatchPass() : Pass("proc_dlatch", "extract latches from processes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -430,7 +432,7 @@ struct ProcDlatchPass : public Pass {
log("d-type latches.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PROC_DLATCH pass (convert process syncs to latches).\n");
diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc
index 0c8fb83d..e2dc07e5 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -102,7 +102,7 @@ void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
struct ProcInitPass : public Pass {
ProcInitPass() : Pass("proc_init", "convert initial block to init attributes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -113,7 +113,7 @@ struct ProcInitPass : public Pass {
log("respective wire.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PROC_INIT pass (extract init attributes).\n");
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index 57e131ca..1329c1fe 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -382,7 +382,7 @@ void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc, bool ifxmode)
struct ProcMuxPass : public Pass {
ProcMuxPass() : Pass("proc_mux", "convert decision trees to multiplexers") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -396,7 +396,7 @@ struct ProcMuxPass : public Pass {
log(" 'case' expressions and 'if' conditions.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool ifxmode = false;
log_header(design, "Executing PROC_MUX pass (convert decision trees to multiplexers).\n");
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
index 5672fb47..7c334e66 100644
--- a/passes/proc/proc_rmdead.cc
+++ b/passes/proc/proc_rmdead.cc
@@ -65,7 +65,7 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
struct ProcRmdeadPass : public Pass {
ProcRmdeadPass() : Pass("proc_rmdead", "eliminate dead trees in decision trees") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -74,7 +74,7 @@ struct ProcRmdeadPass : public Pass {
log("This pass identifies unreachable branches in decision trees and removes them.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PROC_RMDEAD pass (remove dead branches from decision trees).\n");
diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc
index 6785b750..8ab0280c 100644
--- a/passes/sat/Makefile.inc
+++ b/passes/sat/Makefile.inc
@@ -2,8 +2,10 @@
OBJS += passes/sat/sat.o
OBJS += passes/sat/freduce.o
OBJS += passes/sat/eval.o
+OBJS += passes/sat/sim.o
OBJS += passes/sat/miter.o
OBJS += passes/sat/expose.o
OBJS += passes/sat/assertpmux.o
OBJS += passes/sat/clk2fflogic.o
+OBJS += passes/sat/async2sync.o
diff --git a/passes/sat/assertpmux.cc b/passes/sat/assertpmux.cc
index 63a90767..509cb0ba 100644
--- a/passes/sat/assertpmux.cc
+++ b/passes/sat/assertpmux.cc
@@ -181,7 +181,7 @@ struct AssertpmuxWorker
struct AssertpmuxPass : public Pass {
AssertpmuxPass() : Pass("assertpmux", "convert internal signals to module ports") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -199,7 +199,7 @@ struct AssertpmuxPass : public Pass {
log(" additional constrained and check the $pmux condition always.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_noinit = false;
bool flag_always = false;
diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc
new file mode 100644
index 00000000..c92db711
--- /dev/null
+++ b/passes/sat/async2sync.cc
@@ -0,0 +1,147 @@
+/*
+ * 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 Async2syncPass : public Pass {
+ Async2syncPass() : Pass("async2sync", "convert async FF inputs to sync circuits") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" async2sync [options] [selection]\n");
+ log("\n");
+ log("This command replaces async FF inputs with sync circuits emulating the same\n");
+ log("behavior for when the async signals are actually synchronized to the clock.\n");
+ log("\n");
+ log("This pass assumes negative hold time for the async FF inputs. For example when\n");
+ log("a reset deasserts with the clock edge, then the FF output will still drive the\n");
+ log("reset value in the next cycle regardless of the data-in value at the time of\n");
+ log("the clock edge.\n");
+ log("\n");
+ log("Currently only $adff cells are supported by this pass.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ // bool flag_noinit = false;
+
+ log_header(design, "Executing ASYNC2SYNC pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-noinit") {
+ // flag_noinit = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+ dict<SigBit, State> initbits;
+ pool<SigBit> del_initbits;
+
+ for (auto wire : module->wires())
+ if (wire->attributes.count("\\init") > 0)
+ {
+ Const initval = wire->attributes.at("\\init");
+ SigSpec initsig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ initbits[initsig[i]] = initval[i];
+ }
+
+ for (auto cell : vector<Cell*>(module->selected_cells()))
+ {
+ if (cell->type.in("$adff"))
+ {
+ // bool clk_pol = cell->parameters["\\CLK_POLARITY"].as_bool();
+ bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool();
+ Const arst_val = cell->parameters["\\ARST_VALUE"];
+
+ SigSpec sig_clk = cell->getPort("\\CLK");
+ SigSpec sig_arst = cell->getPort("\\ARST");
+ SigSpec sig_d = cell->getPort("\\D");
+ SigSpec sig_q = cell->getPort("\\Q");
+
+ log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_signal(sig_arst), log_signal(sig_d), log_signal(sig_q));
+
+ Const init_val;
+ for (int i = 0; i < GetSize(sig_q); i++) {
+ SigBit bit = sigmap(sig_q[i]);
+ init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx);
+ del_initbits.insert(bit);
+ }
+
+ Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d));
+ Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
+ new_q->attributes["\\init"] = init_val;
+
+ if (arst_pol) {
+ module->addMux(NEW_ID, sig_d, arst_val, sig_arst, new_d);
+ module->addMux(NEW_ID, new_q, arst_val, sig_arst, sig_q);
+ } else {
+ module->addMux(NEW_ID, arst_val, sig_d, sig_arst, new_d);
+ module->addMux(NEW_ID, arst_val, new_q, sig_arst, sig_q);
+ }
+
+ cell->setPort("\\D", new_d);
+ cell->setPort("\\Q", new_q);
+ cell->unsetPort("\\ARST");
+ cell->unsetParam("\\ARST_POLARITY");
+ cell->unsetParam("\\ARST_VALUE");
+ cell->type = "$dff";
+ continue;
+ }
+ }
+
+ for (auto wire : module->wires())
+ if (wire->attributes.count("\\init") > 0)
+ {
+ bool delete_initattr = true;
+ Const initval = wire->attributes.at("\\init");
+ SigSpec initsig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
+ if (del_initbits.count(initsig[i]) > 0)
+ initval[i] = State::Sx;
+ else if (initval[i] != State::Sx)
+ delete_initattr = false;
+
+ if (delete_initattr)
+ wire->attributes.erase("\\init");
+ else
+ wire->attributes.at("\\init") = initval;
+ }
+ }
+ }
+} Async2syncPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc
index ef6d5dd7..49ec795d 100644
--- a/passes/sat/clk2fflogic.cc
+++ b/passes/sat/clk2fflogic.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct Clk2fflogicPass : public Pass {
Clk2fflogicPass() : Pass("clk2fflogic", "convert clocked FFs to generic $ff cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -36,7 +36,7 @@ struct Clk2fflogicPass : public Pass {
log("multiple clocks.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
// bool flag_noinit = false;
@@ -72,7 +72,88 @@ struct Clk2fflogicPass : public Pass {
for (auto cell : vector<Cell*>(module->selected_cells()))
{
- if (cell->type.in("$dlatch"))
+ if (cell->type.in("$mem"))
+ {
+ int abits = cell->getParam("\\ABITS").as_int();
+ int width = cell->getParam("\\WIDTH").as_int();
+ int rd_ports = cell->getParam("\\RD_PORTS").as_int();
+ int wr_ports = cell->getParam("\\WR_PORTS").as_int();
+
+ for (int i = 0; i < rd_ports; i++) {
+ if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool())
+ log_error("Read port %d of memory %s.%s is clocked. This is not supported by \"clk2fflogic\"! "
+ "Call \"memory\" with -nordff to avoid this error.\n", i, log_id(cell), log_id(module));
+ }
+
+ Const wr_clk_en_param = cell->getParam("\\WR_CLK_ENABLE");
+ Const wr_clk_pol_param = cell->getParam("\\WR_CLK_POLARITY");
+
+ SigSpec wr_clk_port = cell->getPort("\\WR_CLK");
+ SigSpec wr_en_port = cell->getPort("\\WR_EN");
+ SigSpec wr_addr_port = cell->getPort("\\WR_ADDR");
+ SigSpec wr_data_port = cell->getPort("\\WR_DATA");
+
+ for (int wport = 0; wport < wr_ports; wport++)
+ {
+ bool clken = wr_clk_en_param[wport] == State::S1;
+ bool clkpol = wr_clk_pol_param[wport] == State::S1;
+
+ if (!clken)
+ continue;
+
+ SigBit clk = wr_clk_port[wport];
+ SigSpec en = wr_en_port.extract(wport*width, width);
+ SigSpec addr = wr_addr_port.extract(wport*abits, abits);
+ SigSpec data = wr_data_port.extract(wport*width, width);
+
+ log("Modifying write port %d on memory %s.%s: CLK=%s, A=%s, D=%s\n",
+ wport, log_id(module), log_id(cell), log_signal(clk),
+ log_signal(addr), log_signal(data));
+
+ Wire *past_clk = module->addWire(NEW_ID);
+ past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0;
+ module->addFf(NEW_ID, clk, past_clk);
+
+ SigSpec clock_edge_pattern;
+
+ if (clkpol) {
+ clock_edge_pattern.append_bit(State::S0);
+ clock_edge_pattern.append_bit(State::S1);
+ } else {
+ clock_edge_pattern.append_bit(State::S1);
+ clock_edge_pattern.append_bit(State::S0);
+ }
+
+ SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern);
+
+ SigSpec en_q = module->addWire(NEW_ID, GetSize(en));
+ module->addFf(NEW_ID, en, en_q);
+
+ SigSpec addr_q = module->addWire(NEW_ID, GetSize(addr));
+ module->addFf(NEW_ID, addr, addr_q);
+
+ SigSpec data_q = module->addWire(NEW_ID, GetSize(data));
+ module->addFf(NEW_ID, data, data_q);
+
+ wr_clk_port[wport] = State::S0;
+ wr_en_port.replace(wport*width, module->Mux(NEW_ID, Const(0, GetSize(en_q)), en_q, clock_edge));
+ wr_addr_port.replace(wport*abits, addr_q);
+ wr_data_port.replace(wport*width, data_q);
+
+ wr_clk_en_param[wport] = State::S0;
+ wr_clk_pol_param[wport] = State::S0;
+ }
+
+ cell->setParam("\\WR_CLK_ENABLE", wr_clk_en_param);
+ cell->setParam("\\WR_CLK_POLARITY", wr_clk_pol_param);
+
+ cell->setPort("\\WR_CLK", wr_clk_port);
+ cell->setPort("\\WR_EN", wr_en_port);
+ cell->setPort("\\WR_ADDR", wr_addr_port);
+ cell->setPort("\\WR_DATA", wr_data_port);
+ }
+
+ if (cell->type.in("$dlatch", "$dlatchsr"))
{
bool enpol = cell->parameters["\\EN_POLARITY"].as_bool();
@@ -87,10 +168,31 @@ struct Clk2fflogicPass : public Pass {
Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
module->addFf(NEW_ID, sig_q, past_q);
- if (enpol)
- module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q);
+ if (cell->type == "$dlatch")
+ {
+ if (enpol)
+ module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q);
+ else
+ module->addMux(NEW_ID, sig_d, past_q, sig_en, sig_q);
+ }
else
- module->addMux(NEW_ID, sig_d, past_q, sig_en, sig_q);
+ {
+ SigSpec t;
+ if (enpol)
+ t = module->Mux(NEW_ID, past_q, sig_d, sig_en);
+ else
+ t = module->Mux(NEW_ID, sig_d, past_q, sig_en);
+
+ SigSpec s = cell->getPort("\\SET");
+ if (!cell->parameters["\\SET_POLARITY"].as_bool())
+ s = module->Not(NEW_ID, s);
+ t = module->Or(NEW_ID, t, s);
+
+ SigSpec c = cell->getPort("\\CLR");
+ if (cell->parameters["\\CLR_POLARITY"].as_bool())
+ c = module->Not(NEW_ID, c);
+ module->addAnd(NEW_ID, t, c, sig_q);
+ }
Const initval;
bool assign_initval = false;
diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc
index 09f69cc5..008cd2df 100644
--- a/passes/sat/eval.cc
+++ b/passes/sat/eval.cc
@@ -360,7 +360,7 @@ struct VlogHammerReporter
struct EvalPass : public Pass {
EvalPass() : Pass("eval", "evaluate the circuit given an input") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -383,7 +383,7 @@ struct EvalPass : public Pass {
log(" then all output ports of the current module are used.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<std::pair<std::string, std::string>> sets;
std::vector<std::string> shows, tables;
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index 9427547f..80934548 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -220,7 +220,7 @@ RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width
struct ExposePass : public Pass {
ExposePass() : Pass("expose", "convert internal signals to module ports") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -236,6 +236,10 @@ struct ExposePass : public Pass {
log(" when exposing a wire, create an input/output pair and cut the internal\n");
log(" signal path at that wire.\n");
log("\n");
+ log(" -input\n");
+ log(" when exposing a wire, create an input port and disconnect the internal\n");
+ log(" driver.\n");
+ log("\n");
log(" -shared\n");
log(" only expose those signals that are shared among the selected modules.\n");
log(" this is useful for preparing modules for equivalence checking.\n");
@@ -253,12 +257,13 @@ struct ExposePass : public Pass {
log(" designator for the exposed signal.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_shared = false;
bool flag_evert = false;
bool flag_dff = false;
bool flag_cut = false;
+ bool flag_input = false;
bool flag_evert_dff = false;
std::string sep = ".";
@@ -279,10 +284,14 @@ struct ExposePass : public Pass {
flag_dff = true;
continue;
}
- if (args[argidx] == "-cut") {
+ if (args[argidx] == "-cut" && !flag_input) {
flag_cut = true;
continue;
}
+ if (args[argidx] == "-input" && !flag_cut) {
+ flag_input = true;
+ continue;
+ }
if (args[argidx] == "-evert-dff") {
flag_evert_dff = true;
continue;
@@ -464,16 +473,42 @@ struct ExposePass : public Pass {
continue;
}
- if (!it.second->port_output) {
- it.second->port_output = true;
- log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name));
+ if (flag_input)
+ {
+ if (!it.second->port_input) {
+ it.second->port_input = true;
+ log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name));
+ RTLIL::Wire *w = module->addWire(NEW_ID, GetSize(it.second));
+ out_to_in_map.add(it.second, w);
+ }
+ }
+ else
+ {
+ if (!it.second->port_output) {
+ it.second->port_output = true;
+ log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name));
+ }
+
+ if (flag_cut) {
+ RTLIL::Wire *in_wire = add_new_wire(module, it.second->name.str() + sep + "i", it.second->width);
+ in_wire->port_input = true;
+ out_to_in_map.add(sigmap(it.second), in_wire);
+ }
}
+ }
- if (flag_cut) {
- RTLIL::Wire *in_wire = add_new_wire(module, it.second->name.str() + sep + "i", it.second->width);
- in_wire->port_input = true;
- out_to_in_map.add(sigmap(it.second), in_wire);
+ if (flag_input)
+ {
+ for (auto &it : module->cells_) {
+ if (!ct.cell_known(it.second->type))
+ continue;
+ for (auto &conn : it.second->connections_)
+ if (ct.cell_output(it.second->type, conn.first))
+ conn.second = out_to_in_map(sigmap(conn.second));
}
+
+ for (auto &conn : module->connections_)
+ conn.first = out_to_in_map(sigmap(conn.first));
}
if (flag_cut)
diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc
index 77263f6a..f2963163 100644
--- a/passes/sat/freduce.cc
+++ b/passes/sat/freduce.cc
@@ -687,7 +687,8 @@ struct FreduceWorker
}
std::map<RTLIL::SigBit, int> bitusage;
- module->rewrite_sigspecs(CountBitUsage(sigmap, bitusage));
+ CountBitUsage bitusage_worker(sigmap, bitusage);
+ module->rewrite_sigspecs(bitusage_worker);
if (!dump_prefix.empty())
dump();
@@ -759,7 +760,7 @@ struct FreduceWorker
struct FreducePass : public Pass {
FreducePass() : Pass("freduce", "perform functional reduction") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -790,7 +791,7 @@ struct FreducePass : public Pass {
log("circuit that is analyzed.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
reduce_counter = 0;
reduce_stop_at = 0;
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index 9e150b60..d37f1b12 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -358,7 +358,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
struct MiterPass : public Pass {
MiterPass() : Pass("miter", "automatically create a miter circuit") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -402,7 +402,7 @@ struct MiterPass : public Pass {
log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
if (args.size() > 1 && args[1] == "-equiv") {
create_miter_equiv(this, args, design);
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index a6ac7afd..695a03e1 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -691,7 +691,6 @@ struct SatHelper
// VCD has some limits on internal (non-display) identifier names, so make legal ones
std::map<std::string, std::string> vcdnames;
- fprintf(f, "$timescale 1ns\n"); // arbitrary time scale since actual clock period is unknown/unimportant
fprintf(f, "$scope module %s $end\n", module->name.c_str());
for (auto &info : modelInfo)
{
@@ -891,7 +890,7 @@ void print_qed()
struct SatPass : public Pass {
SatPass() : Pass("sat", "solve a SAT problem in the circuit") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1058,7 +1057,7 @@ struct SatPass : public Pass {
log(" Like -falsify but do not return an error for timeouts.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<std::pair<std::string, std::string>> sets, sets_init, prove, prove_x;
std::map<int, std::vector<std::pair<std::string, std::string>>> sets_at;
diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc
new file mode 100644
index 00000000..53e248ad
--- /dev/null
+++ b/passes/sat/sim.cc
@@ -0,0 +1,862 @@
+/*
+ * 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"
+#include "kernel/celltypes.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SimShared
+{
+ bool debug = false;
+ bool hide_internal = true;
+ bool writeback = false;
+ bool zinit = false;
+ int rstlen = 1;
+};
+
+void zinit(State &v)
+{
+ if (v != State::S1)
+ v = State::S0;
+}
+
+void zinit(Const &v)
+{
+ for (auto &bit : v.bits)
+ zinit(bit);
+}
+
+struct SimInstance
+{
+ SimShared *shared;
+
+ Module *module;
+ Cell *instance;
+
+ SimInstance *parent;
+ dict<Cell*, SimInstance*> children;
+
+ SigMap sigmap;
+ dict<SigBit, State> state_nets;
+ dict<SigBit, pool<Cell*>> upd_cells;
+ dict<SigBit, pool<Wire*>> upd_outports;
+
+ pool<SigBit> dirty_bits;
+ pool<Cell*> dirty_cells;
+ pool<SimInstance*, hash_ptr_ops> dirty_children;
+
+ struct ff_state_t
+ {
+ State past_clock;
+ Const past_d;
+ };
+
+ struct mem_state_t
+ {
+ Const past_wr_clk;
+ Const past_wr_en;
+ Const past_wr_addr;
+ Const past_wr_data;
+ Const data;
+ };
+
+ dict<Cell*, ff_state_t> ff_database;
+ dict<Cell*, mem_state_t> mem_database;
+ pool<Cell*> formal_database;
+
+ dict<Wire*, pair<int, Const>> vcd_database;
+
+ SimInstance(SimShared *shared, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
+ shared(shared), module(module), instance(instance), parent(parent), sigmap(module)
+ {
+ if (parent) {
+ log_assert(parent->children.count(instance) == 0);
+ parent->children[instance] = this;
+ }
+
+ for (auto wire : module->wires())
+ {
+ SigSpec sig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(sig); i++) {
+ if (state_nets.count(sig[i]) == 0)
+ state_nets[sig[i]] = State::Sx;
+ if (wire->port_output) {
+ upd_outports[sig[i]].insert(wire);
+ dirty_bits.insert(sig[i]);
+ }
+ }
+
+ if (wire->attributes.count("\\init")) {
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1) {
+ state_nets[sig[i]] = initval[i];
+ dirty_bits.insert(sig[i]);
+ }
+ }
+ }
+
+ for (auto cell : module->cells())
+ {
+ Module *mod = module->design->module(cell->type);
+
+ if (mod != nullptr) {
+ dirty_children.insert(new SimInstance(shared, mod, cell, this));
+ }
+
+ for (auto &port : cell->connections()) {
+ if (cell->input(port.first))
+ for (auto bit : sigmap(port.second))
+ upd_cells[bit].insert(cell);
+ }
+
+ if (cell->type.in("$dff")) {
+ ff_state_t ff;
+ ff.past_clock = State::Sx;
+ ff.past_d = Const(State::Sx, cell->getParam("\\WIDTH").as_int());
+ ff_database[cell] = ff;
+ }
+
+ if (cell->type == "$mem")
+ {
+ mem_state_t mem;
+
+ mem.past_wr_clk = Const(State::Sx, GetSize(cell->getPort("\\WR_CLK")));
+ mem.past_wr_en = Const(State::Sx, GetSize(cell->getPort("\\WR_EN")));
+ mem.past_wr_addr = Const(State::Sx, GetSize(cell->getPort("\\WR_ADDR")));
+ mem.past_wr_data = Const(State::Sx, GetSize(cell->getPort("\\WR_DATA")));
+
+ mem.data = cell->getParam("\\INIT");
+ int sz = cell->getParam("\\SIZE").as_int() * cell->getParam("\\WIDTH").as_int();
+
+ if (GetSize(mem.data) > sz)
+ mem.data.bits.resize(sz);
+
+ while (GetSize(mem.data) < sz)
+ mem.data.bits.push_back(State::Sx);
+
+ mem_database[cell] = mem;
+ }
+
+ if (cell->type.in("$assert", "$cover", "$assume")) {
+ formal_database.insert(cell);
+ }
+ }
+
+ if (shared->zinit)
+ {
+ for (auto &it : ff_database)
+ {
+ Cell *cell = it.first;
+ ff_state_t &ff = it.second;
+ zinit(ff.past_d);
+
+ SigSpec qsig = cell->getPort("\\Q");
+ Const qdata = get_state(qsig);
+ zinit(qdata);
+ set_state(qsig, qdata);
+ }
+
+ for (auto &it : mem_database) {
+ mem_state_t &mem = it.second;
+ zinit(mem.past_wr_en);
+ zinit(mem.data);
+ }
+ }
+ }
+
+ ~SimInstance()
+ {
+ for (auto child : children)
+ delete child.second;
+ }
+
+ IdString name() const
+ {
+ if (instance != nullptr)
+ return instance->name;
+ return module->name;
+ }
+
+ std::string hiername() const
+ {
+ if (instance != nullptr)
+ return parent->hiername() + "." + log_id(instance->name);
+
+ return log_id(module->name);
+ }
+
+ Const get_state(SigSpec sig)
+ {
+ Const value;
+
+ for (auto bit : sigmap(sig))
+ if (bit.wire == nullptr)
+ value.bits.push_back(bit.data);
+ else if (state_nets.count(bit))
+ value.bits.push_back(state_nets.at(bit));
+ else
+ value.bits.push_back(State::Sz);
+
+ if (shared->debug)
+ log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
+ return value;
+ }
+
+ bool set_state(SigSpec sig, Const value)
+ {
+ bool did_something = false;
+
+ sig = sigmap(sig);
+ log_assert(GetSize(sig) == GetSize(value));
+
+ for (int i = 0; i < GetSize(sig); i++)
+ if (state_nets.at(sig[i]) != value[i]) {
+ state_nets.at(sig[i]) = value[i];
+ dirty_bits.insert(sig[i]);
+ did_something = true;
+ }
+
+ if (shared->debug)
+ log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
+ return did_something;
+ }
+
+ void update_cell(Cell *cell)
+ {
+ if (ff_database.count(cell))
+ return;
+
+ if (formal_database.count(cell))
+ return;
+
+ if (mem_database.count(cell))
+ {
+ mem_state_t &mem = mem_database.at(cell);
+
+ int num_rd_ports = cell->getParam("\\RD_PORTS").as_int();
+
+ int size = cell->getParam("\\SIZE").as_int();
+ int offset = cell->getParam("\\OFFSET").as_int();
+ int abits = cell->getParam("\\ABITS").as_int();
+ int width = cell->getParam("\\WIDTH").as_int();
+
+ if (cell->getParam("\\RD_CLK_ENABLE").as_bool())
+ log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(cell));
+
+ SigSpec rd_addr_sig = cell->getPort("\\RD_ADDR");
+ SigSpec rd_data_sig = cell->getPort("\\RD_DATA");
+
+ for (int port_idx = 0; port_idx < num_rd_ports; port_idx++)
+ {
+ Const addr = get_state(rd_addr_sig.extract(port_idx*abits, abits));
+ Const data = Const(State::Sx, width);
+
+ if (addr.is_fully_def()) {
+ int index = addr.as_int() - offset;
+ if (index >= 0 && index < size)
+ data = mem.data.extract(index*width, width);
+ }
+
+ set_state(rd_data_sig.extract(port_idx*width, width), data);
+ }
+
+ return;
+ }
+
+ if (children.count(cell))
+ {
+ auto child = children.at(cell);
+ for (auto &conn: cell->connections())
+ if (cell->input(conn.first)) {
+ Const value = get_state(conn.second);
+ child->set_state(child->module->wire(conn.first), value);
+ }
+ dirty_children.insert(child);
+ return;
+ }
+
+ if (yosys_celltypes.cell_evaluable(cell->type))
+ {
+ RTLIL::SigSpec sig_a, sig_b, sig_c, sig_d, sig_s, sig_y;
+ bool has_a, has_b, has_c, has_d, has_s, has_y;
+
+ has_a = cell->hasPort("\\A");
+ has_b = cell->hasPort("\\B");
+ has_c = cell->hasPort("\\C");
+ has_d = cell->hasPort("\\D");
+ has_s = cell->hasPort("\\S");
+ has_y = cell->hasPort("\\Y");
+
+ if (has_a) sig_a = cell->getPort("\\A");
+ if (has_b) sig_b = cell->getPort("\\B");
+ if (has_c) sig_c = cell->getPort("\\C");
+ if (has_d) sig_d = cell->getPort("\\D");
+ if (has_s) sig_s = cell->getPort("\\S");
+ if (has_y) sig_y = cell->getPort("\\Y");
+
+ if (shared->debug)
+ log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell), log_id(cell->type));
+
+ // Simple (A -> Y) and (A,B -> Y) cells
+ if (has_a && !has_c && !has_d && !has_s && has_y) {
+ set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b)));
+ return;
+ }
+
+ // (A,B,C -> Y) cells
+ if (has_a && has_b && has_c && !has_d && !has_s && has_y) {
+ set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_c)));
+ return;
+ }
+
+ // (A,B,S -> Y) cells
+ if (has_a && has_b && !has_c && !has_d && has_s && has_y) {
+ set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_s)));
+ return;
+ }
+
+ log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
+ return;
+ }
+
+ log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
+ }
+
+ void update_ph1()
+ {
+ pool<Cell*> queue_cells;
+ pool<Wire*> queue_outports;
+
+ queue_cells.swap(dirty_cells);
+
+ while (1)
+ {
+ for (auto bit : dirty_bits)
+ {
+ if (upd_cells.count(bit))
+ for (auto cell : upd_cells.at(bit))
+ queue_cells.insert(cell);
+
+ if (upd_outports.count(bit) && parent != nullptr)
+ for (auto wire : upd_outports.at(bit))
+ queue_outports.insert(wire);
+ }
+
+ dirty_bits.clear();
+
+ if (!queue_cells.empty())
+ {
+ for (auto cell : queue_cells)
+ update_cell(cell);
+
+ queue_cells.clear();
+ continue;
+ }
+
+ for (auto wire : queue_outports)
+ if (instance->hasPort(wire->name)) {
+ Const value = get_state(wire);
+ parent->set_state(instance->getPort(wire->name), value);
+ }
+
+ queue_outports.clear();
+
+ for (auto child : dirty_children)
+ child->update_ph1();
+
+ dirty_children.clear();
+
+ if (dirty_bits.empty())
+ break;
+ }
+ }
+
+ bool update_ph2()
+ {
+ bool did_something = false;
+
+ for (auto &it : ff_database)
+ {
+ Cell *cell = it.first;
+ ff_state_t &ff = it.second;
+
+ if (cell->type.in("$dff"))
+ {
+ bool clkpol = cell->getParam("\\CLK_POLARITY").as_bool();
+ State current_clock = get_state(cell->getPort("\\CLK"))[0];
+
+ if (clkpol ? (ff.past_clock == State::S1 || current_clock != State::S1) :
+ (ff.past_clock == State::S0 || current_clock != State::S0))
+ continue;
+
+ if (set_state(cell->getPort("\\Q"), ff.past_d))
+ did_something = true;
+ }
+ }
+
+ for (auto &it : mem_database)
+ {
+ Cell *cell = it.first;
+ mem_state_t &mem = it.second;
+
+ int num_wr_ports = cell->getParam("\\WR_PORTS").as_int();
+
+ int size = cell->getParam("\\SIZE").as_int();
+ int offset = cell->getParam("\\OFFSET").as_int();
+ int abits = cell->getParam("\\ABITS").as_int();
+ int width = cell->getParam("\\WIDTH").as_int();
+
+ Const wr_clk_enable = cell->getParam("\\WR_CLK_ENABLE");
+ Const wr_clk_polarity = cell->getParam("\\WR_CLK_POLARITY");
+ Const current_wr_clk = get_state(cell->getPort("\\WR_CLK"));
+
+ for (int port_idx = 0; port_idx < num_wr_ports; port_idx++)
+ {
+ Const addr, data, enable;
+
+ if (wr_clk_enable[port_idx] == State::S0)
+ {
+ addr = get_state(cell->getPort("\\WR_ADDR").extract(port_idx*abits, abits));
+ data = get_state(cell->getPort("\\WR_DATA").extract(port_idx*width, width));
+ enable = get_state(cell->getPort("\\WR_EN").extract(port_idx*width, width));
+ }
+ else
+ {
+ if (wr_clk_polarity[port_idx] == State::S1 ?
+ (mem.past_wr_clk[port_idx] == State::S1 || current_wr_clk[port_idx] != State::S1) :
+ (mem.past_wr_clk[port_idx] == State::S0 || current_wr_clk[port_idx] != State::S0))
+ continue;
+
+ addr = mem.past_wr_addr.extract(port_idx*abits, abits);
+ data = mem.past_wr_data.extract(port_idx*width, width);
+ enable = mem.past_wr_en.extract(port_idx*width, width);
+ }
+
+ if (addr.is_fully_def())
+ {
+ int index = addr.as_int() - offset;
+ if (index >= 0 && index < size)
+ for (int i = 0; i < width; i++)
+ if (enable[i] == State::S1 && mem.data.bits.at(index*width+i) != data[i]) {
+ mem.data.bits.at(index*width+i) = data[i];
+ dirty_cells.insert(cell);
+ did_something = true;
+ }
+ }
+ }
+ }
+
+ for (auto it : children)
+ if (it.second->update_ph2()) {
+ dirty_children.insert(it.second);
+ did_something = true;
+ }
+
+ return did_something;
+ }
+
+ void update_ph3()
+ {
+ for (auto &it : ff_database)
+ {
+ Cell *cell = it.first;
+ ff_state_t &ff = it.second;
+
+ if (cell->type.in("$dff")) {
+ ff.past_clock = get_state(cell->getPort("\\CLK"))[0];
+ ff.past_d = get_state(cell->getPort("\\D"));
+ }
+ }
+
+ for (auto &it : mem_database)
+ {
+ Cell *cell = it.first;
+ mem_state_t &mem = it.second;
+
+ mem.past_wr_clk = get_state(cell->getPort("\\WR_CLK"));
+ mem.past_wr_en = get_state(cell->getPort("\\WR_EN"));
+ mem.past_wr_addr = get_state(cell->getPort("\\WR_ADDR"));
+ mem.past_wr_data = get_state(cell->getPort("\\WR_DATA"));
+ }
+
+ for (auto cell : formal_database)
+ {
+ string label = log_id(cell);
+ if (cell->attributes.count("\\src"))
+ label = cell->attributes.at("\\src").decode_string();
+
+ State a = get_state(cell->getPort("\\A"))[0];
+ State en = get_state(cell->getPort("\\EN"))[0];
+
+ if (cell->type == "$cover" && en == State::S1 && a != State::S1)
+ log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell), label.c_str());
+
+ if (cell->type == "$assume" && en == State::S1 && a != State::S1)
+ log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
+
+ if (cell->type == "$assert" && en == State::S1 && a != State::S1)
+ log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
+ }
+
+ for (auto it : children)
+ it.second->update_ph3();
+ }
+
+ void writeback(pool<Module*> &wbmods)
+ {
+ if (wbmods.count(module))
+ log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module));
+
+ wbmods.insert(module);
+
+ for (auto wire : module->wires())
+ wire->attributes.erase("\\init");
+
+ for (auto &it : ff_database)
+ {
+ Cell *cell = it.first;
+ SigSpec sig_q = cell->getPort("\\Q");
+ Const initval = get_state(sig_q);
+
+ for (int i = 0; i < GetSize(sig_q); i++)
+ {
+ Wire *w = sig_q[i].wire;
+
+ if (w->attributes.count("\\init") == 0)
+ w->attributes["\\init"] = Const(State::Sx, GetSize(w));
+
+ w->attributes["\\init"][sig_q[i].offset] = initval[i];
+ }
+ }
+
+ for (auto &it : mem_database)
+ {
+ Cell *cell = it.first;
+ mem_state_t &mem = it.second;
+ Const initval = mem.data;
+
+ while (GetSize(initval) >= 2) {
+ if (initval[GetSize(initval)-1] != State::Sx) break;
+ if (initval[GetSize(initval)-2] != State::Sx) break;
+ initval.bits.pop_back();
+ }
+
+ cell->setParam("\\INIT", initval);
+ }
+
+ for (auto it : children)
+ it.second->writeback(wbmods);
+ }
+
+ void write_vcd_header(std::ofstream &f, int &id)
+ {
+ f << stringf("$scope module %s $end\n", log_id(name()));
+
+ for (auto wire : module->wires())
+ {
+ if (shared->hide_internal && wire->name[0] == '$')
+ continue;
+
+ f << stringf("$var wire %d n%d %s%s $end\n", GetSize(wire), id, wire->name[0] == '$' ? "\\" : "", log_id(wire));
+ vcd_database[wire] = make_pair(id++, Const());
+ }
+
+ for (auto child : children)
+ child.second->write_vcd_header(f, id);
+
+ f << stringf("$upscope $end\n");
+ }
+
+ void write_vcd_step(std::ofstream &f)
+ {
+ for (auto &it : vcd_database)
+ {
+ Wire *wire = it.first;
+ Const value = get_state(wire);
+ int id = it.second.first;
+
+ if (it.second.second == value)
+ continue;
+
+ it.second.second = value;
+
+ f << "b";
+ for (int i = GetSize(value)-1; i >= 0; i--) {
+ switch (value[i]) {
+ case State::S0: f << "0"; break;
+ case State::S1: f << "1"; break;
+ case State::Sx: f << "x"; break;
+ default: f << "z";
+ }
+ }
+
+ f << stringf(" n%d\n", id);
+ }
+
+ for (auto child : children)
+ child.second->write_vcd_step(f);
+ }
+};
+
+struct SimWorker : SimShared
+{
+ SimInstance *top = nullptr;
+ std::ofstream vcdfile;
+ pool<IdString> clock, clockn, reset, resetn;
+
+ ~SimWorker()
+ {
+ delete top;
+ }
+
+ void write_vcd_header()
+ {
+ if (!vcdfile.is_open())
+ return;
+
+ int id = 1;
+ top->write_vcd_header(vcdfile, id);
+
+ vcdfile << stringf("$enddefinitions $end\n");
+ }
+
+ void write_vcd_step(int t)
+ {
+ if (!vcdfile.is_open())
+ return;
+
+ vcdfile << stringf("#%d\n", t);
+ top->write_vcd_step(vcdfile);
+ }
+
+ void update()
+ {
+ while (1)
+ {
+ if (debug)
+ log("\n-- ph1 --\n");
+
+ top->update_ph1();
+
+ if (debug)
+ log("\n-- ph2 --\n");
+
+ if (!top->update_ph2())
+ break;
+ }
+
+ if (debug)
+ log("\n-- ph3 --\n");
+
+ top->update_ph3();
+ }
+
+ void set_inports(pool<IdString> ports, State value)
+ {
+ for (auto portname : ports)
+ {
+ Wire *w = top->module->wire(portname);
+
+ if (w == nullptr)
+ log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
+
+ top->set_state(w, value);
+ }
+ }
+
+ void run(Module *topmod, int numcycles)
+ {
+ log_assert(top == nullptr);
+ top = new SimInstance(this, topmod);
+
+ if (debug)
+ log("\n===== 0 =====\n");
+ else
+ log("Simulating cycle 0.\n");
+
+ set_inports(reset, State::S1);
+ set_inports(resetn, State::S0);
+
+ set_inports(clock, State::Sx);
+ set_inports(clockn, State::Sx);
+
+ update();
+
+ write_vcd_header();
+ write_vcd_step(0);
+
+ for (int cycle = 0; cycle < numcycles; cycle++)
+ {
+ if (debug)
+ log("\n===== %d =====\n", 10*cycle + 5);
+
+ set_inports(clock, State::S0);
+ set_inports(clockn, State::S1);
+
+ update();
+ write_vcd_step(10*cycle + 5);
+
+ if (debug)
+ log("\n===== %d =====\n", 10*cycle + 10);
+ else
+ log("Simulating cycle %d.\n", cycle+1);
+
+ set_inports(clock, State::S1);
+ set_inports(clockn, State::S0);
+
+ if (cycle+1 == rstlen) {
+ set_inports(reset, State::S0);
+ set_inports(resetn, State::S1);
+ }
+
+ update();
+ write_vcd_step(10*cycle + 10);
+ }
+
+ write_vcd_step(10*numcycles + 2);
+
+ if (writeback) {
+ pool<Module*> wbmods;
+ top->writeback(wbmods);
+ }
+ }
+};
+
+struct SimPass : public Pass {
+ SimPass() : Pass("sim", "simulate the circuit") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" sim [options] [top-level]\n");
+ log("\n");
+ log("This command simulates the circuit using the given top-level module.\n");
+ log("\n");
+ log(" -vcd <filename>\n");
+ log(" write the simulation results to the given VCD file\n");
+ log("\n");
+ log(" -clock <portname>\n");
+ log(" name of top-level clock input\n");
+ log("\n");
+ log(" -clockn <portname>\n");
+ log(" name of top-level clock input (inverse polarity)\n");
+ log("\n");
+ log(" -reset <portname>\n");
+ log(" name of top-level reset input (active high)\n");
+ log("\n");
+ log(" -resetn <portname>\n");
+ log(" name of top-level inverted reset input (active low)\n");
+ log("\n");
+ log(" -rstlen <integer>\n");
+ log(" number of cycles reset should stay active (default: 1)\n");
+ log("\n");
+ log(" -zinit\n");
+ log(" zero-initialize all uninitialized regs and memories\n");
+ log("\n");
+ log(" -n <integer>\n");
+ log(" number of cycles to simulate (default: 20)\n");
+ log("\n");
+ log(" -a\n");
+ log(" include all nets in VCD output, not just those with public names\n");
+ log("\n");
+ log(" -w\n");
+ log(" writeback mode: use final simulation state as new init state\n");
+ log("\n");
+ log(" -d\n");
+ log(" enable debug output\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ SimWorker worker;
+ int numcycles = 20;
+
+ log_header(design, "Executing SIM pass (simulate the circuit).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-vcd" && argidx+1 < args.size()) {
+ worker.vcdfile.open(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-n" && argidx+1 < args.size()) {
+ numcycles = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-rstlen" && argidx+1 < args.size()) {
+ worker.rstlen = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-clock" && argidx+1 < args.size()) {
+ worker.clock.insert(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ if (args[argidx] == "-clockn" && argidx+1 < args.size()) {
+ worker.clockn.insert(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ if (args[argidx] == "-reset" && argidx+1 < args.size()) {
+ worker.reset.insert(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ if (args[argidx] == "-resetn" && argidx+1 < args.size()) {
+ worker.resetn.insert(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ if (args[argidx] == "-a") {
+ worker.hide_internal = false;
+ continue;
+ }
+ if (args[argidx] == "-d") {
+ worker.debug = true;
+ continue;
+ }
+ if (args[argidx] == "-w") {
+ worker.writeback = true;
+ continue;
+ }
+ if (args[argidx] == "-zinit") {
+ worker.zinit = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ Module *top_mod = nullptr;
+
+ if (design->full_selection()) {
+ top_mod = design->top_module();
+ } else {
+ auto mods = design->selected_whole_modules();
+ if (GetSize(mods) != 1)
+ log_cmd_error("Only one top module must be selected.\n");
+ top_mod = mods.front();
+ }
+
+ worker.run(top_mod, numcycles);
+ }
+} SimPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 311a1af9..4faa0ab0 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -16,6 +16,9 @@ ifneq ($(SMALL),1)
OBJS += passes/techmap/iopadmap.o
OBJS += passes/techmap/hilomap.o
OBJS += passes/techmap/extract.o
+OBJS += passes/techmap/extract_fa.o
+OBJS += passes/techmap/extract_counter.o
+OBJS += passes/techmap/extract_reduce.o
OBJS += passes/techmap/alumacc.o
OBJS += passes/techmap/dff2dffe.o
OBJS += passes/techmap/dffinit.o
@@ -32,6 +35,7 @@ OBJS += passes/techmap/insbuf.o
OBJS += passes/techmap/attrmvcp.o
OBJS += passes/techmap/attrmap.o
OBJS += passes/techmap/zinit.o
+OBJS += passes/techmap/dff2dffs.o
endif
GENFILES += passes/techmap/techmap.inc
@@ -54,4 +58,3 @@ yosys-filterlib$(EXE): passes/techmap/filterlib.o
$(Q) mkdir -p $(dir $@)
$(P) $(LD) -o yosys-filterlib$(EXE) $(LDFLAGS) $^ $(LDLIBS)
endif
-
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index cc79296c..d2d15a4a 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -29,17 +29,17 @@
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
// http://en.wikipedia.org/wiki/Topological_sorting
-#define ABC_COMMAND_LIB "strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}"
-#define ABC_COMMAND_CTR "strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_COMMAND_LUT "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; if; mfs"
-#define ABC_COMMAND_SOP "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; cover {I} {P}"
-#define ABC_COMMAND_DFL "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; map"
-
-#define ABC_FAST_COMMAND_LIB "retime -o {D}; map {D}"
-#define ABC_FAST_COMMAND_CTR "retime -o {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_FAST_COMMAND_LUT "retime -o; if"
-#define ABC_FAST_COMMAND_SOP "retime -o; cover -I {I} -P {P}"
-#define ABC_FAST_COMMAND_DFL "retime -o; map"
+#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
+#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
+#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
+#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
+
+#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
+#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_FAST_COMMAND_LUT "strash; dretime; if"
+#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}"
+#define ABC_FAST_COMMAND_DFL "strash; dretime; map"
#include "kernel/register.h"
#include "kernel/sigtools.h"
@@ -60,6 +60,10 @@
#include "frontends/blif/blifparse.h"
+#ifdef YOSYS_LINK_ABC
+extern "C" int Abc_RealMain(int argc, char *argv[]);
+#endif
+
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -74,6 +78,8 @@ enum class gate_type_t {
G_NOR,
G_XOR,
G_XNOR,
+ G_ANDNOT,
+ G_ORNOT,
G_MUX,
G_AOI3,
G_OAI3,
@@ -90,6 +96,7 @@ struct gate_t
int in1, in2, in3, in4;
bool is_port;
RTLIL::SigBit bit;
+ RTLIL::State init;
};
bool map_mux4;
@@ -102,10 +109,13 @@ SigMap assign_map;
RTLIL::Module *module;
std::vector<gate_t> signal_list;
std::map<RTLIL::SigBit, int> signal_map;
+std::map<RTLIL::SigBit, RTLIL::State> signal_init;
pool<std::string> enabled_gates;
+bool recover_init;
bool clk_polarity, en_polarity;
RTLIL::SigSpec clk_sig, en_sig;
+dict<int, std::string> pi_map, po_map;
int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1)
{
@@ -121,6 +131,10 @@ int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1,
gate.in4 = -1;
gate.is_port = false;
gate.bit = bit;
+ if (signal_init.count(bit))
+ gate.init = signal_init.at(bit);
+ else
+ gate.init = State::Sx;
signal_list.push_back(gate);
signal_map[bit] = gate.id;
}
@@ -207,7 +221,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
return;
}
- if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
+ if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_b = cell->getPort("\\B");
@@ -232,6 +246,10 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
map_signal(sig_y, G(XOR), mapped_a, mapped_b);
else if (cell->type == "$_XNOR_")
map_signal(sig_y, G(XNOR), mapped_a, mapped_b);
+ else if (cell->type == "$_ANDNOT_")
+ map_signal(sig_y, G(ANDNOT), mapped_a, mapped_b);
+ else if (cell->type == "$_ORNOT_")
+ map_signal(sig_y, G(ORNOT), mapped_a, mapped_b);
else
log_abort();
@@ -532,11 +550,13 @@ std::string replace_tempdir(std::string text, std::string tempdir_name, bool sho
}
std::string selfdir_name = proc_self_dirname();
- while (1) {
- size_t pos = text.find(selfdir_name);
- if (pos == std::string::npos)
- break;
- text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name));
+ if (selfdir_name != "/") {
+ while (1) {
+ size_t pos = text.find(selfdir_name);
+ if (pos == std::string::npos)
+ break;
+ text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name));
+ }
}
return text;
@@ -588,6 +608,14 @@ struct abc_output_filter
void next_line(const std::string &line)
{
+ int pi, po;
+ if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) {
+ log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n",
+ pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???",
+ po, po_map.count(po) ? po_map.at(po).c_str() : "???");
+ return;
+ }
+
for (char ch : line)
next_char(ch);
}
@@ -595,7 +623,7 @@ struct abc_output_filter
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
- bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, bool fast_mode,
+ bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode)
{
module = current_module;
@@ -603,11 +631,12 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
signal_map.clear();
signal_list.clear();
+ pi_map.clear();
+ po_map.clear();
+ recover_init = false;
if (clk_str != "$")
{
- assign_map.set(module);
-
clk_polarity = true;
clk_sig = RTLIL::SigSpec();
@@ -615,6 +644,30 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
en_sig = RTLIL::SigSpec();
}
+ if (!clk_str.empty() && clk_str != "$")
+ {
+ if (clk_str.find(',') != std::string::npos) {
+ int pos = clk_str.find(',');
+ std::string en_str = clk_str.substr(pos+1);
+ clk_str = clk_str.substr(0, pos);
+ if (en_str[0] == '!') {
+ en_polarity = false;
+ en_str = en_str.substr(1);
+ }
+ if (module->wires_.count(RTLIL::escape_id(en_str)) != 0)
+ en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0));
+ }
+ if (clk_str[0] == '!') {
+ clk_polarity = false;
+ clk_str = clk_str.substr(1);
+ }
+ if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0)
+ clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
+ }
+
+ if (dff_mode && clk_sig.empty())
+ log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
+
std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
if (!cleanup)
tempdir_name[0] = tempdir_name[4] = '_';
@@ -652,7 +705,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
all_luts_cost_same = false;
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
if (all_luts_cost_same && !fast_mode)
- abc_script += "; lutpack";
+ abc_script += "; lutpack {S}";
} else if (!liberty_file.empty())
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
else if (sop_mode)
@@ -660,6 +713,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
else
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
+ if (script_file.empty() && !delay_target.empty())
+ for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
+ abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8);
+
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
@@ -669,6 +726,9 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3);
+ for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
+ abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
+
abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
abc_script = add_echos_to_abc_cmd(abc_script);
@@ -680,30 +740,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, "%s\n", abc_script.c_str());
fclose(f);
- if (!clk_str.empty() && clk_str != "$")
- {
- if (clk_str.find(',') != std::string::npos) {
- int pos = clk_str.find(',');
- std::string en_str = clk_str.substr(pos+1);
- clk_str = clk_str.substr(0, pos);
- if (en_str[0] == '!') {
- en_polarity = false;
- en_str = en_str.substr(1);
- }
- if (module->wires_.count(RTLIL::escape_id(en_str)) != 0)
- en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0));
- }
- if (clk_str[0] == '!') {
- clk_polarity = false;
- clk_str = clk_str.substr(1);
- }
- if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0)
- clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
- }
-
- if (dff_mode && clk_sig.empty())
- log_error("Clock domain %s not found.\n", clk_str.c_str());
-
if (dff_mode || !clk_str.empty())
{
if (clk_sig.size() == 0)
@@ -749,7 +785,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (!si.is_port || si.type != G(NONE))
continue;
fprintf(f, " n%d", si.id);
- count_input++;
+ pi_map[count_input++] = log_signal(si.bit);
}
if (count_input == 0)
fprintf(f, " dummy_input\n");
@@ -761,7 +797,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (!si.is_port || si.type == G(NONE))
continue;
fprintf(f, " n%d", si.id);
- count_output++;
+ po_map[count_output++] = log_signal(si.bit);
}
fprintf(f, "\n");
@@ -806,6 +842,13 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
fprintf(f, "00 1\n");
fprintf(f, "11 1\n");
+ } else if (si.type == G(ANDNOT)) {
+ fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, "10 1\n");
+ } else if (si.type == G(ORNOT)) {
+ fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, "1- 1\n");
+ fprintf(f, "-0 1\n");
} else if (si.type == G(MUX)) {
fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
fprintf(f, "1-0 1\n");
@@ -829,7 +872,11 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, "00-- 1\n");
fprintf(f, "--00 1\n");
} else if (si.type == G(FF)) {
- fprintf(f, ".latch n%d n%d\n", si.in1, si.id);
+ if (si.init == State::S0 || si.init == State::S1) {
+ fprintf(f, ".latch n%d n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0);
+ recover_init = true;
+ } else
+ fprintf(f, ".latch n%d n%d 2\n", si.in1, si.id);
} else if (si.type != G(NONE))
log_abort();
if (si.type != G(NONE))
@@ -851,38 +898,42 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
f = fopen(buffer.c_str(), "wt");
if (f == NULL)
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
- fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
- fprintf(f, "GATE ONE 1 Y=CONST1;\n");
- fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_BUF_"));
- fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOT_"));
+ fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
+ fprintf(f, "GATE ONE 1 Y=CONST1;\n");
+ fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_BUF_"));
+ fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOT_"));
if (enabled_gates.empty() || enabled_gates.count("AND"))
- fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_"));
+ fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_"));
if (enabled_gates.empty() || enabled_gates.count("NAND"))
- fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_"));
+ fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_"));
if (enabled_gates.empty() || enabled_gates.count("OR"))
- fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_"));
+ fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_"));
if (enabled_gates.empty() || enabled_gates.count("NOR"))
- fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_"));
+ fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_"));
if (enabled_gates.empty() || enabled_gates.count("XOR"))
- fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_"));
+ fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_"));
if (enabled_gates.empty() || enabled_gates.count("XNOR"))
- fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_"));
+ fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_"));
+ if (enabled_gates.empty() || enabled_gates.count("ANDNOT"))
+ fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ANDNOT_"));
+ if (enabled_gates.empty() || enabled_gates.count("ORNOT"))
+ fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ORNOT_"));
if (enabled_gates.empty() || enabled_gates.count("AOI3"))
- fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_"));
+ fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_"));
if (enabled_gates.empty() || enabled_gates.count("OAI3"))
- fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_"));
+ fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_"));
if (enabled_gates.empty() || enabled_gates.count("AOI4"))
- fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_"));
+ fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_"));
if (enabled_gates.empty() || enabled_gates.count("OAI4"))
- fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_"));
+ fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_"));
if (enabled_gates.empty() || enabled_gates.count("MUX"))
- fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_"));
if (map_mux4)
- fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*get_cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*get_cell_cost("$_MUX_"));
if (map_mux8)
- fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*get_cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*get_cell_cost("$_MUX_"));
if (map_mux16)
- fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*get_cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*get_cell_cost("$_MUX_"));
fclose(f);
if (!lut_costs.empty()) {
@@ -898,8 +949,24 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
+#ifndef YOSYS_LINK_ABC
abc_output_filter filt(tempdir_name, show_tempdir);
int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
+#else
+ // These needs to be mutable, supposedly due to getopt
+ char *abc_argv[5];
+ string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str());
+ abc_argv[0] = strdup(exe_file.c_str());
+ abc_argv[1] = strdup("-s");
+ abc_argv[2] = strdup("-f");
+ abc_argv[3] = strdup(tmp_script_name.c_str());
+ abc_argv[4] = 0;
+ int ret = Abc_RealMain(4, abc_argv);
+ free(abc_argv[0]);
+ free(abc_argv[1]);
+ free(abc_argv[2]);
+ free(abc_argv[3]);
+#endif
if (ret != 0)
log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
@@ -954,7 +1021,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
design->select(module, cell);
continue;
}
- if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" || c->type == "\\XNOR") {
+ if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" ||
+ c->type == "\\XNOR" || c->type == "\\ANDNOT" || c->type == "\\ORNOT") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
@@ -1130,6 +1198,15 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
module->connect(conn);
}
+ if (recover_init)
+ for (auto wire : mapped_mod->wires()) {
+ if (wire->attributes.count("\\init")) {
+ Wire *w = module->wires_[remap_name(wire->name)];
+ log_assert(w->attributes.count("\\init") == 0);
+ w->attributes["\\init"] = wire->attributes.at("\\init");
+ }
+ }
+
for (auto &it : cell_stats)
log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
int in_wires = 0, out_wires = 0;
@@ -1171,7 +1248,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
struct AbcPass : public Pass {
AbcPass() : Pass("abc", "use ABC for technology mapping") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1205,7 +1282,7 @@ struct AbcPass : public Pass {
log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
log("\n");
log(" for -lut/-luts (only one LUT size):\n");
- log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack").c_str());
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack {S}").c_str());
log("\n");
log(" for -lut/-luts (different LUT sizes):\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str());
@@ -1253,6 +1330,8 @@ struct AbcPass : public Pass {
log(" -D <picoseconds>\n");
log(" set delay target. the string {D} in the default scripts above is\n");
log(" replaced by this option when used, and an empty string otherwise.\n");
+ log(" this also replaces 'dretime' with 'dretime; retime -o {D}' in the\n");
+ log(" default scripts above.\n");
log("\n");
log(" -I <num>\n");
log(" maximum number of SOP inputs.\n");
@@ -1262,6 +1341,10 @@ struct AbcPass : public Pass {
log(" maximum number of SOP products.\n");
log(" (replaces {P} in the default scripts above)\n");
log("\n");
+ log(" -S <num>\n");
+ log(" maximum number of LUT inputs shared.\n");
+ log(" (replaces {S} in the default scripts above, default: -S 1)\n");
+ log("\n");
log(" -lut <width>\n");
log(" generate netlist using luts of (max) the specified width.\n");
log("\n");
@@ -1283,10 +1366,21 @@ struct AbcPass : public Pass {
// log(" (ignored when used with -liberty or -lut)\n");
// log("\n");
log(" -g type1,type2,...\n");
- log(" Map the the specified list of gate types. Supported gates types are:\n");
- log(" AND, NAND, OR, NOR, XOR, XNOR, MUX, AOI3, OAI3, AOI4, OAI4.\n");
+ log(" Map to the specified list of gate types. Supported gates types are:\n");
+ log(" AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX, AOI3, OAI3, AOI4, OAI4.\n");
log(" (The NOT gate is always added to this list automatically.)\n");
log("\n");
+ log(" The following aliases can be used to reference common sets of gate types:\n");
+ log(" simple: AND OR XOR MUX\n");
+ log(" cmos2: NAND NOR\n");
+ log(" cmos3: NAND NOR AOI3 OAI3\n");
+ log(" cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n");
+ log(" gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n");
+ log(" aig: AND NAND OR NOR ANDNOT ORNOT\n");
+ log("\n");
+ log(" Prefix a gate type with a '-' to remove it from the list. For example\n");
+ log(" the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent.\n");
+ log("\n");
log(" -dff\n");
log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
log(" clock domains are automatically partitioned in clock domains and each\n");
@@ -1316,24 +1410,35 @@ struct AbcPass : public Pass {
log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n");
log("loaded into ABC before the ABC script is executed.\n");
log("\n");
- log("This pass does not operate on modules with unprocessed processes in it.\n");
- log("(I.e. the 'proc' pass should be used first to convert processes to netlists.)\n");
+ log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
+ log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
+ log("ABC on logic snippets extracted from your design. You will not get any useful\n");
+ log("output when passing an ABC script that writes a file. Instead write your full\n");
+ log("design as BLIF file with write_blif and the load that into ABC externally if\n");
+ log("you want to use ABC to convert your design into another format.\n");
log("\n");
log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ABC pass (technology mapping using ABC).\n");
log_push();
+ assign_map.clear();
+ signal_list.clear();
+ signal_map.clear();
+ signal_init.clear();
+ pi_map.clear();
+ po_map.clear();
+
#ifdef ABCEXTERNAL
std::string exe_file = ABCEXTERNAL;
#else
std::string exe_file = proc_self_dirname() + "yosys-abc";
#endif
std::string script_file, liberty_file, constr_file, clk_str;
- std::string delay_target, sop_inputs, sop_products;
+ std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
bool show_tempdir = false, sop_mode = false;
vector<int> lut_costs;
@@ -1365,17 +1470,20 @@ struct AbcPass : public Pass {
}
if (arg == "-script" && argidx+1 < args.size()) {
script_file = args[++argidx];
+ rewrite_filename(script_file);
if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
script_file = std::string(pwd) + "/" + script_file;
continue;
}
if (arg == "-liberty" && argidx+1 < args.size()) {
liberty_file = args[++argidx];
+ rewrite_filename(liberty_file);
if (!liberty_file.empty() && !is_absolute_path(liberty_file))
liberty_file = std::string(pwd) + "/" + liberty_file;
continue;
}
if (arg == "-constr" && argidx+1 < args.size()) {
+ rewrite_filename(constr_file);
constr_file = args[++argidx];
if (!constr_file.empty() && !is_absolute_path(constr_file))
constr_file = std::string(pwd) + "/" + constr_file;
@@ -1393,6 +1501,10 @@ struct AbcPass : public Pass {
sop_products = "-P " + args[++argidx];
continue;
}
+ if (arg == "-S" && argidx+1 < args.size()) {
+ lutin_shared = "-S " + args[++argidx];
+ continue;
+ }
if (arg == "-lut" && argidx+1 < args.size()) {
string arg = args[++argidx];
size_t pos = arg.find_first_of(':');
@@ -1445,20 +1557,83 @@ struct AbcPass : public Pass {
}
if (arg == "-g" && argidx+1 < args.size()) {
for (auto g : split_tokens(args[++argidx], ",")) {
+ vector<string> gate_list;
+ bool remove_gates = false;
+ if (GetSize(g) > 0 && g[0] == '-') {
+ remove_gates = true;
+ g = g.substr(1);
+ }
if (g == "AND") goto ok_gate;
if (g == "NAND") goto ok_gate;
if (g == "OR") goto ok_gate;
if (g == "NOR") goto ok_gate;
if (g == "XOR") goto ok_gate;
if (g == "XNOR") goto ok_gate;
+ if (g == "ANDNOT") goto ok_gate;
+ if (g == "ORNOT") goto ok_gate;
if (g == "MUX") goto ok_gate;
if (g == "AOI3") goto ok_gate;
if (g == "OAI3") goto ok_gate;
if (g == "AOI4") goto ok_gate;
if (g == "OAI4") goto ok_gate;
+ if (g == "simple") {
+ gate_list.push_back("AND");
+ gate_list.push_back("OR");
+ gate_list.push_back("XOR");
+ gate_list.push_back("MUX");
+ goto ok_alias;
+ }
+ if (g == "cmos2") {
+ gate_list.push_back("NAND");
+ gate_list.push_back("NOR");
+ goto ok_alias;
+ }
+ if (g == "cmos3") {
+ gate_list.push_back("NAND");
+ gate_list.push_back("NOR");
+ gate_list.push_back("AOI3");
+ gate_list.push_back("OAI3");
+ goto ok_alias;
+ }
+ if (g == "cmos4") {
+ gate_list.push_back("NAND");
+ gate_list.push_back("NOR");
+ gate_list.push_back("AOI3");
+ gate_list.push_back("OAI3");
+ gate_list.push_back("AOI4");
+ gate_list.push_back("OAI4");
+ goto ok_alias;
+ }
+ if (g == "gates") {
+ gate_list.push_back("AND");
+ gate_list.push_back("NAND");
+ gate_list.push_back("OR");
+ gate_list.push_back("NOR");
+ gate_list.push_back("XOR");
+ gate_list.push_back("XNOR");
+ gate_list.push_back("ANDNOT");
+ gate_list.push_back("ORNOT");
+ goto ok_alias;
+ }
+ if (g == "aig") {
+ gate_list.push_back("AND");
+ gate_list.push_back("NAND");
+ gate_list.push_back("OR");
+ gate_list.push_back("NOR");
+ gate_list.push_back("ANDNOT");
+ gate_list.push_back("ORNOT");
+ goto ok_alias;
+ }
cmd_error(args, argidx, stringf("Unsupported gate type: %s", g.c_str()));
ok_gate:
- enabled_gates.insert(g);
+ gate_list.push_back(g);
+ ok_alias:
+ for (auto gate : gate_list) {
+ if (remove_gates)
+ enabled_gates.erase(gate);
+ else
+ enabled_gates.insert(gate);
+ }
}
continue;
}
@@ -1501,163 +1676,190 @@ struct AbcPass : public Pass {
log_cmd_error("Got -constr but no -liberty!\n");
for (auto mod : design->selected_modules())
- if (mod->processes.size() > 0)
+ {
+ if (mod->processes.size() > 0) {
log("Skipping module %s as it contains processes.\n", log_id(mod));
- else if (!dff_mode || !clk_str.empty())
- abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
- delay_target, sop_inputs, sop_products, fast_mode, mod->selected_cells(), show_tempdir, sop_mode);
- else
- {
- assign_map.set(mod);
- CellTypes ct(design);
+ continue;
+ }
- std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
- std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
+ assign_map.set(mod);
+ signal_init.clear();
+
+ for (Wire *wire : mod->wires())
+ if (wire->attributes.count("\\init")) {
+ SigSpec initsig = assign_map(wire);
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
+ switch (initval[i]) {
+ case State::S0:
+ signal_init[initsig[i]] = State::S0;
+ break;
+ case State::S1:
+ signal_init[initsig[i]] = State::S0;
+ break;
+ default:
+ break;
+ }
+ }
- std::set<RTLIL::Cell*> expand_queue, next_expand_queue;
- std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
- std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
+ if (!dff_mode || !clk_str.empty()) {
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
+ delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode);
+ continue;
+ }
- typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
- std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
- std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
+ CellTypes ct(design);
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
- std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down;
+ std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
+ std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
- for (auto cell : all_cells)
- {
- clkdomain_t key;
-
- for (auto &conn : cell->connections())
- for (auto bit : conn.second) {
- bit = assign_map(bit);
- if (bit.wire != nullptr) {
- cell_to_bit[cell].insert(bit);
- bit_to_cell[bit].insert(cell);
- if (ct.cell_input(cell->type, conn.first)) {
- cell_to_bit_up[cell].insert(bit);
- bit_to_cell_down[bit].insert(cell);
- }
- if (ct.cell_output(cell->type, conn.first)) {
- cell_to_bit_down[cell].insert(bit);
- bit_to_cell_up[bit].insert(cell);
- }
- }
- }
+ std::set<RTLIL::Cell*> expand_queue, next_expand_queue;
+ std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
+ std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
- if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
- {
- key = clkdomain_t(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")), true, RTLIL::SigSpec());
- }
- else
- if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
- {
- bool this_clk_pol = cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_";
- bool this_en_pol = cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_";
- key = clkdomain_t(this_clk_pol, assign_map(cell->getPort("\\C")), this_en_pol, assign_map(cell->getPort("\\E")));
- }
- else
- continue;
+ typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
+ std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
+ std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
- unassigned_cells.erase(cell);
- expand_queue.insert(cell);
- expand_queue_up.insert(cell);
- expand_queue_down.insert(cell);
+ std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
+ std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down;
- assigned_cells[key].push_back(cell);
- assigned_cells_reverse[cell] = key;
+ for (auto cell : all_cells)
+ {
+ clkdomain_t key;
+
+ for (auto &conn : cell->connections())
+ for (auto bit : conn.second) {
+ bit = assign_map(bit);
+ if (bit.wire != nullptr) {
+ cell_to_bit[cell].insert(bit);
+ bit_to_cell[bit].insert(cell);
+ if (ct.cell_input(cell->type, conn.first)) {
+ cell_to_bit_up[cell].insert(bit);
+ bit_to_cell_down[bit].insert(cell);
+ }
+ if (ct.cell_output(cell->type, conn.first)) {
+ cell_to_bit_down[cell].insert(bit);
+ bit_to_cell_up[bit].insert(cell);
+ }
+ }
}
- while (!expand_queue_up.empty() || !expand_queue_down.empty())
+ if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
{
- if (!expand_queue_up.empty())
- {
- RTLIL::Cell *cell = *expand_queue_up.begin();
- clkdomain_t key = assigned_cells_reverse.at(cell);
- expand_queue_up.erase(cell);
-
- for (auto bit : cell_to_bit_up[cell])
- for (auto c : bit_to_cell_up[bit])
- if (unassigned_cells.count(c)) {
- unassigned_cells.erase(c);
- next_expand_queue_up.insert(c);
- assigned_cells[key].push_back(c);
- assigned_cells_reverse[c] = key;
- expand_queue.insert(c);
- }
- }
+ key = clkdomain_t(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")), true, RTLIL::SigSpec());
+ }
+ else
+ if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
+ {
+ bool this_clk_pol = cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_";
+ bool this_en_pol = cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_";
+ key = clkdomain_t(this_clk_pol, assign_map(cell->getPort("\\C")), this_en_pol, assign_map(cell->getPort("\\E")));
+ }
+ else
+ continue;
- if (!expand_queue_down.empty())
- {
- RTLIL::Cell *cell = *expand_queue_down.begin();
- clkdomain_t key = assigned_cells_reverse.at(cell);
- expand_queue_down.erase(cell);
-
- for (auto bit : cell_to_bit_down[cell])
- for (auto c : bit_to_cell_down[bit])
- if (unassigned_cells.count(c)) {
- unassigned_cells.erase(c);
- next_expand_queue_up.insert(c);
- assigned_cells[key].push_back(c);
- assigned_cells_reverse[c] = key;
- expand_queue.insert(c);
- }
- }
+ unassigned_cells.erase(cell);
+ expand_queue.insert(cell);
+ expand_queue_up.insert(cell);
+ expand_queue_down.insert(cell);
- if (expand_queue_up.empty() && expand_queue_down.empty()) {
- expand_queue_up.swap(next_expand_queue_up);
- expand_queue_down.swap(next_expand_queue_down);
- }
- }
+ assigned_cells[key].push_back(cell);
+ assigned_cells_reverse[cell] = key;
+ }
- while (!expand_queue.empty())
+ while (!expand_queue_up.empty() || !expand_queue_down.empty())
+ {
+ if (!expand_queue_up.empty())
{
- RTLIL::Cell *cell = *expand_queue.begin();
+ RTLIL::Cell *cell = *expand_queue_up.begin();
clkdomain_t key = assigned_cells_reverse.at(cell);
- expand_queue.erase(cell);
-
- for (auto bit : cell_to_bit.at(cell)) {
- for (auto c : bit_to_cell[bit])
- if (unassigned_cells.count(c)) {
- unassigned_cells.erase(c);
- next_expand_queue.insert(c);
- assigned_cells[key].push_back(c);
- assigned_cells_reverse[c] = key;
- }
- bit_to_cell[bit].clear();
- }
+ expand_queue_up.erase(cell);
+
+ for (auto bit : cell_to_bit_up[cell])
+ for (auto c : bit_to_cell_up[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue_up.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ expand_queue.insert(c);
+ }
+ }
- if (expand_queue.empty())
- expand_queue.swap(next_expand_queue);
+ if (!expand_queue_down.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue_down.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue_down.erase(cell);
+
+ for (auto bit : cell_to_bit_down[cell])
+ for (auto c : bit_to_cell_down[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue_up.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ expand_queue.insert(c);
+ }
}
- clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
- for (auto cell : unassigned_cells) {
- assigned_cells[key].push_back(cell);
- assigned_cells_reverse[cell] = key;
+ if (expand_queue_up.empty() && expand_queue_down.empty()) {
+ expand_queue_up.swap(next_expand_queue_up);
+ expand_queue_down.swap(next_expand_queue_down);
}
+ }
- log_header(design, "Summary of detected clock domains:\n");
- for (auto &it : assigned_cells)
- log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
- std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
- std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
-
- for (auto &it : assigned_cells) {
- clk_polarity = std::get<0>(it.first);
- clk_sig = assign_map(std::get<1>(it.first));
- en_polarity = std::get<2>(it.first);
- en_sig = assign_map(std::get<3>(it.first));
- abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
- keepff, delay_target, sop_inputs, sop_products, fast_mode, it.second, show_tempdir, sop_mode);
- assign_map.set(mod);
+ while (!expand_queue.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue.erase(cell);
+
+ for (auto bit : cell_to_bit.at(cell)) {
+ for (auto c : bit_to_cell[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ }
+ bit_to_cell[bit].clear();
}
+
+ if (expand_queue.empty())
+ expand_queue.swap(next_expand_queue);
+ }
+
+ clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
+ for (auto cell : unassigned_cells) {
+ assigned_cells[key].push_back(cell);
+ assigned_cells_reverse[cell] = key;
}
+ log_header(design, "Summary of detected clock domains:\n");
+ for (auto &it : assigned_cells)
+ log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
+ std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
+ std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
+
+ for (auto &it : assigned_cells) {
+ clk_polarity = std::get<0>(it.first);
+ clk_sig = assign_map(std::get<1>(it.first));
+ en_polarity = std::get<2>(it.first);
+ en_sig = assign_map(std::get<3>(it.first));
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
+ keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode);
+ assign_map.set(mod);
+ }
+ }
+
assign_map.clear();
signal_list.clear();
signal_map.clear();
+ signal_init.clear();
+ pi_map.clear();
+ po_map.clear();
log_pop();
}
diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc
index b9ac7ade..35df2ff7 100644
--- a/passes/techmap/aigmap.cc
+++ b/passes/techmap/aigmap.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct AigmapPass : public Pass {
AigmapPass() : Pass("aigmap", "map logic to and-inverter-graph circuit") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" aigmap [options] [selection]\n");
@@ -37,7 +37,7 @@ struct AigmapPass : public Pass {
log(" Enable creation of $_NAND_ cells\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool nand_mode = false;
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
index 9f6dd02d..dc7d416b 100644
--- a/passes/techmap/alumacc.cc
+++ b/passes/techmap/alumacc.cc
@@ -55,19 +55,19 @@ struct AlumaccWorker
RTLIL::SigSpec get_gt() {
if (GetSize(cached_gt) == 0)
- cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq()));
+ cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq()), false, alu_cell->get_src_attribute());
return cached_gt;
}
RTLIL::SigSpec get_eq() {
if (GetSize(cached_eq) == 0)
- cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X"));
+ cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X"), false, alu_cell->get_src_attribute());
return cached_eq;
}
RTLIL::SigSpec get_ne() {
if (GetSize(cached_ne) == 0)
- cached_ne = alu_cell->module->Not(NEW_ID, get_eq());
+ cached_ne = alu_cell->module->Not(NEW_ID, get_eq(), false, alu_cell->get_src_attribute());
return cached_ne;
}
@@ -75,7 +75,7 @@ struct AlumaccWorker
if (GetSize(cached_cf) == 0) {
cached_cf = alu_cell->getPort("\\CO");
log_assert(GetSize(cached_cf) >= 1);
- cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[GetSize(cached_cf)-1]);
+ cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[GetSize(cached_cf)-1], false, alu_cell->get_src_attribute());
}
return cached_cf;
}
@@ -352,10 +352,13 @@ struct AlumaccWorker
{
auto n = it.second;
auto cell = module->addCell(NEW_ID, "$macc");
+
macc_counter++;
log(" creating $macc cell for %s: %s\n", log_id(n->cell), log_id(cell));
+ cell->set_src_attribute(n->cell->get_src_attribute());
+
n->macc.optimize(GetSize(n->y));
n->macc.to_cell(cell);
cell->setPort("\\Y", n->y);
@@ -452,6 +455,7 @@ struct AlumaccWorker
void replace_alu()
{
+ std::string src("");
for (auto &it1 : sig_alu)
for (auto n : it1.second)
{
@@ -475,6 +479,9 @@ struct AlumaccWorker
log("%s%s", i ? ", ": "", log_id(n->cells[i]));
log(": %s\n", log_id(n->alu_cell));
+ if (n->cells.size() > 0)
+ n->alu_cell->set_src_attribute(n->cells[0]->get_src_attribute());
+
n->alu_cell->setPort("\\A", n->a);
n->alu_cell->setPort("\\B", n->b);
n->alu_cell->setPort("\\CI", GetSize(n->c) ? n->c : RTLIL::S0);
@@ -532,7 +539,7 @@ struct AlumaccWorker
struct AlumaccPass : public Pass {
AlumaccPass() : Pass("alumacc", "extract ALU and MACC cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -542,7 +549,7 @@ struct AlumaccPass : public Pass {
log("and $macc cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ALUMACC pass (create $alu and $macc cells).\n");
diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc
index dec81d21..0b5576b0 100644
--- a/passes/techmap/attrmap.cc
+++ b/passes/techmap/attrmap.cc
@@ -81,7 +81,7 @@ struct AttrmapAction {
struct AttrmapTocase : AttrmapAction {
string name;
- virtual bool apply(IdString &id, Const&) {
+ bool apply(IdString &id, Const&) YS_OVERRIDE {
if (match_name(name, id, true))
id = RTLIL::escape_id(name);
return true;
@@ -90,7 +90,7 @@ struct AttrmapTocase : AttrmapAction {
struct AttrmapRename : AttrmapAction {
string old_name, new_name;
- virtual bool apply(IdString &id, Const&) {
+ bool apply(IdString &id, Const&) YS_OVERRIDE {
if (match_name(old_name, id))
id = RTLIL::escape_id(new_name);
return true;
@@ -101,7 +101,7 @@ struct AttrmapMap : AttrmapAction {
bool imap;
string old_name, new_name;
string old_value, new_value;
- virtual bool apply(IdString &id, Const &val) {
+ bool apply(IdString &id, Const &val) YS_OVERRIDE {
if (match_name(old_name, id) && match_value(old_value, val, true)) {
id = RTLIL::escape_id(new_name);
val = make_value(new_value);
@@ -112,7 +112,7 @@ struct AttrmapMap : AttrmapAction {
struct AttrmapRemove : AttrmapAction {
string name, value;
- virtual bool apply(IdString &id, Const &val) {
+ bool apply(IdString &id, Const &val) YS_OVERRIDE {
return !(match_name(name, id) && match_value(value, val));
}
};
@@ -144,7 +144,7 @@ void attrmap_apply(string objname, vector<std::unique_ptr<AttrmapAction>> &actio
struct AttrmapPass : public Pass {
AttrmapPass() : Pass("attrmap", "renaming attributes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -179,7 +179,7 @@ struct AttrmapPass : public Pass {
log(" -imap keep=\"false\" keep=0 -remove keep=0\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n");
diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc
index 1537def0..e59aa651 100644
--- a/passes/techmap/attrmvcp.cc
+++ b/passes/techmap/attrmvcp.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct AttrmvcpPass : public Pass {
AttrmvcpPass() : Pass("attrmvcp", "move or copy attributes from wires to driving cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" attrmvcp [options] [selection]\n");
@@ -53,7 +53,7 @@ struct AttrmvcpPass : public Pass {
log(" multiple times.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ATTRMVCP pass (move or copy attributes).\n");
diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc
index ed4e4576..9f0c7bf6 100644
--- a/passes/techmap/deminout.cc
+++ b/passes/techmap/deminout.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct DeminoutPass : public Pass {
DeminoutPass() : Pass("deminout", "demote inout ports to input or output") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" deminout [options] [selection]\n");
@@ -33,7 +33,7 @@ struct DeminoutPass : public Pass {
log("\"Demote\" inout ports to input or output ports, if possible.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DEMINOUT pass (demote inout ports to input or output).\n");
@@ -57,7 +57,7 @@ struct DeminoutPass : public Pass {
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
- pool<SigBit> bits_written, bits_used, bits_inout;
+ pool<SigBit> bits_written, bits_used, bits_inout, bits_tribuf;
dict<SigBit, int> bits_numports;
for (auto wire : module->wires())
@@ -82,6 +82,25 @@ struct DeminoutPass : public Pass {
if (cellport_in)
for (auto bit : sigmap(conn.second))
bits_used.insert(bit);
+
+ if (conn.first == "\\Y" && cell->type.in("$mux", "$pmux", "$_MUX_", "$_TBUF_"))
+ {
+ bool tribuf = (cell->type == "$_TBUF_");
+
+ if (!tribuf) {
+ for (auto &c : cell->connections()) {
+ if (!c.first.in("\\A", "\\B"))
+ continue;
+ for (auto b : sigmap(c.second))
+ if (b == State::Sz)
+ tribuf = true;
+ }
+ }
+
+ if (tribuf)
+ for (auto bit : sigmap(conn.second))
+ bits_tribuf.insert(bit);
+ }
}
for (auto wire : module->selected_wires())
@@ -95,10 +114,15 @@ struct DeminoutPass : public Pass {
if (bits_numports[bit] > 1 || bits_inout.count(bit))
new_input = true, new_output = true;
- if (bits_written.count(bit))
+ if (bits_written.count(bit)) {
new_output = true;
- else if (bits_used.count(bit))
- new_input = true;
+ if (bits_tribuf.count(bit))
+ goto tribuf_bit;
+ } else {
+ tribuf_bit:
+ if (bits_used.count(bit))
+ new_input = true;
+ }
}
if (new_input != new_output) {
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
index 1b8920bb..3291f5a4 100644
--- a/passes/techmap/dff2dffe.cc
+++ b/passes/techmap/dff2dffe.cc
@@ -253,7 +253,7 @@ struct Dff2dffeWorker
struct Dff2dffePass : public Pass {
Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -279,11 +279,12 @@ struct Dff2dffePass : public Pass {
log(" -direct-match <pattern>\n");
log(" like -direct for all DFF cell types matching the expression.\n");
log(" this will use $__DFFE_* as <external_gate_type> matching the\n");
- log(" internal gate type $_DFF_*_, except for $_DFF_[NP]_, which is\n");
- log(" converted to $_DFFE_[NP]_.\n");
+ log(" internal gate type $_DFF_*_, and $__DFFSE_* for those matching\n");
+ log(" $_DFFS_*_, except for $_DFF_[NP]_, which is converted to \n");
+ log(" $_DFFE_[NP]_.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
@@ -315,6 +316,15 @@ struct Dff2dffePass : public Pass {
if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict["$_DFF_PN1_"] = "$__DFFE_PN1";
if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict["$_DFF_PP0_"] = "$__DFFE_PP0";
if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict["$_DFF_PP1_"] = "$__DFFE_PP1";
+
+ if (patmatch(pattern, "$__DFFS_NN0_")) found_match = true, direct_dict["$__DFFS_NN0_"] = "$__DFFSE_NN0";
+ if (patmatch(pattern, "$__DFFS_NN1_")) found_match = true, direct_dict["$__DFFS_NN1_"] = "$__DFFSE_NN1";
+ if (patmatch(pattern, "$__DFFS_NP0_")) found_match = true, direct_dict["$__DFFS_NP0_"] = "$__DFFSE_NP0";
+ if (patmatch(pattern, "$__DFFS_NP1_")) found_match = true, direct_dict["$__DFFS_NP1_"] = "$__DFFSE_NP1";
+ if (patmatch(pattern, "$__DFFS_PN0_")) found_match = true, direct_dict["$__DFFS_PN0_"] = "$__DFFSE_PN0";
+ if (patmatch(pattern, "$__DFFS_PN1_")) found_match = true, direct_dict["$__DFFS_PN1_"] = "$__DFFSE_PN1";
+ if (patmatch(pattern, "$__DFFS_PP0_")) found_match = true, direct_dict["$__DFFS_PP0_"] = "$__DFFSE_PP0";
+ if (patmatch(pattern, "$__DFFS_PP1_")) found_match = true, direct_dict["$__DFFS_PP1_"] = "$__DFFSE_PP1";
if (!found_match)
log_cmd_error("No cell types matched pattern '%s'.\n", pattern);
continue;
diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc
new file mode 100644
index 00000000..39a4f6ad
--- /dev/null
+++ b/passes/techmap/dff2dffs.cc
@@ -0,0 +1,142 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 David Shah <dave@ds0.me>
+ *
+ * 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 Dff2dffsPass : public Pass {
+ Dff2dffsPass() : Pass("dff2dffs", "process sync set/reset with SR over CE priority") { }
+ void help() YS_OVERRIDE
+ {
+ log("\n");
+ log(" dff2dffs [options] [selection]\n");
+ log("\n");
+ log("Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before\n");
+ log("dff2dffe for SR over CE priority.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ pool<IdString> dff_types;
+ dff_types.insert("$_DFF_N_");
+ dff_types.insert("$_DFF_P_");
+
+ for (auto module : design->selected_modules())
+ {
+ log("Merging set/reset $_MUX_ cells into DFFs in %s.\n", log_id(module));
+
+ SigMap sigmap(module);
+ dict<SigBit, Cell*> sr_muxes;
+ vector<Cell*> ff_cells;
+
+ for (auto cell : module->selected_cells())
+ {
+ if (dff_types.count(cell->type)) {
+ ff_cells.push_back(cell);
+ continue;
+ }
+
+ if (cell->type != "$_MUX_")
+ continue;
+
+ SigBit bit_a = sigmap(cell->getPort("\\A"));
+ SigBit bit_b = sigmap(cell->getPort("\\B"));
+
+ if (bit_a.wire == nullptr || bit_b.wire == nullptr)
+ sr_muxes[sigmap(cell->getPort("\\Y"))] = cell;
+ }
+
+ for (auto cell : ff_cells)
+ {
+ SigSpec sig_d = cell->getPort("\\D");
+
+ if (GetSize(sig_d) < 1)
+ continue;
+
+ SigBit bit_d = sigmap(sig_d[0]);
+
+ if (sr_muxes.count(bit_d) == 0)
+ continue;
+
+ Cell *mux_cell = sr_muxes.at(bit_d);
+ SigBit bit_a = sigmap(mux_cell->getPort("\\A"));
+ SigBit bit_b = sigmap(mux_cell->getPort("\\B"));
+ SigBit bit_s = sigmap(mux_cell->getPort("\\S"));
+
+ log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
+ log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
+
+ SigBit sr_val, sr_sig;
+ bool invert_sr;
+ sr_sig = bit_s;
+ if (bit_a.wire == nullptr) {
+ bit_d = bit_b;
+ sr_val = bit_a;
+ invert_sr = true;
+ } else {
+ log_assert(bit_b.wire == nullptr);
+ bit_d = bit_a;
+ sr_val = bit_b;
+ invert_sr = false;
+ }
+
+ if (sr_val == State::S1) {
+ if (cell->type == "$_DFF_N_") {
+ if (invert_sr) cell->type = "$__DFFS_NN1_";
+ else cell->type = "$__DFFS_NP1_";
+ } else {
+ log_assert(cell->type == "$_DFF_P_");
+ if (invert_sr) cell->type = "$__DFFS_PN1_";
+ else cell->type = "$__DFFS_PP1_";
+ }
+ } else {
+ if (cell->type == "$_DFF_N_") {
+ if (invert_sr) cell->type = "$__DFFS_NN0_";
+ else cell->type = "$__DFFS_NP0_";
+ } else {
+ log_assert(cell->type == "$_DFF_P_");
+ if (invert_sr) cell->type = "$__DFFS_PN0_";
+ else cell->type = "$__DFFS_PP0_";
+ }
+ }
+ cell->setPort("\\R", sr_sig);
+ cell->setPort("\\D", bit_d);
+ }
+ }
+ }
+} Dff2dffsPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc
index d737b342..a8eecc97 100644
--- a/passes/techmap/dffinit.cc
+++ b/passes/techmap/dffinit.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct DffinitPass : public Pass {
DffinitPass() : Pass("dffinit", "set INIT param on FF cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -38,15 +38,25 @@ struct DffinitPass : public Pass {
log(" operate on the specified cell type. this option can be used\n");
log(" multiple times.\n");
log("\n");
+ log(" -highlow\n");
+ log(" use the string values \"high\" and \"low\" to represent a single-bit\n");
+ log(" initial value of 1 or 0. (multi-bit values are not supported in this\n");
+ log(" mode.)\n");
+ log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n");
dict<IdString, dict<IdString, IdString>> ff_types;
+ bool highlow_mode = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-highlow") {
+ highlow_mode = true;
+ continue;
+ }
if (args[argidx] == "-ff" && argidx+3 < args.size()) {
IdString cell_name = RTLIL::escape_id(args[++argidx]);
IdString output_port = RTLIL::escape_id(args[++argidx]);
@@ -106,6 +116,16 @@ struct DffinitPass : public Pass {
cleanup_bits.insert(sig[i]);
}
+ if (highlow_mode && GetSize(value) != 0) {
+ if (GetSize(value) != 1)
+ log_error("Multi-bit init value for %s.%s.%s is incompatible with -highlow mode.\n",
+ log_id(module), log_id(cell), log_id(it.second));
+ if (value[0] == State::S1)
+ value = Const("high");
+ else
+ value = Const("low");
+ }
+
log("Setting %s.%s.%s (port=%s, net=%s) to %s.\n", log_id(module), log_id(cell), log_id(it.second),
log_id(it.first), log_signal(sig), log_signal(value));
cell->setParam(it.second, value);
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index c8104fb7..416ed2bd 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -240,6 +240,10 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
if (cell->id != "cell" || cell->args.size() != 1)
continue;
+ LibertyAst *dn = cell->find("dont_use");
+ if (dn != NULL && dn->value == "true")
+ continue;
+
LibertyAst *ff = cell->find("ff");
if (ff == NULL)
continue;
@@ -478,11 +482,15 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
auto cell_type = cell->type;
auto cell_name = cell->name;
auto cell_connections = cell->connections();
+ std::string src = cell->get_src_attribute();
+
module->remove(cell);
cell_mapping &cm = cell_mappings[cell_type];
RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : "\\" + cm.cell_name);
+ new_cell->set_src_attribute(src);
+
bool has_q = false, has_qn = false;
for (auto &port : cm.ports) {
if (port.second == 'Q') has_q = true;
@@ -529,7 +537,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
struct DfflibmapPass : public Pass {
DfflibmapPass() : Pass("dfflibmap", "technology mapping of flip-flops") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" dfflibmap [-prepare] -liberty <file> [selection]\n");
@@ -545,7 +553,7 @@ struct DfflibmapPass : public Pass {
log("liberty file.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
diff --git a/passes/techmap/dffsr2dff.cc b/passes/techmap/dffsr2dff.cc
index 0d4d5362..086a1d2f 100644
--- a/passes/techmap/dffsr2dff.cc
+++ b/passes/techmap/dffsr2dff.cc
@@ -176,7 +176,7 @@ void adff_worker(SigMap &sigmap, Module *module, Cell *cell)
struct Dffsr2dffPass : public Pass {
Dffsr2dffPass() : Pass("dffsr2dff", "convert DFFSR cells to simpler FF cell types") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -186,7 +186,7 @@ struct Dffsr2dffPass : public Pass {
log("$_DFF_???_) to simpler FF cell types when any of the set/reset inputs is unused.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DFFSR2DFF pass (mapping DFFSR cells to simpler FFs).\n");
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index 71e29c60..fff90f13 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -352,7 +352,7 @@ bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right)
struct ExtractPass : public Pass {
ExtractPass() : Pass("extract", "find subcircuits and replace them with cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -440,7 +440,7 @@ struct ExtractPass : public Pass {
log("See 'help techmap' for a pass that does the opposite thing.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing EXTRACT pass (map subcircuits to cells).\n");
log_push();
diff --git a/passes/techmap/extract_counter.cc b/passes/techmap/extract_counter.cc
new file mode 100644
index 00000000..a8d0bc83
--- /dev/null
+++ b/passes/techmap/extract_counter.cc
@@ -0,0 +1,651 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2017 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"
+#include "kernel/modtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+//get the list of cells hooked up to at least one bit of a given net
+pool<Cell*> get_other_cells(const RTLIL::SigSpec& port, ModIndex& index, Cell* src)
+{
+ pool<Cell*> rval;
+ for(auto b : port)
+ {
+ pool<ModIndex::PortInfo> ports = index.query_ports(b);
+ for(auto x : ports)
+ {
+ if(x.cell == src)
+ continue;
+ rval.insert(x.cell);
+ }
+ }
+ return rval;
+}
+
+//return true if there is a full-width bus connection from cell a port ap to cell b port bp
+//if other_conns_allowed is false, then we require a strict point to point connection (no other links)
+bool is_full_bus(
+ const RTLIL::SigSpec& sig,
+ ModIndex& index,
+ Cell* a,
+ RTLIL::IdString ap,
+ Cell* b,
+ RTLIL::IdString bp,
+ bool other_conns_allowed = false)
+{
+ for(auto s : sig)
+ {
+ pool<ModIndex::PortInfo> ports = index.query_ports(s);
+ bool found_a = false;
+ bool found_b = false;
+ for(auto x : ports)
+ {
+ if( (x.cell == a) && (x.port == ap) )
+ found_a = true;
+ else if( (x.cell == b) && (x.port == bp) )
+ found_b = true;
+ else if(!other_conns_allowed)
+ return false;
+ }
+
+ if( (!found_a) || (!found_b) )
+ return false;
+ }
+
+ return true;
+}
+
+//return true if the signal connects to one port only (nothing on the other end)
+bool is_unconnected(const RTLIL::SigSpec& port, ModIndex& index)
+{
+ for(auto b : port)
+ {
+ pool<ModIndex::PortInfo> ports = index.query_ports(b);
+ if(ports.size() > 1)
+ return false;
+ }
+
+ return true;
+}
+
+struct CounterExtraction
+{
+ int width; //counter width
+ RTLIL::Wire* rwire; //the register output
+ bool has_reset; //true if we have a reset
+ bool has_ce; //true if we have a clock enable
+ RTLIL::SigSpec rst; //reset pin
+ bool rst_inverted; //true if reset is active low
+ bool rst_to_max; //true if we reset to max instead of 0
+ int count_value; //value we count from
+ RTLIL::SigSpec ce; //clock signal
+ RTLIL::SigSpec clk; //clock enable, if any
+ RTLIL::SigSpec outsig; //counter output signal
+ RTLIL::Cell* count_mux; //counter mux
+ RTLIL::Cell* count_reg; //counter register
+ RTLIL::Cell* underflow_inv; //inverter reduction for output-underflow detect
+ pool<ModIndex::PortInfo> pouts; //Ports that take a parallel output from us
+};
+
+//attempt to extract a counter centered on the given adder cell
+//For now we only support DOWN counters.
+//TODO: up/down support
+int counter_tryextract(
+ ModIndex& index,
+ Cell *cell,
+ CounterExtraction& extract,
+ pool<RTLIL::IdString>& parallel_cells,
+ int maxwidth)
+{
+ SigMap& sigmap = index.sigmap;
+
+ //A counter with less than 2 bits makes no sense
+ //TODO: configurable min threshold
+ int a_width = cell->getParam("\\A_WIDTH").as_int();
+ extract.width = a_width;
+ if( (a_width < 2) || (a_width > maxwidth) )
+ return 1;
+
+ //Second input must be a single bit
+ int b_width = cell->getParam("\\B_WIDTH").as_int();
+ if(b_width != 1)
+ return 2;
+
+ //Both inputs must be unsigned, so don't extract anything with a signed input
+ bool a_sign = cell->getParam("\\A_SIGNED").as_bool();
+ bool b_sign = cell->getParam("\\B_SIGNED").as_bool();
+ if(a_sign || b_sign)
+ return 3;
+
+ //To be a counter, one input of the ALU must be a constant 1
+ //TODO: can A or B be swapped in synthesized RTL or is B always the 1?
+ const RTLIL::SigSpec b_port = sigmap(cell->getPort("\\B"));
+ if(!b_port.is_fully_const() || (b_port.as_int() != 1) )
+ return 4;
+
+ //BI and CI must be constant 1 as well
+ const RTLIL::SigSpec bi_port = sigmap(cell->getPort("\\BI"));
+ if(!bi_port.is_fully_const() || (bi_port.as_int() != 1) )
+ return 5;
+ const RTLIL::SigSpec ci_port = sigmap(cell->getPort("\\CI"));
+ if(!ci_port.is_fully_const() || (ci_port.as_int() != 1) )
+ return 6;
+
+ //CO and X must be unconnected (exactly one connection to each port)
+ if(!is_unconnected(sigmap(cell->getPort("\\CO")), index))
+ return 7;
+ if(!is_unconnected(sigmap(cell->getPort("\\X")), index))
+ return 8;
+
+ //Y must have exactly one connection, and it has to be a $mux cell.
+ //We must have a direct bus connection from our Y to their A.
+ const RTLIL::SigSpec aluy = sigmap(cell->getPort("\\Y"));
+ pool<Cell*> y_loads = get_other_cells(aluy, index, cell);
+ if(y_loads.size() != 1)
+ return 9;
+ Cell* count_mux = *y_loads.begin();
+ extract.count_mux = count_mux;
+ if(count_mux->type != "$mux")
+ return 10;
+ if(!is_full_bus(aluy, index, cell, "\\Y", count_mux, "\\A"))
+ return 11;
+
+ //B connection of the mux is our underflow value
+ const RTLIL::SigSpec underflow = sigmap(count_mux->getPort("\\B"));
+ if(!underflow.is_fully_const())
+ return 12;
+ extract.count_value = underflow.as_int();
+
+ //S connection of the mux must come from an inverter (need not be the only load)
+ const RTLIL::SigSpec muxsel = sigmap(count_mux->getPort("\\S"));
+ extract.outsig = muxsel;
+ pool<Cell*> muxsel_conns = get_other_cells(muxsel, index, count_mux);
+ Cell* underflow_inv = NULL;
+ for(auto c : muxsel_conns)
+ {
+ if(c->type != "$logic_not")
+ continue;
+ if(!is_full_bus(muxsel, index, c, "\\Y", count_mux, "\\S", true))
+ continue;
+
+ underflow_inv = c;
+ break;
+ }
+ if(underflow_inv == NULL)
+ return 13;
+ extract.underflow_inv = underflow_inv;
+
+ //Y connection of the mux must have exactly one load, the counter's internal register, if there's no clock enable
+ //If we have a clock enable, Y drives the B input of a mux. A of that mux must come from our register
+ const RTLIL::SigSpec muxy = sigmap(count_mux->getPort("\\Y"));
+ pool<Cell*> muxy_loads = get_other_cells(muxy, index, count_mux);
+ if(muxy_loads.size() != 1)
+ return 14;
+ Cell* muxload = *muxy_loads.begin();
+ Cell* count_reg = muxload;
+ Cell* cemux = NULL;
+ RTLIL::SigSpec cey;
+ if(muxload->type == "$mux")
+ {
+ //This mux is probably a clock enable mux.
+ //Find our count register (should be our only load)
+ cemux = muxload;
+ cey = sigmap(cemux->getPort("\\Y"));
+ pool<Cell*> cey_loads = get_other_cells(cey, index, cemux);
+ if(cey_loads.size() != 1)
+ return 24;
+ count_reg = *cey_loads.begin();
+
+ //Mux should have A driven by count Q, and B by muxy
+ //TODO: if A and B are swapped, CE polarity is inverted
+ if(sigmap(cemux->getPort("\\B")) != muxy)
+ return 24;
+ if(sigmap(cemux->getPort("\\A")) != sigmap(count_reg->getPort("\\Q")))
+ return 24;
+ if(sigmap(cemux->getPort("\\Y")) != sigmap(count_reg->getPort("\\D")))
+ return 24;
+
+ //Select of the mux is our clock enable
+ extract.has_ce = true;
+ extract.ce = sigmap(cemux->getPort("\\S"));
+ }
+ else
+ extract.has_ce = false;
+
+ extract.count_reg = count_reg;
+ if(count_reg->type == "$dff")
+ extract.has_reset = false;
+ else if(count_reg->type == "$adff")
+ {
+ extract.has_reset = true;
+
+ //Check polarity of reset - we may have to add an inverter later on!
+ extract.rst_inverted = (count_reg->getParam("\\ARST_POLARITY").as_int() != 1);
+
+ //Verify ARST_VALUE is zero or full scale
+ int rst_value = count_reg->getParam("\\ARST_VALUE").as_int();
+ if(rst_value == 0)
+ extract.rst_to_max = false;
+ else if(rst_value == extract.count_value)
+ extract.rst_to_max = true;
+ else
+ return 23;
+
+ //Save the reset
+ extract.rst = sigmap(count_reg->getPort("\\ARST"));
+ }
+ //TODO: support synchronous reset
+ else
+ return 15;
+
+ //Sanity check that we use the ALU output properly
+ if(extract.has_ce)
+ {
+ if(!is_full_bus(muxy, index, count_mux, "\\Y", cemux, "\\B"))
+ return 16;
+ if(!is_full_bus(cey, index, cemux, "\\Y", count_reg, "\\D"))
+ return 16;
+ }
+ else if(!is_full_bus(muxy, index, count_mux, "\\Y", count_reg, "\\D"))
+ return 16;
+
+ //TODO: Verify count_reg CLK_POLARITY is 1
+
+ //Register output must have exactly two loads, the inverter and ALU
+ //(unless we have a parallel output!)
+ //If we have a clock enable, 3 is OK
+ const RTLIL::SigSpec qport = count_reg->getPort("\\Q");
+ const RTLIL::SigSpec cnout = sigmap(qport);
+ pool<Cell*> cnout_loads = get_other_cells(cnout, index, count_reg);
+ unsigned int max_loads = 2;
+ if(extract.has_ce)
+ max_loads = 3;
+ if(cnout_loads.size() > max_loads)
+ {
+ for(auto c : cnout_loads)
+ {
+ if(c == underflow_inv)
+ continue;
+ if(c == cell)
+ continue;
+ if(c == muxload)
+ continue;
+
+ //If we specified a limited set of cells for parallel output, check that we only drive them
+ if(!parallel_cells.empty())
+ {
+ //Make sure we're in the whitelist
+ if( parallel_cells.find(c->type) == parallel_cells.end())
+ return 17;
+ }
+
+ //Figure out what port(s) are driven by it
+ //TODO: this can probably be done more efficiently w/o multiple iterations over our whole net?
+ for(auto b : qport)
+ {
+ pool<ModIndex::PortInfo> ports = index.query_ports(b);
+ for(auto x : ports)
+ {
+ if(x.cell != c)
+ continue;
+ extract.pouts.insert(ModIndex::PortInfo(c, x.port, 0));
+ }
+ }
+ }
+ }
+ if(!is_full_bus(cnout, index, count_reg, "\\Q", underflow_inv, "\\A", true))
+ return 18;
+ if(!is_full_bus(cnout, index, count_reg, "\\Q", cell, "\\A", true))
+ return 19;
+
+ //Look up the clock from the register
+ extract.clk = sigmap(count_reg->getPort("\\CLK"));
+
+ //Register output net must have an INIT attribute equal to the count value
+ extract.rwire = cnout.as_wire();
+ if(extract.rwire->attributes.find("\\init") == extract.rwire->attributes.end())
+ return 20;
+ int rinit = extract.rwire->attributes["\\init"].as_int();
+ if(rinit != extract.count_value)
+ return 21;
+
+ return 0;
+}
+
+void counter_worker(
+ ModIndex& index,
+ Cell *cell,
+ unsigned int& total_counters,
+ pool<Cell*>& cells_to_remove,
+ pool<pair<Cell*, string>>& cells_to_rename,
+ pool<RTLIL::IdString>& parallel_cells,
+ int maxwidth)
+{
+ SigMap& sigmap = index.sigmap;
+
+ //Core of the counter must be an ALU
+ if (cell->type != "$alu")
+ return;
+
+ //A input is the count value. Check if it has COUNT_EXTRACT set.
+ //If it's not a wire, don't even try
+ auto port = sigmap(cell->getPort("\\A"));
+ if(!port.is_wire())
+ return;
+ RTLIL::Wire* a_wire = port.as_wire();
+ bool force_extract = false;
+ bool never_extract = false;
+ string count_reg_src = a_wire->attributes["\\src"].decode_string().c_str();
+ if(a_wire->attributes.find("\\COUNT_EXTRACT") != a_wire->attributes.end())
+ {
+ pool<string> sa = a_wire->get_strpool_attribute("\\COUNT_EXTRACT");
+ string extract_value;
+ if(sa.size() >= 1)
+ {
+ extract_value = *sa.begin();
+ log(" Signal %s declared at %s has COUNT_EXTRACT = %s\n",
+ log_id(a_wire),
+ count_reg_src.c_str(),
+ extract_value.c_str());
+
+ if(extract_value == "FORCE")
+ force_extract = true;
+ else if(extract_value == "NO")
+ never_extract = true;
+ else if(extract_value == "AUTO")
+ {} //default
+ else
+ log_error(" Illegal COUNT_EXTRACT value %s (must be one of FORCE, NO, AUTO)\n",
+ extract_value.c_str());
+ }
+ }
+
+ //If we're explicitly told not to extract, don't infer a counter
+ if(never_extract)
+ return;
+
+ //Attempt to extract a counter
+ CounterExtraction extract;
+ int reason = counter_tryextract(index, cell, extract, parallel_cells, maxwidth);
+
+ //Nonzero code - we could not find a matchable counter.
+ //Do nothing, unless extraction was forced in which case give an error
+ if(reason != 0)
+ {
+ static const char* reasons[25]=
+ {
+ "no problem", //0
+ "counter is too large/small", //1
+ "counter does not count by one", //2
+ "counter uses signed math", //3
+ "counter does not count by one", //4
+ "ALU is not a subtractor", //5
+ "ALU is not a subtractor", //6
+ "ALU ports used outside counter", //7
+ "ALU ports used outside counter", //8
+ "ALU output used outside counter", //9
+ "ALU output is not a mux", //10
+ "ALU output is not full bus", //11
+ "Underflow value is not constant", //12
+ "No underflow detector found", //13
+ "Mux output is used outside counter", //14
+ "Counter reg is not DFF/ADFF", //15
+ "Counter input is not full bus", //16
+ "Count register is used outside counter, but not by an allowed cell", //17
+ "Register output is not full bus", //18
+ "Register output is not full bus", //19
+ "No init value found", //20
+ "Underflow value is not equal to init value", //21
+ "RESERVED, not implemented", //22, kept for compatibility but not used anymore
+ "Reset is not to zero or COUNT_TO", //23
+ "Clock enable configuration is unsupported" //24
+ };
+
+ if(force_extract)
+ {
+ log_error(
+ "Counter extraction is set to FORCE on register %s, but a counter could not be inferred (%s)\n",
+ log_id(a_wire),
+ reasons[reason]);
+ }
+ return;
+ }
+
+ //Get new cell name
+ string countname = string("$COUNTx$") + log_id(extract.rwire->name.str());
+
+ //Wipe all of the old connections to the ALU
+ cell->unsetPort("\\A");
+ cell->unsetPort("\\B");
+ cell->unsetPort("\\BI");
+ cell->unsetPort("\\CI");
+ cell->unsetPort("\\CO");
+ cell->unsetPort("\\X");
+ cell->unsetPort("\\Y");
+ cell->unsetParam("\\A_SIGNED");
+ cell->unsetParam("\\A_WIDTH");
+ cell->unsetParam("\\B_SIGNED");
+ cell->unsetParam("\\B_WIDTH");
+ cell->unsetParam("\\Y_WIDTH");
+
+ //Change the cell type
+ cell->type = "$__COUNT_";
+
+ //Hook up resets
+ if(extract.has_reset)
+ {
+ //TODO: support other kinds of reset
+ cell->setParam("\\RESET_MODE", RTLIL::Const("LEVEL"));
+
+ //If the reset is active low, infer an inverter ($__COUNT_ cells always have active high reset)
+ if(extract.rst_inverted)
+ {
+ auto realreset = cell->module->addWire(NEW_ID);
+ cell->module->addNot(NEW_ID, extract.rst, RTLIL::SigSpec(realreset));
+ cell->setPort("\\RST", realreset);
+ }
+ else
+ cell->setPort("\\RST", extract.rst);
+ }
+ else
+ {
+ cell->setParam("\\RESET_MODE", RTLIL::Const("RISING"));
+ cell->setPort("\\RST", RTLIL::SigSpec(false));
+ }
+
+ //Hook up other stuff
+ //cell->setParam("\\CLKIN_DIVIDE", RTLIL::Const(1));
+ cell->setParam("\\COUNT_TO", RTLIL::Const(extract.count_value));
+ cell->setParam("\\WIDTH", RTLIL::Const(extract.width));
+ cell->setPort("\\CLK", extract.clk);
+ cell->setPort("\\OUT", extract.outsig);
+
+ //Hook up clock enable
+ if(extract.has_ce)
+ {
+ cell->setParam("\\HAS_CE", RTLIL::Const(1));
+ cell->setPort("\\CE", extract.ce);
+ }
+ else
+ cell->setParam("\\HAS_CE", RTLIL::Const(0));
+
+ //Hook up hard-wired ports (for now up/down are not supported), default to no parallel output
+ cell->setParam("\\HAS_POUT", RTLIL::Const(0));
+ cell->setParam("\\RESET_TO_MAX", RTLIL::Const(0));
+ cell->setParam("\\DIRECTION", RTLIL::Const("DOWN"));
+ cell->setPort("\\CE", RTLIL::Const(1));
+ cell->setPort("\\UP", RTLIL::Const(0));
+
+ //Hook up any parallel outputs
+ for(auto load : extract.pouts)
+ {
+ log(" Counter has parallel output to cell %s port %s\n", log_id(load.cell->name), log_id(load.port));
+
+ //Find the wire hooked to the old port
+ auto sig = load.cell->getPort(load.port);
+
+ //Connect it to our parallel output
+ //(this is OK to do more than once b/c they all go to the same place)
+ cell->setPort("\\POUT", sig);
+ cell->setParam("\\HAS_POUT", RTLIL::Const(1));
+ }
+
+ //Delete the cells we've replaced (let opt_clean handle deleting the now-redundant wires)
+ cells_to_remove.insert(extract.count_mux);
+ cells_to_remove.insert(extract.count_reg);
+ cells_to_remove.insert(extract.underflow_inv);
+
+ //Log it
+ total_counters ++;
+ string reset_type = "non-resettable";
+ if(extract.has_reset)
+ {
+ if(extract.rst_inverted)
+ reset_type = "negative";
+ else
+ reset_type = "positive";
+
+ //TODO: support other kind of reset
+ reset_type += " async resettable";
+ }
+ log(" Found %d-bit (%s) down counter %s (counting from %d) for register %s, declared at %s\n",
+ extract.width,
+ reset_type.c_str(),
+ countname.c_str(),
+ extract.count_value,
+ log_id(extract.rwire->name),
+ count_reg_src.c_str());
+
+ //Optimize the counter
+ //If we have no parallel output, and we have redundant bits, shrink us
+ if(extract.pouts.empty())
+ {
+ //TODO: Need to update this when we add support for counters with nonzero reset values
+ //to make sure the reset value fits in our bit space too
+
+ //Optimize it
+ int newbits = ceil(log2(extract.count_value));
+ if(extract.width != newbits)
+ {
+ cell->setParam("\\WIDTH", RTLIL::Const(newbits));
+ log(" Optimizing out %d unused high-order bits (new width is %d)\n",
+ extract.width - newbits,
+ newbits);
+ }
+ }
+
+ //Finally, rename the cell
+ cells_to_rename.insert(pair<Cell*, string>(cell, countname));
+}
+
+struct ExtractCounterPass : public Pass {
+ ExtractCounterPass() : Pass("extract_counter", "Extract GreenPak4 counter cells") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" extract_counter [options] [selection]\n");
+ log("\n");
+ log("This pass converts non-resettable or async resettable down counters to\n");
+ log("counter cells. Use a target-specific 'techmap' map file to convert those cells\n");
+ log("to the actual target cells.\n");
+ log("\n");
+ log(" -maxwidth N\n");
+ log(" Only extract counters up to N bits wide\n");
+ log("\n");
+ log(" -pout X,Y,...\n");
+ log(" Only allow parallel output from the counter to the listed cell types\n");
+ log(" (if not specified, parallel outputs are not restricted)\n");
+ log("\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing EXTRACT_COUNTER pass (find counters in netlist).\n");
+
+ int maxwidth = 64;
+ size_t argidx;
+ pool<RTLIL::IdString> parallel_cells;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-pout")
+ {
+ if(argidx + 1 >= args.size())
+ {
+ log_error("extract_counter -pout requires an argument\n");
+ return;
+ }
+
+ std::string pouts = args[++argidx];
+ std::string tmp;
+ for(size_t i=0; i<pouts.length(); i++)
+ {
+ if(pouts[i] == ',')
+ {
+ parallel_cells.insert(RTLIL::escape_id(tmp));
+ tmp = "";
+ }
+ else
+ tmp += pouts[i];
+ }
+ parallel_cells.insert(RTLIL::escape_id(tmp));
+ continue;
+ }
+
+ if (args[argidx] == "-maxwidth" && argidx+1 < args.size())
+ {
+ maxwidth = atoi(args[++argidx].c_str());
+ continue;
+ }
+ }
+ extra_args(args, argidx, design);
+
+ //Extract all of the counters we could find
+ unsigned int total_counters = 0;
+ for (auto module : design->selected_modules())
+ {
+ pool<Cell*> cells_to_remove;
+ pool<pair<Cell*, string>> cells_to_rename;
+
+ ModIndex index(module);
+ for (auto cell : module->selected_cells())
+ counter_worker(index, cell, total_counters, cells_to_remove, cells_to_rename, parallel_cells, maxwidth);
+
+ for(auto cell : cells_to_remove)
+ {
+ //log("Removing cell %s\n", log_id(cell->name));
+ module->remove(cell);
+ }
+
+ for(auto cpair : cells_to_rename)
+ {
+ //log("Renaming cell %s to %s\n", log_id(cpair.first->name), cpair.second.c_str());
+ module->rename(cpair.first, cpair.second);
+ }
+ }
+
+ if(total_counters)
+ log("Extracted %u counters\n", total_counters);
+ }
+} ExtractCounterPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc
new file mode 100644
index 00000000..9e6dc0d2
--- /dev/null
+++ b/passes/techmap/extract_fa.cc
@@ -0,0 +1,605 @@
+/*
+ * 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"
+#include "kernel/consteval.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ExtractFaConfig
+{
+ bool enable_fa = false;
+ bool enable_ha = false;
+ bool verbose = false;
+ int maxdepth = 20;
+ int maxbreadth = 6;
+};
+
+// http://svn.clifford.at/handicraft/2016/bindec/bindec.c
+int bindec(unsigned char v)
+{
+ int r = v & 1;
+ r += (~((v & 2) - 1)) & 10;
+ r += (~((v & 4) - 1)) & 100;
+ r += (~((v & 8) - 1)) & 1000;
+ r += (~((v & 16) - 1)) & 10000;
+ r += (~((v & 32) - 1)) & 100000;
+ r += (~((v & 64) - 1)) & 1000000;
+ r += (~((v & 128) - 1)) & 10000000;
+ return r;
+}
+
+struct ExtractFaWorker
+{
+ const ExtractFaConfig &config;
+ Module *module;
+ ConstEval ce;
+ SigMap &sigmap;
+
+ dict<SigBit, Cell*> driver;
+ pool<SigBit> handled_bits;
+
+ const int xor2_func = 0x6, xnor2_func = 0x9;
+ const int xor3_func = 0x96, xnor3_func = 0x69;
+
+ pool<tuple<SigBit, SigBit>> xorxnor2;
+ pool<tuple<SigBit, SigBit, SigBit>> xorxnor3;
+
+ dict<tuple<SigBit, SigBit>, dict<int, pool<SigBit>>> func2;
+ dict<tuple<SigBit, SigBit, SigBit>, dict<int, pool<SigBit>>> func3;
+
+ int count_func2;
+ int count_func3;
+
+ struct func2_and_info_t {
+ bool inv_a, inv_b, inv_y;
+ };
+
+ struct func3_maj_info_t {
+ bool inv_a, inv_b, inv_c, inv_y;
+ };
+
+ dict<int, func2_and_info_t> func2_and_info;
+ dict<int, func3_maj_info_t> func3_maj_info;
+
+ ExtractFaWorker(const ExtractFaConfig &config, Module *module) :
+ config(config), module(module), ce(module), sigmap(ce.assign_map)
+ {
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type.in( "$_BUF_", "$_NOT_", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_",
+ "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$_MUX_",
+ "$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_"))
+ {
+ SigBit y = sigmap(SigBit(cell->getPort("\\Y")));
+ log_assert(driver.count(y) == 0);
+ driver[y] = cell;
+ }
+ }
+
+ for (int ia = 0; ia < 2; ia++)
+ for (int ib = 0; ib < 2; ib++)
+ {
+ func2_and_info_t f2i;
+
+ f2i.inv_a = ia;
+ f2i.inv_b = ib;
+ f2i.inv_y = false;
+
+ int func = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ bool a = (i & 1) ? !f2i.inv_a : f2i.inv_a;
+ bool b = (i & 2) ? !f2i.inv_b : f2i.inv_b;
+ if (a && b) func |= 1 << i;
+ }
+
+ log_assert(func2_and_info.count(func) == 0);
+ func2_and_info[func] = f2i;
+
+ f2i.inv_y = true;
+ func ^= 15;
+
+ log_assert(func2_and_info.count(func) == 0);
+ func2_and_info[func] = f2i;
+ }
+
+ for (int ia = 0; ia < 2; ia++)
+ for (int ib = 0; ib < 2; ib++)
+ for (int ic = 0; ic < 2; ic++)
+ {
+ func3_maj_info_t f3i;
+
+ f3i.inv_a = ia;
+ f3i.inv_b = ib;
+ f3i.inv_c = ic;
+ f3i.inv_y = false;
+
+ int func = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ bool a = (i & 1) ? !f3i.inv_a : f3i.inv_a;
+ bool b = (i & 2) ? !f3i.inv_b : f3i.inv_b;
+ bool c = (i & 4) ? !f3i.inv_c : f3i.inv_c;
+ if ((a && b) || (a && c) || (b &&c)) func |= 1 << i;
+ }
+
+ log_assert(func3_maj_info.count(func) == 0);
+ func3_maj_info[func] = f3i;
+
+ // f3i.inv_y = true;
+ // func ^= 255;
+
+ // log_assert(func3_maj_info.count(func) == 0);
+ // func3_maj_info[func] = f3i;
+ }
+ }
+
+ void check_partition(SigBit root, pool<SigBit> &leaves)
+ {
+ if (config.enable_ha && GetSize(leaves) == 2)
+ {
+ leaves.sort();
+
+ SigBit A = SigSpec(leaves)[0];
+ SigBit B = SigSpec(leaves)[1];
+
+ int func = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ bool a_value = (i & 1) != 0;
+ bool b_value = (i & 2) != 0;
+
+ ce.push();
+ ce.set(A, a_value ? State::S1 : State::S0);
+ ce.set(B, b_value ? State::S1 : State::S0);
+
+ SigSpec sig = root;
+
+ if (!ce.eval(sig))
+ log_abort();
+
+ if (sig == State::S1)
+ func |= 1 << i;
+
+ ce.pop();
+ }
+
+ // log("%04d %s %s -> %s\n", bindec(func), log_signal(A), log_signal(B), log_signal(root));
+
+ if (func == xor2_func || func == xnor2_func)
+ xorxnor2.insert(tuple<SigBit, SigBit>(A, B));
+
+ count_func2++;
+ func2[tuple<SigBit, SigBit>(A, B)][func].insert(root);
+ }
+
+ if (config.enable_fa && GetSize(leaves) == 3)
+ {
+ leaves.sort();
+
+ SigBit A = SigSpec(leaves)[0];
+ SigBit B = SigSpec(leaves)[1];
+ SigBit C = SigSpec(leaves)[2];
+
+ int func = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ bool a_value = (i & 1) != 0;
+ bool b_value = (i & 2) != 0;
+ bool c_value = (i & 4) != 0;
+
+ ce.push();
+ ce.set(A, a_value ? State::S1 : State::S0);
+ ce.set(B, b_value ? State::S1 : State::S0);
+ ce.set(C, c_value ? State::S1 : State::S0);
+
+ SigSpec sig = root;
+
+ if (!ce.eval(sig))
+ log_abort();
+
+ if (sig == State::S1)
+ func |= 1 << i;
+
+ ce.pop();
+ }
+
+ // log("%08d %s %s %s -> %s\n", bindec(func), log_signal(A), log_signal(B), log_signal(C), log_signal(root));
+
+ if (func == xor3_func || func == xnor3_func)
+ xorxnor3.insert(tuple<SigBit, SigBit, SigBit>(A, B, C));
+
+ count_func3++;
+ func3[tuple<SigBit, SigBit, SigBit>(A, B, C)][func].insert(root);
+ }
+ }
+
+ void find_partitions(SigBit root, pool<SigBit> &leaves, pool<pool<SigBit>> &cache, int maxdepth, int maxbreadth)
+ {
+ if (cache.count(leaves))
+ return;
+
+ // log("%*s[%d] %s:", 20-maxdepth, "", maxdepth, log_signal(root));
+ // for (auto bit : leaves)
+ // log(" %s", log_signal(bit));
+ // log("\n");
+
+ cache.insert(leaves);
+ check_partition(root, leaves);
+
+ if (maxdepth == 0)
+ return;
+
+ for (SigBit bit : leaves)
+ {
+ if (driver.count(bit) == 0)
+ continue;
+
+ Cell *cell = driver.at(bit);
+ pool<SigBit> new_leaves = leaves;
+
+ new_leaves.erase(bit);
+ if (cell->hasPort("\\A")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\A"))));
+ if (cell->hasPort("\\B")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\B"))));
+ if (cell->hasPort("\\C")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\C"))));
+ if (cell->hasPort("\\D")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\D"))));
+
+ if (GetSize(new_leaves) > maxbreadth)
+ continue;
+
+ find_partitions(root, new_leaves, cache, maxdepth-1, maxbreadth);
+ }
+ }
+
+ void assign_new_driver(SigBit bit, SigBit new_driver)
+ {
+ Cell *cell = driver.at(bit);
+ if (sigmap(cell->getPort("\\Y")) == bit) {
+ cell->setPort("\\Y", module->addWire(NEW_ID));
+ module->connect(bit, new_driver);
+ }
+ }
+
+ void run()
+ {
+ log("Extracting full/half adders from %s:\n", log_id(module));
+
+ for (auto it : driver)
+ {
+ if (it.second->type.in("$_BUF_", "$_NOT_"))
+ continue;
+
+ SigBit root = it.first;
+ pool<SigBit> leaves = { root };
+ pool<pool<SigBit>> cache;
+
+ if (config.verbose)
+ log(" checking %s\n", log_signal(it.first));
+
+ count_func2 = 0;
+ count_func3 = 0;
+
+ find_partitions(root, leaves, cache, config.maxdepth, config.maxbreadth);
+
+ if (config.verbose && count_func2 > 0)
+ log(" extracted %d two-input functions\n", count_func2);
+
+ if (config.verbose && count_func3 > 0)
+ log(" extracted %d three-input functions\n", count_func3);
+ }
+
+ for (auto &key : xorxnor3)
+ {
+ SigBit A = get<0>(key);
+ SigBit B = get<1>(key);
+ SigBit C = get<2>(key);
+
+ log(" 3-Input XOR/XNOR %s %s %s:\n", log_signal(A), log_signal(B), log_signal(C));
+
+ for (auto &it : func3.at(key))
+ {
+ if (it.first != xor3_func && it.first != xnor3_func)
+ continue;
+
+ log(" %08d ->", bindec(it.first));
+ for (auto bit : it.second)
+ log(" %s", log_signal(bit));
+ log("\n");
+ }
+
+ dict<int, tuple<SigBit, SigBit, Cell*>> facache;
+
+ for (auto &it : func3_maj_info)
+ {
+ int func = it.first;
+ auto f3i = it.second;
+
+ if (func3.at(key).count(func) == 0)
+ continue;
+
+ if (func3.at(key).count(xor3_func) == 0 && func3.at(key).count(xnor3_func) != 0) {
+ f3i.inv_a = !f3i.inv_a;
+ f3i.inv_b = !f3i.inv_b;
+ f3i.inv_c = !f3i.inv_c;
+ f3i.inv_y = !f3i.inv_y;
+ }
+
+ if (!f3i.inv_a && !f3i.inv_b && !f3i.inv_c && !f3i.inv_y) {
+ log(" Majority without inversions:\n");
+ } else {
+ log(" Majority with inverted");
+ if (f3i.inv_a) log(" A");
+ if (f3i.inv_b) log(" B");
+ if (f3i.inv_c) log(" C");
+ if (f3i.inv_y) log(" Y");
+ log(":\n");
+ }
+
+ log(" %08d ->", bindec(func));
+ for (auto bit : func3.at(key).at(func))
+ log(" %s", log_signal(bit));
+ log("\n");
+
+ int fakey = 0;
+ if (f3i.inv_a) fakey |= 1;
+ if (f3i.inv_b) fakey |= 2;
+ if (f3i.inv_c) fakey |= 4;
+
+ int fakey_inv = fakey ^ 7;
+ bool invert_xy = false;
+ SigBit X, Y;
+
+ if (facache.count(fakey))
+ {
+ auto &fa = facache.at(fakey);
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ if (facache.count(fakey_inv))
+ {
+ auto &fa = facache.at(fakey_inv);
+ invert_xy = true;
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ {
+ Cell *cell = module->addCell(NEW_ID, "$fa");
+ cell->setParam("\\WIDTH", 1);
+
+ log(" Created $fa cell %s.\n", log_id(cell));
+
+ cell->setPort("\\A", f3i.inv_a ? module->NotGate(NEW_ID, A) : A);
+ cell->setPort("\\B", f3i.inv_b ? module->NotGate(NEW_ID, B) : B);
+ cell->setPort("\\C", f3i.inv_c ? module->NotGate(NEW_ID, C) : C);
+
+ X = module->addWire(NEW_ID);
+ Y = module->addWire(NEW_ID);
+
+ cell->setPort("\\X", X);
+ cell->setPort("\\Y", Y);
+
+ facache[fakey] = make_tuple(X, Y, cell);
+ }
+
+ if (func3.at(key).count(xor3_func)) {
+ SigBit YY = invert_xy ? module->NotGate(NEW_ID, Y) : Y;
+ for (auto bit : func3.at(key).at(xor3_func))
+ assign_new_driver(bit, YY);
+ }
+
+ if (func3.at(key).count(xnor3_func)) {
+ SigBit YY = invert_xy ? Y : module->NotGate(NEW_ID, Y);
+ for (auto bit : func3.at(key).at(xnor3_func))
+ assign_new_driver(bit, YY);
+ }
+
+ SigBit XX = invert_xy != f3i.inv_y ? module->NotGate(NEW_ID, X) : X;
+
+ for (auto bit : func3.at(key).at(func))
+ assign_new_driver(bit, XX);
+ }
+ }
+
+ for (auto &key : xorxnor2)
+ {
+ SigBit A = get<0>(key);
+ SigBit B = get<1>(key);
+
+ log(" 2-Input XOR/XNOR %s %s:\n", log_signal(A), log_signal(B));
+
+ for (auto &it : func2.at(key))
+ {
+ if (it.first != xor2_func && it.first != xnor2_func)
+ continue;
+
+ log(" %04d ->", bindec(it.first));
+ for (auto bit : it.second)
+ log(" %s", log_signal(bit));
+ log("\n");
+ }
+
+ dict<int, tuple<SigBit, SigBit, Cell*>> facache;
+
+ for (auto &it : func2_and_info)
+ {
+ int func = it.first;
+ auto &f2i = it.second;
+
+ if (func2.at(key).count(func) == 0)
+ continue;
+
+ if (!f2i.inv_a && !f2i.inv_b && !f2i.inv_y) {
+ log(" AND without inversions:\n");
+ } else {
+ log(" AND with inverted");
+ if (f2i.inv_a) log(" A");
+ if (f2i.inv_b) log(" B");
+ if (f2i.inv_y) log(" Y");
+ log(":\n");
+ }
+
+ log(" %04d ->", bindec(func));
+ for (auto bit : func2.at(key).at(func))
+ log(" %s", log_signal(bit));
+ log("\n");
+
+ int fakey = 0;
+ if (f2i.inv_a) fakey |= 1;
+ if (f2i.inv_b) fakey |= 2;
+
+ int fakey_inv = fakey ^ 3;
+ bool invert_xy = false;
+ SigBit X, Y;
+
+ if (facache.count(fakey))
+ {
+ auto &fa = facache.at(fakey);
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ if (facache.count(fakey_inv))
+ {
+ auto &fa = facache.at(fakey_inv);
+ invert_xy = true;
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ {
+ Cell *cell = module->addCell(NEW_ID, "$fa");
+ cell->setParam("\\WIDTH", 1);
+
+ log(" Created $fa cell %s.\n", log_id(cell));
+
+ cell->setPort("\\A", f2i.inv_a ? module->NotGate(NEW_ID, A) : A);
+ cell->setPort("\\B", f2i.inv_b ? module->NotGate(NEW_ID, B) : B);
+ cell->setPort("\\C", State::S0);
+
+ X = module->addWire(NEW_ID);
+ Y = module->addWire(NEW_ID);
+
+ cell->setPort("\\X", X);
+ cell->setPort("\\Y", Y);
+ }
+
+ if (func2.at(key).count(xor2_func)) {
+ SigBit YY = invert_xy ? module->NotGate(NEW_ID, Y) : Y;
+ for (auto bit : func2.at(key).at(xor2_func))
+ assign_new_driver(bit, YY);
+ }
+
+ if (func2.at(key).count(xnor2_func)) {
+ SigBit YY = invert_xy ? Y : module->NotGate(NEW_ID, Y);
+ for (auto bit : func2.at(key).at(xnor2_func))
+ assign_new_driver(bit, YY);
+ }
+
+ SigBit XX = invert_xy != f2i.inv_y ? module->NotGate(NEW_ID, X) : X;
+
+ for (auto bit : func2.at(key).at(func))
+ assign_new_driver(bit, XX);
+ }
+ }
+ }
+};
+
+struct ExtractFaPass : public Pass {
+ ExtractFaPass() : Pass("extract_fa", "find and extract full/half adders") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" extract_fa [options] [selection]\n");
+ log("\n");
+ log("This pass extracts full/half adders from a gate-level design.\n");
+ log("\n");
+ log(" -fa, -ha\n");
+ log(" Enable cell types (fa=full adder, ha=half adder)\n");
+ log(" All types are enabled if none of this options is used\n");
+ log("\n");
+ log(" -d <int>\n");
+ log(" Set maximum depth for extracted logic cones (default=20)\n");
+ log("\n");
+ log(" -b <int>\n");
+ log(" Set maximum breadth for extracted logic cones (default=6)\n");
+ log("\n");
+ log(" -v\n");
+ log(" Verbose output\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ ExtractFaConfig config;
+
+ log_header(design, "Executing EXTRACT_FA pass (find and extract full/half adders).\n");
+ log_push();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-fa") {
+ config.enable_fa = true;
+ continue;
+ }
+ if (args[argidx] == "-ha") {
+ config.enable_ha = true;
+ continue;
+ }
+ if (args[argidx] == "-v") {
+ config.verbose = true;
+ continue;
+ }
+ if (args[argidx] == "-d" && argidx+2 < args.size()) {
+ config.maxdepth = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-b" && argidx+2 < args.size()) {
+ config.maxbreadth = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!config.enable_fa && !config.enable_ha) {
+ config.enable_fa = true;
+ config.enable_ha = true;
+ }
+
+ for (auto module : design->selected_modules())
+ {
+ ExtractFaWorker worker(config, module);
+ worker.run();
+ }
+
+ log_pop();
+ }
+} ExtractFaPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc
new file mode 100644
index 00000000..a77bbc0b
--- /dev/null
+++ b/passes/techmap/extract_reduce.cc
@@ -0,0 +1,324 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2017 Robert Ou <rqou@robertou.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"
+#include <deque>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ExtractReducePass : public Pass
+{
+ enum GateType {
+ And,
+ Or,
+ Xor
+ };
+
+ ExtractReducePass() : Pass("extract_reduce", "converts gate chains into $reduce_* cells") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" extract_reduce [options] [selection]\n");
+ log("\n");
+ log("converts gate chains into $reduce_* cells\n");
+ log("\n");
+ log("This command finds chains of $_AND_, $_OR_, and $_XOR_ cells and replaces them\n");
+ log("with their corresponding $reduce_* cells. Because this command only operates on\n");
+ log("these cell types, it is recommended to map the design to only these cell types\n");
+ log("using the `abc -g` command. Note that, in some cases, it may be more effective\n");
+ log("to map the design to only $_AND_ cells, run extract_reduce, map the remaining\n");
+ log("parts of the design to AND/OR/XOR cells, and run extract_reduce a second time.\n");
+ log("\n");
+ log(" -allow-off-chain\n");
+ log(" Allows matching of cells that have loads outside the chain. These cells\n");
+ log(" will be replicated and folded into the $reduce_* cell, but the original\n");
+ log(" cell will remain, driving its original loads.\n");
+ log("\n");
+ }
+
+ inline bool IsRightType(Cell* cell, GateType gt)
+ {
+ return (cell->type == "$_AND_" && gt == GateType::And) ||
+ (cell->type == "$_OR_" && gt == GateType::Or) ||
+ (cell->type == "$_XOR_" && gt == GateType::Xor);
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing EXTRACT_REDUCE pass.\n");
+ log_push();
+
+ size_t argidx;
+ bool allow_off_chain = false;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-allow-off-chain")
+ {
+ allow_off_chain = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+
+ // Index all of the nets in the module
+ dict<SigBit, Cell*> sig_to_driver;
+ dict<SigBit, pool<Cell*>> sig_to_sink;
+ for (auto cell : module->selected_cells())
+ {
+ for (auto &conn : cell->connections())
+ {
+ if (cell->output(conn.first))
+ for (auto bit : sigmap(conn.second))
+ sig_to_driver[bit] = cell;
+
+ if (cell->input(conn.first))
+ {
+ for (auto bit : sigmap(conn.second))
+ {
+ if (sig_to_sink.count(bit) == 0)
+ sig_to_sink[bit] = pool<Cell*>();
+ sig_to_sink[bit].insert(cell);
+ }
+ }
+ }
+ }
+
+ // Need to check if any wires connect to module ports
+ pool<SigBit> port_sigs;
+ for (auto wire : module->selected_wires())
+ if (wire->port_input || wire->port_output)
+ for (auto bit : sigmap(wire))
+ port_sigs.insert(bit);
+
+ // Actual logic starts here
+ pool<Cell*> consumed_cells;
+ for (auto cell : module->selected_cells())
+ {
+ if (consumed_cells.count(cell))
+ continue;
+
+ GateType gt;
+
+ if (cell->type == "$_AND_")
+ gt = GateType::And;
+ else if (cell->type == "$_OR_")
+ gt = GateType::Or;
+ else if (cell->type == "$_XOR_")
+ gt = GateType::Xor;
+ else
+ continue;
+
+ log("Working on cell %s...\n", cell->name.c_str());
+
+ // If looking for a single chain, follow linearly to the sink
+ pool<Cell*> sinks;
+ if(!allow_off_chain)
+ {
+ Cell* head_cell = cell;
+ Cell* x = cell;
+ while (true)
+ {
+ if(!IsRightType(x, gt))
+ break;
+
+ head_cell = x;
+
+ auto y = sigmap(x->getPort("\\Y"));
+ log_assert(y.size() == 1);
+
+ // Should only continue if there is one fanout back into a cell (not to a port)
+ if (sig_to_sink[y[0]].size() != 1)
+ break;
+
+ x = *sig_to_sink[y[0]].begin();
+ }
+
+ sinks.insert(head_cell);
+ }
+
+ //If off-chain loads are allowed, we have to do a wider traversal to see what the longest chain is
+ else
+ {
+ //BFS, following all chains until they hit a cell of a different type
+ //Pick the longest one
+ auto y = sigmap(cell->getPort("\\Y"));
+ pool<Cell*> current_loads = sig_to_sink[y];
+ pool<Cell*> next_loads;
+
+ while(!current_loads.empty())
+ {
+ //Find each sink and see what they are
+ for(auto x : current_loads)
+ {
+ //Not one of our gates? Don't follow any further
+ //(but add the originating cell to the list of sinks)
+ if(!IsRightType(x, gt))
+ {
+ sinks.insert(cell);
+ continue;
+ }
+
+ //If this signal drives a port, add it to the sinks
+ //(even though it may not be the end of a chain)
+ if(port_sigs.count(x) && !consumed_cells.count(x))
+ sinks.insert(x);
+
+ //It's a match, search everything out from it
+ auto& next = sig_to_sink[x];
+ for(auto z : next)
+ next_loads.insert(z);
+ }
+
+ //If we couldn't find any downstream loads, stop.
+ //Create a reduction for each of the max-length chains we found
+ if(next_loads.empty())
+ {
+ for(auto s : current_loads)
+ {
+ //Not one of our gates? Don't follow any further
+ if(!IsRightType(s, gt))
+ continue;
+
+ sinks.insert(s);
+ }
+ break;
+ }
+
+ //Otherwise, continue down the chain
+ current_loads = next_loads;
+ next_loads.clear();
+ }
+ }
+
+ //We have our list, go act on it
+ for(auto head_cell : sinks)
+ {
+ log(" Head cell is %s\n", head_cell->name.c_str());
+
+ //Avoid duplication if we already were covered
+ if(consumed_cells.count(head_cell))
+ continue;
+
+ pool<Cell*> cur_supercell;
+ std::deque<Cell*> bfs_queue = {head_cell};
+ while (bfs_queue.size())
+ {
+ Cell* x = bfs_queue.front();
+ bfs_queue.pop_front();
+
+ cur_supercell.insert(x);
+
+ auto a = sigmap(x->getPort("\\A"));
+ log_assert(a.size() == 1);
+
+ // Must have only one sink unless we're going off chain
+ // XXX: Check that it is indeed this node?
+ if( allow_off_chain || (sig_to_sink[a[0]].size() + port_sigs.count(a[0]) == 1) )
+ {
+ Cell* cell_a = sig_to_driver[a[0]];
+ if(cell_a && IsRightType(cell_a, gt))
+ {
+ // The cell here is the correct type, and it's definitely driving
+ // this current cell.
+ bfs_queue.push_back(cell_a);
+ }
+ }
+
+ auto b = sigmap(x->getPort("\\B"));
+ log_assert(b.size() == 1);
+
+ // Must have only one sink
+ // XXX: Check that it is indeed this node?
+ if( allow_off_chain || (sig_to_sink[b[0]].size() + port_sigs.count(b[0]) == 1) )
+ {
+ Cell* cell_b = sig_to_driver[b[0]];
+ if(cell_b && IsRightType(cell_b, gt))
+ {
+ // The cell here is the correct type, and it's definitely driving only
+ // this current cell.
+ bfs_queue.push_back(cell_b);
+ }
+ }
+ }
+
+ log(" Cells:\n");
+ for (auto x : cur_supercell)
+ log(" %s\n", x->name.c_str());
+
+ if (cur_supercell.size() > 1)
+ {
+ // Worth it to create reduce cell
+ log(" Creating $reduce_* cell!\n");
+
+ pool<SigBit> input_pool;
+ pool<SigBit> input_pool_intermed;
+ for (auto x : cur_supercell)
+ {
+ input_pool.insert(sigmap(x->getPort("\\A"))[0]);
+ input_pool.insert(sigmap(x->getPort("\\B"))[0]);
+ input_pool_intermed.insert(sigmap(x->getPort("\\Y"))[0]);
+ }
+ SigSpec input;
+ for (auto b : input_pool)
+ if (input_pool_intermed.count(b) == 0)
+ input.append_bit(b);
+
+ SigBit output = sigmap(head_cell->getPort("\\Y")[0]);
+
+ auto new_reduce_cell = module->addCell(NEW_ID,
+ gt == GateType::And ? "$reduce_and" :
+ gt == GateType::Or ? "$reduce_or" :
+ gt == GateType::Xor ? "$reduce_xor" : "");
+ new_reduce_cell->setParam("\\A_SIGNED", 0);
+ new_reduce_cell->setParam("\\A_WIDTH", input.size());
+ new_reduce_cell->setParam("\\Y_WIDTH", 1);
+ new_reduce_cell->setPort("\\A", input);
+ new_reduce_cell->setPort("\\Y", output);
+
+ if(allow_off_chain)
+ consumed_cells.insert(head_cell);
+ else
+ {
+ for (auto x : cur_supercell)
+ consumed_cells.insert(x);
+ }
+ }
+ }
+ }
+
+ // Remove all of the head cells, since we supplant them.
+ // Do not remove the upstream cells since some might still be in use ("clean" will get rid of unused ones)
+ for (auto cell : consumed_cells)
+ module->remove(cell);
+ }
+
+ log_pop();
+ }
+} ExtractReducePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc
index 82cecac2..9ec651ae 100644
--- a/passes/techmap/hilomap.cc
+++ b/passes/techmap/hilomap.cc
@@ -55,7 +55,7 @@ void hilomap_worker(RTLIL::SigSpec &sig)
struct HilomapPass : public Pass {
HilomapPass() : Pass("hilomap", "technology mapping of constant hi- and/or lo-drivers") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" hilomap [options] [selection]\n");
@@ -74,7 +74,7 @@ struct HilomapPass : public Pass {
log(" each constant bit.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing HILOMAP pass (mapping to constant drivers).\n");
diff --git a/passes/techmap/insbuf.cc b/passes/techmap/insbuf.cc
index aa81468d..2173049b 100644
--- a/passes/techmap/insbuf.cc
+++ b/passes/techmap/insbuf.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct InsbufPass : public Pass {
InsbufPass() : Pass("insbuf", "insert buffer cells for connected wires") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" insbuf [options] [selection]\n");
@@ -37,7 +37,7 @@ struct InsbufPass : public Pass {
log(" call to \"clean\" will remove all $_BUF_ in the design.)\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing INSBUF pass (insert buffer cells for connected wires).\n");
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index 4acbf7c0..efcc082d 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -34,7 +34,7 @@ void split_portname_pair(std::string &port1, std::string &port2)
struct IopadmapPass : public Pass {
IopadmapPass() : Pass("iopadmap", "technology mapping of i/o pads (or buffers)") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" iopadmap [options] [selection]\n");
@@ -78,7 +78,7 @@ struct IopadmapPass : public Pass {
log("Tristate PADS (-toutpad, -tinoutpad) always operate in -bits mode.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n");
@@ -146,11 +146,37 @@ struct IopadmapPass : public Pass {
for (auto module : design->selected_modules())
{
dict<IdString, pool<int>> skip_wires;
+ pool<SigBit> skip_wire_bits;
+ SigMap sigmap(module);
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type == RTLIL::escape_id(inpad_celltype) && cell->hasPort(RTLIL::escape_id(inpad_portname2)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inpad_portname2))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(outpad_celltype) && cell->hasPort(RTLIL::escape_id(outpad_portname2)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(outpad_portname2))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(inoutpad_celltype) && cell->hasPort(RTLIL::escape_id(inoutpad_portname2)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inoutpad_portname2))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(toutpad_celltype) && cell->hasPort(RTLIL::escape_id(toutpad_portname3)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(toutpad_portname3))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(tinoutpad_celltype) && cell->hasPort(RTLIL::escape_id(tinoutpad_portname4)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(tinoutpad_portname4))))
+ skip_wire_bits.insert(bit);
+ }
if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
{
- SigMap sigmap(module);
dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits;
+ pool<pair<IdString, IdString>> norewrites;
+ SigMap rewrites;
for (auto cell : module->cells())
if (cell->type == "$_TBUF_") {
@@ -177,6 +203,9 @@ struct IopadmapPass : public Pass {
if (tbuf_bits.count(mapped_wire_bit) == 0)
continue;
+ if (skip_wire_bits.count(mapped_wire_bit))
+ continue;
+
auto &tbuf_cache = tbuf_bits.at(mapped_wire_bit);
Cell *tbuf_cell = module->cell(tbuf_cache.first);
@@ -219,6 +248,9 @@ struct IopadmapPass : public Pass {
module->remove(tbuf_cell);
skip_wires[wire->name].insert(i);
+
+ norewrites.insert(make_pair(cell->name, RTLIL::escape_id(tinoutpad_portname4)));
+ rewrites.add(sigmap(wire_bit), owire);
continue;
}
@@ -256,6 +288,22 @@ struct IopadmapPass : public Pass {
}
}
}
+
+ if (GetSize(norewrites))
+ {
+ for (auto cell : module->cells())
+ for (auto port : cell->connections())
+ {
+ if (norewrites.count(make_pair(cell->name, port.first)))
+ continue;
+
+ SigSpec orig_sig = sigmap(port.second);
+ SigSpec new_sig = rewrites(orig_sig);
+
+ if (orig_sig != new_sig)
+ cell->setPort(port.first, new_sig);
+ }
+ }
}
for (auto wire : module->selected_wires())
@@ -272,6 +320,13 @@ struct IopadmapPass : public Pass {
skip_bit_indices = skip_wires.at(wire->name);
}
+ for (int i = 0; i < GetSize(wire); i++)
+ if (skip_wire_bits.count(sigmap(SigBit(wire, i))))
+ skip_bit_indices.insert(i);
+
+ if (GetSize(wire) == GetSize(skip_bit_indices))
+ continue;
+
if (wire->port_input && !wire->port_output) {
if (inpad_celltype.empty()) {
log("Don't map input port %s.%s: Missing option -inpad.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index d5254c02..d3b1ff02 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -100,8 +100,15 @@ int LibertyParser::lexer(std::string &str)
break;
}
f.unget();
- // fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str());
- return 'v';
+ if (str == "+" || str == "-") {
+ /* Single operator is not an identifier */
+ // fprintf(stderr, "LEX: char >>%s<<\n", str.c_str());
+ return str[0];
+ }
+ else {
+ // fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str());
+ return 'v';
+ }
}
if (c == '"') {
@@ -191,6 +198,19 @@ LibertyAst *LibertyParser::parse()
tok = lexer(ast->value);
if (tok != 'v')
error();
+ tok = lexer(str);
+ while (tok == '+' || tok == '-' || tok == '*' || tok == '/') {
+ ast->value += tok;
+ tok = lexer(str);
+ if (tok != 'v')
+ error();
+ ast->value += str;
+ tok = lexer(str);
+ }
+ if (tok == ';')
+ break;
+ else
+ error();
continue;
}
diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc
index 2bb0bd8b..d32bbff1 100644
--- a/passes/techmap/lut2mux.cc
+++ b/passes/techmap/lut2mux.cc
@@ -56,7 +56,7 @@ int lut2mux(Cell *cell)
struct Lut2muxPass : public Pass {
Lut2muxPass() : Pass("lut2mux", "convert $lut to $_MUX_") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -65,7 +65,7 @@ struct Lut2muxPass : public Pass {
log("This pass converts $lut cells to $_MUX_ gates.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing LUT2MUX pass (convert $lut to $_MUX_).\n");
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
index 32569d07..3e8e59e6 100644
--- a/passes/techmap/maccmap.cc
+++ b/passes/techmap/maccmap.cc
@@ -365,7 +365,7 @@ PRIVATE_NAMESPACE_BEGIN
struct MaccmapPass : public Pass {
MaccmapPass() : Pass("maccmap", "mapping macc cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -375,7 +375,7 @@ struct MaccmapPass : public Pass {
log("is used then the $macc cell is mapped to $add, $sub, etc. cells instead.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool unmap_mode = false;
diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc
index 1dc64958..12da9ed0 100644
--- a/passes/techmap/muxcover.cc
+++ b/passes/techmap/muxcover.cc
@@ -561,7 +561,7 @@ struct MuxcoverWorker
struct MuxcoverPass : public Pass {
MuxcoverPass() : Pass("muxcover", "cover trees of MUX cells with wider MUXes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -579,7 +579,7 @@ struct MuxcoverPass : public Pass {
log(" less efficient than the original circuit.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing MUXCOVER pass (mapping to wider MUXes).\n");
diff --git a/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc
index 6fcdf82b..cc765d89 100644
--- a/passes/techmap/nlutmap.cc
+++ b/passes/techmap/nlutmap.cc
@@ -92,7 +92,7 @@ struct NlutmapWorker
for (auto bit : sigmap(conn.second))
bit_lut_count[bit]++;
}
-
+
for (auto &cand : candidate_ratings)
{
for (auto &conn : cand.first->connections())
@@ -129,7 +129,7 @@ struct NlutmapWorker
struct NlutmapPass : public Pass {
NlutmapPass() : Pass("nlutmap", "map to LUTs of different sizes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -149,7 +149,7 @@ struct NlutmapPass : public Pass {
log("to generic logic gates ($_AND_, etc.).\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
NlutmapConfig config;
diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc
index c626dbcc..b7a22dc3 100644
--- a/passes/techmap/pmuxtree.cc
+++ b/passes/techmap/pmuxtree.cc
@@ -67,7 +67,7 @@ static SigSpec recursive_mux_generator(Module *module, const SigSpec &sig_data,
struct PmuxtreePass : public Pass {
PmuxtreePass() : Pass("pmuxtree", "transform $pmux cells to trees of $mux cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -76,7 +76,7 @@ struct PmuxtreePass : public Pass {
log("This pass transforms $pmux cells to a trees of $mux cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PMUXTREE pass.\n");
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index 6936b499..f20863ba 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -391,7 +391,7 @@ struct ShregmapWorker
struct ShregmapPass : public Pass {
ShregmapPass() : Pass("shregmap", "map shift registers") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -449,7 +449,7 @@ struct ShregmapPass : public Pass {
log(" map to greenpak4 shift registers.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
ShregmapOptions opts;
string clkpol, enpol;
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index c6b932bd..660b6060 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -575,7 +575,7 @@ PRIVATE_NAMESPACE_BEGIN
struct SimplemapPass : public Pass {
SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -590,7 +590,7 @@ struct SimplemapPass : public Pass {
log(" $sr, $ff, $dff, $dffsr, $adff, $dlatch\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
extra_args(args, 1, design);
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 6784f48c..d0e5e223 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -171,18 +171,15 @@ struct TechmapWorker
}
std::string orig_cell_name;
- pool<string> extra_src_attrs;
+ pool<string> extra_src_attrs = cell->get_strpool_attribute("\\src");
- if (!flatten_mode)
- {
+ if (!flatten_mode) {
for (auto &it : tpl->cells_)
if (it.first == "\\_TECHMAP_REPLACE_") {
orig_cell_name = cell->name.str();
module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str());
break;
}
-
- extra_src_attrs = cell->get_strpool_attribute("\\src");
}
dict<IdString, IdString> memory_renames;
@@ -247,6 +244,9 @@ struct TechmapWorker
continue;
}
+ if (GetSize(it.second) == 0)
+ continue;
+
RTLIL::Wire *w = tpl->wires_.at(portname);
RTLIL::SigSig c, extra_connect;
@@ -305,10 +305,15 @@ struct TechmapWorker
// approach that yields nicer outputs:
// replace internal wires that are connected to external wires
- if (w->port_output)
+ if (w->port_output && !w->port_input) {
port_signal_map.add(c.second, c.first);
- else
+ } else
+ if (!w->port_output && w->port_input) {
port_signal_map.add(c.first, c.second);
+ } else {
+ module->connect(c);
+ extra_connect = SigSig();
+ }
for (auto &attr : w->attributes) {
if (attr.first == "\\src")
@@ -322,8 +327,9 @@ struct TechmapWorker
for (auto &it : tpl->cells_)
{
std::string c_name = it.second->name.str();
+ bool techmap_replace_cell = (!flatten_mode) && (c_name == "\\_TECHMAP_REPLACE_");
- if (!flatten_mode && c_name == "\\_TECHMAP_REPLACE_")
+ if (techmap_replace_cell)
c_name = orig_cell_name;
else
apply_prefix(cell->name.str(), c_name);
@@ -353,6 +359,11 @@ struct TechmapWorker
if (c->attributes.count("\\src"))
c->add_strpool_attribute("\\src", extra_src_attrs);
+
+ if (techmap_replace_cell)
+ for (auto attr : cell->attributes)
+ if (!c->attributes.count(attr.first))
+ c->attributes[attr.first] = attr.second;
}
for (auto &it : tpl->connections()) {
@@ -451,6 +462,7 @@ struct TechmapWorker
bool mapped_cell = false;
std::string cell_type = cell->type.str();
+
if (in_recursion && cell_type.substr(0, 2) == "\\$")
cell_type = cell_type.substr(1);
@@ -498,6 +510,8 @@ struct TechmapWorker
extmapper_module = extmapper_design->addModule(m_name);
RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type, cell);
+ extmapper_cell->set_src_attribute(cell->get_src_attribute());
+
int port_counter = 1;
for (auto &c : extmapper_cell->connections_) {
RTLIL::Wire *w = extmapper_module->addWire(c.first, GetSize(c.second));
@@ -877,7 +891,7 @@ struct TechmapWorker
struct TechmapPass : public Pass {
TechmapPass() : Pass("techmap", "generic technology mapper") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -919,7 +933,7 @@ struct TechmapPass : public Pass {
log(" -D <define>, -I <incdir>\n");
log(" this options are passed as-is to the Verilog frontend for loading the\n");
log(" map file. Note that the Verilog frontend is also called with the\n");
- log(" '-ignore_redef' option set.\n");
+ log(" '-nooverwrite' option set.\n");
log("\n");
log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n");
log("match cells with a type that match the text value of this attribute. Otherwise\n");
@@ -1000,7 +1014,7 @@ struct TechmapPass : public Pass {
log("constant value.\n");
log("\n");
log("A cell with the name _TECHMAP_REPLACE_ in the map file will inherit the name\n");
- log("of the cell that is being replaced.\n");
+ log("and attributes of the cell that is being replaced.\n");
log("\n");
log("See 'help extract' for a pass that does the opposite thing.\n");
log("\n");
@@ -1008,7 +1022,7 @@ struct TechmapPass : public Pass {
log("essentially techmap but using the design itself as map library).\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing TECHMAP pass (map to technology primitives).\n");
log_push();
@@ -1017,7 +1031,7 @@ struct TechmapPass : public Pass {
simplemap_get_mappers(worker.simplemap_mappers);
std::vector<std::string> map_files;
- std::string verilog_frontend = "verilog -ignore_redef";
+ std::string verilog_frontend = "verilog -nooverwrite";
int max_iter = -1;
size_t argidx;
@@ -1076,6 +1090,7 @@ struct TechmapPass : public Pass {
std::ifstream f;
rewrite_filename(fn);
f.open(fn.c_str());
+ yosys_input_files.insert(fn);
if (f.fail())
log_cmd_error("Can't open map file `%s'\n", fn.c_str());
Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
@@ -1126,7 +1141,7 @@ struct TechmapPass : public Pass {
struct FlattenPass : public Pass {
FlattenPass() : Pass("flatten", "flatten design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1140,7 +1155,7 @@ struct FlattenPass : public Pass {
log("flattened by this command.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FLATTEN pass (flatten design).\n");
log_push();
diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc
index 03629082..587cb903 100644
--- a/passes/techmap/tribuf.cc
+++ b/passes/techmap/tribuf.cc
@@ -139,7 +139,7 @@ struct TribufWorker {
struct TribufPass : public Pass {
TribufPass() : Pass("tribuf", "infer tri-state buffers") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -156,7 +156,7 @@ struct TribufPass : public Pass {
log(" to non-tristate logic. this option implies -merge.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
TribufConfig config;
diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc
index a577e123..b46147fb 100644
--- a/passes/techmap/zinit.cc
+++ b/passes/techmap/zinit.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ZinitPass : public Pass {
ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -37,7 +37,7 @@ struct ZinitPass : public Pass {
log(" also add zero initialization to uninitialized FFs\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool all_mode = false;
diff --git a/passes/tests/test_abcloop.cc b/passes/tests/test_abcloop.cc
index 09cb4195..5d5466af 100644
--- a/passes/tests/test_abcloop.cc
+++ b/passes/tests/test_abcloop.cc
@@ -244,7 +244,7 @@ static void test_abcloop()
struct TestAbcloopPass : public Pass {
TestAbcloopPass() : Pass("test_abcloop", "automatically test handling of loops in abc command") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -259,7 +259,7 @@ struct TestAbcloopPass : public Pass {
log(" use this value as rng seed value (default = unix time).\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
{
int num_iter = 100;
xorshift32_state = 0;
diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc
index cb31056f..bfb1d664 100644
--- a/passes/tests/test_autotb.cc
+++ b/passes/tests/test_autotb.cc
@@ -324,7 +324,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s
struct TestAutotbBackend : public Backend {
TestAutotbBackend() : Backend("=test_autotb", "generate simple test benches") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -349,7 +349,7 @@ struct TestAutotbBackend : public Backend {
log(" number of iterations the test bench should run (default = 1000)\n");
log("\n");
}
- virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
int num_iter = 1000;
int seed = 0;
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
index 049c2053..e360b5ed 100644
--- a/passes/tests/test_cell.cc
+++ b/passes/tests/test_cell.cc
@@ -652,7 +652,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
struct TestCellPass : public Pass {
TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -712,7 +712,7 @@ struct TestCellPass : public Pass {
log(" create a Verilog test bench to test simlib and write_verilog\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
{
int num_iter = 100;
std::string techmap_cmd = "techmap -assert";
@@ -852,8 +852,6 @@ struct TestCellPass : public Pass {
// cell_types["$slice"] = "A";
// cell_types["$concat"] = "A";
- // cell_types["$assert"] = "A";
- // cell_types["$assume"] = "A";
cell_types["$lut"] = "*";
cell_types["$sop"] = "*";