cxxrtl: fix typo.
[yosys.git] / backends / edif / edif.cc
index cb1b4c284002a7b76e33f74aaa552a1acd3cf84c..e0013238c8321b320de162fc86df6a397f6b03f3 100644 (file)
@@ -90,7 +90,7 @@ struct EdifNames
 
 struct EdifBackend : public Backend {
        EdifBackend() : Backend("edif", "write design to EDIF netlist file") { }
-       void help() YS_OVERRIDE
+       void help() override
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
                log("\n");
@@ -113,6 +113,9 @@ struct EdifBackend : public Backend {
                log("    -attrprop\n");
                log("        create EDIF properties for cell attributes\n");
                log("\n");
+               log("    -keep\n");
+               log("        create extra KEEP nets by allowing a cell to drive multiple nets.\n");
+               log("\n");
                log("    -pvector {par|bra|ang}\n");
                log("        sets the delimiting character for module port rename clauses to\n");
                log("        parentheses, square brackets, or angle brackets.\n");
@@ -123,14 +126,14 @@ struct EdifBackend : public Backend {
                log("is targeted.\n");
                log("\n");
        }
-       void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+       void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
        {
                log_header(design, "Executing EDIF backend.\n");
                std::string top_module_name;
                bool port_rename = false;
                bool attr_properties = false;
                std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
-               bool nogndvcc = false, gndvccy = false;
+               bool nogndvcc = false, gndvccy = false, keepmode = false;
                CellTypes ct(design);
                EdifNames edif_names;
 
@@ -153,6 +156,10 @@ struct EdifBackend : public Backend {
                                attr_properties = true;
                                continue;
                        }
+                       if (args[argidx] == "-keep") {
+                               keepmode = true;
+                               continue;
+                       }
                        if (args[argidx] == "-pvector" && argidx+1 < args.size()) {
                                std::string parray;
                                port_rename = true;
@@ -172,7 +179,7 @@ struct EdifBackend : public Backend {
 
                if (top_module_name.empty())
                        for (auto module : design->modules())
-                               if (module->get_bool_attribute("\\top"))
+                               if (module->get_bool_attribute(ID::top))
                                        top_module_name = module->name.str();
 
                for (auto module : design->modules())
@@ -323,7 +330,7 @@ struct EdifBackend : public Backend {
                                }
                                *f << stringf("\n            (property %s (string \"%d'h%s\"))", EDIF_DEF(name), GetSize(val.bits), hex_string.c_str());
                        }
-               };              
+               };
                for (auto module : sorted_modules)
                {
                        if (module->get_blackbox_attribute())
@@ -337,6 +344,71 @@ struct EdifBackend : public Backend {
                        *f << stringf("      (view VIEW_NETLIST\n");
                        *f << stringf("        (viewType NETLIST)\n");
                        *f << stringf("        (interface\n");
+
+                       for (auto cell : module->cells()) {
+                               for (auto &conn : cell->connections())
+                                       if (cell->output(conn.first))
+                                               sigmap.add(conn.second);
+                       }
+
+                       for (auto wire : module->wires())
+                               for (auto b1 : SigSpec(wire))
+                               {
+                                       auto b2 = sigmap(b1);
+
+                                       if (b1 == b2 || !b2.wire)
+                                               continue;
+
+                                       log_assert(b1.wire != nullptr);
+
+                                       Wire *w1 = b1.wire;
+                                       Wire *w2 = b2.wire;
+
+                                       {
+                                               int c1 = w1->get_bool_attribute(ID::keep);
+                                               int c2 = w2->get_bool_attribute(ID::keep);
+
+                                               if (c1 > c2) goto promote;
+                                               if (c1 < c2) goto nopromote;
+                                       }
+
+                                       {
+                                               int c1 = w1->name.isPublic();
+                                               int c2 = w2->name.isPublic();
+
+                                               if (c1 > c2) goto promote;
+                                               if (c1 < c2) goto nopromote;
+                                       }
+
+                                       {
+                                               auto count_nontrivial_attr = [](Wire *w) {
+                                                       int count = w->attributes.size();
+                                                       count -= w->attributes.count(ID::src);
+                                                       count -= w->attributes.count(ID::unused_bits);
+                                                       return count;
+                                               };
+
+                                               int c1 = count_nontrivial_attr(w1);
+                                               int c2 = count_nontrivial_attr(w2);
+
+                                               if (c1 > c2) goto promote;
+                                               if (c1 < c2) goto nopromote;
+                                       }
+
+                                       {
+                                               int c1 = w1->port_id ? INT_MAX - w1->port_id : 0;
+                                               int c2 = w2->port_id ? INT_MAX - w2->port_id : 0;
+
+                                               if (c1 > c2) goto promote;
+                                               if (c1 < c2) goto nopromote;
+                                       }
+
+                               nopromote:
+                                       if (0)
+                               promote:
+                                               sigmap.add(b1);
+                               }
+
                        for (auto wire : module->wires()) {
                                if (wire->port_id == 0)
                                        continue;
@@ -369,12 +441,15 @@ struct EdifBackend : public Backend {
                                        }
                                }
                        }
+
                        *f << stringf("        )\n");
                        *f << stringf("        (contents\n");
+
                        if (!nogndvcc) {
                                *f << stringf("          (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n");
                                *f << stringf("          (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n");
                        }
+
                        for (auto cell : module->cells()) {
                                *f << stringf("          (instance %s\n", EDIF_DEF(cell->name));
                                *f << stringf("            (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_REF(cell->type),
@@ -412,6 +487,7 @@ struct EdifBackend : public Backend {
                                                }
                                }
                        }
+
                        for (auto &it : net_join_db) {
                                RTLIL::SigBit sig = it.first;
                                if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1) {
@@ -440,7 +516,7 @@ struct EdifBackend : public Backend {
                                }
                                *f << stringf("          (net %s (joined\n", EDIF_DEF(netname));
                                for (auto &ref : it.second)
-                                       *f << stringf("            %s\n", ref.first.c_str());
+                                       *f << stringf("              %s\n", ref.first.c_str());
                                if (sig.wire == NULL) {
                                        if (nogndvcc)
                                                log_error("Design contains constant nodes (map with \"hilomap\" first).\n");
@@ -448,37 +524,55 @@ struct EdifBackend : public Backend {
                                                *f << stringf("            (portRef %c (instanceRef GND))\n", gndvccy ? 'Y' : 'G');
                                        if (sig == RTLIL::State::S1)
                                                *f << stringf("            (portRef %c (instanceRef VCC))\n", gndvccy ? 'Y' : 'P');
-                               }                               
+                               }
                                *f << stringf("            )");
                                if (attr_properties && sig.wire != NULL)
                                        for (auto &p : sig.wire->attributes)
                                                add_prop(p.first, p.second);
                                *f << stringf("\n          )\n");
                        }
-                       for (auto wire : module->wires()) {
+
+                       for (auto wire : module->wires())
+                       {
                                if (!wire->get_bool_attribute(ID::keep))
                                        continue;
-                               for(int i = 0; i < wire->width; i++) {
+
+                               for(int i = 0; i < wire->width; i++)
+                               {
                                        SigBit raw_sig = RTLIL::SigSpec(wire, i);
                                        SigBit mapped_sig = sigmap(raw_sig);
+
                                        if (raw_sig == mapped_sig || net_join_db.count(mapped_sig) == 0)
                                                continue;
+
                                        std::string netname = log_signal(raw_sig);
                                        for (size_t i = 0; i < netname.size(); i++)
                                                if (netname[i] == ' ' || netname[i] == '\\')
                                                        netname.erase(netname.begin() + i--);
-                                       *f << stringf("          (net %s (joined\n", EDIF_DEF(netname));
-                                       auto &refs = net_join_db.at(mapped_sig);
-                                       for (auto &ref : refs)
-                                               if (ref.second)
-                                                       *f << stringf("            %s\n", ref.first.c_str());
-                                       *f << stringf("            )");
-                                       if (attr_properties && raw_sig.wire != NULL)
-                                               for (auto &p : raw_sig.wire->attributes)
-                                                       add_prop(p.first, p.second);
-                                       *f << stringf("\n          )\n");
+
+                                       if (keepmode)
+                                       {
+                                               *f << stringf("          (net %s (joined\n", EDIF_DEF(netname));
+
+                                               auto &refs = net_join_db.at(mapped_sig);
+                                               for (auto &ref : refs)
+                                                       if (ref.second)
+                                                               *f << stringf("              %s\n", ref.first.c_str());
+                                               *f << stringf("            )");
+
+                                               if (attr_properties && raw_sig.wire != NULL)
+                                                       for (auto &p : raw_sig.wire->attributes)
+                                                               add_prop(p.first, p.second);
+
+                                               *f << stringf("\n          )\n");
+                                       }
+                                       else
+                                       {
+                                               log_warning("Ignoring conflicting 'keep' property on net %s. Use -keep to generate the extra net nevertheless.\n", EDIF_DEF(netname));
+                                       }
                                }
                        }
+
                        *f << stringf("        )\n");
                        *f << stringf("      )\n");
                        *f << stringf("    )\n");