Add "ltp" command
authorClifford Wolf <clifford@clifford.at>
Tue, 31 Oct 2017 11:40:25 +0000 (12:40 +0100)
committerClifford Wolf <clifford@clifford.at>
Tue, 31 Oct 2017 11:40:25 +0000 (12:40 +0100)
passes/cmds/Makefile.inc
passes/cmds/ltp.cc [new file with mode: 0644]

index 9e3934e16e7206d5f5e2244b76f33e83ded74e63..44a83b2b9525144e4f5d9ddeaedc1c953b590b6a 100644 (file)
@@ -28,4 +28,5 @@ 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/ltp.cc b/passes/cmds/ltp.cc
new file mode 100644 (file)
index 0000000..42dc794
--- /dev/null
@@ -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") { }
+       virtual void help()
+       {
+               //   |---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");
+       }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               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