Added connwrappers command
authorClifford Wolf <clifford@clifford.at>
Thu, 20 Feb 2014 19:44:11 +0000 (20:44 +0100)
committerClifford Wolf <clifford@clifford.at>
Thu, 20 Feb 2014 19:44:11 +0000 (20:44 +0100)
passes/cmds/Makefile.inc
passes/cmds/connwrappers.cc [new file with mode: 0644]

index f01a1c4b51e8ca226ddfd324b80b6bf0335be5cd..77cac2b45fa324828a6ab5fbf4d3e35d8f2472c8 100644 (file)
@@ -15,4 +15,5 @@ OBJS += passes/cmds/copy.o
 OBJS += passes/cmds/splice.o
 OBJS += passes/cmds/scc.o
 OBJS += passes/cmds/log.o
+OBJS += passes/cmds/connwrappers.o
 
diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc
new file mode 100644 (file)
index 0000000..dd8b4fe
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ *  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/rtlil.h"
+#include "kernel/log.h"
+
+struct ConnwrappersWorker
+{
+       struct portdecl_t {
+               // key: celltype, portname;
+               std::string widthparam, signparam;
+               bool is_signed;
+       };
+
+       std::set<std::string> decl_celltypes;
+       std::map<std::pair<std::string, std::string>, portdecl_t> decls;
+
+       void add_port(std::string celltype, std::string portname, std::string widthparam, std::string signparam)
+       {
+               std::pair<std::string, std::string> key(RTLIL::escape_id(celltype), RTLIL::escape_id(portname));
+               decl_celltypes.insert(key.first);
+
+               if (decls.count(key))
+                       log_cmd_error("Duplicate port decl: %s %s\n", celltype.c_str(), portname.c_str());
+
+               portdecl_t decl;
+               decl.widthparam = RTLIL::escape_id(widthparam);
+               decl.signparam = RTLIL::escape_id(signparam);
+               decl.is_signed = false;
+               decls[key] = decl;
+       }
+
+       void add_port(std::string celltype, std::string portname, std::string widthparam, bool is_signed)
+       {
+               std::pair<std::string, std::string> key(RTLIL::escape_id(celltype), RTLIL::escape_id(portname));
+               decl_celltypes.insert(key.first);
+
+               if (decls.count(key))
+                       log_cmd_error("Duplicate port decl: %s %s\n", celltype.c_str(), portname.c_str());
+
+               portdecl_t decl;
+               decl.widthparam = RTLIL::escape_id(widthparam);
+               decl.is_signed = is_signed;
+               decls[key] = decl;
+       }
+
+       void work(RTLIL::Design *design, RTLIL::Module *module)
+       {
+               std::map<RTLIL::SigBit, std::pair<bool, RTLIL::SigSpec>> extend_map;
+               SigMap sigmap(module);
+
+               for (auto &it : module->cells)
+               {
+                       RTLIL::Cell *cell = it.second;
+
+                       if (!decl_celltypes.count(cell->type))
+                               continue;
+
+                       for (auto &conn : cell->connections)
+                       {
+                               std::pair<std::string, std::string> key(cell->type, conn.first);
+
+                               if (!decls.count(key))
+                                       continue;
+
+                               portdecl_t &decl = decls.at(key);
+
+                               if (!cell->parameters.count(decl.widthparam))
+                                       continue;
+
+                               if (!decl.signparam.empty() && !cell->parameters.count(decl.signparam))
+                                       continue;
+
+                               int inner_width = cell->parameters.at(decl.widthparam).as_int();
+                               int outer_width = conn.second.width;
+                               bool is_signed = decl.signparam.empty() ? decl.is_signed : cell->parameters.at(decl.signparam).as_bool();
+
+                               if (inner_width >= outer_width)
+                                       continue;
+
+                               RTLIL::SigSpec sig = sigmap(conn.second);
+                               extend_map[sig.extract(inner_width - 1, 1)] = std::pair<bool, RTLIL::SigSpec>(is_signed,
+                                               sig.extract(inner_width, outer_width - inner_width));
+                       }
+               }
+
+               for (auto &it : module->cells)
+               {
+                       RTLIL::Cell *cell = it.second;
+
+                       if (!design->selected(module, cell))
+                               continue;
+
+                       for (auto &conn : cell->connections)
+                       {
+                               std::vector<RTLIL::SigBit> sigbits = sigmap(conn.second).to_sigbit_vector();
+                               RTLIL::SigSpec old_sig;
+
+                               for (size_t i = 0; i < sigbits.size(); i++)
+                               {
+                                       if (!extend_map.count(sigbits[i]))
+                                               continue;
+
+                                       bool is_signed = extend_map.at(sigbits[i]).first;
+                                       RTLIL::SigSpec extend_sig = extend_map.at(sigbits[i]).second;
+
+                                       int extend_width = 0;
+                                       RTLIL::SigBit extend_bit = is_signed ? sigbits[i] : RTLIL::SigBit(RTLIL::State::S0);
+                                       while (extend_width < extend_sig.width && i + extend_width + 1 < sigbits.size() &&
+                                                       sigbits[i + extend_width + 1] == extend_bit) extend_width++;
+
+                                       if (extend_width == 0)
+                                               continue;
+
+                                       if (old_sig.width == 0)
+                                               old_sig = conn.second;
+
+                                       conn.second.replace(i+1, extend_sig.extract(0, extend_width));
+                                       i += extend_width;
+                               }
+
+                               if (old_sig.width)
+                                       log("Connected extended bits of %s.%s:%s: %s -> %s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name),
+                                                       RTLIL::id2cstr(conn.first), log_signal(old_sig), log_signal(conn.second));
+                       }
+               }
+       }
+};
+
+struct ConnwrappersPass : public Pass {
+       ConnwrappersPass() : Pass("connwrappers", "replace undef values with defined constants") { }
+       virtual void help()
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    connwrappers [options] [selection]\n");
+               log("\n");
+               log("Wrappers are used in coarse-grain synthesis to wrap cells with smaller ports\n");
+               log("in wrapper cells with a (larger) constant port size. I.e. the upper bits\n");
+               log("of the wrapper outut are signed/unsigned bit extended. This command uses this\n");
+               log("knowlege to rewire the inputs of the driven cells to match the output of\n");
+               log("the driving cell.\n");
+               log("\n");
+               log("    -signed <cell_type> <port_name> <width_param>\n");
+               log("    -unsigned <cell_type> <port_name> <width_param>\n");
+               log("        consider the specified signed/unsigned wrapper output\n");
+               log("\n");
+               log("    -port <cell_type> <port_name> <width_param> <sign_param>\n");
+               log("        use the specified parameter to decide if signed or unsigned\n");
+               log("\n");
+               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)
+       {
+               ConnwrappersWorker worker;
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++)
+               {
+                       if (args[argidx] == "-signed" && argidx+3 < args.size()) {
+                               worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], true);
+                               argidx += 3;
+                               continue;
+                       }
+                       if (args[argidx] == "-unsigned" && argidx+3 < args.size()) {
+                               worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], false);
+                               argidx += 3;
+                               continue;
+                       }
+                       if (args[argidx] == "-port" && argidx+4 < args.size()) {
+                               worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], args[argidx+4]);
+                               argidx += 4;
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               log_header("Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n");
+
+               for (auto &mod_it : design->modules)
+                       if (design->selected(mod_it.second))
+                               worker.work(design, mod_it.second);
+       }
+} ConnwrappersPass;