Merge branch 'eddie/abc9_refactor' into xaig_dff
authorEddie Hung <eddie@fpgeh.com>
Fri, 16 Aug 2019 23:51:22 +0000 (16:51 -0700)
committerEddie Hung <eddie@fpgeh.com>
Fri, 16 Aug 2019 23:51:22 +0000 (16:51 -0700)
1  2 
backends/aiger/xaiger.cc
frontends/aiger/aigerparse.cc
passes/techmap/abc9.cc
techlibs/xilinx/Makefile.inc
techlibs/xilinx/synth_xilinx.cc

index 5eeae3b82264a39ba2e869f4a04196ef4fcc96ea,41a79d9dd6ce24b94471a7b8781252301bf4af34..5d3677ab302095d81350c39468461453e9bf9d73
@@@ -768,19 -568,18 +726,18 @@@ struct XAigerWrite
                        std::stringstream h_buffer;
                        auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1);
                        write_h_buffer(1);
-                       log_debug("ciNum = %zu\n", input_bits.size() + ff_bits.size() + ci_bits.size());
 -                      log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ci_bits));
 -                      write_h_buffer(input_bits.size() + ci_bits.size());
 -                      log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(co_bits));
 -                      write_h_buffer(output_bits.size() + co_bits.size());
 -                      log_debug("piNum = %d\n", GetSize(input_bits));
 -                      write_h_buffer(input_bits.size());
 -                      log_debug("poNum = %d\n", GetSize(output_bits));
 -                      write_h_buffer(output_bits.size());
++                      log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ff_bits) + GetSize(ci_bits));
 +                      write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size());
-                       log_debug("coNum = %zu\n", output_bits.size() + ff_bits.size() + co_bits.size());
-                       write_h_buffer(output_bits.size() + ff_bits.size() + co_bits.size());
-                       log_debug("piNum = %zu\n", input_bits.size() + ff_bits.size());
-                       write_h_buffer(input_bits.size()+ ff_bits.size());
-                       log_debug("poNum = %zu\n", output_bits.size() + ff_bits.size());
++                      log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(ff_bits) + GetSize(co_bits));
++                      write_h_buffer(output_bits.size() + GetSize(ff_bits) + GetSize(co_bits));
++                      log_debug("piNum = %d\n", GetSize(input_bits) + GetSize(ff_bits));
++                      write_h_buffer(input_bits.size() + ff_bits.size());
++                      log_debug("poNum = %d\n", GetSize(output_bits) + GetSize(ff_bits));
 +                      write_h_buffer(output_bits.size() + ff_bits.size());
-                       log_debug("boxNum = %zu\n", box_list.size());
+                       log_debug("boxNum = %d\n", GetSize(box_list));
                        write_h_buffer(box_list.size());
  
-                       RTLIL::Module *holes_module = nullptr;
-                       holes_module = module->design->addModule("$__holes__");
+                       RTLIL::Module *holes_module = module->design->addModule("$__holes__");
                        log_assert(holes_module);
  
                        int port_id = 1;
                                        if (!cell->type.in("$_NOT_", "$_AND_"))
                                                log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n");
  
-                               Pass::call(holes_module->design, "clean -purge");
+                               holes_module->design->selection_stack.pop_back();
+                               // Move into a new (temporary) design so that "clean" will only
+                               // operate (and run checks on) this one module
+                               RTLIL::Design *holes_design = new RTLIL::Design;
+                               holes_module->design->modules_.erase(holes_module->name);
+                               holes_design->add(holes_module);
+                               Pass::call(holes_design, "clean -purge");
  
                                std::stringstream a_buffer;
 -                              XAigerWriter writer(holes_module, true /* holes_mode */);
 +                              XAigerWriter writer(holes_module, false /*zinit_mode*/, true /* holes_mode */);
                                writer.write_aiger(a_buffer, false /*ascii_mode*/);
  
