+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();
+}
+
+void reintegrate(RTLIL::Module *module)
+{
+ auto design = module->design;
+ log_assert(design);
+
+ map_autoidx = autoidx++;
+
+ RTLIL::Module *mapped_mod = design->module(stringf("%s$abc9", module->name.c_str()));
+ if (mapped_mod == NULL)
+ log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module));
+
+ for (auto w : mapped_mod->wires())
+ module->addWire(remap_name(w->name), GetSize(w));
+
+ std::vector<Cell*> boxes;
+ for (auto cell : module->cells().to_vector()) {
+ if (cell->has_keep_attr())
+ continue;
+ if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_)))
+ module->remove(cell);
+ else if (cell->attributes.erase("\\abc9_box_seq"))
+ boxes.emplace_back(cell);
+ }
+
+ 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;
+
+ dict<IdString,std::vector<IdString>> box_ports;
+ std::map<IdString, int> cell_stats;
+ for (auto mapped_cell : mapped_mod->cells())
+ {
+ toposort.node(mapped_cell->name);
+
+ if (mapped_cell->type == ID($_NOT_)) {
+ RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A);
+ RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y);
+ bit_users[a_bit].insert(mapped_cell->name);
+ // Ignore inouts for topo ordering
+ if (y_bit.wire && !(y_bit.wire->port_input && y_bit.wire->port_output))
+ bit_drivers[y_bit].insert(mapped_cell->name);
+
+ if (!a_bit.wire) {
+ mapped_cell->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), State::S1);
+ }
+ else {
+ RTLIL::Cell* driver_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,
+ // find the driver LUT and clone that to guarantee that we won't
+ // increase the max logic depth
+ // (TODO: Optimise by not cloning unless will increase depth)
+ RTLIL::IdString driver_name;
+ if (GetSize(a_bit.wire) == 1)
+ driver_name = stringf("$lut%s", a_bit.wire->name.c_str());
+ else
+ driver_name = stringf("$lut%s[%d]", a_bit.wire->name.c_str(), a_bit.offset);
+ driver_lut = mapped_mod->cell(driver_name);
+ }
+
+ if (!driver_lut) {
+ // If a driver couldn't be found (could be from PI or box CI)
+ // then implement using a LUT
+ RTLIL::Cell *cell = module->addLut(remap_name(stringf("$lut%s", mapped_cell->name.c_str())),
+ 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)]++;