+void prep_delays(RTLIL::Design *design)
+{
+ std::set<int> delays;
+ pool<Module*> flops;
+ std::vector<Cell*> cells;
+ dict<IdString,dict<IdString,std::vector<int>>> requireds_cache;
+ for (auto module : design->selected_modules()) {
+ if (module->processes.size() > 0) {
+ log("Skipping module %s as it contains processes.\n", log_id(module));
+ continue;
+ }
+
+ cells.clear();
+ for (auto cell : module->cells()) {
+ if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY)))
+ continue;
+
+ RTLIL::Module* inst_module = module->design->module(cell->type);
+ if (!inst_module)
+ continue;
+ if (!inst_module->get_blackbox_attribute())
+ continue;
+ if (inst_module->get_bool_attribute(ID(abc9_flop))) {
+ IdString derived_type = inst_module->derive(design, cell->parameters);
+ inst_module = design->module(derived_type);
+ log_assert(inst_module);
+ flops.insert(inst_module);
+ continue; // because all flop required times
+ // will be captured in the flop box
+ }
+ if (inst_module->attributes.count(ID(abc9_box_id)))
+ continue;
+ cells.emplace_back(cell);
+ }
+
+ delays.clear();
+ for (auto cell : cells) {
+ RTLIL::Module* inst_module = module->design->module(cell->type);
+ log_assert(inst_module);
+ auto &cell_requireds = requireds_cache[cell->type];
+ for (auto &conn : cell->connections_) {
+ auto port_wire = inst_module->wire(conn.first);
+ if (!port_wire->port_input)
+ continue;
+
+ auto r = cell_requireds.insert(conn.first);
+ auto &requireds = r.first->second;
+ if (r.second) {
+ auto it = port_wire->attributes.find("\\abc9_required");
+ if (it == port_wire->attributes.end())
+ continue;
+ if (it->second.flags == 0) {
+ int delay = it->second.as_int();
+ delays.insert(delay);
+ requireds.emplace_back(delay);
+ }
+ else
+ for (const auto &tok : split_tokens(it->second.decode_string())) {
+ int delay = atoi(tok.c_str());
+ delays.insert(delay);
+ requireds.push_back(delay);
+ }
+ }
+
+ if (requireds.empty())
+ continue;
+ if (GetSize(requireds) > 1 && GetSize(requireds) != GetSize(port_wire))
+ log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first),
+ GetSize(port_wire), log_signal(port_wire->attributes.at("\\abc9_required")), GetSize(requireds));
+
+ SigSpec O = module->addWire(NEW_ID, GetSize(conn.second));
+ auto it = requireds.begin();
+ for (int i = 0; i < GetSize(conn.second); ++i) {
+#ifndef NDEBUG
+ if (ys_debug(1)) {
+ static std::set<std::pair<IdString,IdString>> seen;
+ if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_required = %d\n", log_id(cell->type), log_id(conn.first), requireds[i]);
+ }
+#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), *it);
+ if (requireds.size() > 1)
+ it++;
+ conn.second[i] = O[i];
+ }
+ }
+ }
+
+ std::stringstream ss;
+ bool first = true;
+ for (auto d : delays) {
+ if (first)
+ first = false;
+ else
+ ss << " ";
+ ss << d;
+ }
+ module->attributes[ID(abc9_delays)] = ss.str();
+ }
+
+ int flops_id = ABC9_FLOPS_BASE_ID;
+ std::stringstream ss;
+ for (auto flop_module : flops) {
+ int num_inputs = 0, num_outputs = 0;
+ for (auto port_name : flop_module->ports) {
+ auto wire = flop_module->wire(port_name);
+ if (wire->port_input) num_inputs++;
+ if (wire->port_output) num_outputs++;
+ }
+ log_assert(num_outputs == 1);
+
+ auto r = flop_module->attributes.insert(ID(abc9_box_id));
+ if (r.second)
+ r.first->second = flops_id++;
+
+ ss << log_id(flop_module) << " " << r.first->second.as_int();
+ ss << " 1 " << num_inputs+1 << " " << num_outputs << std::endl;
+ bool first = true;
+ for (auto port_name : flop_module->ports) {
+ auto wire = flop_module->wire(port_name);
+ if (!wire->port_input)
+ continue;
+ if (first)
+ first = false;
+ else
+ ss << " ";
+ ss << wire->attributes.at("\\abc9_required", 0).as_int();
+ }
+ // Last input is 'abc9_ff.Q'
+ ss << " 0" << std::endl << std::endl;
+ }
+ design->scratchpad_set_string("abc9_ops.box.flops", ss.str());
+}
+
+void write_box(RTLIL::Module *module, const std::string &src, const std::string &dst) {
+ std::ofstream ofs(dst);
+ log_assert(ofs.is_open());
+
+ // Since ABC can only accept one box file, we have to copy
+ // over the existing box file
+ if (src != "(null)") {
+ std::ifstream ifs(src);
+ ofs << ifs.rdbuf() << std::endl;
+ ifs.close();
+ }
+
+ ofs << module->design->scratchpad_get_string("abc9_ops.box.flops");
+
+ auto it = module->attributes.find(ID(abc9_delays));
+ if (it != module->attributes.end()) {
+ for (const auto &tok : split_tokens(it->second.decode_string())) {
+ int d = atoi(tok.c_str());
+ ofs << "$__ABC9_DELAY@" << d << " " << ABC9_DELAY_BASE_ID + d << " 0 1 1" << std::endl;
+ ofs << d << std::endl;
+ }
+ module->attributes.erase(it);
+ }
+
+ ofs.close();
+}
+