-                               holes_module->design->selection_stack.pop_back();
+                               delete holes_design;
  
                                f << "a";
                                std::string buffer_str = a_buffer.str();
  
                                if (output_bits.count(b)) {
                                        int o = ordered_outputs.at(b);
 -                                      output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), i, log_id(wire));
 +                                      int init = 2;
 +                                      auto it = init_map.find(b);
 +                                      if (it != init_map.end())
 +                                              init = it->second ? 1 : 0;
-                                       output_lines[o] += stringf("output %lu %d %s %d\n", o - co_bits.size(), i, log_id(wire), init);
++                                      output_lines[o] += stringf("output %d %d %s %d\n", o - GetSize(co_bits), i, log_id(wire), init);
                                        continue;
                                }
  
Simple merge
index b9eb71cf1af8938eeaba1cdc8e157abe0e5041ab,4cdd392b5aa72abd4ceb07e4c955c052ee24d304..50a6e0fe55784534a3cbba7a72c1dd02507a1317
@@@ -86,8 -85,8 +85,8 @@@ void handle_loops(RTLIL::Design *design
        // cell in the component, and select (and mark) all its output
        // wires
        pool<RTLIL::Const> ids_seen;
 -      for (auto cell : module->cells()) {
 +      for (auto cell : module->selected_cells()) {
-               auto it = cell->attributes.find("\\abc_scc_id");
+               auto it = cell->attributes.find(ID(abc_scc_id));
                if (it != cell->attributes.end()) {
                        auto r = ids_seen.insert(it->second);
                        if (r.second) {
@@@ -285,10 -269,12 +269,12 @@@ struct abc_output_filte
  };
  
  void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
 -              bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
 +              bool cleanup, vector<int> lut_costs, bool /*retime_mode*/, std::string clk_str,
                bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
                bool show_tempdir, std::string box_file, std::string lut_file,
-               std::string wire_delay)
+               std::string wire_delay, const dict<int,IdString> &box_lookup,
+               const dict<IdString,pool<IdString>> &scc_break_inputs
+ )
  {
        module = current_module;
        map_autoidx = autoidx++;
                }
                ifs.close();
                Pass::call(design, stringf("write_verilog -noexpr -norename"));
-               design->remove(design->module("$__abc9__"));
+               design->remove(design->module(ID($__abc9__)));
  #endif
  
 -              design->selection_stack.pop_back();
 -
                // Now 'unexpose' those wires by undoing
                // the expose operation -- remove them from PO/PI
                // and re-connecting them back together
  
                dict<IdString, bool> abc_box;
                vector<RTLIL::Cell*> boxes;
 -              for (const auto &it : module->cells_) {
 -                      auto cell = it.second;
 -                      if (cell->type.in(ID($_AND_), ID($_NOT_))) {
 +              for (auto cell : module->selected_cells()) {
-                       if (cell->type.in("$_AND_", "$_NOT_", "$__ABC_FF_")) {
++                      if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC_FF_))) {
                                module->remove(cell);
                                continue;
                        }
                                boxes.emplace_back(cell);
                }
  
-               std::map<std::string, int> cell_stats;
+               dict<SigBit, pool<IdString>> bit_drivers, bit_users;
+               TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
+               dict<RTLIL::Cell*,RTLIL::Cell*> not2drivers;
+               dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;
+               std::map<IdString, int> cell_stats;
                for (auto c : mapped_mod->cells())
                {
+                       toposort.node(c->name);
                        RTLIL::Cell *cell = nullptr;
-                       if (c->type == "$_NOT_") {
-                               RTLIL::SigBit a_bit = c->getPort("\\A").as_bit();
-                               RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit();
+                       if (c->type == ID($_NOT_)) {
+                               RTLIL::SigBit a_bit = c->getPort(ID(A));
+                               RTLIL::SigBit y_bit = c->getPort(ID(Y));
+                               bit_users[a_bit].insert(c->name);
+                               bit_drivers[y_bit].insert(c->name);
                                if (!a_bit.wire) {
-                                       c->setPort("\\Y", module->addWire(NEW_ID));
+                                       c->setPort(ID(Y), module->addWire(NEW_ID));
                                        RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
                                        log_assert(wire);
-                                       module->connect(RTLIL::SigBit(wire, y_bit.offset), RTLIL::S1);
+                                       module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1);
                                }
 -                              else if (!lut_costs.empty() || !lut_file.empty()) {
 -                                      RTLIL::Cell* driver_lut = nullptr;
 +                              else {
 +                                      RTLIL::Cell* driving_lut = nullptr;
                                        // ABC can return NOT gates that drive POs
                                        if (!a_bit.wire->port_input) {
                                                // If it's not a NOT gate that that comes from a PI directly,
                                                        driver_name = stringf("%s$lut", a_bit.wire->name.c_str());
                                                else
                                                        driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset);
 -                                              driver_lut = mapped_mod->cell(driver_name);
 +                                              driving_lut = mapped_mod->cell(driver_name);
                                        }
  
 -                                      if (!driver_lut) {
 +                                      if (!driving_lut) {
-                                               // If a driver couldn't be found (could be from PI,
-                                               // or from a box) then implement using a LUT
+                                               // If a driver couldn't be found (could be from PI or box CI)
+                                               // then implement using a LUT
                                                cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
-                                                               RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset),
-                                                               RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
-                                                               1);
+                                                               RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
+                                                               RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
+                                                               RTLIL::Const::from_string("01"));
+                                               bit2sinks[cell->getPort(ID(A))].push_back(cell);
+                                               cell_stats[ID($lut)]++;
                                        }
-                                       else {
-                                               auto driver_a = driving_lut->getPort("\\A").chunks();
-                                               for (auto &chunk : driver_a)
-                                                       chunk.wire = module->wires_[remap_name(chunk.wire->name)];
-                                               RTLIL::Const driver_lut = driving_lut->getParam("\\LUT");
-                                               for (auto &b : driver_lut.bits) {
-                                                       if (b == RTLIL::State::S0) b = RTLIL::State::S1;
-                                                       else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
-                                               }
-                                               cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
-                                                               driver_a,
-                                                               RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
-                                                               driver_lut);
-                                       }
-                                       cell_stats["$lut"]++;
+                                       else
 -                                              not2drivers[c] = driver_lut;
++                                              not2drivers[c] = driving_lut;
+                                       continue;
                                }
-                               if (cell && markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
 -                              else
 -                                      log_abort();
+                               if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
                                continue;
                        }
-                       cell_stats[RTLIL::unescape_id(c->type)]++;
+                       cell_stats[c->type]++;
  
-                         RTLIL::Cell *existing_cell = nullptr;
-                       if (c->type == "$lut") {
-                               if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
-                                       SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
-                                       SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)];
+                       RTLIL::Cell *existing_cell = nullptr;
+                       if (c->type == ID($lut)) {
+                               if (GetSize(c->getPort(ID(A))) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) {
+                                       SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID(A)).as_wire()->name));
+                                       SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID(Y)).as_wire()->name));
                                        module->connect(my_y, my_a);
