Merge remote-tracking branch 'origin/master' into xaig_dff
[yosys.git] / passes / techmap / abc9.cc
index 5a9cbc24503d0ae0339a8eee9b2d28921473e8cd..def347c210d3b676763dbe66e4eae9b5b66a0262 100644 (file)
@@ -30,7 +30,7 @@
                                                "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\
                                                "&mfs; &ps -l"
 #else
-#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l; time"
+#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l"
 #endif
 
 
@@ -89,20 +89,30 @@ void handle_loops(RTLIL::Design *design, RTLIL::Module *module)
                                        if (cell->output(c.first)) {
                                                SigBit b = c.second.as_bit();
                                                Wire *w = b.wire;
-                                               log_assert(!w->port_input);
-                                               w->port_input = true;
-                                               w = module->wire(stringf("%s.abci", w->name.c_str()));
-                                               if (!w) {
-                                                       w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire));
-                                                       w->port_output = true;
+                                               if (w->port_input) {
+                                                       // In this case, hopefully the loop break has been already created
+                                                       // Get the non-prefixed wire
+                                                       Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str()));
+                                                       log_assert(wo != nullptr);
+                                                       log_assert(wo->port_output);
+                                                       log_assert(b.offset < GetSize(wo));
+                                                       c.second = RTLIL::SigBit(wo, b.offset);
                                                }
                                                else {
-                                                       log_assert(w->port_input);
-                                                       log_assert(b.offset < GetSize(w));
+                                                       // Create a new output/input loop break
+                                                       w->port_input = true;
+                                                       w = module->wire(stringf("%s.abco", w->name.c_str()));
+                                                       if (!w) {
+                                                               w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire));
+                                                               w->port_output = true;
+                                                       }
+                                                       else {
+                                                               log_assert(w->port_input);
+                                                               log_assert(b.offset < GetSize(w));
+                                                       }
+                                                       w->set_bool_attribute(ID(abc9_scc_break));
+                                                       c.second = RTLIL::SigBit(w, b.offset);
                                                }
-                                               w->set_bool_attribute(ID(abc9_scc_break));
-                                               module->swap_names(b.wire, w);
-                                               c.second = RTLIL::SigBit(w, b.offset);
                                        }
                                }
                        }
@@ -311,7 +321,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip
                for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos))
                        abc9_script = abc9_script.erase(pos, strlen("&mfs"));
 
-       abc9_script += stringf("; &write %s/output.aig", tempdir_name.c_str());
+       abc9_script += stringf("; &write -n %s/output.aig", tempdir_name.c_str());
        abc9_script = add_echos_to_abc9_cmd(abc9_script);
 
        for (size_t i = 0; i+1 < abc9_script.size(); i++)
@@ -354,24 +364,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip
                design->remove(design->module(ID($__abc9__)));
 #endif
 
-               // Now 'unexpose' those wires by undoing
-               // the expose operation -- remove them from PO/PI
-               // and re-connecting them back together
-               for (auto wire : module->wires()) {
-                       auto it = wire->attributes.find(ID(abc9_scc_break));
-                       if (it != wire->attributes.end()) {
-                               wire->attributes.erase(it);
-                               log_assert(wire->port_output);
-                               wire->port_output = false;
-                               RTLIL::Wire *i_wire = module->wire(wire->name.str() + ".abci");
-                               log_assert(i_wire);
-                               log_assert(i_wire->port_input);
-                               i_wire->port_input = false;
-                               module->connect(i_wire, wire);
-                       }
-               }
-               module->fixup_ports();
-
                log_header(design, "Executing ABC9.\n");
 
                if (!lut_costs.empty()) {
@@ -429,26 +421,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip
                if (mapped_mod == NULL)
                        log_error("ABC output file does not contain a module `$__abc9__'.\n");
 
-               pool<RTLIL::SigBit> output_bits;
                for (auto &it : mapped_mod->wires_) {
                        RTLIL::Wire *w = it.second;
                        RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w));
                        if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx;
-                       if (w->port_output) {
-                               RTLIL::Wire *wire = module->wire(w->name);
-                               log_assert(wire);
-                               for (int i = 0; i < GetSize(w); i++)
-                                       output_bits.insert({wire, i});
-                       }
-               }
-
-               for (auto &it : module->connections_) {
-                       auto &signal = it.first;
-                       auto bits = signal.bits();
-                       for (auto &b : bits)
-                               if (output_bits.count(b))
-                                       b = module->addWire(NEW_ID);
-                       signal = std::move(bits);
                }
 
                dict<IdString, bool> abc9_box;
@@ -721,6 +697,25 @@ clone_lut:
                        }
                }
 
