cxxrtl: fix typo.
[yosys.git] / backends / edif / edif.cc
index 6d9469538eba648522d775a5eb38ac91b02f829d..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;
@@ -171,13 +178,12 @@ struct EdifBackend : public Backend {
                extra_args(f, filename, args, argidx);
 
                if (top_module_name.empty())
-                       for (auto & mod_it:design->modules_)
-                               if (mod_it.second->get_bool_attribute("\\top"))
-                                       top_module_name = mod_it.first.str();
+                       for (auto module : design->modules())
+                               if (module->get_bool_attribute(ID::top))
+                                       top_module_name = module->name.str();
 
-               for (auto module_it : design->modules_)
+               for (auto module : design->modules())
                {
-                       RTLIL::Module *module = module_it.second;
                        if (module->get_blackbox_attribute())
                                continue;
 
@@ -185,14 +191,13 @@ struct EdifBackend : public Backend {
                                top_module_name = module->name.str();
 
                        if (module->processes.size() != 0)
-                               log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name));
+                               log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", log_id(module->name));
                        if (module->memories.size() != 0)
-                               log_error("Found unmapped memories in module %s: unmapped memories are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name));
+                               log_error("Found unmapped memories in module %s: unmapped memories are not supported in EDIF backend!\n", log_id(module->name));
 
-                       for (auto cell_it : module->cells_)
+                       for (auto cell : module->cells())
                        {
-                               RTLIL::Cell *cell = cell_it.second;
-                               if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_blackbox_attribute()) {
+                               if (design->module(cell->type) == nullptr || design->module(cell->type)->get_blackbox_attribute()) {
                                        lib_cell_ports[cell->type];
                                        for (auto p : cell->connections())
                                                lib_cell_ports[cell->type][p.first] = GetSize(p.second);
@@ -246,19 +251,25 @@ struct EdifBackend : public Backend {
                                        else if (!ct.cell_input(cell_it.first, port_it.first))
                                                dir = "OUTPUT";
                                }
-                               if (port_it.second == 1)
+                               int width = port_it.second;
+                               int start = 0;
+                               bool upto = false;
+                               auto m = design->module(cell_it.first);
+                               if (m) {
+                                       auto w = m->wire(port_it.first);
+                                       if (w) {
+                                               width = GetSize(w);
+                                               start = w->start_offset;
+                                               upto = w->upto;
+                                       }
+                               }
+                               if (width == 1)
                                        *f << stringf("          (port %s (direction %s))\n", EDIF_DEF(port_it.first), dir);
                                else {
-                                       int b[2] = {port_it.second-1, 0};
-                                       auto m = design->module(cell_it.first);
-                                       if (m) {
-                                               auto w = m->wire(port_it.first);
-                                               if (w) {
-                                                       b[w->upto ? 0 : 1] = w->start_offset;
-                                                       b[w->upto ? 1 : 0] = w->start_offset+GetSize(w)-1;
-                                               }
-                                       }
-                                       *f << stringf("          (port (array %s %d) (direction %s))\n", EDIF_DEFR(port_it.first, port_rename, b[0], b[1]), port_it.second, dir);
+                                       int b[2];
+                                       b[upto ? 0 : 1] = start;
+                                       b[upto ? 1 : 0] = start+width-1;
+                                       *f << stringf("          (port (array %s %d) (direction %s))\n", EDIF_DEFR(port_it.first, port_rename, b[0], b[1]), width, dir);
                                }
                        }
                        *f << stringf("        )\n");
@@ -271,11 +282,11 @@ struct EdifBackend : public Backend {
 
                // extract module dependencies
                std::map<RTLIL::Module*, std::set<RTLIL::Module*>> module_deps;
-               for (auto &mod_it : design->modules_) {
-                       module_deps[mod_it.second] = std::set<RTLIL::Module*>();
-                       for (auto &cell_it : mod_it.second->cells_)
-                               if (design->modules_.count(cell_it.second->type) > 0)
-                                       module_deps[mod_it.second].insert(design->modules_.at(cell_it.second->type));
+               for (auto module : design->modules()) {
+                       module_deps[module] = std::set<RTLIL::Module*>();
+                       for (auto cell : module->cells())
+                               if (design->module(cell->type) != nullptr)
+                                       module_deps[module].insert(design->module(cell->type));
                }
 
                // simple good-enough topological sort
@@ -286,12 +297,12 @@ struct EdifBackend : public Backend {
                                for (auto &dep : it.second)
                                        if (module_deps.count(dep) > 0)
                                                goto not_ready_yet;
-                               // log("Next in topological sort: %s\n", RTLIL::id2cstr(it.first->name));
+                               // log("Next in topological sort: %s\n", log_id(it.first->name));
                                sorted_modules.push_back(it.first);
                        not_ready_yet:;
                        }
                        if (sorted_modules_idx == sorted_modules.size())
-                               log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", RTLIL::id2cstr(module_deps.begin()->first->name));
+                               log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", log_id(module_deps.begin()->first->name));
                        while (sorted_modules_idx < sorted_modules.size())
                                module_deps.erase(sorted_modules.at(sorted_modules_idx++));
                }
@@ -300,21 +311,105 @@ struct EdifBackend : public Backend {
                *f << stringf("  (library DESIGN\n");
                *f << stringf("    (edifLevel 0)\n");
                *f << stringf("    (technology (numberDefinition))\n");
+
+               auto add_prop = [&](IdString name, Const val) {
+                       if ((val.flags & RTLIL::CONST_FLAG_STRING) != 0)
+                               *f << stringf("\n            (property %s (string \"%s\"))", EDIF_DEF(name), val.decode_string().c_str());
+                       else if (val.bits.size() <= 32 && RTLIL::SigSpec(val).is_fully_def())
+                               *f << stringf("\n            (property %s (integer %u))", EDIF_DEF(name), val.as_int());
+                       else {
+                               std::string hex_string = "";
+                               for (size_t i = 0; i < val.bits.size(); i += 4) {
+                                       int digit_value = 0;
+                                       if (i+0 < val.bits.size() && val.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1;
+                                       if (i+1 < val.bits.size() && val.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2;
+                                       if (i+2 < val.bits.size() && val.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4;
+                                       if (i+3 < val.bits.size() && val.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8;
+                                       char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
+                                       hex_string = std::string(digit_str) + hex_string;
+                               }
+                               *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())
                                continue;
 
                        SigMap sigmap(module);
-                       std::map<RTLIL::SigSpec, std::set<std::string>> net_join_db;
+                       std::map<RTLIL::SigSpec, std::set<std::pair<std::string, bool>>> net_join_db;
 
                        *f << stringf("    (cell %s\n", EDIF_DEF(module->name));
                        *f << stringf("      (cellType GENERIC)\n");
                        *f << stringf("      (view VIEW_NETLIST\n");
                        *f << stringf("        (viewType NETLIST)\n");
                        *f << stringf("        (interface\n");
-                       for (auto &wire_it : module->wires_) {
-                               RTLIL::Wire *wire = wire_it.second;
+
+                       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;
                                const char *dir = "INOUT";
@@ -323,52 +418,42 @@ struct EdifBackend : public Backend {
                                else if (!wire->port_input)
                                        dir = "OUTPUT";
                                if (wire->width == 1) {
-                                       *f << stringf("          (port %s (direction %s))\n", EDIF_DEF(wire->name), dir);
+                                       *f << stringf("          (port %s (direction %s)", EDIF_DEF(wire->name), dir);
+                                       if (attr_properties)
+                                               for (auto &p : wire->attributes)
+                                                       add_prop(p.first, p.second);
+                                       *f << ")\n";
                                        RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire));
-                                       net_join_db[sig].insert(stringf("(portRef %s)", EDIF_REF(wire->name)));
+                                       net_join_db[sig].insert(make_pair(stringf("(portRef %s)", EDIF_REF(wire->name)), wire->port_input));
                                } else {
                                        int b[2];
                                        b[wire->upto ? 0 : 1] = wire->start_offset;
                                        b[wire->upto ? 1 : 0] = wire->start_offset + GetSize(wire) - 1;
-                                       *f << stringf("          (port (array %s %d) (direction %s))\n", EDIF_DEFR(wire->name, port_rename, b[0], b[1]), wire->width, dir);
+                                       *f << stringf("          (port (array %s %d) (direction %s)", EDIF_DEFR(wire->name, port_rename, b[0], b[1]), wire->width, dir);
+                                       if (attr_properties)
+                                               for (auto &p : wire->attributes)
+                                                       add_prop(p.first, p.second);
+
+                                       *f << ")\n";
                                        for (int i = 0; i < wire->width; i++) {
                                                RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, i));
-                                               net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), GetSize(wire)-i-1));
+                                               net_join_db[sig].insert(make_pair(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), GetSize(wire)-i-1), wire->port_input));
                                        }
                                }
                        }
+
                        *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_it : module->cells_) {
-                               RTLIL::Cell *cell = cell_it.second;
+
+                       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),
                                                lib_cell_ports.count(cell->type) > 0 ? " (libraryRef LIB)" : "");
