Add split_shiftx command
authorEddie Hung <eddie@fpgeh.com>
Fri, 26 Apr 2019 00:23:59 +0000 (17:23 -0700)
committerEddie Hung <eddie@fpgeh.com>
Fri, 26 Apr 2019 00:23:59 +0000 (17:23 -0700)
passes/pmgen/split_shiftx.cc [new file with mode: 0644]
passes/pmgen/split_shiftx.pmg [new file with mode: 0644]

diff --git a/passes/pmgen/split_shiftx.cc b/passes/pmgen/split_shiftx.cc
new file mode 100644 (file)
index 0000000..71fb4e9
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *  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 "passes/pmgen/split_shiftx_pm.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void create_split_shiftx(split_shiftx_pm &pm)
+{
+       if (pm.st.shiftxB.empty())
+               return;
+       log_assert(pm.st.shiftx);
+       SigSpec A = pm.st.shiftx->getPort("\\A");
+       SigSpec Y = pm.st.shiftx->getPort("\\Y");
+       const int A_WIDTH = pm.st.shiftx->getParam("\\A_WIDTH").as_int();
+       const int Y_WIDTH = pm.st.shiftx->getParam("\\Y_WIDTH").as_int();
+       log_assert(Y_WIDTH > 1);
+       std::vector<SigBit> bits;
+       bits.resize(A_WIDTH / Y_WIDTH);
+       for (int i = 0; i < Y_WIDTH; ++i) {
+               for (int j = 0; j < A_WIDTH/Y_WIDTH; ++j)
+                       bits[j] = A[j*Y_WIDTH + i];
+               pm.module->addShiftx(NEW_ID, bits, pm.st.shiftxB, Y[i]);
+       }
+       pm.st.shiftx->unsetPort("\\Y");
+
+       pm.autoremove(pm.st.shiftx);
+       pm.autoremove(pm.st.macc);
+}
+
+struct BitblastShiftxPass : public Pass {
+       BitblastShiftxPass() : Pass("split_shiftx", "Split up multi-bit $shiftx cells") { }
+       void help() YS_OVERRIDE
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    split_shiftx [selection]\n");
+               log("\n");
+               log("Split up $shiftx cells where Y_WIDTH > 1, with consideration for any $macc\n");
+               log("cells that may be driving their B inputs.\n");
+               log("\n");
+       }
+       void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+       {
+               log_header(design, "Executing SPLIT_SHIFTX pass.\n");
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++)
+               {
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               for (auto module : design->selected_modules())
+                       split_shiftx_pm(module, module->selected_cells()).run(create_split_shiftx);
+       }
+} BitblastShiftxPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/pmgen/split_shiftx.pmg b/passes/pmgen/split_shiftx.pmg
new file mode 100644 (file)
index 0000000..11b19bf
--- /dev/null
@@ -0,0 +1,56 @@
+state <SigSpec> shiftxB
+
+match shiftx
+       select shiftx->type == $shiftx
+       select param(shiftx, \Y_WIDTH).as_int() > 1
+endmatch
+
+code shiftxB
+       shiftxB = port(shiftx, \B);
+       const int b_width = param(shiftx, \B_WIDTH).as_int();
+       if (param(shiftx, \B_SIGNED) != 0 && shiftxB[b_width-1] == RTLIL::S0)
+               shiftxB = shiftxB.extract(0, b_width-1);
+endcode
+
+match macc
+       select macc->type == $macc
+       select param(macc, \B_WIDTH).as_int() == 0
+       index <SigSpec> port(macc, \Y) === shiftxB
+       optional
+endmatch
+
+code shiftxB
+       if (macc) {
+               Const config = param(macc, \CONFIG);
+               const int config_width = param(macc, \CONFIG_WIDTH).as_int();
+               const int num_bits = config.extract(0, 4).as_int();
+               const int num_ports = (config_width - 4) / (2 + 2*num_bits);
+               if (num_ports != 1) {
+                       shiftxB = nullptr;
+                       reject;
+               }
+               // IS_SIGNED?
+               if (config[4] == 1) {
+                       shiftxB = nullptr;
+                       reject;
+               }
+               // DO_SUBTRACT?
+               if (config[5] == 1) {
+                       shiftxB = nullptr;
+                       reject;
+               }
+               const int port_size_A = config.extract(6, num_bits).as_int();
+               const int port_size_B = config.extract(6 + num_bits, num_bits).as_int();
+               const SigSpec port_B = port(macc, \A).extract(port_size_A, port_size_B);
+               if (!port_B.is_fully_const()) {
+                       shiftxB = nullptr;
+                       reject;
+               }
+               const int multiply_factor = port_B.as_int();
+               if (multiply_factor != param(shiftx, \Y_WIDTH).as_int()) {
+                       shiftxB = nullptr;
+                       reject;
+               }
+               shiftxB = port(macc, \A).extract(0, port_size_A);
+       }
+endcode