+#ifndef NDEBUG
+ if (ys_debug(1)) {
+ static std::set<std::tuple<IdString,IdString,int>> seen;
+ if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n",
+ log_id(cell->type), log_id(conn.first), i, d);
+ }
+#endif
+ auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY));
+ box->setPort(ID(I), conn.second[i]);
+ box->setPort(ID(O), O[i]);
+ box->setParam(ID(DELAY), d);
+ conn.second[i] = O[i];
+ }
+ }
+ }
+}
+
+void prep_lut(RTLIL::Design *design, int maxlut)
+{
+ TimingInfo timing;
+
+ std::vector<std::tuple<int, IdString, int, std::vector<int>>> table;
+ for (auto module : design->modules()) {
+ auto it = module->attributes.find(ID(abc9_lut));
+ if (it == module->attributes.end())
+ continue;
+
+ auto &t = timing.setup_module(module);
+
+ TimingInfo::NameBit o;
+ std::vector<int> specify;
+ for (const auto &i : t.comb) {
+ auto &d = i.first.second;
+ if (o == TimingInfo::NameBit())
+ o = d;
+ else if (o != d)
+ log_error("(* abc9_lut *) module '%s' with has more than one output.\n", log_id(module));
+ specify.push_back(i.second);
+ }
+
+ if (maxlut && GetSize(specify) > maxlut)
+ continue;
+ // ABC requires non-decreasing LUT input delays
+ std::sort(specify.begin(), specify.end());
+ table.emplace_back(GetSize(specify), module->name, it->second.as_int(), std::move(specify));
+ }
+ // ABC requires ascending size
+ std::sort(table.begin(), table.end());
+
+ std::stringstream ss;
+ const auto &first = table.front();
+ // If the first entry does not start from a 1-input LUT,
+ // (as ABC requires) crop the first entry to do so
+ for (int i = 1; i < std::get<0>(first); i++) {
+ ss << "# $__ABC9_LUT" << i << std::endl;
+ ss << i << " " << std::get<2>(first);
+ for (int j = 0; j < i; j++)
+ ss << " " << std::get<3>(first)[j];
+ ss << std::endl;
+ }
+ for (const auto &i : table) {
+ ss << "# " << log_id(std::get<1>(i)) << std::endl;
+ ss << std::get<0>(i) << " " << std::get<2>(i);
+ for (const auto &j : std::get<3>(i))
+ ss << " " << j;
+ ss << std::endl;
+ }
+ design->scratchpad_set_string("abc9_ops.lut_library", ss.str());
+}
+
+void write_lut(RTLIL::Module *module, const std::string &dst) {
+ std::ofstream ofs(dst);
+ log_assert(ofs.is_open());
+ ofs << module->design->scratchpad_get_string("abc9_ops.lut_library");
+ ofs.close();
+}
+
+void prep_box(RTLIL::Design *design, bool dff_mode)
+{
+ TimingInfo timing;
+
+ std::stringstream ss;
+ int abc9_box_id = 1;
+ for (auto module : design->modules()) {
+ auto it = module->attributes.find(ID(abc9_box_id));
+ if (it == module->attributes.end())
+ continue;
+ abc9_box_id = std::max(abc9_box_id, it->second.as_int());
+ }
+
+ dict<IdString,std::vector<IdString>> box_ports;
+ for (auto module : design->modules()) {
+ auto abc9_flop = module->get_bool_attribute(ID(abc9_flop));
+ if (abc9_flop) {
+ auto r = module->attributes.insert(ID(abc9_box_id));
+ if (!r.second)
+ continue;
+ r.first->second = abc9_box_id++;
+
+ if (dff_mode) {
+ int num_inputs = 0, num_outputs = 0;
+ for (auto port_name : module->ports) {
+ auto wire = module->wire(port_name);
+ log_assert(GetSize(wire) == 1);
+ if (wire->port_input) num_inputs++;
+ if (wire->port_output) num_outputs++;
+ }
+ log_assert(num_outputs == 1);
+
+ ss << log_id(module) << " " << r.first->second.as_int();
+ ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
+ ss << " " << num_inputs+1 << " " << num_outputs << std::endl;
+
+ ss << "#";
+ bool first = true;
+ for (auto port_name : module->ports) {
+ auto wire = module->wire(port_name);
+ if (!wire->port_input)