Add xilinx_dsp for register packing
authorEddie Hung <eddie@fpgeh.com>
Mon, 15 Jul 2019 21:46:31 +0000 (14:46 -0700)
committerEddie Hung <eddie@fpgeh.com>
Mon, 15 Jul 2019 21:46:31 +0000 (14:46 -0700)
passes/pmgen/.gitignore
passes/pmgen/xilinx_dsp.cc [new file with mode: 0644]
passes/pmgen/xilinx_dsp.pmg [new file with mode: 0644]

index 0ad36ea2c979b35816f2d871b54bc1bb4be8bb5f..10e245e006b62c88b00cb6bfd911422d38ee2f21 100644 (file)
@@ -1,2 +1 @@
-/ice40_dsp_pm.h
-/peepopt_pm.h
+/%_pm.h
diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc
new file mode 100644 (file)
index 0000000..b98703d
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  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
+
+#include "passes/pmgen/xilinx_dsp_pm.h"
+
+void create_xilinx_dsp(xilinx_dsp_pm &pm)
+{
+       auto &st = pm.st_xilinx_dsp;
+
+#if 0
+       log("\n");
+       log("ffA:   %s\n", log_id(st.ffA, "--"));
+       log("ffB:   %s\n", log_id(st.ffB, "--"));
+       log("mul:   %s\n", log_id(st.mul, "--"));
+       log("ffY:   %s\n", log_id(st.ffY, "--"));
+#endif
+
+       log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.mul));
+
+       Cell *cell = st.mul;
+       log_assert(cell);
+
+       // Input Interface
+
+       cell->setPort("\\A", st.sigA);
+       cell->setPort("\\B", st.sigB);
+
+       cell->setParam("\\AREG", st.ffA ? State::S1 : State::S0);
+       cell->setParam("\\BREG", st.ffB ? State::S1 : State::S0);
+
+       if (st.clock != SigBit())
+       {
+               cell->setPort("\\CLK", st.clock);
+
+               if (st.ffA) {
+                       cell->setParam("\\AREG", State::S1);
+                       cell->setPort("\\CEA2", State::S1);
+               }
+               if (st.ffB) {
+                       cell->setParam("\\BREG", State::S1);
+                       cell->setPort("\\CEA2", State::S1);
+               }
+               if (st.ffY) {
+                       cell->setPort("\\PREG", State::S1);
+                       cell->setPort("\\CEP", State::S1);
+               }
+
+               log("  clock: %s (%s)", log_signal(st.clock), "posedge");
+
+               if (st.ffA)
+                       log(" ffA:%s", log_id(st.ffA));
+
+               if (st.ffB)
+                       log(" ffB:%s", log_id(st.ffB));
+
+               if (st.ffY)
+                       log(" ffY:%s", log_id(st.ffY));
+
+               log("\n");
+       }
+
+       // Output Interface
+
+       pm.autoremove(st.ffY);
+}
+
+struct Ice40DspPass : public Pass {
+       Ice40DspPass() : Pass("xilinx_dsp", "Xilinx: pack DSP registers") { }
+       void help() YS_OVERRIDE
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    xilinx_dsp [options] [selection]\n");
+               log("\n");
+               log("Pack registers into Xilinx DSPs\n");
+               log("\n");
+       }
+       void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+       {
+               log_header(design, "Executing ICE40_DSP pass (map multipliers).\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);
+
+               for (auto module : design->selected_modules())
+                       xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(create_xilinx_dsp);
+       }
+} Ice40DspPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg
new file mode 100644 (file)
index 0000000..6bb4e7b
--- /dev/null
@@ -0,0 +1,71 @@
+pattern xilinx_dsp
+
+state <SigBit> clock
+state <SigSpec> sigA sigB sigY sigS
+state <Cell*> addAB muxAB
+
+match mul
+       select mul->type.in($__MUL25X18)
+endmatch
+
+match ffA
+       select ffA->type.in($dff) /* TODO: $dffe */
+       // select nusers(port(ffA, \Q)) == 2
+       index <SigSpec> port(ffA, \Q) === port(mul, \A)
+       // DSP48E1 does not support clock inversion
+       index <SigBit> port(ffA, \CLK_POLARITY) === State::S1
+       optional
+endmatch
+
+code sigA clock
+       sigA = port(mul, \A);
+
+       if (ffA) {
+               sigA = port(ffA, \D);
+               clock = port(ffA, \CLK).as_bit();
+       }
+endcode
+
+match ffB
+       select ffB->type.in($dff)
+       // select nusers(port(ffB, \Q)) == 2
+       index <SigSpec> port(ffB, \Q) === port(mul, \B)
+       index <SigBit> port(ffB, \CLK_POLARITY) === State::S1
+       optional
+endmatch
+
+code sigB clock 
+       sigB = port(mul, \B);
+
+       if (ffB) {
+               sigB = port(ffB, \D);
+               SigBit c = port(ffB, \CLK).as_bit();
+
+               if (clock != SigBit() && c != clock)
+                       reject;
+
+               clock = c;
+       }
+endcode
+
+match ffY
+       select ffY->type.in($dff)
+       select nusers(port(ffY, \D)) == 2
+       index <SigSpec> port(ffY, \D) === port(mul, \Y)
+       index <SigBit> port(ffY, \CLK_POLARITY) === State::S1
+       optional
+endmatch
+
+code sigY clock
+       sigY = port(mul, \Y);
+
+       if (ffY) {
+               sigY = port(ffY, \Q);
+               SigBit c = port(ffY, \CLK).as_bit();
+
+               if (clock != SigBit() && c != clock)
+                       reject;
+
+               clock = c;
+       }
+endcode