+               // Now 'unexpose' those wires by undoing
+               // the expose operation -- remove them from PO/PI
+               // and re-connecting them back together
+               for (auto wire : module->wires()) {
+                       auto it = wire->attributes.find(ID(abc9_scc_break));
+                       if (it != wire->attributes.end()) {
+                               wire->attributes.erase(it);
+                               log_assert(wire->port_output);
+                               wire->port_output = false;
+                               std::string name = wire->name.str();
+                               RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5));
+                               log_assert(i_wire);
+                               log_assert(i_wire->port_input);
+                               i_wire->port_input = false;
+                               module->connect(i_wire, wire);
+                       }
+               }
+               module->fixup_ports();
+
                //log("ABC RESULTS:        internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
                log("ABC RESULTS:           input signals: %8d\n", in_wires);
                log("ABC RESULTS:          output signals: %8d\n", out_wires);
@@ -752,10 +747,6 @@ struct Abc9Pass : public Pass {
                log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n");
                log("library to a target architecture.\n");
                log("\n");
-               log("Selection must only contain fully selected modules. It is assumed that such\n");
-               log("modules contain only cells belonging to the same clock domain, as produced by\n");
-               log("the 'clkpart' command.\n");
-               log("\n");
                log("    -exe <command>\n");
 #ifdef ABCEXTERNAL
                log("        use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
@@ -921,29 +912,28 @@ struct Abc9Pass : public Pass {
                        //}
                        if (arg == "-lut" && argidx+1 < args.size()) {
                                string arg = args[++argidx];
-                               size_t pos = arg.find_first_of(':');
-                               int lut_mode = 0, lut_mode2 = 0;
-                               if (pos != string::npos) {
-                                       lut_mode = atoi(arg.substr(0, pos).c_str());
-                                       lut_mode2 = atoi(arg.substr(pos+1).c_str());
-                               } else {
-                                       pos = arg.find_first_of('.');
+                               if (arg.find_first_not_of("0123456789:") == std::string::npos) {
+                                       size_t pos = arg.find_first_of(':');
+                                       int lut_mode = 0, lut_mode2 = 0;
                                        if (pos != string::npos) {
-                                               lut_file = arg;
-                                               rewrite_filename(lut_file);
-                                               if (!lut_file.empty() && !is_absolute_path(lut_file))
-                                                       lut_file = std::string(pwd) + "/" + lut_file;
-                                       }
-                                       else {
+                                               lut_mode = atoi(arg.substr(0, pos).c_str());
+                                               lut_mode2 = atoi(arg.substr(pos+1).c_str());
+                                       } else {
                                                lut_mode = atoi(arg.c_str());
                                                lut_mode2 = lut_mode;
                                        }
+                                       lut_costs.clear();
+                                       for (int i = 0; i < lut_mode; i++)
+                                               lut_costs.push_back(1);
+                                       for (int i = lut_mode; i < lut_mode2; i++)
+                                               lut_costs.push_back(2 << (i - lut_mode));
+                               }
+                               else {
+                                       lut_file = arg;
+                                       rewrite_filename(lut_file);
+                                       if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+')
+                                               lut_file = std::string(pwd) + "/" + lut_file;
                                }
-                               lut_costs.clear();
-                               for (int i = 0; i < lut_mode; i++)
-                                       lut_costs.push_back(1);
-                               for (int i = lut_mode; i < lut_mode2; i++)
-                                       lut_costs.push_back(2 << (i - lut_mode));
                                continue;
                        }
                        if (arg == "-luts" && argidx+1 < args.size()) {
@@ -1012,7 +1002,7 @@ struct Abc9Pass : public Pass {
                    box_file = "+/dummy.box";
 
                rewrite_filename(box_file);
-               if (!box_file.empty() && !is_absolute_path(box_file))
+               if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+')
                    box_file = std::string(pwd) + "/" + box_file;
 
                dict<int,IdString> box_lookup;
@@ -1076,6 +1066,8 @@ struct Abc9Pass : public Pass {
                        }
                }
 
+               SigMap assign_map;
+               CellTypes ct(design);
                for (auto module : design->selected_modules())
                {
                        if (module->attributes.count(ID(abc9_box_id)))
@@ -1086,54 +1078,188 @@ struct Abc9Pass : public Pass {
                                continue;
                        }
 
-                       if (!design->selected_whole_module(module)) {
-                               log("Skipping module %s as it is partially selected.\n", log_id(module));
-                               continue;
-                       }
+                       assign_map.set(module);
+
+                       std::vector<RTLIL::Cell*> all_cells = module->selected_cells();
+                       pool<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
 
-                       SigMap sigmap(module);
+                       pool<RTLIL::Cell*> expand_queue, next_expand_queue;
+                       pool<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
+                       pool<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
 
-                       typedef std::pair<IdString, SigSpec> ctrldomain_t;
-                       std::map<ctrldomain_t, int> mergeability_class;
-                       pool<Wire*> clocks;
-                       std::string target = delay_target;
+                       typedef SigSpec clkdomain_t;
+                       std::map<clkdomain_t, pool<RTLIL::IdString>> assigned_cells;
+                       std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
+
+                       std::map<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
+                       std::map<RTLIL::SigBit, pool<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down;
+
+                       for (auto cell : all_cells)
+                               for (auto &conn : cell->connections())
+                               for (auto bit : assign_map(conn.second))
+                                       if (bit.wire != nullptr) {
+                                               cell_to_bit[cell].insert(bit);
+                                               bit_to_cell[bit].insert(cell);
+                                               if (ct.cell_input(cell->type, conn.first)) {
+                                                       cell_to_bit_up[cell].insert(bit);
+                                                       bit_to_cell_down[bit].insert(cell);
+                                               }
+                                               if (ct.cell_output(cell->type, conn.first)) {
+                                                       cell_to_bit_down[cell].insert(bit);
+                                                       bit_to_cell_up[bit].insert(cell);
+                                               }
+                                       }
 
-                       for (auto cell : module->cells()) {
+                       for (auto cell : all_cells) {
                                auto inst_module = design->module(cell->type);
                                if (!inst_module || !inst_module->attributes.count("\\abc9_flop"))
                                        continue;
 
-                               if (delay_target.empty()) {
-                                       Wire *abc9_clock_wire = module->wire(stringf("%s.$abc9_clock", cell->name.c_str()));
-                                       if (abc9_clock_wire == NULL)
-                                               log_error("'%s$abc9_clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
-                                       SigBit abc9_clock = sigmap(abc9_clock_wire);
-                                       auto r = clocks.insert(abc9_clock.wire);
-                                       if (r.second) {
-                                               auto it = abc9_clock.wire->attributes.find("\\abc9_period");
-                                               if (it != abc9_clock.wire->attributes.end()) {
-                                                       int period = it->second.as_int();
-                                                       log("Identified target period = %d ps for clock %s\n", period, log_signal(abc9_clock));
-                                                       target = stringf("-D %d", period);
-                                               }
+                               Wire *abc9_clock_wire = module->wire(stringf("%s.$abc9_clock", cell->name.c_str()));
+                               if (abc9_clock_wire == NULL)
+                                       log_error("'%s$abc9_clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
+                               SigSpec abc9_clock = assign_map(abc9_clock_wire);
+
+                               unassigned_cells.erase(cell);
+                               expand_queue_up.insert(cell);
+                               clkdomain_t key(abc9_clock);
+                               assigned_cells[key].insert(cell->name);
+                               assigned_cells_reverse[cell] = key;
+
+                               auto YS_ATTRIBUTE(unused) r2 = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), 1));
+                               log_assert(r2.second);
+
+                               Wire *abc9_init_wire = module->wire(stringf("%s.$abc9_init", cell->name.c_str()));
+                               if (abc9_init_wire == NULL)
+                                   log_error("'%s.$abc9_init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
+                               log_assert(GetSize(abc9_init_wire) == 1);
+                               SigSpec abc9_init = assign_map(abc9_init_wire);
+                               if (!abc9_init.is_fully_const())
+                                   log_error("'%s.$abc9_init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
+                               r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const()));
+                               log_assert(r2.second);
+
+                               // Also assign these special ABC9 cells to the
+                               //   same clock domain
+                               for (auto b : cell_to_bit_down[cell])
+                               for (auto c : bit_to_cell_down[b])
+                                       if (c->type == "$__ABC9_FF_") {
+                                               cell = c;
+                                               unassigned_cells.erase(cell);
+                                               assigned_cells[key].insert(cell->name);
+                                               assigned_cells_reverse[cell] = key;
+                                               break;
+                                       }
+                               for (auto b : cell_to_bit_down[cell])
+                               for (auto c : bit_to_cell_down[b])
+                                       if (c->type == "$__ABC9_ASYNC") {
+                                               cell = c;
+                                               unassigned_cells.erase(cell);
+                                               assigned_cells[key].insert(cell->name);
+                                               assigned_cells_reverse[cell] = key;
+                                               break;
                                        }
+
+                               expand_queue.insert(cell);
+                               expand_queue_down.insert(cell);
+                       }
+
+                       while (!expand_queue_up.empty() || !expand_queue_down.empty())
+                       {
+                               if (!expand_queue_up.empty())
+                               {
+                                       RTLIL::Cell *cell = *expand_queue_up.begin();
+                                       auto key = assigned_cells_reverse.at(cell);
+                                       expand_queue_up.erase(cell);
+
+                                       for (auto bit : cell_to_bit_up[cell])
+                                       for (auto c : bit_to_cell_up[bit])
+                                               if (unassigned_cells.count(c)) {
+                                                       unassigned_cells.erase(c);
+                                                       next_expand_queue_up.insert(c);
+                                                       assigned_cells[key].insert(c->name);
+                                                       assigned_cells_reverse[c] = key;
+                                                       expand_queue.insert(c);
+                                               }
                                }
 
-                               Wire *abc9_control_wire = module->wire(stringf("%s.$abc9_control", cell->name.c_str()));
-                               if (abc9_control_wire == NULL)
-                                       log_error("'%s$abc9_control' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
-                               SigSpec abc9_control = sigmap(abc9_control_wire);
+                               if (!expand_queue_down.empty())
+                               {
+                                       RTLIL::Cell *cell = *expand_queue_down.begin();
+                                       auto key = assigned_cells_reverse.at(cell);
+                                       expand_queue_down.erase(cell);
+
+                                       for (auto bit : cell_to_bit_down[cell])
+                                       for (auto c : bit_to_cell_down[bit])
+                                               if (unassigned_cells.count(c)) {
+                                                       unassigned_cells.erase(c);
+                                                       next_expand_queue_up.insert(c);
+                                                       assigned_cells[key].insert(c->name);
+                                                       assigned_cells_reverse[c] = key;
+                                                       expand_queue.insert(c);
+                                               }
+                               }
 
-                               ctrldomain_t key(cell->type, abc9_control);
-                               auto r = mergeability_class.emplace(key, mergeability_class.size() + 1);
-                               auto YS_ATTRIBUTE(unused) r2 = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second));
-                               log_assert(r2.second);
+                               if (expand_queue_up.empty() && expand_queue_down.empty()) {
+                                       expand_queue_up.swap(next_expand_queue_up);
+                                       expand_queue_down.swap(next_expand_queue_down);
+                               }
                        }
 
+                       while (!expand_queue.empty())
+                       {
+                               RTLIL::Cell *cell = *expand_queue.begin();
+                               auto key = assigned_cells_reverse.at(cell);
+                               expand_queue.erase(cell);
+
+                               for (auto bit : cell_to_bit.at(cell)) {
+                                       for (auto c : bit_to_cell[bit])
+                                               if (unassigned_cells.count(c)) {
+                                                       unassigned_cells.erase(c);
+                                                       next_expand_queue.insert(c);
+                                                       assigned_cells[key].insert(c->name);
+                                                       assigned_cells_reverse[c] = key;
+                                               }
+                                       bit_to_cell[bit].clear();
+                               }
+
+                               if (expand_queue.empty())
+                                       expand_queue.swap(next_expand_queue);
+                       }
+
+                       clkdomain_t key;
+                       for (auto cell : unassigned_cells) {
+                               assigned_cells[key].insert(cell->name);
+                               assigned_cells_reverse[cell] = key;
+                       }
+
+                       log_header(design, "Summary of detected clock domains:\n");
+                       for (auto &it : assigned_cells)
+                               log("  %d cells in clk=%s\n", GetSize(it.second), log_signal(it.first));
+
+                       design->selection_stack.emplace_back(false);
                        design->selected_active_module = module->name.str();
-                       abc9_module(design, module, script_file, exe_file, cleanup, lut_costs, false, "$",
-                                       keepff, target, lutin_shared, fast_mode, show_tempdir,
-                                       box_file, lut_file, wire_delay, box_lookup, nomfs);
+                       for (auto &it : assigned_cells) {
+                               std::string target = delay_target;
+                               if (target.empty()) {
+                                       for (auto b : assign_map(it.first))
+                                               if (b.wire) {
+                                                       auto jt = b.wire->attributes.find("\\abc9_period");
+                                                       if (jt != b.wire->attributes.end()) {
+                                                               target = stringf("-D %d", jt->second.as_int());
+                                                               log("Target period = %s ps for clock domain %s\n", target.c_str(), log_signal(it.first));
+                                                               break;
+                                                       }
+                                               }
+                               }
+                               RTLIL::Selection& sel = design->selection_stack.back();
+                               sel.selected_members[module->name] = std::move(it.second);
+                               abc9_module(design, module, script_file, exe_file, cleanup, lut_costs, false, "$",
+                                               keepff, target, lutin_shared, fast_mode, show_tempdir,
+                                               box_file, lut_file, wire_delay, box_lookup, nomfs);
+                               assign_map.set(module);
+                       }
+                       design->selection_stack.pop_back();
                        design->selected_active_module.clear();
                }