Added techmap CONSTMAP feature
authorClifford Wolf <clifford@clifford.at>
Wed, 30 Jul 2014 20:04:30 +0000 (22:04 +0200)
committerClifford Wolf <clifford@clifford.at>
Wed, 30 Jul 2014 20:04:30 +0000 (22:04 +0200)
kernel/rtlil.h
passes/techmap/techmap.cc
techlibs/common/stdcells.v

index d6acb5bcc01f5a6403cf573cc69cf7b5df3394aa..7bd75bd1d64a8c162935d5096c6dfc2486b7f15b 100644 (file)
@@ -278,6 +278,9 @@ namespace RTLIL
                                result.push_back(it.second);
                        return result;
                }
+
+               std::set<T> to_set() const { return *this; }
+               std::vector<T> to_vector() const { return *this; }
        };
 };
 
index 0ae5220e062498c54d2cd07c7001e5771eb53cd2..75b9dee9b2d9f7337c9b52a296283ae1d4b97966 100644 (file)
  *
  */
 
-#include "kernel/compatibility.h"
-#include "kernel/register.h"
-#include "kernel/sigtools.h"
+#include "kernel/yosys.h"
 #include "kernel/toposort.h"
-#include "kernel/log.h"
+#include "kernel/sigtools.h"
+#include "libs/sha1/sha1.h"
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -66,6 +66,36 @@ struct TechmapWorker
 
        typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires;
 
+       std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose)
+       {
+               std::string constmap_info;
+               std::map<RTLIL::SigBit, std::pair<std::string, int>> connbits_map;
+
+               for (auto conn : cell->connections())
+                       for (int i = 0; i < SIZE(conn.second); i++) {
+                               RTLIL::SigBit bit = sigmap(conn.second[i]);
+                               if (bit.wire == nullptr) {
+                                       if (verbose)
+                                               log("  Constant input on bit %d of port %s: %s\n", i, log_id(conn.first), log_signal(bit));
+                                       constmap_info += stringf("|%s %d %d", log_id(conn.first), i, bit.data);
+                               } else if (connbits_map.count(bit)) {
+                                       if (verbose)
+                                               log("  Bit %d of port %s and bit %d of port %s are connected.\n", i, log_id(conn.first),
+                                                               connbits_map.at(bit).second, log_id(connbits_map.at(bit).first));
+                                       constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i,
+                                                       log_id(connbits_map.at(bit).first), connbits_map.at(bit).second);
+                               } else
+                                       connbits_map[bit] = std::pair<std::string, int>(conn.first, i);stringf("%s %d", log_id(conn.first), i, bit.data);
+                       }
+
+               unsigned char hash[20];
+               char hash_hex_string[41];
+               sha1::calc(constmap_info.c_str(), constmap_info.size(), hash);
+               sha1::toHexString(hash, hash_hex_string);
+
+               return stringf("$paramod$constmap$%s%s", hash_hex_string, tpl->name.c_str());
+       }
+
        TechmapWires techmap_find_special_wires(RTLIL::Module *module)
        {
                TechmapWires result;
@@ -374,14 +404,19 @@ struct TechmapWorker
                                } else {
                                        if (cell->parameters.size() != 0) {
                                                derived_name = tpl->derive(map, parameters);
-                                               tpl = map->modules_[derived_name];
+                                               tpl = map->module(derived_name);
                                                log_continue = true;
                                        }
                                        techmap_cache[key] = tpl;
                                }
 