-                                         if (markgroups) c->attributes["\\abcgroup"] = map_autoidx;
+                                       if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx;
+                                       log_abort();
                                        continue;
                                }
                                cell = module->addCell(remap_name(c->name), c->type);
@@@ -999,12 -1066,75 +1075,78 @@@ struct Abc9Pass : public Pass 
                }
                extra_args(args, argidx, design);
  
 +              if (lut_costs.empty() && lut_file.empty())
 +                      log_cmd_error("abc9 must be called with '-lut' or '-luts'\n");
 +
+               dict<int,IdString> box_lookup;
+               dict<IdString,pool<IdString>> scc_break_inputs;
+               for (auto m : design->modules()) {
+                       auto it = m->attributes.find(ID(abc_box_id));
+                       if (it == m->attributes.end())
+                               continue;
+                       if (m->name.begins_with("$paramod"))
+                               continue;
+                       auto id = it->second.as_int();
+                       auto r = box_lookup.insert(std::make_pair(id, m->name));
+                       if (!r.second)
+                               log_error("Module '%s' has the same abc_box_id = %d value as '%s'.\n",
+                                               log_id(m), id, log_id(r.first->second));
+                       log_assert(r.second);
+                       RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
+                       for (auto p : m->ports) {
+                               auto w = m->wire(p);
+                               log_assert(w);
+                               if (w->port_input) {
+                                       if (w->attributes.count(ID(abc_scc_break)))
+                                               scc_break_inputs[m->name].insert(p);
+                                       if (w->attributes.count(ID(abc_carry_in))) {
+                                               if (carry_in)
+                                                       log_error("Module '%s' contains more than one 'abc_carry_in' port.\n", log_id(m));
+                                               carry_in = w;
+                                       }
+                               }
+                               if (w->port_output) {
+                                       if (w->attributes.count(ID(abc_carry_out))) {
+                                               if (carry_out)
+                                                       log_error("Module '%s' contains more than one 'abc_carry_out' port.\n", log_id(m));
+                                               carry_out = w;
+                                       }
+                               }
+                       }
+                       if (carry_in || carry_out) {
+                               if (carry_in && !carry_out)
+                                       log_error("Module '%s' contains an 'abc_carry_in' port but no 'abc_carry_out' port.\n", log_id(m));
+                               if (!carry_in && carry_out)
+                                       log_error("Module '%s' contains an 'abc_carry_out' port but no 'abc_carry_in' port.\n", log_id(m));
+                               // Make carry_in the last PI, and carry_out the last PO
+                               //   since ABC requires it this way
+                               auto &ports = m->ports;
+                               for (auto it = ports.begin(); it != ports.end(); ) {
+                                       RTLIL::Wire* w = m->wire(*it);
+                                       log_assert(w);
+                                       if (w == carry_in || w == carry_out) {
+                                               it = ports.erase(it);
+                                               continue;
+                                       }
+                                       if (w->port_id > carry_in->port_id)
+                                               --w->port_id;
+                                       if (w->port_id > carry_out->port_id)
+                                               --w->port_id;
+                                       log_assert(w->port_input || w->port_output);
+                                       log_assert(ports[w->port_id-1] == w->name);
+                                       ++it;
+                               }
+                               ports.push_back(carry_in->name);
+                               carry_in->port_id = ports.size();
+                               ports.push_back(carry_out->name);
+                               carry_out->port_id = ports.size();
+                       }
+               }
                for (auto mod : design->selected_modules())
                {
-                       if (mod->attributes.count("\\abc_box_id"))
+                       if (mod->attributes.count(ID(abc_box_id)))
                                continue;
  
                        if (mod->processes.size() > 0) {
  
                        assign_map.set(mod);
  
 -                      if (!dff_mode || !clk_str.empty()) {
 -                              abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
 +                      if (true || /*!dff_mode ||*/ !clk_str.empty()) {
 +
 +                              design->selection_stack.emplace_back(false);
 +                              RTLIL::Selection& sel = design->selection_stack.back();
 +                              sel.select(mod);
 +
 +                              abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, false, clk_str, keepff,
                                                delay_target, lutin_shared, fast_mode, show_tempdir,
-                                               box_file, lut_file, wire_delay);
+                                               box_file, lut_file, wire_delay, box_lookup, scc_break_inputs);
 +                              design->selection_stack.pop_back();
                                continue;
                        }
  
                                clk_sig = assign_map(std::get<1>(it.first));
                                en_polarity = std::get<2>(it.first);
                                en_sig = assign_map(std::get<3>(it.first));
 +
 +                              pool<RTLIL::IdString> assigned_names;
 +                              for (auto i : it.second)
 +                                      assigned_names.insert(i->name);
 +                              sel.selected_members[mod->name] = std::move(assigned_names);
 +
                                abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$",
                                                keepff, delay_target, lutin_shared, fast_mode, show_tempdir,
-                                               box_file, lut_file, wire_delay);
+                                               box_file, lut_file, wire_delay, box_lookup, scc_break_inputs);
                                assign_map.set(mod);
                        }
 +
 +                      design->selection_stack.pop_back();
                }
  
-               Pass::call(design, "clean");
                assign_map.clear();
  
+               // The "clean" pass also contains a design->check() call
+               Pass::call(design, "clean");
                log_pop();
        }
  } Abc9Pass;
Simple merge
Simple merge