diff options
| -rw-r--r-- | fpga_interchange/arch.cc | 243 | ||||
| -rw-r--r-- | fpga_interchange/arch.h | 54 | ||||
| -rw-r--r-- | fpga_interchange/arch_pack_io.cc | 4 | ||||
| -rw-r--r-- | fpga_interchange/dedicated_interconnect.cc | 524 | ||||
| -rw-r--r-- | fpga_interchange/dedicated_interconnect.h | 40 | ||||
| -rw-r--r-- | fpga_interchange/fpga_interchange.cpp | 52 | ||||
| -rw-r--r-- | fpga_interchange/site_router.cc | 86 | ||||
| -rw-r--r-- | fpga_interchange/site_router.h | 45 | 
8 files changed, 626 insertions, 422 deletions
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index 776fbdb0..dc99f1cd 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -195,10 +195,7 @@ Arch::Arch(ArchArgs args) : args(args)      default_tags.resize(max_tag_count);  } - -void Arch::init() { -    dedicated_interconnect.init(getCtx()); -} +void Arch::init() { dedicated_interconnect.init(getCtx()); }  // ----------------------------------------------------------------------- @@ -615,6 +612,14 @@ bool Arch::place()  {      std::string placer = str_or_default(settings, id("placer"), defaultPlacer); +    // Re-map BEL pins without constant pins +    for (BelId bel : getBels()) { +        CellInfo *cell = getBoundBelCell(bel); +        if (cell != nullptr && cell->cell_mapping != -1) { +            map_cell_pins(cell, cell->cell_mapping, /*bind_constants=*/false); +        } +    } +      if (placer == "heap") {          PlacerHeapCfg cfg(getCtx());          cfg.criticalityExponent = 7; @@ -644,6 +649,14 @@ bool Arch::route()  {      std::string router = str_or_default(settings, id("router"), defaultRouter); +    // Re-map BEL pins with constant pins +    for (BelId bel : getBels()) { +        CellInfo *cell = getBoundBelCell(bel); +        if (cell != nullptr && cell->cell_mapping != -1) { +            map_cell_pins(cell, cell->cell_mapping, /*bind_constants=*/true); +        } +    } +      bool result;      if (router == "router1") {          result = router1(getCtx(), Router1Cfg(getCtx())); @@ -683,13 +696,33 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; };  delay_t Arch::estimateDelay(WireId src, WireId dst) const  {      // FIXME: Implement something to push the A* router in the right direction. -    return 0; +    int src_x, src_y; +    get_tile_x_y(src.tile, &src_x, &src_y); + +    int dst_x, dst_y; +    get_tile_x_y(dst.tile, &dst_x, &dst_y); + +    delay_t base = 30 * std::min(std::abs(dst_x - src_x), 18) + 10 * std::max(std::abs(dst_x - src_x) - 18, 0) + +                   60 * std::min(std::abs(dst_y - src_y), 6) + 20 * std::max(std::abs(dst_y - src_y) - 6, 0) + 300; + +    base = (base * 3) / 2; +    return base;  }  delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const  {      // FIXME: Implement when adding timing-driven place and route. -    return 0; +    int src_x, src_y; +    get_tile_x_y(net_info->driver.cell->bel.tile, &src_x, &src_y); + +    int dst_x, dst_y; +    get_tile_x_y(sink.cell->bel.tile, &dst_x, &dst_y); + +    delay_t base = 30 * std::min(std::abs(dst_x - src_x), 18) + 10 * std::max(std::abs(dst_x - src_x) - 18, 0) + +                   60 * std::min(std::abs(dst_y - src_y), 6) + 20 * std::max(std::abs(dst_y - src_y) - 6, 0) + 300; + +    base = (base * 3) / 2; +    return base;  }  bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const @@ -755,57 +788,64 @@ const std::vector<std::string> Arch::availablePlacers = {"sa",  const std::string Arch::defaultRouter = "router2";  const std::vector<std::string> Arch::availableRouters = {"router1", "router2"}; -void Arch::map_cell_pins(CellInfo *cell, int32_t mapping) +void Arch::map_cell_pins(CellInfo *cell, int32_t mapping, bool bind_constants)  {      cell->cell_mapping = mapping;      cell->cell_bel_pins.clear(); +    for (IdString const_port : cell->const_ports) { +        NPNR_ASSERT(cell->ports.erase(const_port)); +    }      const CellBelMapPOD &cell_pin_map = chip_info->cell_map->cell_bel_map[mapping]; +    IdString gnd_net_name(chip_info->constants->gnd_net_name); +    IdString vcc_net_name(chip_info->constants->vcc_net_name); +      for (const auto &pin_map : cell_pin_map.common_pins) {          IdString cell_pin(pin_map.cell_pin);          IdString bel_pin(pin_map.bel_pin);          if (cell_pin.str(this) == "GND") { -            IdString gnd_net_name(chip_info->constants->gnd_net_name); - -            PortInfo port_info; -            port_info.name = bel_pin; -            port_info.type = PORT_IN; -            port_info.net = nullptr; +            if (bind_constants) { +                PortInfo port_info; +                port_info.name = bel_pin; +                port_info.type = PORT_IN; +                port_info.net = nullptr; -            auto result = cell->ports.emplace(bel_pin, port_info); -            if(result.second) { -                cell->cell_bel_pins[bel_pin].push_back(bel_pin); -                connectPort(gnd_net_name, cell->name, bel_pin); -            } else { -                NPNR_ASSERT(result.first->second.net == getNetByAlias(gnd_net_name)); -                auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin})); -                NPNR_ASSERT(result2.first->second.at(0) == bel_pin); -                NPNR_ASSERT(result2.first->second.size() == 1); +                auto result = cell->ports.emplace(bel_pin, port_info); +                if (result.second) { +                    cell->cell_bel_pins[bel_pin].push_back(bel_pin); +                    connectPort(gnd_net_name, cell->name, bel_pin); +                    cell->const_ports.emplace(bel_pin); +                } else { +                    NPNR_ASSERT(result.first->second.net == getNetByAlias(gnd_net_name)); +                    auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin})); +                    NPNR_ASSERT(result2.first->second.at(0) == bel_pin); +                    NPNR_ASSERT(result2.first->second.size() == 1); +                }              }              continue;          }          if (cell_pin.str(this) == "VCC") { -            IdString vcc_net_name(chip_info->constants->vcc_net_name); - -            PortInfo port_info; -            port_info.name = bel_pin; -            port_info.type = PORT_IN; -            port_info.net = nullptr; +            if (bind_constants) { +                PortInfo port_info; +                port_info.name = bel_pin; +                port_info.type = PORT_IN; +                port_info.net = nullptr; -            auto result = cell->ports.emplace(bel_pin, port_info); -            if(result.second) { -                cell->cell_bel_pins[bel_pin].push_back(bel_pin); -                connectPort(vcc_net_name, cell->name, bel_pin); -            } else { -                NPNR_ASSERT(result.first->second.net == getNetByAlias(vcc_net_name)); -                auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin})); -                NPNR_ASSERT(result2.first->second.at(0) == bel_pin); -                NPNR_ASSERT(result2.first->second.size() == 1); +                auto result = cell->ports.emplace(bel_pin, port_info); +                if (result.second) { +                    cell->cell_bel_pins[bel_pin].push_back(bel_pin); +                    connectPort(vcc_net_name, cell->name, bel_pin); +                    cell->const_ports.emplace(bel_pin); +                } else { +                    NPNR_ASSERT(result.first->second.net == getNetByAlias(vcc_net_name)); +                    auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin})); +                    NPNR_ASSERT(result2.first->second.at(0) == bel_pin); +                    NPNR_ASSERT(result2.first->second.size() == 1); +                }              } -              continue;          } @@ -830,30 +870,44 @@ void Arch::map_cell_pins(CellInfo *cell, int32_t mapping)              IdString bel_pin(pin_map.bel_pin);              if (cell_pin.str(this) == "GND") { -                PortInfo port_info; -                port_info.name = bel_pin; -                port_info.type = PORT_IN; - -                auto result = cell->ports.emplace(bel_pin, port_info); -                NPNR_ASSERT(result.second); - -                cell->cell_bel_pins[bel_pin].push_back(bel_pin); - -                connectPort(IdString(chip_info->constants->gnd_net_name), cell->name, bel_pin); +                if (bind_constants) { +                    PortInfo port_info; +                    port_info.name = bel_pin; +                    port_info.type = PORT_IN; + +                    auto result = cell->ports.emplace(bel_pin, port_info); +                    if (result.second) { +                        cell->cell_bel_pins[bel_pin].push_back(bel_pin); +                        connectPort(gnd_net_name, cell->name, bel_pin); +                        cell->const_ports.emplace(bel_pin); +                    } else { +                        NPNR_ASSERT(result.first->second.net == getNetByAlias(gnd_net_name)); +                        auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin})); +                        NPNR_ASSERT(result2.first->second.at(0) == bel_pin); +                        NPNR_ASSERT(result2.first->second.size() == 1); +                    } +                }                  continue;              }              if (cell_pin.str(this) == "VCC") { -                PortInfo port_info; -                port_info.name = bel_pin; -                port_info.type = PORT_IN; - -                auto result = cell->ports.emplace(bel_pin, port_info); -                NPNR_ASSERT(result.second); - -                cell->cell_bel_pins[bel_pin].push_back(bel_pin); - -                connectPort(IdString(chip_info->constants->vcc_net_name), cell->name, bel_pin); +                if (bind_constants) { +                    PortInfo port_info; +                    port_info.name = bel_pin; +                    port_info.type = PORT_IN; + +                    auto result = cell->ports.emplace(bel_pin, port_info); +                    if (result.second) { +                        cell->cell_bel_pins[bel_pin].push_back(bel_pin); +                        connectPort(vcc_net_name, cell->name, bel_pin); +                        cell->const_ports.emplace(bel_pin); +                    } else { +                        NPNR_ASSERT(result.first->second.net == getNetByAlias(vcc_net_name)); +                        auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin})); +                        NPNR_ASSERT(result2.first->second.at(0) == bel_pin); +                        NPNR_ASSERT(result2.first->second.size() == 1); +                    } +                }                  continue;              } @@ -912,9 +966,10 @@ size_t Arch::get_cell_type_index(IdString cell_type) const      return cell_offset;  } -void Arch::merge_constant_nets() { -    NetInfo* gnd_net = nullptr; -    NetInfo* vcc_net = nullptr; +void Arch::merge_constant_nets() +{ +    NetInfo *gnd_net = nullptr; +    NetInfo *vcc_net = nullptr;      bool need_gnd_source = false;      bool need_vcc_source = false; @@ -924,7 +979,7 @@ void Arch::merge_constant_nets() {      IdString gnd_cell_port(chip_info->constants->gnd_cell_port);      auto gnd_iter = nets.find(gnd_net_name); -    if(gnd_iter != nets.end()) { +    if (gnd_iter != nets.end()) {          NPNR_ASSERT(gnd_iter->second->driver.cell != nullptr);          NPNR_ASSERT(gnd_iter->second->driver.cell->type == gnd_cell_type);          NPNR_ASSERT(gnd_iter->second->driver.port == gnd_cell_port); @@ -940,7 +995,7 @@ void Arch::merge_constant_nets() {      IdString vcc_cell_port(chip_info->constants->vcc_cell_port);      auto vcc_iter = nets.find(vcc_net_name); -    if(vcc_iter != nets.end()) { +    if (vcc_iter != nets.end()) {          NPNR_ASSERT(vcc_iter->second->driver.cell != nullptr);          NPNR_ASSERT(vcc_iter->second->driver.cell->type == vcc_cell_type);          NPNR_ASSERT(vcc_iter->second->driver.port == vcc_cell_port); @@ -954,28 +1009,28 @@ void Arch::merge_constant_nets() {      std::vector<IdString> other_gnd_nets;      std::vector<IdString> other_vcc_nets; -    for(auto & net_pair : nets) { -        if(net_pair.first == gnd_net_name) { +    for (auto &net_pair : nets) { +        if (net_pair.first == gnd_net_name) {              NPNR_ASSERT(net_pair.second.get() == gnd_net);              continue;          } -        if(net_pair.first == vcc_net_name) { +        if (net_pair.first == vcc_net_name) {              NPNR_ASSERT(net_pair.second.get() == vcc_net);              continue;          }          NetInfo *net = net_pair.second.get(); -        if(net->driver.cell == nullptr) { +        if (net->driver.cell == nullptr) {              continue;          } -        if(net->driver.cell->type == gnd_cell_type) { +        if (net->driver.cell->type == gnd_cell_type) {              NPNR_ASSERT(net->driver.port == gnd_cell_port);              other_gnd_nets.push_back(net_pair.first); -            if(need_gnd_source) { +            if (need_gnd_source) {                  IdString driver_cell = net->driver.cell->name;                  disconnectPort(driver_cell, gnd_cell_port);                  connectPort(gnd_net_name, driver_cell, gnd_cell_port); @@ -984,7 +1039,7 @@ void Arch::merge_constant_nets() {              NPNR_ASSERT(net->driver.port == gnd_cell_port);              std::vector<PortRef> users_copy = net->users; -            for(const PortRef & port_ref : users_copy) { +            for (const PortRef &port_ref : users_copy) {                  IdString cell = port_ref.cell->name;                  disconnectPort(cell, port_ref.port);                  connectPort(gnd_net_name, cell, port_ref.port); @@ -993,12 +1048,12 @@ void Arch::merge_constant_nets() {              continue;          } -        if(net->driver.cell->type == vcc_cell_type) { +        if (net->driver.cell->type == vcc_cell_type) {              NPNR_ASSERT(net->driver.port == vcc_cell_port);              other_vcc_nets.push_back(net_pair.first); -            if(need_vcc_source) { +            if (need_vcc_source) {                  IdString driver_cell = net->driver.cell->name;                  disconnectPort(driver_cell, vcc_cell_port);                  connectPort(vcc_net_name, driver_cell, vcc_cell_port); @@ -1007,7 +1062,7 @@ void Arch::merge_constant_nets() {              NPNR_ASSERT(net->driver.port == vcc_cell_port);              std::vector<PortRef> users_copy = net->users; -            for(const PortRef & port_ref : users_copy) { +            for (const PortRef &port_ref : users_copy) {                  IdString cell = port_ref.cell->name;                  disconnectPort(cell, port_ref.port);                  connectPort(vcc_net_name, cell, port_ref.port); @@ -1015,10 +1070,10 @@ void Arch::merge_constant_nets() {          }      } -    for(IdString other_gnd_net : other_gnd_nets) { -        NetInfo * net = getNetByAlias(other_gnd_net); +    for (IdString other_gnd_net : other_gnd_nets) { +        NetInfo *net = getNetByAlias(other_gnd_net);          NPNR_ASSERT(net->users.empty()); -        if(net->driver.cell) { +        if (net->driver.cell) {              PortRef driver = net->driver;              IdString cell_to_remove = driver.cell->name;              disconnectPort(driver.cell->name, driver.port); @@ -1026,10 +1081,10 @@ void Arch::merge_constant_nets() {          }      } -    for(IdString other_vcc_net : other_vcc_nets) { -        NetInfo * net = getNetByAlias(other_vcc_net); +    for (IdString other_vcc_net : other_vcc_nets) { +        NetInfo *net = getNetByAlias(other_vcc_net);          NPNR_ASSERT(net->users.empty()); -        if(net->driver.cell) { +        if (net->driver.cell) {              PortRef driver = net->driver;              IdString cell_to_remove = driver.cell->name;              disconnectPort(driver.cell->name, driver.port); @@ -1037,31 +1092,49 @@ void Arch::merge_constant_nets() {          }      } -    for(IdString other_gnd_net : other_gnd_nets) { +    for (IdString other_gnd_net : other_gnd_nets) {          NPNR_ASSERT(nets.erase(other_gnd_net));          gnd_net->aliases.push_back(other_gnd_net);          net_aliases[other_gnd_net] = gnd_net_name;      } -    for(IdString other_vcc_net : other_vcc_nets) { +    for (IdString other_vcc_net : other_vcc_nets) {          NPNR_ASSERT(nets.erase(other_vcc_net));          vcc_net->aliases.push_back(other_vcc_net);          net_aliases[other_vcc_net] = vcc_net_name;      } -    if(need_gnd_source) { -        CellInfo * gnd_cell = createCell(gnd_cell_type, gnd_cell_type); +    if (need_gnd_source) { +        CellInfo *gnd_cell = createCell(gnd_cell_type, gnd_cell_type);          gnd_cell->addOutput(gnd_cell_port);          connectPort(gnd_net_name, gnd_cell_type, gnd_cell_port);      } -    if(need_vcc_source) { -        CellInfo * vcc_cell = createCell(vcc_cell_type, vcc_cell_type); +    if (need_vcc_source) { +        CellInfo *vcc_cell = createCell(vcc_cell_type, vcc_cell_type);          vcc_cell->addOutput(vcc_cell_port);          connectPort(vcc_net_name, vcc_cell_type, vcc_cell_port);      }  } +const std::vector<IdString> &Arch::getBelPinsForCellPin(const CellInfo *cell_info, IdString pin) const +{ +    auto iter = cell_info->cell_bel_pins.find(pin); +    if (iter == cell_info->cell_bel_pins.end()) { +        return no_pins; +    } else { +        return iter->second; +    } +} + +void Arch::report_invalid_bel(BelId bel, CellInfo *cell) const +{ +    int32_t mapping = bel_info(chip_info, bel).pin_map[get_cell_type_index(cell->type)]; +    NPNR_ASSERT(mapping < 0); +    log_error("Cell %s (%s) cannot be placed at BEL %s (mapping %d)\n", cell->name.c_str(this), cell->type.c_str(this), +              nameOfBel(bel), mapping); +} +  // Instance constraint templates.  template void Arch::ArchConstraints::bindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange);  template void Arch::ArchConstraints::unbindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange); diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h index c713ddb9..13cab02f 100644 --- a/fpga_interchange/arch.h +++ b/fpga_interchange/arch.h @@ -30,6 +30,7 @@  #include "constraints.h"  #include "dedicated_interconnect.h" +#include "site_router.h"  NEXTPNR_NAMESPACE_BEGIN @@ -773,7 +774,14 @@ struct ArchRanges      using BucketBelRangeT = FilteredBelRange;  }; -struct DedicatedInterconnect; +static constexpr size_t kMaxState = 8; + +struct TileStatus +{ +    std::vector<ExclusiveStateGroup<kMaxState>> tags; +    std::vector<CellInfo *> boundcells; +    std::vector<SiteRouter> sites; +};  struct Arch : ArchAPI<ArchRanges>  { @@ -787,31 +795,6 @@ struct Arch : ArchAPI<ArchRanges>      std::unordered_map<WireId, NetInfo *> wire_to_net;      std::unordered_map<PipId, NetInfo *> pip_to_net; -    static constexpr size_t kMaxState = 8; - -    struct TileStatus; -    struct SiteRouter -    { -        SiteRouter(int16_t site) : site(site), dirty(false), site_ok(true) {} - -        std::unordered_set<CellInfo *> cells_in_site; -        const int16_t site; - -        mutable bool dirty; -        mutable bool site_ok; - -        void bindBel(CellInfo *cell); -        void unbindBel(CellInfo *cell); -        bool checkSiteRouting(const Context *ctx, const TileStatus &tile_status) const; -    }; - -    struct TileStatus -    { -        std::vector<ExclusiveStateGroup<kMaxState>> tags; -        std::vector<CellInfo *> boundcells; -        std::vector<SiteRouter> sites; -    }; -      DedicatedInterconnect dedicated_interconnect;      std::unordered_map<int32_t, TileStatus> tileStatus; @@ -871,7 +854,7 @@ struct Arch : ArchAPI<ArchRanges>      uint32_t getBelChecksum(BelId bel) const override { return bel.index; } -    void map_cell_pins(CellInfo *cell, int32_t mapping); +    void map_cell_pins(CellInfo *cell, int32_t mapping, bool bind_constants);      void map_port_pins(BelId bel, CellInfo *cell) const;      TileStatus &get_tile_status(int32_t tile) @@ -931,10 +914,13 @@ struct Arch : ArchAPI<ArchRanges>          if (io_port_types.count(cell->type) == 0) {              int32_t mapping = bel_info(chip_info, bel).pin_map[get_cell_type_index(cell->type)]; +            if (mapping < 0) { +                report_invalid_bel(bel, cell); +            }              NPNR_ASSERT(mapping >= 0);              if (cell->cell_mapping != mapping) { -                map_cell_pins(cell, mapping); +                map_cell_pins(cell, mapping, /*bind_constants=*/false);              }              constraints.bindBel(tile_status.tags.data(), get_cell_constraints(bel, cell->type));          } else { @@ -1078,10 +1064,7 @@ struct Arch : ArchAPI<ArchRanges>          return str_range;      } -    const std::vector<IdString> &getBelPinsForCellPin(const CellInfo *cell_info, IdString pin) const override -    { -        return cell_info->cell_bel_pins.at(pin); -    } +    const std::vector<IdString> &getBelPinsForCellPin(const CellInfo *cell_info, IdString pin) const override;      // ------------------------------------------------- @@ -1509,7 +1492,7 @@ struct Arch : ArchAPI<ArchRanges>          if (cell == nullptr) {              return true;          } else { -            if(!dedicated_interconnect.isBelLocationValid(bel, cell)) { +            if (!dedicated_interconnect.isBelLocationValid(bel, cell)) {                  return false;              } @@ -1718,6 +1701,11 @@ struct Arch : ArchAPI<ArchRanges>      }      void merge_constant_nets(); +    void report_invalid_bel(BelId bel, CellInfo *cell) const; + +    std::vector<IdString> no_pins; +    IdString gnd_cell_pin; +    IdString vcc_cell_pin;  };  NEXTPNR_NAMESPACE_END diff --git a/fpga_interchange/arch_pack_io.cc b/fpga_interchange/arch_pack_io.cc index 6a0ffe0b..06cfa002 100644 --- a/fpga_interchange/arch_pack_io.cc +++ b/fpga_interchange/arch_pack_io.cc @@ -243,7 +243,9 @@ void Arch::pack_ports()          for (CellInfo *cell : placed_cells) {              NPNR_ASSERT(cell->bel != BelId()); -            NPNR_ASSERT(isBelLocationValid(cell->bel)); +            if (!isBelLocationValid(cell->bel)) { +                log_error("Tightly bound BEL %s was not valid!\n", nameOfBel(cell->bel)); +            }          }      }  } diff --git a/fpga_interchange/dedicated_interconnect.cc b/fpga_interchange/dedicated_interconnect.cc index b9ef93b5..820896a3 100644 --- a/fpga_interchange/dedicated_interconnect.cc +++ b/fpga_interchange/dedicated_interconnect.cc @@ -18,8 +18,8 @@   *   */ -#include "nextpnr.h"  #include "log.h" +#include "nextpnr.h"  #include "util.h"  NEXTPNR_NAMESPACE_BEGIN @@ -32,13 +32,15 @@ NEXTPNR_NAMESPACE_BEGIN  // terminate at another site.  Routing that "flys" over a site is expressed as  // a psuedo-pip connected the relevant site pin wires, rather than traversing  // the site. -enum WireNodeState { +enum WireNodeState +{      IN_SINK_SITE = 0,      IN_ROUTING = 1,      IN_SOURCE_SITE = 2  }; -struct WireNode { +struct WireNode +{      WireId wire;      WireNodeState state;      int depth; @@ -50,32 +52,33 @@ struct WireNode {  // interconnect.  constexpr int kMaxDepth = 20; -void DedicatedInterconnect::init(const Context *ctx) { +void DedicatedInterconnect::init(const Context *ctx) +{      this->ctx = ctx; -    if(ctx->debug) { +    if (ctx->debug) {          log_info("Finding dedicated interconnect!\n");      }      find_dedicated_interconnect(); -    if(ctx->debug) { +    if (ctx->debug) {          print_dedicated_interconnect();      }  } -bool DedicatedInterconnect::check_routing( -        BelId src_bel, IdString src_bel_pin, -        BelId dst_bel, IdString dst_bel_pin) const { +bool DedicatedInterconnect::check_routing(BelId src_bel, IdString src_bel_pin, BelId dst_bel, +                                          IdString dst_bel_pin) const +{      std::vector<WireNode> nodes_to_expand;      WireId src_wire = ctx->getBelPinWire(src_bel, src_bel_pin); -    const auto & src_wire_data = ctx->wire_info(src_wire); +    const auto &src_wire_data = ctx->wire_info(src_wire);      NPNR_ASSERT(src_wire_data.site != -1);      WireId dst_wire = ctx->getBelPinWire(dst_bel, dst_bel_pin); -    const auto & dst_wire_data = ctx->wire_info(dst_wire); +    const auto &dst_wire_data = ctx->wire_info(dst_wire);      NPNR_ASSERT(dst_wire_data.site != -1);      WireNode wire_node; @@ -85,30 +88,29 @@ bool DedicatedInterconnect::check_routing(      nodes_to_expand.push_back(wire_node); -    while(!nodes_to_expand.empty()) { +    while (!nodes_to_expand.empty()) {          WireNode node_to_expand = nodes_to_expand.back();          nodes_to_expand.pop_back(); -        for(PipId pip : ctx->getPipsDownhill(node_to_expand.wire)) { -            if(ctx->is_pip_synthetic(pip)) { +        for (PipId pip : ctx->getPipsDownhill(node_to_expand.wire)) { +            if (ctx->is_pip_synthetic(pip)) {                  continue;              }              WireId wire = ctx->getPipDstWire(pip); -            if(wire == WireId()) { +            if (wire == WireId()) {                  continue;              }  #ifdef DEBUG_EXPANSION -            log_info(" - At wire %s via %s\n", -                    ctx->nameOfWire(wire), ctx->nameOfPip(pip)); +            log_info(" - At wire %s via %s\n", ctx->nameOfWire(wire), ctx->nameOfPip(pip));  #endif              WireNode next_node;              next_node.wire = wire;              next_node.depth = node_to_expand.depth += 1; -            if(next_node.depth > kMaxDepth) { +            if (next_node.depth > kMaxDepth) {                  // Dedicated routing should reach sources by kMaxDepth (with                  // tuning).                  // @@ -116,55 +118,52 @@ bool DedicatedInterconnect::check_routing(                  return false;              } -            auto const & wire_data = ctx->wire_info(wire); +            auto const &wire_data = ctx->wire_info(wire);              bool expand_node = true; -            if(ctx->is_site_port(pip)) { -                switch(node_to_expand.state) { -                    case IN_SOURCE_SITE: -                        NPNR_ASSERT(wire_data.site == -1); -                        next_node.state = IN_ROUTING; -                        break; -                    case IN_ROUTING: -                        NPNR_ASSERT(wire_data.site != -1); -                        if(wire.tile == src_wire.tile && wire_data.site == src_wire_data.site) { -                            // Dedicated routing won't have straight loops, -                            // general routing looks like that. +            if (ctx->is_site_port(pip)) { +                switch (node_to_expand.state) { +                case IN_SOURCE_SITE: +                    NPNR_ASSERT(wire_data.site == -1); +                    next_node.state = IN_ROUTING; +                    break; +                case IN_ROUTING: +                    NPNR_ASSERT(wire_data.site != -1); +                    if (wire.tile == src_wire.tile && wire_data.site == src_wire_data.site) { +                        // Dedicated routing won't have straight loops, +                        // general routing looks like that.  #ifdef DEBUG_EXPANSION -                            log_info(" - Not dedicated site routing because loop!"); +                        log_info(" - Not dedicated site routing because loop!");  #endif -                            return false; -                        } -                        next_node.state = IN_SINK_SITE; -                        break; -                    case IN_SINK_SITE: -                        // Once entering a site, do not leave it again. -                        // This path is not a legal route! -                        expand_node = false; -                        break; -                    default: -                        // Unreachable!!! -                        NPNR_ASSERT(false); +                        return false; +                    } +                    next_node.state = IN_SINK_SITE; +                    break; +                case IN_SINK_SITE: +                    // Once entering a site, do not leave it again. +                    // This path is not a legal route! +                    expand_node = false; +                    break; +                default: +                    // Unreachable!!! +                    NPNR_ASSERT(false);                  }              } else {                  next_node.state = node_to_expand.state;              } -            if(expand_node) { +            if (expand_node) {                  nodes_to_expand.push_back(next_node);              } else {                  continue;              } -            if(next_node.state == IN_SINK_SITE) { -                for(BelPin bel_pin : ctx->getWireBelPins(wire)) { -                    if(bel_pin.bel == dst_bel && bel_pin.pin == dst_bel_pin) { -                        if(ctx->verbose) { -                            log_info("Valid dedicated interconnect from %s/%s to %s/%s\n", -                                    ctx->nameOfBel(src_bel), -                                    src_bel_pin.c_str(ctx), -                                    ctx->nameOfBel(dst_bel), -                                    dst_bel_pin.c_str(ctx)); +            if (next_node.state == IN_SINK_SITE) { +                for (BelPin bel_pin : ctx->getWireBelPins(wire)) { +                    if (bel_pin.bel == dst_bel && bel_pin.pin == dst_bel_pin) { +                        if (ctx->debug) { +                            log_info("Valid dedicated interconnect from %s/%s to %s/%s\n", ctx->nameOfBel(src_bel), +                                     src_bel_pin.c_str(ctx), ctx->nameOfBel(dst_bel), dst_bel_pin.c_str(ctx));                          }                          return true;                      } @@ -176,8 +175,9 @@ bool DedicatedInterconnect::check_routing(      return false;  } -bool DedicatedInterconnect::is_driver_on_net_valid(BelId driver_bel, -        const CellInfo* cell, IdString driver_port, NetInfo *net) const { +bool DedicatedInterconnect::is_driver_on_net_valid(BelId driver_bel, const CellInfo *cell, IdString driver_port, +                                                   NetInfo *net) const +{      const auto &driver_bel_data = bel_info(ctx->chip_info, driver_bel);      TileTypeBelPin type_bel_pin; @@ -186,27 +186,34 @@ bool DedicatedInterconnect::is_driver_on_net_valid(BelId driver_bel,      Loc driver_loc = ctx->getBelLocation(driver_bel); -    for(IdString driver_bel_pin : ctx->getBelPinsForCellPin(cell, driver_port)) { +    for (IdString driver_bel_pin : ctx->getBelPinsForCellPin(cell, driver_port)) {          type_bel_pin.bel_pin = driver_bel_pin;          auto iter = sources.find(type_bel_pin); -        if(iter == sources.end()) { +        if (iter == sources.end()) {              // This BEL pin doesn't have a dedicate interconnect.              continue;          } -        for(const PortRef & port_ref : net->users) { +        for (const PortRef &port_ref : net->users) {              NPNR_ASSERT(port_ref.cell != nullptr); -            if(port_ref.cell->bel == BelId()) { -                return true; +            if (port_ref.cell->bel == BelId()) { +                // FIXME: This should actually return "unknown!" because the +                // sink is unplaced.  Once the sink is placed, this constraint +                // can be evaluated. +                if (ctx->debug) { +                    log_info("BEL %s is not valid because sink cell %s/%s is not placed\n", ctx->nameOfBel(driver_bel), +                             port_ref.cell->name.c_str(ctx), port_ref.port.c_str(ctx)); +                } +                return false;              }              BelId sink_bel = port_ref.cell->bel;              const auto &sink_bel_data = bel_info(ctx->chip_info, sink_bel);              Loc sink_loc = ctx->getBelLocation(port_ref.cell->bel); -            if(sink_bel.tile == driver_bel.tile && sink_bel_data.site == driver_bel_data.site) { +            if (sink_bel.tile == driver_bel.tile && sink_bel_data.site == driver_bel_data.site) {                  // This is a site local routing, even though this is a sink                  // with a dedicated interconnect.                  continue; @@ -218,18 +225,15 @@ bool DedicatedInterconnect::is_driver_on_net_valid(BelId driver_bel,              sink_type_bel_pin.type_bel_pin.tile_type = ctx->chip_info->tiles[sink_bel.tile].type;              sink_type_bel_pin.type_bel_pin.bel_index = sink_bel.index; -            for(IdString sink_bel_pin : ctx->getBelPinsForCellPin(port_ref.cell, port_ref.port)) { +            for (IdString sink_bel_pin : ctx->getBelPinsForCellPin(port_ref.cell, port_ref.port)) {                  sink_type_bel_pin.type_bel_pin.bel_pin = sink_bel_pin;                  // Do fast routing check to see if the pair of driver and sink                  // every are valid. -                if(iter->second.count(sink_type_bel_pin) == 0) { -                    if(ctx->verbose) { -                        log_info("BEL %s is not valid because pin %s cannot reach %s/%s\n", -                                ctx->nameOfBel(driver_bel), -                                driver_bel_pin.c_str(ctx), -                                ctx->nameOfBel(sink_bel), -                                sink_bel_pin.c_str(ctx)); +                if (iter->second.count(sink_type_bel_pin) == 0) { +                    if (ctx->debug) { +                        log_info("BEL %s is not valid because pin %s cannot reach %s/%s\n", ctx->nameOfBel(driver_bel), +                                 driver_bel_pin.c_str(ctx), ctx->nameOfBel(sink_bel), sink_bel_pin.c_str(ctx));                      }                      return false;                  } @@ -239,15 +243,11 @@ bool DedicatedInterconnect::is_driver_on_net_valid(BelId driver_bel,                  // FIXME: This might be too slow, but it handles a case on                  // SLICEL.COUT -> SLICEL.CIN has delta_y = {1, 2}, but the                  // delta_y=2 case is rare. -                if(!check_routing( -                        driver_bel, driver_bel_pin, -                        sink_bel, sink_bel_pin)) { -                    if(ctx->verbose) { +                if (!check_routing(driver_bel, driver_bel_pin, sink_bel, sink_bel_pin)) { +                    if (ctx->debug) {                          log_info("BEL %s is not valid because pin %s cannot be reach %s/%s (via detailed check)\n", -                                ctx->nameOfBel(driver_bel), -                                driver_bel_pin.c_str(ctx), -                                ctx->nameOfBel(sink_bel), -                                sink_bel_pin.c_str(ctx)); +                                 ctx->nameOfBel(driver_bel), driver_bel_pin.c_str(ctx), ctx->nameOfBel(sink_bel), +                                 sink_bel_pin.c_str(ctx));                      }                      return false;                  } @@ -258,52 +258,62 @@ bool DedicatedInterconnect::is_driver_on_net_valid(BelId driver_bel,      return true;  } -bool DedicatedInterconnect::is_sink_on_net_valid(BelId bel, const CellInfo* cell, IdString port_name, NetInfo *net) const { -    BelId driver_bel = net->driver.cell->bel; -    if(driver_bel == BelId()) { -        return true; -    } - +bool DedicatedInterconnect::is_sink_on_net_valid(BelId bel, const CellInfo *cell, IdString port_name, +                                                 NetInfo *net) const +{      const auto &bel_data = bel_info(ctx->chip_info, bel); -    const auto &driver_bel_data = bel_info(ctx->chip_info, driver_bel); -      Loc bel_loc = ctx->getBelLocation(bel); -    Loc driver_loc = ctx->getBelLocation(driver_bel); -    DeltaTileTypeBelPin driver_type_bel_pin; -    driver_type_bel_pin.delta_x = driver_loc.x - bel_loc.x; -    driver_type_bel_pin.delta_y = driver_loc.y - bel_loc.y; -    driver_type_bel_pin.type_bel_pin.tile_type = ctx->chip_info->tiles[driver_bel.tile].type; -    driver_type_bel_pin.type_bel_pin.bel_index = driver_bel.index; -    driver_type_bel_pin.type_bel_pin.bel_pin = get_only_value(ctx->getBelPinsForCellPin(net->driver.cell, net->driver.port)); +    BelId driver_bel = net->driver.cell->bel; -    for(IdString bel_pin : ctx->getBelPinsForCellPin(cell, port_name)) { +    for (IdString bel_pin : ctx->getBelPinsForCellPin(cell, port_name)) {          TileTypeBelPin type_bel_pin;          type_bel_pin.tile_type = ctx->chip_info->tiles[bel.tile].type;          type_bel_pin.bel_index = bel.index;          type_bel_pin.bel_pin = bel_pin;          auto iter = sinks.find(type_bel_pin); -        if(iter == sinks.end()) { +        if (iter == sinks.end()) {              // This BEL pin doesn't have a dedicate interconnect.              continue;          } -        if(bel.tile == driver_bel.tile && bel_data.site == driver_bel_data.site) { +        if (driver_bel == BelId()) { +            // FIXME: This should actually return "unknown!" because the +            // driver is unplaced.  Once the driver is placed, this constraint +            // can be evaluated. +            if (ctx->debug) { +                log_info("BEL %s is not valid because driver cell %s/%s is not placed\n", ctx->nameOfBel(bel), +                         net->driver.cell->name.c_str(ctx), net->driver.port.c_str(ctx)); +            } +            return false; +        } + +        const auto &driver_bel_data = bel_info(ctx->chip_info, driver_bel); + +        if (bel.tile == driver_bel.tile && bel_data.site == driver_bel_data.site) {              // This is a site local routing, even though this is a sink              // with a dedicated interconnect.              continue;          } +        Loc driver_loc = ctx->getBelLocation(driver_bel); + +        DeltaTileTypeBelPin driver_type_bel_pin; +        driver_type_bel_pin.delta_x = driver_loc.x - bel_loc.x; +        driver_type_bel_pin.delta_y = driver_loc.y - bel_loc.y; +        driver_type_bel_pin.type_bel_pin.tile_type = ctx->chip_info->tiles[driver_bel.tile].type; +        driver_type_bel_pin.type_bel_pin.bel_index = driver_bel.index; +        driver_type_bel_pin.type_bel_pin.bel_pin = +                get_only_value(ctx->getBelPinsForCellPin(net->driver.cell, net->driver.port)); +          // Do fast routing check to see if the pair of driver and sink          // every are valid. -        if(iter->second.count(driver_type_bel_pin) == 0) { -            if(ctx->verbose) { -                log_info("BEL %s is not valid because pin %s cannot be driven by %s/%s\n", -                        ctx->nameOfBel(bel), -                        bel_pin.c_str(ctx), -                        ctx->nameOfBel(driver_bel), -                        driver_type_bel_pin.type_bel_pin.bel_pin.c_str(ctx)); +        if (iter->second.count(driver_type_bel_pin) == 0) { +            if (ctx->debug) { +                log_info("BEL %s is not valid because pin %s cannot be driven by %s/%s\n", ctx->nameOfBel(bel), +                         bel_pin.c_str(ctx), ctx->nameOfBel(driver_bel), +                         driver_type_bel_pin.type_bel_pin.bel_pin.c_str(ctx));              }              return false;          } @@ -313,15 +323,11 @@ bool DedicatedInterconnect::is_sink_on_net_valid(BelId bel, const CellInfo* cell          // FIXME: This might be too slow, but it handles a case on          // SLICEL.COUT -> SLICEL.CIN has delta_y = {1, 2}, but the          // delta_y=2 case is rare. -        if(!check_routing( -                driver_bel, driver_type_bel_pin.type_bel_pin.bel_pin, -                bel, bel_pin)) { -            if(ctx->verbose) { +        if (!check_routing(driver_bel, driver_type_bel_pin.type_bel_pin.bel_pin, bel, bel_pin)) { +            if (ctx->debug) {                  log_info("BEL %s is not valid because pin %s cannot be driven by %s/%s (via detailed check)\n", -                        ctx->nameOfBel(bel), -                        bel_pin.c_str(ctx), -                        ctx->nameOfBel(driver_bel), -                        driver_type_bel_pin.type_bel_pin.bel_pin.c_str(ctx)); +                         ctx->nameOfBel(bel), bel_pin.c_str(ctx), ctx->nameOfBel(driver_bel), +                         driver_type_bel_pin.type_bel_pin.bel_pin.c_str(ctx));              }              return false;          } @@ -330,13 +336,14 @@ bool DedicatedInterconnect::is_sink_on_net_valid(BelId bel, const CellInfo* cell      return true;  } -bool DedicatedInterconnect::isBelLocationValid(BelId bel, const CellInfo* cell) const { +bool DedicatedInterconnect::isBelLocationValid(BelId bel, const CellInfo *cell) const +{      NPNR_ASSERT(bel != BelId()); -    for(const auto &port_pair : cell->ports) { +    for (const auto &port_pair : cell->ports) {          IdString port_name = port_pair.first;          NetInfo *net = port_pair.second.net; -        if(net == nullptr) { +        if (net == nullptr) {              continue;          } @@ -344,12 +351,12 @@ bool DedicatedInterconnect::isBelLocationValid(BelId bel, const CellInfo* cell)          NPNR_ASSERT(net->driver.cell != nullptr);          // Only check sink BELs. -        if(net->driver.cell == cell && net->driver.port == port_name) { -            if(!is_driver_on_net_valid(bel, cell, port_name, net)) { +        if (net->driver.cell == cell && net->driver.port == port_name) { +            if (!is_driver_on_net_valid(bel, cell, port_name, net)) {                  return false;              }          } else { -            if(!is_sink_on_net_valid(bel, cell, port_name, net)) { +            if (!is_sink_on_net_valid(bel, cell, port_name, net)) {                  return false;              }          } @@ -358,100 +365,84 @@ bool DedicatedInterconnect::isBelLocationValid(BelId bel, const CellInfo* cell)      return true;  } -void DedicatedInterconnect::print_dedicated_interconnect() const { +void DedicatedInterconnect::print_dedicated_interconnect() const +{      log_info("Found %zu sinks with dedicated interconnect\n", sinks.size());      log_info("Found %zu sources with dedicated interconnect\n", sources.size());      std::vector<TileTypeBelPin> sorted_keys; -    for(const auto & sink_to_srcs : sinks) { +    for (const auto &sink_to_srcs : sinks) {          sorted_keys.push_back(sink_to_srcs.first);      } -    for(const auto & src_to_sinks : sources) { +    for (const auto &src_to_sinks : sources) {          sorted_keys.push_back(src_to_sinks.first);      }      std::sort(sorted_keys.begin(), sorted_keys.end()); -    for(const auto & key : sorted_keys) { +    for (const auto &key : sorted_keys) {          auto iter = sinks.find(key); -        if(iter != sinks.end()) { +        if (iter != sinks.end()) {              auto dst = key; -            for(const auto & src_delta : iter->second) { +            for (const auto &src_delta : iter->second) {                  auto src = src_delta.type_bel_pin;                  auto delta_x = src_delta.delta_x;                  auto delta_y = src_delta.delta_y; -                const TileTypeInfoPOD & src_tile_type = ctx->chip_info->tile_types[src.tile_type]; -                const BelInfoPOD & src_bel_info = src_tile_type.bel_data[src.bel_index]; +                const TileTypeInfoPOD &src_tile_type = ctx->chip_info->tile_types[src.tile_type]; +                const BelInfoPOD &src_bel_info = src_tile_type.bel_data[src.bel_index];                  IdString src_site_type = IdString(src_tile_type.site_types[src_bel_info.site]);                  IdString src_bel_pin = src.bel_pin; -                const TileTypeInfoPOD & dst_tile_type = ctx->chip_info->tile_types[dst.tile_type]; -                const BelInfoPOD & dst_bel_info = dst_tile_type.bel_data[dst.bel_index]; +                const TileTypeInfoPOD &dst_tile_type = ctx->chip_info->tile_types[dst.tile_type]; +                const BelInfoPOD &dst_bel_info = dst_tile_type.bel_data[dst.bel_index];                  IdString dst_site_type = IdString(dst_tile_type.site_types[dst_bel_info.site]);                  IdString dst_bel_pin = dst.bel_pin; -                log_info("%s.%s[%d]/%s/%s (%d, %d) -> %s.%s[%d]/%s/%s\n", -                        IdString(src_tile_type.name).c_str(ctx), -                        src_site_type.c_str(ctx), -                        src_bel_info.site, -                        IdString(src_bel_info.name).c_str(ctx), -                        src_bel_pin.c_str(ctx), -                        delta_x, -                        delta_y, -                        IdString(dst_tile_type.name).c_str(ctx), -                        dst_site_type.c_str(ctx), -                        dst_bel_info.site, -                        IdString(dst_bel_info.name).c_str(ctx), -                        dst_bel_pin.c_str(ctx)); - +                log_info("%s.%s[%d]/%s/%s (%d, %d) -> %s.%s[%d]/%s/%s\n", IdString(src_tile_type.name).c_str(ctx), +                         src_site_type.c_str(ctx), src_bel_info.site, IdString(src_bel_info.name).c_str(ctx), +                         src_bel_pin.c_str(ctx), delta_x, delta_y, IdString(dst_tile_type.name).c_str(ctx), +                         dst_site_type.c_str(ctx), dst_bel_info.site, IdString(dst_bel_info.name).c_str(ctx), +                         dst_bel_pin.c_str(ctx));              }          } else {              auto src = key; -            for(const auto & dst_delta : sources.at(key)) { +            for (const auto &dst_delta : sources.at(key)) {                  auto dst = dst_delta.type_bel_pin;                  auto delta_x = dst_delta.delta_x;                  auto delta_y = dst_delta.delta_y; -                const TileTypeInfoPOD & src_tile_type = ctx->chip_info->tile_types[src.tile_type]; -                const BelInfoPOD & src_bel_info = src_tile_type.bel_data[src.bel_index]; +                const TileTypeInfoPOD &src_tile_type = ctx->chip_info->tile_types[src.tile_type]; +                const BelInfoPOD &src_bel_info = src_tile_type.bel_data[src.bel_index];                  IdString src_site_type = IdString(src_tile_type.site_types[src_bel_info.site]);                  IdString src_bel_pin = src.bel_pin; -                const TileTypeInfoPOD & dst_tile_type = ctx->chip_info->tile_types[dst.tile_type]; -                const BelInfoPOD & dst_bel_info = dst_tile_type.bel_data[dst.bel_index]; +                const TileTypeInfoPOD &dst_tile_type = ctx->chip_info->tile_types[dst.tile_type]; +                const BelInfoPOD &dst_bel_info = dst_tile_type.bel_data[dst.bel_index];                  IdString dst_site_type = IdString(dst_tile_type.site_types[dst_bel_info.site]);                  IdString dst_bel_pin = dst.bel_pin; -                log_info("%s.%s[%d]/%s/%s -> %s.%s[%d]/%s/%s  (%d, %d)\n", -                        IdString(src_tile_type.name).c_str(ctx), -                        src_site_type.c_str(ctx), -                        src_bel_info.site, -                        IdString(src_bel_info.name).c_str(ctx), -                        src_bel_pin.c_str(ctx), -                        IdString(dst_tile_type.name).c_str(ctx), -                        dst_site_type.c_str(ctx), -                        dst_bel_info.site, -                        IdString(dst_bel_info.name).c_str(ctx), -                        dst_bel_pin.c_str(ctx), -                        delta_x, -                        delta_y); - +                log_info("%s.%s[%d]/%s/%s -> %s.%s[%d]/%s/%s  (%d, %d)\n", IdString(src_tile_type.name).c_str(ctx), +                         src_site_type.c_str(ctx), src_bel_info.site, IdString(src_bel_info.name).c_str(ctx), +                         src_bel_pin.c_str(ctx), IdString(dst_tile_type.name).c_str(ctx), dst_site_type.c_str(ctx), +                         dst_bel_info.site, IdString(dst_bel_info.name).c_str(ctx), dst_bel_pin.c_str(ctx), delta_x, +                         delta_y);              }          }      }  } -void DedicatedInterconnect::find_dedicated_interconnect() { -    for(BelId bel : ctx->getBels()) { -        const auto & bel_data = bel_info(ctx->chip_info, bel); -        if(bel_data.category != BEL_CATEGORY_LOGIC) { +void DedicatedInterconnect::find_dedicated_interconnect() +{ +    for (BelId bel : ctx->getBels()) { +        const auto &bel_data = bel_info(ctx->chip_info, bel); +        if (bel_data.category != BEL_CATEGORY_LOGIC) {              continue;          } -        if(bel_data.synthetic) { +        if (bel_data.synthetic) {              continue;          } -        for(size_t i = 0; i < bel_data.num_bel_wires; ++i) { -            if(bel_data.types[i] != PORT_IN) { +        for (size_t i = 0; i < bel_data.num_bel_wires; ++i) { +            if (bel_data.types[i] != PORT_IN) {                  continue;              } @@ -464,27 +455,26 @@ void DedicatedInterconnect::find_dedicated_interconnect() {      }      std::unordered_set<TileTypeBelPin> seen_pins; -    for(auto sink_pair : sinks) { -        for(auto src : sink_pair.second) { +    for (auto sink_pair : sinks) { +        for (auto src : sink_pair.second) {              seen_pins.emplace(src.type_bel_pin);          }      } -    for(BelId bel : ctx->getBels()) { -        const auto & bel_data = bel_info(ctx->chip_info, bel); -        if(bel_data.category != BEL_CATEGORY_LOGIC) { +    for (BelId bel : ctx->getBels()) { +        const auto &bel_data = bel_info(ctx->chip_info, bel); +        if (bel_data.category != BEL_CATEGORY_LOGIC) {              continue;          } -        if(bel_data.synthetic) { +        if (bel_data.synthetic) {              continue;          } -        for(size_t i = 0; i < bel_data.num_bel_wires; ++i) { -            if(bel_data.types[i] != PORT_OUT) { +        for (size_t i = 0; i < bel_data.num_bel_wires; ++i) { +            if (bel_data.types[i] != PORT_OUT) {                  continue;              } -              IdString bel_pin(bel_data.ports[i]);              TileTypeBelPin type_bel_pin; @@ -493,7 +483,7 @@ void DedicatedInterconnect::find_dedicated_interconnect() {              type_bel_pin.bel_pin = bel_pin;              // Don't visit src pins already handled in the sink expansion! -            if(seen_pins.count(type_bel_pin)) { +            if (seen_pins.count(type_bel_pin)) {                  continue;              } @@ -506,7 +496,8 @@ void DedicatedInterconnect::find_dedicated_interconnect() {      }  } -void DedicatedInterconnect::expand_sink_bel(BelId sink_bel, IdString sink_pin, WireId sink_wire) { +void DedicatedInterconnect::expand_sink_bel(BelId sink_bel, IdString sink_pin, WireId sink_wire) +{      NPNR_ASSERT(sink_bel != BelId());  #ifdef DEBUG_EXPANSION      log_info("Expanding from %s/%s\n", ctx->nameOfBel(sink_bel), pin.c_str(ctx)); @@ -514,7 +505,7 @@ void DedicatedInterconnect::expand_sink_bel(BelId sink_bel, IdString sink_pin, W      std::vector<WireNode> nodes_to_expand; -    const auto & sink_wire_data = ctx->wire_info(sink_wire); +    const auto &sink_wire_data = ctx->wire_info(sink_wire);      NPNR_ASSERT(sink_wire_data.site != -1);      WireNode wire_node; @@ -527,89 +518,91 @@ void DedicatedInterconnect::expand_sink_bel(BelId sink_bel, IdString sink_pin, W      Loc sink_loc = ctx->getBelLocation(sink_bel);      std::unordered_set<DeltaTileTypeBelPin> srcs; -    while(!nodes_to_expand.empty()) { +    while (!nodes_to_expand.empty()) {          WireNode node_to_expand = nodes_to_expand.back();          nodes_to_expand.pop_back(); -        for(PipId pip : ctx->getPipsUphill(node_to_expand.wire)) { -            if(ctx->is_pip_synthetic(pip)) { +        for (PipId pip : ctx->getPipsUphill(node_to_expand.wire)) { +            if (ctx->is_pip_synthetic(pip)) {                  continue;              }              WireId wire = ctx->getPipSrcWire(pip); -            if(wire == WireId()) { +            if (wire == WireId()) {                  continue;              }  #ifdef DEBUG_EXPANSION -            log_info(" - At wire %s via %s\n", -                    ctx->nameOfWire(wire), ctx->nameOfPip(pip)); +            log_info(" - At wire %s via %s\n", ctx->nameOfWire(wire), ctx->nameOfPip(pip));  #endif              WireNode next_node;              next_node.wire = wire;              next_node.depth = node_to_expand.depth += 1; -            if(next_node.depth > kMaxDepth) { +            if (next_node.depth > kMaxDepth) {                  // Dedicated routing should reach sources by kMaxDepth (with                  // tuning).                  //                  // FIXME: Consider removing kMaxDepth and use kMaxSources? +#ifdef DEBUG_EXPANSION +                log_info(" - Exceeded max depth!\n"); +#endif                  return;              } -            auto const & wire_data = ctx->wire_info(wire); +            auto const &wire_data = ctx->wire_info(wire);              bool expand_node = true; -            if(ctx->is_site_port(pip)) { -                switch(node_to_expand.state) { -                    case IN_SINK_SITE: -                        NPNR_ASSERT(wire_data.site == -1); -                        next_node.state = IN_ROUTING; -                        break; -                    case IN_ROUTING: -                        NPNR_ASSERT(wire_data.site != -1); -                        if(wire.tile == sink_wire.tile && wire_data.site == sink_wire_data.site) { -                            // Dedicated routing won't have straight loops, -                            // general routing looks like that. +            if (ctx->is_site_port(pip)) { +                switch (node_to_expand.state) { +                case IN_SINK_SITE: +                    NPNR_ASSERT(wire_data.site == -1); +                    next_node.state = IN_ROUTING; +                    break; +                case IN_ROUTING: +                    NPNR_ASSERT(wire_data.site != -1); +                    if (wire.tile == sink_wire.tile && wire_data.site == sink_wire_data.site) { +                        // Dedicated routing won't have straight loops, +                        // general routing looks like that.  #ifdef DEBUG_EXPANSION -                            log_info(" - Not dedicated site routing because loop!"); +                        log_info(" - Not dedicated site routing because loop!");  #endif -                            return; -                        } -                        next_node.state = IN_SOURCE_SITE; -                        break; -                    case IN_SOURCE_SITE: -                        // Once entering a site, do not leave it again. -                        // This path is not a legal route! -                        expand_node = false; -                        break; -                    default: -                        // Unreachable!!! -                        NPNR_ASSERT(false); +                        return; +                    } +                    next_node.state = IN_SOURCE_SITE; +                    break; +                case IN_SOURCE_SITE: +                    // Once entering a site, do not leave it again. +                    // This path is not a legal route! +                    expand_node = false; +                    break; +                default: +                    // Unreachable!!! +                    NPNR_ASSERT(false);                  }              } else {                  next_node.state = node_to_expand.state;              } -            if(expand_node) { +            if (expand_node) {                  nodes_to_expand.push_back(next_node);              } else {                  continue;              } -            if(next_node.state == IN_SOURCE_SITE) { -                for(BelPin bel_pin : ctx->getWireBelPins(wire)) { +            if (next_node.state == IN_SOURCE_SITE) { +                for (BelPin bel_pin : ctx->getWireBelPins(wire)) {                      BelId src_bel = bel_pin.bel; -                    auto const & bel_data = bel_info(ctx->chip_info, src_bel); +                    auto const &bel_data = bel_info(ctx->chip_info, src_bel); -                    if(bel_data.category != BEL_CATEGORY_LOGIC) { +                    if (bel_data.category != BEL_CATEGORY_LOGIC) {                          continue;                      } -                    if(bel_data.synthetic) { +                    if (bel_data.synthetic) {                          continue;                      } -                    if(ctx->getBelPinType(bel_pin.bel, bel_pin.pin) != PORT_OUT) { +                    if (ctx->getBelPinType(bel_pin.bel, bel_pin.pin) != PORT_OUT) {                          continue;                      } @@ -637,24 +630,25 @@ void DedicatedInterconnect::expand_sink_bel(BelId sink_bel, IdString sink_pin, W      type_bel_pin.bel_pin = sink_pin;      auto result = sinks.emplace(type_bel_pin, srcs); -    if(!result.second) { +    if (!result.second) {          // type_bel_pin was already present! Add any new sources from this          // sink type (if any); -        for(auto src : srcs) { +        for (auto src : srcs) {              result.first->second.emplace(src);          }      }  } -void DedicatedInterconnect::expand_source_bel(BelId src_bel, IdString src_pin, WireId src_wire) { +void DedicatedInterconnect::expand_source_bel(BelId src_bel, IdString src_pin, WireId src_wire) +{      NPNR_ASSERT(src_bel != BelId());  #ifdef DEBUG_EXPANSION -    log_info("Expanding from %s/%s\n", ctx->nameOfBel(src_bel), pin.c_str(ctx)); +    log_info("Expanding from %s/%s\n", ctx->nameOfBel(src_bel), src_pin.c_str(ctx));  #endif      std::vector<WireNode> nodes_to_expand; -    const auto & src_wire_data = ctx->wire_info(src_wire); +    const auto &src_wire_data = ctx->wire_info(src_wire);      NPNR_ASSERT(src_wire_data.site != -1);      WireNode wire_node; @@ -667,89 +661,91 @@ void DedicatedInterconnect::expand_source_bel(BelId src_bel, IdString src_pin, W      Loc src_loc = ctx->getBelLocation(src_bel);      std::unordered_set<DeltaTileTypeBelPin> dsts; -    while(!nodes_to_expand.empty()) { +    while (!nodes_to_expand.empty()) {          WireNode node_to_expand = nodes_to_expand.back();          nodes_to_expand.pop_back(); -        for(PipId pip : ctx->getPipsDownhill(node_to_expand.wire)) { -            if(ctx->is_pip_synthetic(pip)) { +        for (PipId pip : ctx->getPipsDownhill(node_to_expand.wire)) { +            if (ctx->is_pip_synthetic(pip)) {                  continue;              }              WireId wire = ctx->getPipDstWire(pip); -            if(wire == WireId()) { +            if (wire == WireId()) {                  continue;              }  #ifdef DEBUG_EXPANSION -            log_info(" - At wire %s via %s\n", -                    ctx->nameOfWire(wire), ctx->nameOfPip(pip)); +            log_info(" - At wire %s via %s\n", ctx->nameOfWire(wire), ctx->nameOfPip(pip));  #endif              WireNode next_node;              next_node.wire = wire;              next_node.depth = node_to_expand.depth += 1; -            if(next_node.depth > kMaxDepth) { +            if (next_node.depth > kMaxDepth) {                  // Dedicated routing should reach sources by kMaxDepth (with                  // tuning).                  //                  // FIXME: Consider removing kMaxDepth and use kMaxSources? +#ifdef DEBUG_EXPANSION +                log_info(" - Exceeded max depth!\n"); +#endif                  return;              } -            auto const & wire_data = ctx->wire_info(wire); +            auto const &wire_data = ctx->wire_info(wire);              bool expand_node = true; -            if(ctx->is_site_port(pip)) { -                switch(node_to_expand.state) { -                    case IN_SOURCE_SITE: -                        NPNR_ASSERT(wire_data.site == -1); -                        next_node.state = IN_ROUTING; -                        break; -                    case IN_ROUTING: -                        NPNR_ASSERT(wire_data.site != -1); -                        if(wire.tile == src_wire.tile && wire_data.site == src_wire_data.site) { -                            // Dedicated routing won't have straight loops, -                            // general routing looks like that. +            if (ctx->is_site_port(pip)) { +                switch (node_to_expand.state) { +                case IN_SOURCE_SITE: +                    NPNR_ASSERT(wire_data.site == -1); +                    next_node.state = IN_ROUTING; +                    break; +                case IN_ROUTING: +                    NPNR_ASSERT(wire_data.site != -1); +                    if (wire.tile == src_wire.tile && wire_data.site == src_wire_data.site) { +                        // Dedicated routing won't have straight loops, +                        // general routing looks like that.  #ifdef DEBUG_EXPANSION -                            log_info(" - Not dedicated site routing because loop!"); +                        log_info(" - Not dedicated site routing because loop!");  #endif -                            return; -                        } -                        next_node.state = IN_SINK_SITE; -                        break; -                    case IN_SINK_SITE: -                        // Once entering a site, do not leave it again. -                        // This path is not a legal route! -                        expand_node = false; -                        break; -                    default: -                        // Unreachable!!! -                        NPNR_ASSERT(false); +                        return; +                    } +                    next_node.state = IN_SINK_SITE; +                    break; +                case IN_SINK_SITE: +                    // Once entering a site, do not leave it again. +                    // This path is not a legal route! +                    expand_node = false; +                    break; +                default: +                    // Unreachable!!! +                    NPNR_ASSERT(false);                  }              } else {                  next_node.state = node_to_expand.state;              } -            if(expand_node) { +            if (expand_node) {                  nodes_to_expand.push_back(next_node);              } else {                  continue;              } -            if(next_node.state == IN_SINK_SITE) { -                for(BelPin bel_pin : ctx->getWireBelPins(wire)) { +            if (next_node.state == IN_SINK_SITE) { +                for (BelPin bel_pin : ctx->getWireBelPins(wire)) {                      BelId sink_bel = bel_pin.bel; -                    auto const & bel_data = bel_info(ctx->chip_info, sink_bel); +                    auto const &bel_data = bel_info(ctx->chip_info, sink_bel); -                    if(bel_data.category != BEL_CATEGORY_LOGIC) { +                    if (bel_data.category != BEL_CATEGORY_LOGIC) {                          continue;                      } -                    if(bel_data.synthetic) { +                    if (bel_data.synthetic) {                          continue;                      } -                    if(ctx->getBelPinType(bel_pin.bel, bel_pin.pin) != PORT_IN) { +                    if (ctx->getBelPinType(bel_pin.bel, bel_pin.pin) != PORT_IN) {                          continue;                      } @@ -776,11 +772,11 @@ void DedicatedInterconnect::expand_source_bel(BelId src_bel, IdString src_pin, W      type_bel_pin.bel_index = src_bel.index;      type_bel_pin.bel_pin = src_pin; -    auto result = sinks.emplace(type_bel_pin, dsts); -    if(!result.second) { +    auto result = sources.emplace(type_bel_pin, dsts); +    if (!result.second) {          // type_bel_pin was already present! Add any new sources from this          // sink type (if any); -        for(auto dst : dsts) { +        for (auto dst : dsts) {              result.first->second.emplace(dst);          }      } diff --git a/fpga_interchange/dedicated_interconnect.h b/fpga_interchange/dedicated_interconnect.h index d603039e..66e1d41b 100644 --- a/fpga_interchange/dedicated_interconnect.h +++ b/fpga_interchange/dedicated_interconnect.h @@ -24,40 +24,47 @@  NEXTPNR_NAMESPACE_BEGIN -struct TileTypeBelPin { +struct TileTypeBelPin +{      int32_t tile_type;      int32_t bel_index;      IdString bel_pin; -    bool operator < (const TileTypeBelPin &other) const { -        if(tile_type >= other.tile_type) { +    bool operator<(const TileTypeBelPin &other) const +    { +        if (tile_type >= other.tile_type) {              return false;          } -        if(bel_index >= other.bel_index) { +        if (bel_index >= other.bel_index) {              return false;          }          return bel_pin < other.bel_pin;      } -    bool operator ==(const TileTypeBelPin &other) const { +    bool operator==(const TileTypeBelPin &other) const +    {          return tile_type == other.tile_type && bel_index == other.bel_index && bel_pin == other.bel_pin;      } -    bool operator !=(const TileTypeBelPin &other) const { +    bool operator!=(const TileTypeBelPin &other) const +    {          return tile_type != other.tile_type || bel_index != other.bel_index || bel_pin != other.bel_pin;      }  }; -struct DeltaTileTypeBelPin { +struct DeltaTileTypeBelPin +{      int32_t delta_x;      int32_t delta_y;      TileTypeBelPin type_bel_pin; -    bool operator ==(const DeltaTileTypeBelPin &other) const { +    bool operator==(const DeltaTileTypeBelPin &other) const +    {          return delta_x == other.delta_x && delta_y == other.delta_y && type_bel_pin == other.type_bel_pin;      } -    bool operator !=(const DeltaTileTypeBelPin &other) const { +    bool operator!=(const DeltaTileTypeBelPin &other) const +    {          return delta_x != other.delta_x || delta_y != other.delta_y || type_bel_pin != other.type_bel_pin;      }  }; @@ -105,7 +112,8 @@ struct Context;  //  This class discovers dedicated interconnect by examing the routing graph.  //  This discovery make be expensive, and require caching to accelerate  //  startup. -struct DedicatedInterconnect { +struct DedicatedInterconnect +{      const Context *ctx;      std::unordered_map<TileTypeBelPin, std::unordered_set<DeltaTileTypeBelPin>> sinks; @@ -117,20 +125,16 @@ struct DedicatedInterconnect {      // interconnect?      //      // Note: Only BEL pin sinks are checked. -    bool isBelLocationValid(BelId bel, const CellInfo* cell) const; +    bool isBelLocationValid(BelId bel, const CellInfo *cell) const;      void find_dedicated_interconnect();      void print_dedicated_interconnect() const; -    bool check_routing( -        BelId src_bel, IdString src_bel_pin, -        BelId dst_bel, IdString dst_bel_pin) const; +    bool check_routing(BelId src_bel, IdString src_bel_pin, BelId dst_bel, IdString dst_bel_pin) const;      void expand_sink_bel(BelId bel, IdString pin, WireId wire);      void expand_source_bel(BelId bel, IdString pin, WireId wire); -    bool is_driver_on_net_valid(BelId driver_bel, -            const CellInfo* cell, IdString driver_port, NetInfo *net) const; -    bool is_sink_on_net_valid(BelId bel, const CellInfo* cell, -            IdString port_name, NetInfo *net) const; +    bool is_driver_on_net_valid(BelId driver_bel, const CellInfo *cell, IdString driver_port, NetInfo *net) const; +    bool is_sink_on_net_valid(BelId bel, const CellInfo *cell, IdString port_name, NetInfo *net) const;  };  NEXTPNR_NAMESPACE_END diff --git a/fpga_interchange/fpga_interchange.cpp b/fpga_interchange/fpga_interchange.cpp index 027513c8..a1642789 100644 --- a/fpga_interchange/fpga_interchange.cpp +++ b/fpga_interchange/fpga_interchange.cpp @@ -111,20 +111,37 @@ static PhysicalNetlist::PhysNetlist::RouteBranch::Builder emit_branch(          if(bel_data.category == BEL_CATEGORY_LOGIC) {              // This is a psuedo site-pip.              auto in_bel_pin = branch.getRouteSegment().initBelPin(); -            IdString src_wire_name = IdString(tile_type.wire_data[pip_data.src_index].name); -            IdString dst_wire_name = IdString(tile_type.wire_data[pip_data.dst_index].name); +            WireId src_wire = ctx->getPipSrcWire(pip); +            WireId dst_wire = ctx->getPipDstWire(pip); + +            IdString src_pin; +            IdString dst_pin; +            for(IdString pin : ctx->getBelPins(bel)) { +                if(ctx->getBelPinWire(bel, pin) == src_wire) { +                    NPNR_ASSERT(src_pin == IdString()); +                    src_pin = pin; +                } + +                if(ctx->getBelPinWire(bel, pin) == dst_wire) { +                    NPNR_ASSERT(dst_pin == IdString()); +                    dst_pin = pin; +                } +            } + +            NPNR_ASSERT(src_pin != IdString()); +            NPNR_ASSERT(dst_pin != IdString());              int bel_idx = strings->get_index(bel_name[1].str(ctx));              in_bel_pin.setSite(site_idx);              in_bel_pin.setBel(bel_idx); -            in_bel_pin.setPin(strings->get_index(src_wire_name.str(ctx))); +            in_bel_pin.setPin(strings->get_index(src_pin.str(ctx)));              auto subbranch = branch.initBranches(1);              auto bel_pin_branch = subbranch[0];              auto out_bel_pin = bel_pin_branch.getRouteSegment().initBelPin();              out_bel_pin.setSite(site_idx);              out_bel_pin.setBel(bel_idx); -            out_bel_pin.setPin(strings->get_index(dst_wire_name.str(ctx))); +            out_bel_pin.setPin(strings->get_index(dst_pin.str(ctx)));              return bel_pin_branch;          } else if(bel_data.category == BEL_CATEGORY_ROUTING) { @@ -614,6 +631,8 @@ struct ModuleReader {      ModuleReader(const LogicalNetlistImpl *root,              LogicalNetlist::Netlist::CellInstance::Reader cell_inst, bool is_top); + +    size_t translate_port_index(LogicalNetlist::Netlist::PortInstance::Reader port_inst) const;  };  struct PortReader { @@ -850,8 +869,8 @@ struct LogicalNetlistImpl      bool is_vector_bit_constant(const std::vector<int32_t> &bits, int i) const      { -        // FIXME: Check if this is right.  Assumption is that cells have been -        // emitted for GND and VCC, e.g. VCC vcc(.P(vcc_net)). +        // Note: This appears weird, but is correct.  This is because VCC/GND +        // nets are not handled in frontend_base for FPGA interchange.          return false;      } @@ -929,11 +948,8 @@ ModuleReader::ModuleReader(const LogicalNetlistImpl *root,              PortKey port_key(inst_idx, port_inst.getPort());              std::vector<int32_t> & port_connections = connections.at(port_key); -            if(port_inst.getBusIdx().isSingleBit()) { -                port_connections[0] = net_idx; -            } else { -                port_connections.at(port_inst.getBusIdx().getIdx()) = net_idx; -            } +            size_t port_idx = translate_port_index(port_inst); +            port_connections.at(port_idx) = net_idx;          }      } @@ -993,5 +1009,19 @@ void FpgaInterchange::read_logical_netlist(Context * ctx, const std::string &fil      GenericFrontend<LogicalNetlistImpl>(ctx, netlist_reader, /*split_io=*/false)();  } +size_t ModuleReader::translate_port_index(LogicalNetlist::Netlist::PortInstance::Reader port_inst) const { +    LogicalNetlist::Netlist::Port::Reader port = root->root.getPortList()[port_inst.getPort()]; +    if(port_inst.getBusIdx().isSingleBit()) { +        NPNR_ASSERT(port.isBit()); +        return 0; +    } else { +        NPNR_ASSERT(port.isBus()); +        uint32_t idx = port_inst.getBusIdx().getIdx(); +        size_t width = get_port_width(port); +        NPNR_ASSERT(idx >= 0 && idx < width); +        return width - 1 - idx; +    } +} +  NEXTPNR_NAMESPACE_END diff --git a/fpga_interchange/site_router.cc b/fpga_interchange/site_router.cc index a22dfcd3..7232b635 100644 --- a/fpga_interchange/site_router.cc +++ b/fpga_interchange/site_router.cc @@ -22,9 +22,9 @@  NEXTPNR_NAMESPACE_BEGIN -bool verbose_site_router(const Context *ctx) { return ctx->verbose; } +bool verbose_site_router(const Context *ctx) { return ctx->debug; } -void Arch::SiteRouter::bindBel(CellInfo *cell) +void SiteRouter::bindBel(CellInfo *cell)  {      auto result = cells_in_site.emplace(cell);      NPNR_ASSERT(result.second); @@ -32,7 +32,7 @@ void Arch::SiteRouter::bindBel(CellInfo *cell)      dirty = true;  } -void Arch::SiteRouter::unbindBel(CellInfo *cell) +void SiteRouter::unbindBel(CellInfo *cell)  {      NPNR_ASSERT(cells_in_site.erase(cell) == 1); @@ -56,6 +56,22 @@ struct RouteNode      PipId pip;   // What pip was taken to reach this node.      WireId wire; // What wire is this routing node located at? + +    void print_route(const Context *ctx) const +    { +        log_info(" %s (via %s)\n", ctx->nameOfWire(wire), ctx->nameOfPip(pip)); + +        Node node = parent; +        while (node != RouteNode::Node()) { +            if (node->pip != PipId()) { +                log_info(" %s (via %s)\n", ctx->nameOfWire(node->wire), ctx->nameOfPip(node->pip)); +            } else { +                log_info(" %s\n", ctx->nameOfWire(node->wire)); +            } + +            node = node->parent; +        } +    }  };  struct RouteNodeStorage @@ -260,10 +276,9 @@ struct SiteInformation              if (!result.second && result.first->second != net) {                  // Conflict, this wire is already in use and it's not                  // doesn't match! -                if(verbose_site_router(ctx)) { -                    log_info("Cannot select route because net %s != net %s\n", -                            result.first->second->name.c_str(ctx), -                            net->name.c_str(ctx)); +                if (verbose_site_router(ctx)) { +                    log_info("Cannot select route because net %s != net %s\n", result.first->second->name.c_str(ctx), +                             net->name.c_str(ctx));                  }                  return false; @@ -309,6 +324,8 @@ struct SiteInformation      std::unordered_set<const NetInfo *> nets_fully_within_site;      bool is_net_within_site(const NetInfo *net) const { return nets_fully_within_site.count(net); } + +    void print_current_state() const;  };  struct SiteExpansionLoop @@ -605,6 +622,10 @@ bool route_site(const Context *ctx, SiteInformation *site_info)          std::unordered_map<WireId, std::unordered_set<const NetInfo *>> wire_congestion; +        for (auto &consumed_wire : site_info->consumed_wires) { +            wire_congestion[consumed_wire.first].emplace(consumed_wire.second); +        } +          for (auto &expansion_wire : wire_to_expansion) {              auto &expansion = *expansion_wire.second; @@ -642,8 +663,15 @@ bool route_site(const Context *ctx, SiteInformation *site_info)              if (uncongestion_route != RouteNode::Node()) {                  // Select a trivially uncongested route if possible. -                NPNR_ASSERT(site_info->select_route(expansion.first_wire, uncongestion_route, expansion.net_for_wire, -                                                    &newly_consumed_wires)); +                if (!site_info->select_route(expansion.first_wire, uncongestion_route, expansion.net_for_wire, +                                             &newly_consumed_wires)) { +                    log_info("Failed to bind uncongested path with wire %s on net %s\n", +                             ctx->nameOfWire(expansion.first_wire), expansion.net_for_wire->name.c_str(ctx)); +                    uncongestion_route->print_route(ctx); + +                    site_info->print_current_state(); +                    NPNR_ASSERT(false); +                }                  completed_wires.push_back(expansion.first_wire);              }          } @@ -676,7 +704,7 @@ bool route_site(const Context *ctx, SiteInformation *site_info)      return true;  } -bool Arch::SiteRouter::checkSiteRouting(const Context *ctx, const Arch::TileStatus &tile_status) const +bool SiteRouter::checkSiteRouting(const Context *ctx, const TileStatus &tile_status) const  {      if (!dirty) {          return site_ok; @@ -753,4 +781,42 @@ bool Arch::SiteRouter::checkSiteRouting(const Context *ctx, const Arch::TileStat      return site_ok;  } +void SiteInformation::print_current_state() const +{ +    const CellInfo *cell = *cells_in_site.begin(); +    BelId bel = cell->bel; +    const auto &bel_data = bel_info(ctx->chip_info, bel); +    const auto &site_inst = site_inst_info(ctx->chip_info, bel.tile, bel_data.site); + +    log_info("Site %s\n", site_inst.name.get()); + +    log_info(" Cells in site:\n"); +    for (CellInfo *cell : cells_in_site) { +        log_info("  - %s (%s)\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); +    } + +    log_info(" Nets in site:\n"); +    for (auto *net : nets_in_site) { +        log_info("  - %s, pins in site:\n", net->name.c_str(ctx)); +        if (net->driver.cell && cells_in_site.count(net->driver.cell)) { +            log_info("    - %s/%s (%s)\n", net->driver.cell->name.c_str(ctx), net->driver.port.c_str(ctx), +                     net->driver.cell->type.c_str(ctx)); +        } + +        for (const auto user : net->users) { +            if (user.cell && cells_in_site.count(user.cell)) { +                log_info("    - %s/%s (%s)\n", user.cell->name.c_str(ctx), user.port.c_str(ctx), +                         user.cell->type.c_str(ctx)); +            } +        } +    } + +    log_info(" Consumed wires:\n"); +    for (auto consumed_wire : consumed_wires) { +        WireId wire = consumed_wire.first; +        const NetInfo *net = consumed_wire.second; +        log_info("  - %s is bound to %s\n", ctx->nameOfWire(wire), net->name.c_str(ctx)); +    } +} +  NEXTPNR_NAMESPACE_END diff --git a/fpga_interchange/site_router.h b/fpga_interchange/site_router.h new file mode 100644 index 00000000..561dae9d --- /dev/null +++ b/fpga_interchange/site_router.h @@ -0,0 +1,45 @@ +/* + *  nextpnr -- Next Generation Place and Route + * + *  Copyright (C) 2021  Symbiflow Authors + * + * + *  Permission to use, copy, modify, and/or distribute this software for any + *  purpose with or without fee is hereby granted, provided that the above + *  copyright notice and this permission notice appear in all copies. + * + *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef NEXTPNR_H +#error Include "site_router.h" via "nextpnr.h" only. +#endif + +NEXTPNR_NAMESPACE_BEGIN + +struct Context; +struct TileStatus; + +struct SiteRouter +{ +    SiteRouter(int16_t site) : site(site), dirty(false), site_ok(true) {} + +    std::unordered_set<CellInfo *> cells_in_site; +    const int16_t site; + +    mutable bool dirty; +    mutable bool site_ok; + +    void bindBel(CellInfo *cell); +    void unbindBel(CellInfo *cell); +    bool checkSiteRouting(const Context *ctx, const TileStatus &tile_status) const; +}; + +NEXTPNR_NAMESPACE_END  | 