-                               if (flatten_mode)
+                               if (flatten_mode) {
                                        techmap_do_cache[tpl] = true;
+                               } else {
+                                       RTLIL::Module *constmapped_tpl = map->module(constmap_tpl_name(sigmap, tpl, cell, false));
+                                       if (constmapped_tpl != nullptr)
+                                               tpl = constmapped_tpl;
+                               }
 
                                if (techmap_do_cache.count(tpl) == 0)
                                {
@@ -426,14 +461,80 @@ struct TechmapWorker
                                                        const char *q = strrchr(p+1, '.');
                                                        q = q ? q : p+1;
 
+                                                       std::string cmd_string = data.value.as_const().decode_string();
+
+                                                       if (cmd_string.rfind("CONSTMAP; ", 0) == 0)
+                                                       {
+                                                               cmd_string = cmd_string.substr(strlen("CONSTMAP; "));
+
+                                                               log("Analyzing pattern of constant bits for this cell:\n");
+                                                               std::string new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true);
+                                                               log("Creating constmapped module `%s'.\n", log_id(new_tpl_name));
+                                                               log_assert(map->module(new_tpl_name) == nullptr);
+
+                                                               RTLIL::Module *new_tpl = map->addModule(new_tpl_name);
+                                                               tpl->cloneInto(new_tpl);
+
+                                                               techmap_do_cache.erase(tpl);
+                                                               techmap_do_cache[new_tpl] = true;
+                                                               tpl = new_tpl;
+
+                                                               std::map<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map;
+                                                               std::map<RTLIL::SigBit, RTLIL::SigBit> port_connmap;
+                                                               std::map<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits;
+
+                                                               for (auto wire : tpl->wires().to_vector())
+                                                               {
+                                                                       if (!wire->port_input || wire->port_output)
+                                                                               continue;
+
+                                                                       std::string port_name = wire->name;
+                                                                       tpl->rename(wire, NEW_ID);
+
+                                                                       RTLIL::Wire *new_wire = tpl->addWire(port_name, wire);
+                                                                       wire->port_input = false;
+
+                                                                       for (int i = 0; i < wire->width; i++) {
+                                                                               port_new2old_map[RTLIL::SigBit(new_wire, i)] = RTLIL::SigBit(wire, i);
+                                                                               port_connmap[RTLIL::SigBit(wire, i)] = RTLIL::SigBit(new_wire, i);
+                                                                       }
+                                                               }
+
+                                                               for (auto conn : cell->connections())
+                                                                       for (int i = 0; i < SIZE(conn.second); i++)
+                                                                       {
+                                                                               RTLIL::SigBit bit = sigmap(conn.second[i]);
+                                                                               RTLIL::SigBit tplbit(tpl->wire(conn.first), i);
+
+                                                                               if (bit.wire == nullptr)
+                                                                               {
+                                                                                       RTLIL::SigBit oldbit = port_new2old_map.at(tplbit);
+                                                                                       port_connmap.at(oldbit) = bit;
+                                                                               }
+                                                                               else if (cellbits_to_tplbits.count(bit))
+                                                                               {
+                                                                                       RTLIL::SigBit oldbit = port_new2old_map.at(tplbit);
+                                                                                       port_connmap.at(oldbit) = cellbits_to_tplbits[bit];
+                                                                               }
+                                                                               else
+                                                                                       cellbits_to_tplbits[bit] = tplbit;
+                                                                       }
+
+                                                               RTLIL::SigSig port_conn;
+                                                               for (auto &it : port_connmap) {
+                                                                       port_conn.first.append_bit(it.first);
+                                                                       port_conn.second.append_bit(it.second);
+                                                               }
+                                                               tpl->connect(port_conn);
+                                                       }
+
+                                                       Pass::call_on_module(map, tpl, cmd_string);
+
                                                        log_assert(!strncmp(q, "_TECHMAP_DO_", 12));
                                                        std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12);
                                                        while (tpl->wires_.count(new_name))
                                                                new_name += "_";
-                                                       tpl->rename(data.wire, new_name);
-
-                                                       std::string cmd_string = data.value.as_const().decode_string();
-                                                       Pass::call_on_module(map, tpl, cmd_string);
+                                                       tpl->rename(data.wire->name, new_name);
 
                                                        keep_running = true;
                                                        break;
@@ -571,6 +672,14 @@ struct TechmapPass : public Pass {
                log("        wire to start out as non-constant and evaluate to a constant value\n");
                log("        during processing of other _TECHMAP_DO_* commands.\n");
                log("\n");
+               log("        A _TECHMAP_DO_* command may start with the special token 'CONSTMAP; '.\n");
+               log("        in this case techmap will create a copy for each distinct configuration\n");
+               log("        of constant inputs and shorted inputs at this point and import the\n");
+               log("        constant and connected bits into the map module. All further commands\n");
+               log("        are executed in this copy. This is a very convenient way of creating\n");
+               log("        optimizied specializations of techmap modules without using the special\n");
+               log("        parameters described below.\n");
+               log("\n");
                log("In addition to this special wires, techmap also supports special parameters in\n");
                log("modules in the map file:\n");
                log("\n");
index a2fce1313e422de4e310c8a48ffebf530581109d..7ee2771e60d38af5323445829129fde10bf9d551 100644 (file)
@@ -152,7 +152,8 @@ output [Y_WIDTH-1:0] Y;
 localparam WIDTH = `MAX(A_WIDTH, Y_WIDTH);
 localparam BB_WIDTH = `MIN($clog2(shift_left ? Y_WIDTH : A_SIGNED ? WIDTH : A_WIDTH) + 1, B_WIDTH);
 
-wire [1023:0] _TECHMAP_DO_ = "proc; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;";
+wire [1023:0] _TECHMAP_DO_00_ = "proc;;";
+wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;";
 
 integer i;
 reg [WIDTH-1:0] buffer;
@@ -198,7 +199,8 @@ localparam WIDTH = `MAX(A_WIDTH, Y_WIDTH) + (B_SIGNED ? 2**(BB_WIDTH-1) : 0);
 parameter _TECHMAP_CELLTYPE_ = "";
 localparam extbit = _TECHMAP_CELLTYPE_ == "$shift" ? 1'b0 : 1'bx;
 
-wire [1023:0] _TECHMAP_DO_ = "proc; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;";
+wire [1023:0] _TECHMAP_DO_00_ = "proc;;";
+wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;";
 
 integer i;
 reg [WIDTH-1:0] buffer;