diff --git a/techlibs/coolrunner2/coolrunner2_fixup.cc b/techlibs/coolrunner2/coolrunner2_fixup.cc index c260fafdc..c9f88c4d2 100644 --- a/techlibs/coolrunner2/coolrunner2_fixup.cc +++ b/techlibs/coolrunner2/coolrunner2_fixup.cc @@ -41,6 +41,14 @@ RTLIL::Wire *makexorbuffer(RTLIL::Module *module, SigBit inwire) xor_cell->setParam("\\INVERT_OUT", false); xor_cell->setPort("\\OUT", outwire); } + else if (inwire == SigBit(RTLIL::State::Sx)) + { + // x; treat as 0 + log_warning("While buffering, changing x to 0 on wire %s\n", outwire->name.c_str()); + auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR"); + xor_cell->setParam("\\INVERT_OUT", false); + xor_cell->setPort("\\OUT", outwire); + } else { auto and_to_xor_wire = module->addWire(NEW_ID); @@ -174,6 +182,74 @@ struct Coolrunner2FixupPass : public Pass { } } + // This is used to fix the input -> FF -> output scenario + pool sig_fed_by_ibuf; + for (auto cell : module->selected_cells()) + { + if (cell->type == "\\IBUF") + { + auto output = sigmap(cell->getPort("\\O")[0]); + sig_fed_by_ibuf.insert(output); + } + } + + // Find all of the sinks for each output from an IBUF + dict> ibuf_fanouts; + for (auto cell : module->selected_cells()) + { + for (auto &conn : cell->connections()) + { + if (cell->input(conn.first)) + { + for (auto wire_in : sigmap(conn.second)) + { + if (sig_fed_by_ibuf[wire_in]) + { + auto existing_count = ibuf_fanouts[wire_in].first; + ibuf_fanouts[wire_in] = + std::pair(existing_count + 1, cell); + } + } + } + } + } + + dict ibuf_out_to_packed_reg_cell; + pool packed_reg_out; + for (auto x : ibuf_fanouts) + { + auto ibuf_out_wire = x.first; + auto fanout_count = x.second.first; + auto maybe_ff_cell = x.second.second; + + // The register can be packed with the IBUF only if it's + // actually a register and it's the only fanout. Otherwise, + // the pad-to-zia path has to be used up and the register + // can't be packed with the ibuf. + if (fanout_count == 1 && maybe_ff_cell->type.in( + "\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N", + "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE")) + { + SigBit input; + if (maybe_ff_cell->type.in("\\FTCP", "\\FTCP_N", "\\FTDCP")) + input = sigmap(maybe_ff_cell->getPort("\\T")[0]); + else + input = sigmap(maybe_ff_cell->getPort("\\D")[0]); + SigBit output = sigmap(maybe_ff_cell->getPort("\\Q")[0]); + + if (input == ibuf_out_wire) + { + log("Found IBUF %s that can be packed with FF %s (type %s)\n", + ibuf_out_wire.wire->name.c_str(), + maybe_ff_cell->name.c_str(), + maybe_ff_cell->type.c_str()); + + ibuf_out_to_packed_reg_cell[ibuf_out_wire] = maybe_ff_cell; + packed_reg_out.insert(output); + } + } + } + for (auto cell : module->selected_cells()) { if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N", @@ -188,7 +264,12 @@ struct Coolrunner2FixupPass : public Pass { else input = sigmap(cell->getPort("\\D")[0]); - if (!sig_fed_by_xor[input] && !sig_fed_by_io[input]) + // If the input wasn't an XOR nor an IO, then a buffer + // definitely needs to be added. + // Otherwise, if it is an IO, only leave unbuffered + // if we're being packed with the IO. + if ((!sig_fed_by_xor[input] && !sig_fed_by_io[input]) || + (sig_fed_by_io[input] && ibuf_out_to_packed_reg_cell[input] != cell)) { log("Buffering input to \"%s\"\n", cell->name.c_str()); @@ -278,7 +359,8 @@ struct Coolrunner2FixupPass : public Pass { // Buffer IOBUFE inputs. This can only be fed from an XOR or FF. SigBit input = sigmap(cell->getPort("\\I")[0]); - if (!sig_fed_by_xor[input] && !sig_fed_by_ff[input]) + if ((!sig_fed_by_xor[input] && !sig_fed_by_ff[input]) || + packed_reg_out[input]) { log("Buffering input to \"%s\"\n", cell->name.c_str());