coolrunner2: Fix packed register+input buffer insertion
authorR. Ou <rqou@robertou.com>
Mon, 2 Mar 2020 08:32:36 +0000 (00:32 -0800)
committerR. Ou <rqou@robertou.com>
Mon, 2 Mar 2020 08:32:57 +0000 (00:32 -0800)
The register will be packed with the input buffer if and only if the
input buffer doesn't have any other loads.

techlibs/coolrunner2/coolrunner2_fixup.cc

index c260fafdc180ab0da22fd54b56d6552cdc5e66a1..c9f88c4d21247409cbdf2daa5b237a3dd2b04d29 100644 (file)
@@ -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<SigBit> 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<SigBit, std::pair<int, RTLIL::Cell *>> 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<int, RTLIL::Cell *>(existing_count + 1, cell);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       dict<SigBit, RTLIL::Cell *> ibuf_out_to_packed_reg_cell;
+                       pool<SigBit> 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());