-
-                               auto add_prop = [&](IdString name, Const val) {
-                                       if ((val.flags & RTLIL::CONST_FLAG_STRING) != 0)
-                                               *f << stringf("\n            (property %s (string \"%s\"))", EDIF_DEF(name), val.decode_string().c_str());
-                                       else if (val.bits.size() <= 32 && RTLIL::SigSpec(val).is_fully_def())
-                                               *f << stringf("\n            (property %s (integer %u))", EDIF_DEF(name), val.as_int());
-                                       else {
-                                               std::string hex_string = "";
-                                               for (size_t i = 0; i < val.bits.size(); i += 4) {
-                                                       int digit_value = 0;
-                                                       if (i+0 < val.bits.size() && val.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1;
-                                                       if (i+1 < val.bits.size() && val.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2;
-                                                       if (i+2 < val.bits.size() && val.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4;
-                                                       if (i+3 < val.bits.size() && val.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8;
-                                                       char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
-                                                       hex_string = std::string(digit_str) + hex_string;
-                                               }
-                                               *f << stringf("\n            (property %s (string \"%d'h%s\"))", EDIF_DEF(name), GetSize(val.bits), hex_string.c_str());
-                                       }
-                               };
-
                                for (auto &p : cell->parameters)
                                        add_prop(p.first, p.second);
                                if (attr_properties)
@@ -382,31 +467,39 @@ struct EdifBackend : public Backend {
                                                if (sig[i].wire == NULL && sig[i] != RTLIL::State::S0 && sig[i] != RTLIL::State::S1)
                                                        log_warning("Bit %d of cell port %s.%s.%s driven by %s will be left unconnected in EDIF output.\n",
                                                                        i, log_id(module), log_id(cell), log_id(p.first), log_signal(sig[i]));
-                                               else if (sig.size() == 1)
-                                                       net_join_db[sig[i]].insert(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)));
                                                else {
                                                        int member_idx = GetSize(sig)-i-1;
                                                        auto m = design->module(cell->type);
+                                                       int width = sig.size();
                                                        if (m) {
                                                                auto w = m->wire(p.first);
-                                                               if (w)
+                                                               if (w) {
                                                                        member_idx = GetSize(w)-i-1;
+                                                                       width = GetSize(w);
+                                                               }
+                                                       }
+                                                       if (width == 1)
+                                                               net_join_db[sig[i]].insert(make_pair(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)), cell->output(p.first)));
+                                                       else {
+                                                               net_join_db[sig[i]].insert(make_pair(stringf("(portRef (member %s %d) (instanceRef %s))",
+                                                                               EDIF_REF(p.first), member_idx, EDIF_REF(cell->name)), cell->output(p.first)));
                                                        }
-                                                       net_join_db[sig[i]].insert(stringf("(portRef (member %s %d) (instanceRef %s))",
-                                                                       EDIF_REF(p.first), member_idx, EDIF_REF(cell->name)));
                                                }
                                }
                        }
+
                        for (auto &it : net_join_db) {
                                RTLIL::SigBit sig = it.first;
                                if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1) {
                                        if (sig == RTLIL::State::Sx) {
                                                for (auto &ref : it.second)
-                                                       log_warning("Exporting x-bit on %s as zero bit.\n", ref.c_str());
+                                                       log_warning("Exporting x-bit on %s as zero bit.\n", ref.first.c_str());
                                                sig = RTLIL::State::S0;
+                                       } else if (sig == RTLIL::State::Sz) {
+                                               continue;
                                        } else {
                                                for (auto &ref : it.second)
-                                                       log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.c_str());
+                                                       log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.first.c_str());
                                                log_abort();
                                        }
                                }
@@ -423,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.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");
@@ -432,8 +525,54 @@ struct EdifBackend : public Backend {
                                        if (sig == RTLIL::State::S1)
                                                *f << stringf("            (portRef %c (instanceRef VCC))\n", gndvccy ? 'Y' : 'P');
                                }
-                               *f << stringf("          ))\n");
+                               *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())
+                       {
+                               if (!wire->get_bool_attribute(ID::keep))
+                                       continue;
+
+                               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--);
+
+                                       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");