diff options
| author | Maciej Kurc <mkurc@antmicro.com> | 2022-04-28 17:18:26 +0200 | 
|---|---|---|
| committer | Maciej Kurc <mkurc@antmicro.com> | 2022-05-11 16:31:30 +0200 | 
| commit | aafe1a176c821a3919e773b57ac08fb348c91597 (patch) | |
| tree | 7c41b8d2bb8f89fd3d0fcacbf3f3bf1e6be45fc8 /fpga_interchange | |
| parent | 41936fefac2b819ad77204f0ed64ba01e9138c2a (diff) | |
| download | nextpnr-aafe1a176c821a3919e773b57ac08fb348c91597.tar.gz nextpnr-aafe1a176c821a3919e773b57ac08fb348c91597.tar.bz2 nextpnr-aafe1a176c821a3919e773b57ac08fb348c91597.zip | |
Generalized representation of unused LUT pins connections
Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
Diffstat (limited to 'fpga_interchange')
| -rw-r--r-- | fpga_interchange/arch.cc | 43 | ||||
| -rw-r--r-- | fpga_interchange/luts.cc | 82 | ||||
| -rw-r--r-- | fpga_interchange/luts.h | 13 | ||||
| -rw-r--r-- | fpga_interchange/site_arch.cc | 76 | ||||
| -rw-r--r-- | fpga_interchange/site_lut_mapping_cache.cc | 4 | 
5 files changed, 160 insertions, 58 deletions
| diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index e55c94af..05b50ae2 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -874,17 +874,26 @@ static void prepare_sites_for_routing(Context *ctx)      // Fixup LUT vcc pins.      IdString vcc_net_name(ctx->chip_info->constants->vcc_net_name); +    IdString gnd_net_name(ctx->chip_info->constants->gnd_net_name); + +    IdString const_net_name(ctx->chip_info->constants->best_constant_net); +    NPNR_ASSERT(const_net_name == vcc_net_name || const_net_name == gnd_net_name); +      for (BelId bel : ctx->getBels()) {          CellInfo *cell = ctx->getBoundBelCell(bel);          if (cell == nullptr) {              continue;          } -        if (cell->lut_cell.vcc_pins.empty()) { -            continue; -        } +        for (const auto &it : cell->lut_cell.pin_connections) { +            const auto &bel_pin = it.first; +            const auto &conn = it.second; + +            // Connected to an active signal or unconnected +            if (conn == LutCell::PinConnection::Signal || conn == LutCell::PinConnection::Unconnected) { +                continue; +            } -        for (auto bel_pin : cell->lut_cell.vcc_pins) {              // We can't rely on bel pins not clashing with cell names (for Xilinx they use different naming schemes, for              // Nexus they are the same) so add a prefix to the bel pin name to disambiguate it              IdString cell_pin = ctx->id(stringf("%s_PHYS", ctx->nameOf(bel_pin))); @@ -896,17 +905,37 @@ static void prepare_sites_for_routing(Context *ctx)  #ifdef DEBUG_LUT_MAPPING              if (ctx->verbose) { -                log_info("%s must be tied to VCC, tying now\n", ctx->nameOfWire(lut_pin_wire)); +                log_info("%s must be tied to %s, tying now\n", ctx->nameOfWire(lut_pin_wire), +                         LutCell::nameOfPinConnection(conn).c_str());              }  #endif +            IdString tie_net_name; +            switch (conn) { +            case LutCell::PinConnection::Vcc: +                tie_net_name = vcc_net_name; +                break; +            case LutCell::PinConnection::Gnd: +                tie_net_name = gnd_net_name; +                break; +            case LutCell::PinConnection::Const: +                tie_net_name = const_net_name; +                break; +            default: +                // Should never happen +                NPNR_ASSERT_FALSE( +                        stringf("Invalid LUT cell pin connection '%s'", LutCell::nameOfPinConnection(conn).c_str()) +                                .c_str()); +                break; +            } +              auto result = cell->ports.emplace(cell_pin, port_info);              if (result.second) {                  cell->cell_bel_pins[cell_pin].push_back(bel_pin); -                ctx->connectPort(vcc_net_name, cell->name, cell_pin); +                ctx->connectPort(tie_net_name, cell->name, cell_pin);                  cell->const_ports.emplace(cell_pin);              } else { -                NPNR_ASSERT(result.first->second.net == ctx->getNetByAlias(vcc_net_name)); +                NPNR_ASSERT(result.first->second.net == ctx->getNetByAlias(tie_net_name));                  auto result2 = cell->cell_bel_pins.emplace(cell_pin, std::vector<IdString>({bel_pin}));                  NPNR_ASSERT(result2.first->second.at(0) == bel_pin);                  NPNR_ASSERT(result2.first->second.size() == 1); diff --git a/fpga_interchange/luts.cc b/fpga_interchange/luts.cc index d9e17ca9..8c4672c7 100644 --- a/fpga_interchange/luts.cc +++ b/fpga_interchange/luts.cc @@ -47,14 +47,6 @@ bool rotate_and_merge_lut_equation(std::vector<LogicLevel> *result, const LutBel              // This address line is 0, so don't translate this bit to the cell              // address.              if ((bel_address & (1 << bel_pin_idx)) == 0) { -                // This pin is unused, so the line will be tied high, this -                // address is unreachable. -                // -                // FIXME: The assumption is that unused pins are tied VCC. -                // This is not generally true. -                // -                // Use Arch::prefered_constant_net_type to determine what -                // constant net should be used for unused pins.                  if ((used_pins & (1 << bel_pin_idx)) == 0) {                      address_reachable = false;                      break; @@ -132,6 +124,26 @@ struct LutPin      bool operator<(const LutPin &other) const { return max_pin < other.max_pin; }  }; +const std::string LutCell::nameOfPinConnection(LutCell::PinConnection conn) +{ +    switch (conn) { +    case PinConnection::Unconnected: +        return std::string("unconnected"); +    case PinConnection::Gnd: +        return std::string("Gnd"); +    case PinConnection::Vcc: +        return std::string("Vcc"); +    case PinConnection::Const: +        return std::string("Const"); +    case PinConnection::Signal: +        return std::string("Signal"); +    default: +        // Should never happen +        NPNR_ASSERT_FALSE("Invalid value of LutCell::PinConnection"); +        return std::string(); +    } +} +  uint32_t LutMapper::check_wires(const Context *ctx) const  {      // Unlike the 3 argument version of check_wires, this version needs to @@ -184,12 +196,7 @@ uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_          }      } -    // FIXME: The assumption is that unused pins are tied VCC. -    // This is not generally true. -    // -    // Use Arch::prefered_constant_net_type to determine what -    // constant net should be used for unused pins. -    uint32_t vcc_mask = 0; +    uint32_t pin_mask = 0;      DynamicBitarray<> wire_equation;      wire_equation.resize(2); @@ -248,11 +255,11 @@ uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_          bool good_for_wire = valid_pin_for_wire && !invalid_pin_for_wire;          if (!good_for_wire) { -            vcc_mask |= (1 << pin_idx); +            pin_mask |= (1 << pin_idx);          }      } -    return vcc_mask; +    return pin_mask;  }  bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult *lut_mapping, @@ -381,26 +388,18 @@ bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult *lut_mapping      }      // Not all LUT inputs are used -    uint32_t vcc_pins = 0; +    uint32_t pin_mask = 0;      if (cells.size() != element.lut_bels.size()) { -        // Look to see if wires can be run from element inputs to unused -        // outputs. If not, block the BEL pin by tying to VCC. -        // -        // FIXME: The assumption is that unused pins are tied VCC. -        // This is not generally true. -        // -        // Use Arch::prefered_constant_net_type to determine what -        // constant net should be used for unused pins. -        vcc_pins = check_wires(bel_to_cell_pin_remaps, lut_bels, used_pins, blocked_luts); +        pin_mask = check_wires(bel_to_cell_pin_remaps, lut_bels, used_pins, blocked_luts); +    } +  #if defined(DEBUG_LUT_ROTATION) -        log_info("vcc_pins = 0x%x", vcc_pins); -        for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { -            CellInfo *cell = cells[cell_idx]; -            log(", %s => %s", ctx->nameOfBel(cell->bel), cell->name.c_str(ctx)); -        } -        log("\n"); -#endif +    log_info("Cell bindings:\n"); +    for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { +        CellInfo *cell = cells[cell_idx]; +        log_info(" - %s => %s\n", ctx->nameOfBel(cell->bel), cell->name.c_str(ctx));      } +#endif      // Fill in the LUT mapping result @@ -422,28 +421,35 @@ bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult *lut_mapping              cell.belPins[cellPin] = belPin;          } -        cell.lutCell.vcc_pins.clear(); +        cell.lutCell.pin_connections.clear();          // All LUT inputs used          if (cells.size() == element.lut_bels.size()) {              for (size_t bel_pin_idx = 0; bel_pin_idx < lutBel.pins.size(); ++bel_pin_idx) {                  if ((used_pins & (1 << bel_pin_idx)) == 0) {                      NPNR_ASSERT(bel_to_cell_pin_remaps[cell_idx][bel_pin_idx] == -1); -                    cell.lutCell.vcc_pins.emplace(lutBel.pins.at(bel_pin_idx)); +                    cell.lutCell.pin_connections.emplace(lutBel.pins.at(bel_pin_idx), LutCell::PinConnection::Vcc);                  }              }          }          // Only some LUT inputs used          else {              for (size_t bel_pin_idx = 0; bel_pin_idx < lutBel.pins.size(); ++bel_pin_idx) { -                if ((vcc_pins & (1 << bel_pin_idx)) != 0) { +                if ((pin_mask & (1 << bel_pin_idx)) != 0) {                      NPNR_ASSERT(bel_to_cell_pin_remaps[cell_idx][bel_pin_idx] == -1);                      auto pin = lutBel.pins.at(bel_pin_idx); -                    cell.lutCell.vcc_pins.emplace(pin); +                    cell.lutCell.pin_connections.emplace(pin, LutCell::PinConnection::Vcc);                  }              }          } +#if defined(DEBUG_LUT_ROTATION) +        log_info("Pin connections for LUT cell %s:\n", cellInfo->name.c_str(ctx)); +        for (const auto &it : cell.lutCell.pin_connections) { +            log_info(" - %s : %s\n", it.first.c_str(ctx), LutCell::nameOfPinConnection(it.second).c_str()); +        } +#endif +          lut_mapping->cells.push_back(cell);      } @@ -456,7 +462,7 @@ void check_equation(const LutCell &lut_cell, const dict<IdString, IdString> &cel      std::vector<int8_t> pin_map;      pin_map.resize(lut_bel.pins.size(), -1); -    NPNR_ASSERT(lut_cell.pins.size() < std::numeric_limits<decltype(pin_map)::value_type>::max()); +    NPNR_ASSERT(lut_cell.pins.size() < (size_t)std::numeric_limits<decltype(pin_map)::value_type>::max());      for (size_t cell_pin_idx = 0; cell_pin_idx < lut_cell.pins.size(); ++cell_pin_idx) {          IdString cell_pin = lut_cell.pins[cell_pin_idx]; diff --git a/fpga_interchange/luts.h b/fpga_interchange/luts.h index 8f33507a..892f457c 100644 --- a/fpga_interchange/luts.h +++ b/fpga_interchange/luts.h @@ -42,11 +42,22 @@ enum LogicLevel  struct LutCell  { +    enum class PinConnection +    { +        Unconnected, +        Gnd, +        Vcc, +        Const, +        Signal +    }; +      // LUT cell pins for equation, LSB first.      std::vector<IdString> pins;      pool<IdString> lut_pins; -    pool<IdString> vcc_pins; +    dict<IdString, PinConnection> pin_connections;      DynamicBitarray<> equation; + +    static const std::string nameOfPinConnection(PinConnection conn);  };  struct LutBel diff --git a/fpga_interchange/site_arch.cc b/fpga_interchange/site_arch.cc index f78e8af4..bb9c9a11 100644 --- a/fpga_interchange/site_arch.cc +++ b/fpga_interchange/site_arch.cc @@ -133,8 +133,15 @@ SiteArch::SiteArch(const SiteInformation *site_info)      }      // Create list of out of site sources and sinks. -      bool have_vcc_pins = false; +    bool have_gnd_pins = false; + +    IdString vcc_net_name(ctx->chip_info->constants->vcc_net_name); +    IdString gnd_net_name(ctx->chip_info->constants->gnd_net_name); + +    IdString const_net_name(ctx->chip_info->constants->best_constant_net); +    NPNR_ASSERT(const_net_name == vcc_net_name || const_net_name == gnd_net_name); +      for (CellInfo *cell : site_info->cells_in_site) {          for (const auto &pin_pair : cell->cell_bel_pins) {              if (!cell->ports.count(pin_pair.first)) @@ -145,8 +152,18 @@ SiteArch::SiteArch(const SiteInformation *site_info)              }          } -        if (!cell->lut_cell.vcc_pins.empty()) { -            have_vcc_pins = true; +        for (const auto &conn : cell->lut_cell.pin_connections) { +            if (conn.second == LutCell::PinConnection::Vcc) { +                have_vcc_pins = true; +            } else if (conn.second == LutCell::PinConnection::Gnd) { +                have_gnd_pins = true; +            } else if (conn.second == LutCell::PinConnection::Const) { +                if (const_net_name == vcc_net_name) { +                    have_vcc_pins = true; +                } else if (const_net_name == gnd_net_name) { +                    have_gnd_pins = true; +                } +            }          }      } @@ -239,10 +256,9 @@ SiteArch::SiteArch(const SiteInformation *site_info)          }      } -    IdString vcc_net_name(ctx->chip_info->constants->vcc_net_name);      NetInfo *vcc_net = ctx->nets.at(vcc_net_name).get(); -    auto iter = nets.find(vcc_net); -    if (iter == nets.end() && have_vcc_pins) { +    auto vcc_iter = nets.find(vcc_net); +    if (vcc_iter == nets.end() && have_vcc_pins) {          // VCC net isn't present, add it.          SiteNetInfo net_info;          net_info.net = vcc_net; @@ -250,13 +266,53 @@ SiteArch::SiteArch(const SiteInformation *site_info)          net_info.driver.net = vcc_net;          auto result = nets.emplace(vcc_net, net_info);          NPNR_ASSERT(result.second); -        iter = result.first; +        vcc_iter = result.first; +    } + +    NetInfo *gnd_net = ctx->nets.at(gnd_net_name).get(); +    auto gnd_iter = nets.find(gnd_net); +    if (gnd_iter == nets.end() && have_gnd_pins) { +        // GND net isn't present, add it. +        SiteNetInfo net_info; +        net_info.net = gnd_net; +        net_info.driver.type = SiteWire::OUT_OF_SITE_SOURCE; +        net_info.driver.net = gnd_net; +        auto result = nets.emplace(gnd_net, net_info); +        NPNR_ASSERT(result.second); +        gnd_iter = result.first;      }      for (CellInfo *cell : site_info->cells_in_site) { -        for (IdString vcc_pin : cell->lut_cell.vcc_pins) { -            SiteWire wire = getBelPinWire(cell->bel, vcc_pin); -            iter->second.users.emplace(wire); +        for (const auto &it : cell->lut_cell.pin_connections) { +            const auto &pin = it.first; +            const auto &conn = it.second; + +            if (conn == LutCell::PinConnection::Unconnected || conn == LutCell::PinConnection::Signal) { +                continue; +            } + +            if (conn == LutCell::PinConnection::Vcc) { +                SiteWire wire = getBelPinWire(cell->bel, pin); +                vcc_iter->second.users.emplace(wire); +            } else if (conn == LutCell::PinConnection::Gnd) { +                SiteWire wire = getBelPinWire(cell->bel, pin); +                gnd_iter->second.users.emplace(wire); +            } else if (conn == LutCell::PinConnection::Const) { +                SiteWire wire = getBelPinWire(cell->bel, pin); +                if (const_net_name == vcc_net_name) { +                    vcc_iter->second.users.emplace(wire); +                } +                if (const_net_name == gnd_net_name) { +                    gnd_iter->second.users.emplace(wire); +                } +            } + +#ifdef DEBUG_LUT_MAPPING +            if (ctx->verbose) { +                log_info("Tying %s.%s to %s\n", cell->name.c_str(ctx), pin.c_str(ctx), +                         LutCell::nameOfPinConnection(conn).c_str()); +            } +#endif          }      } diff --git a/fpga_interchange/site_lut_mapping_cache.cc b/fpga_interchange/site_lut_mapping_cache.cc index b7a71397..82832ed9 100644 --- a/fpga_interchange/site_lut_mapping_cache.cc +++ b/fpga_interchange/site_lut_mapping_cache.cc @@ -138,8 +138,8 @@ bool SiteLutMappingResult::apply(const SiteInformation &siteInfo)          }          // LUT data -        // FIXME: Is there any other info that is being updated than vcc_pins ? -        cellInfo->lut_cell.vcc_pins = std::move(cell.lutCell.vcc_pins); +        // FIXME: Is there any other info that is being updated than pin_connections ? +        cellInfo->lut_cell.pin_connections = std::move(cell.lutCell.pin_connections);      }      return true; | 
