summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--passes/techmap/Makefile.inc1
-rw-r--r--passes/techmap/pmuxtree.cc112
-rw-r--r--tests/various/muxcover.ys51
3 files changed, 164 insertions, 0 deletions
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 4f72ea6b..a3e429ce 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -12,6 +12,7 @@ OBJS += passes/techmap/extract.o
OBJS += passes/techmap/alumacc.o
OBJS += passes/techmap/dff2dffe.o
OBJS += passes/techmap/dffinit.o
+OBJS += passes/techmap/pmuxtree.o
OBJS += passes/techmap/muxcover.o
endif
diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc
new file mode 100644
index 00000000..87762c0b
--- /dev/null
+++ b/passes/techmap/pmuxtree.cc
@@ -0,0 +1,112 @@
+/*
+ * 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
+
+static SigSpec or_generator(Module *module, const SigSpec &sig)
+{
+ switch (GetSize(sig))
+ {
+ case 0:
+ return State::S0;
+ case 1:
+ return sig;
+ case 2:
+ return module->Or(NEW_ID, sig[0], sig[1]);
+ default:
+ return module->ReduceOr(NEW_ID, sig);
+ }
+}
+
+static SigSpec recursive_mux_generator(Module *module, const SigSpec &sig_data, const SigSpec &sig_sel, SigSpec &sig_or)
+{
+ if (GetSize(sig_sel) == 1) {
+ sig_or.append(sig_sel);
+ return sig_data;
+ }
+
+ int left_size = GetSize(sig_sel) / 2;
+ int right_size = GetSize(sig_sel) - left_size;
+ int stride = GetSize(sig_data) / GetSize(sig_sel);
+
+ SigSpec left_data = sig_data.extract(0, stride*left_size);
+ SigSpec right_data = sig_data.extract(stride*left_size, stride*right_size);
+
+ SigSpec left_sel = sig_sel.extract(0, left_size);
+ SigSpec right_sel = sig_sel.extract(left_size, right_size);
+
+ SigSpec left_or, left_result, right_result;
+
+ left_result = recursive_mux_generator(module, left_data, left_sel, left_or);
+ right_result = recursive_mux_generator(module, right_data, right_sel, sig_or);
+ left_or = or_generator(module, left_or);
+ sig_or.append(left_or);
+
+ return module->Mux(NEW_ID, right_result, left_result, left_or);
+}
+
+struct PmuxtreePass : public Pass {
+ PmuxtreePass() : Pass("pmuxtree", "transform $pmux cells to trees of $mux cells") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" pmuxtree [options] [selection]\n");
+ log("\n");
+ 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)
+ {
+ log_header("Executing PMUXTREE pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type != "$pmux")
+ continue;
+
+ SigSpec sig_data = cell->getPort("\\B");
+ SigSpec sig_sel = cell->getPort("\\S");
+
+ if (!cell->getPort("\\A").is_fully_undef()) {
+ sig_data.append(cell->getPort("\\A"));
+ SigSpec sig_sel_or = module->ReduceOr(NEW_ID, sig_sel);
+ sig_sel.append(module->Not(NEW_ID, sig_sel_or));
+ }
+
+ SigSpec result, result_or;
+ result = recursive_mux_generator(module, sig_data, sig_sel, result_or);
+ module->connect(cell->getPort("\\Y"), result);
+ module->remove(cell);
+ }
+ }
+} PmuxtreePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/tests/various/muxcover.ys b/tests/various/muxcover.ys
new file mode 100644
index 00000000..7ac460f1
--- /dev/null
+++ b/tests/various/muxcover.ys
@@ -0,0 +1,51 @@
+
+read_verilog -formal <<EOT
+ module gate (input [2:0] A, B, C, D, X, output reg [2:0] Y);
+ always @*
+ (* parallel_case *)
+ casez (X)
+ 3'b??1: Y = A;
+ 3'b?1?: Y = B;
+ 3'b1??: Y = C;
+ 3'b000: Y = D;
+ endcase
+ endmodule
+EOT
+
+
+## Examle usage for "pmuxtree" and "muxcover"
+
+proc
+pmuxtree
+techmap
+muxcover -mux4
+
+splitnets -ports
+clean
+# show
+
+
+## Equivalence checking
+
+read_verilog -formal <<EOT
+ module gold (input [2:0] A, B, C, D, X, output reg [2:0] Y);
+ always @*
+ casez (X)
+ 3'b001: Y = A;
+ 3'b010: Y = B;
+ 3'b100: Y = C;
+ 3'b000: Y = D;
+ default: Y = 'bx;
+ endcase
+ endmodule
+EOT
+
+proc
+splitnets -ports
+techmap -map +/simcells.v t:$_MUX4_
+
+equiv_make gold gate equiv
+hierarchy -top equiv
+equiv_simple -undef
+equiv_status -assert
+