diff options
-rw-r--r-- | fpga_interchange/arch.cc | 132 | ||||
-rw-r--r-- | fpga_interchange/arch.h | 14 | ||||
-rw-r--r-- | fpga_interchange/chipdb.h | 3 |
3 files changed, 143 insertions, 6 deletions
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index 4bb72ecb..1cefb6fe 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -747,6 +747,40 @@ bool Arch::route_vcc_to_unused_lut_pins() { std::string router = str_or_default(settings, id("router"), defaultRouter); + HashTables::HashMap<WireId, const NetInfo *> bound_wires; + for (auto &net_pair : nets) { + const NetInfo *net = net_pair.second.get(); + for (auto &wire_pair : net->wires) { + auto result = bound_wires.emplace(wire_pair.first, net); + NPNR_ASSERT(result.first->second == net); + + PipId pip = wire_pair.second.pip; + if (pip == PipId()) { + continue; + } + + const PipInfoPOD &pip_data = pip_info(chip_info, pip); +#ifdef DEBUG_LUT_MAPPING + if (getCtx()->verbose) { + log_info("Pip %s in use, has %zu pseudo wires!\n", nameOfPip(pip), pip_data.pseudo_cell_wires.size()); + } +#endif + + WireId wire; + wire.tile = pip.tile; + for (int32_t wire_index : pip_data.pseudo_cell_wires) { + wire.index = wire_index; +#ifdef DEBUG_LUT_MAPPING + if (getCtx()->verbose) { + log_info("Marking wire %s as in use due to pseudo pip\n", nameOfWire(wire)); + } +#endif + auto result = bound_wires.emplace(wire, net); + NPNR_ASSERT(result.first->second == net); + } + } + } + // Fixup LUT vcc pins. IdString vcc_net_name(chip_info->constants->vcc_net_name); for (BelId bel : getBels()) { @@ -766,14 +800,22 @@ bool Arch::route_vcc_to_unused_lut_pins() port_info.net = nullptr; WireId lut_pin_wire = getBelPinWire(bel, bel_pin); - auto iter = wire_to_net.find(lut_pin_wire); - if (iter != wire_to_net.end()) { - if (iter->second != nullptr) { - // This pin is now used by a route through. - continue; + auto iter = bound_wires.find(lut_pin_wire); + if (iter != bound_wires.end()) { +#ifdef DEBUG_LUT_MAPPING + if (getCtx()->verbose) { + log_info("%s is now used as a LUT route-through, not tying to VCC\n", nameOfWire(lut_pin_wire)); } +#endif + continue; } +#ifdef DEBUG_LUT_MAPPING + if (getCtx()->verbose) { + log_info("%s is an unused LUT pin, tying to VCC\n", nameOfWire(lut_pin_wire)); + } +#endif + auto result = cell->ports.emplace(bel_pin, port_info); if (result.second) { cell->cell_bel_pins[bel_pin].push_back(bel_pin); @@ -1351,6 +1393,55 @@ void Arch::decode_lut_cells() } } +void Arch::remove_pip_pseudo_wires(PipId pip, NetInfo *net) +{ + WireId wire; + wire.tile = pip.tile; + const PipInfoPOD &pip_data = pip_info(chip_info, pip); + for (int32_t wire_index : pip_data.pseudo_cell_wires) { + NPNR_ASSERT(wire_index != -1); + wire.index = wire_index; + + auto iter = wire_to_net.find(wire); + NPNR_ASSERT(iter != wire_to_net.end()); + // This wire better already have been assigned to this net! + if (iter->second != net) { + if (iter->second == nullptr) { + log_error("Wire %s part of pseudo pip %s but net is null\n", nameOfWire(wire), nameOfPip(pip)); + } else { + log_error("Wire %s part of pseudo pip %s but net is '%s' instead of net '%s'\n", nameOfWire(wire), + nameOfPip(pip), iter->second->name.c_str(this), net->name.c_str(this)); + } + } + + auto wire_iter = net->wires.find(wire); + if (wire_iter != net->wires.end()) { +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("Removing %s from net %s, but it's in net wires\n", nameOfWire(wire), net->name.c_str(this)); + } +#endif + // This wire is part of net->wires, make sure it has no pip, + // but leave it alone. It will get cleaned up via + // unbindWire. + if (wire_iter->second.pip != PipId() && wire_iter->second.pip != pip) { + log_error("Wire %s report source'd from pip %s, which is not %s\n", nameOfWire(wire), + nameOfPip(wire_iter->second.pip), nameOfPip(pip)); + } + NPNR_ASSERT(wire_iter->second.pip == PipId() || wire_iter->second.pip == pip); + } else { + // This wire is not in net->wires, update wire_to_net. +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("Removing %s from net %s in remove_pip_pseudo_wires\n", nameOfWire(wire), + net->name.c_str(this)); + } +#endif + iter->second = nullptr; + } + } +} + void Arch::assign_net_to_wire(WireId wire, NetInfo *net, const char *src, bool require_empty) { #ifdef DEBUG_BINDING @@ -1402,6 +1493,7 @@ void Arch::unassign_wire(WireId wire) NPNR_ASSERT(pip_iter != pip_to_net.end()); NPNR_ASSERT(pip_iter->second == net); pip_iter->second = nullptr; + remove_pip_pseudo_wires(pip, net); } net_wires.erase(it); @@ -1430,6 +1522,9 @@ void Arch::unbindPip(PipId pip) WireId dst = getPipDstWire(pip); auto wire_iter = wire_to_net.find(dst); NPNR_ASSERT(wire_iter != wire_to_net.end()); + NPNR_ASSERT(wire_iter->second == net); + + remove_pip_pseudo_wires(pip, net); // Clear the net now. pip_iter->second = nullptr; @@ -1466,6 +1561,7 @@ void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength) } assign_net_to_wire(dst, net, "bindPip", /*require_empty=*/true); + assign_pip_pseudo_wires(pip, net); { auto result = net->wires.emplace(dst, PipMap{pip, strength}); @@ -1516,6 +1612,7 @@ bool Arch::check_pip_avail_for_net(PipId pip, NetInfo *net) const } } + WireId src = getPipSrcWire(pip); WireId dst = getPipDstWire(pip); auto wire_iter = wire_to_net.find(dst); @@ -1550,7 +1647,28 @@ bool Arch::check_pip_avail_for_net(PipId pip, NetInfo *net) const } } + // If this pip is a route-though, make sure all of the route-though + // wires are unbound. const PipInfoPOD &pip_data = pip_info(chip_info, pip); + WireId wire; + wire.tile = pip.tile; + for (int32_t wire_index : pip_data.pseudo_cell_wires) { + wire.index = wire_index; + NPNR_ASSERT(src != wire); + NPNR_ASSERT(dst != wire); + + NetInfo *net = getConflictingWireNet(wire); + if (net != nullptr) { +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("Pip %s is not available because wire %s is tied to net %s\n", getCtx()->nameOfPip(pip), + getCtx()->nameOfWire(wire), net->name.c_str(getCtx())); + } +#endif + return false; + } + } + if (pip_data.site != -1 && net != nullptr) { NPNR_ASSERT(net->driver.cell != nullptr); NPNR_ASSERT(net->driver.cell->bel != BelId()); @@ -1600,6 +1718,10 @@ bool Arch::check_pip_avail_for_net(PipId pip, NetInfo *net) const } } + // FIXME: This pseudo pip check is incomplete, because constraint + // failures will not be detected. However the current FPGA + // interchange schema does not provide a cell type to place. + return true; } diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h index 84c0b7c8..6a3d7ad1 100644 --- a/fpga_interchange/arch.h +++ b/fpga_interchange/arch.h @@ -515,6 +515,20 @@ struct Arch : ArchAPI<ArchRanges> void assign_net_to_wire(WireId wire, NetInfo *net, const char *src, bool require_empty); + void assign_pip_pseudo_wires(PipId pip, NetInfo *net) + { + NPNR_ASSERT(net != nullptr); + WireId wire; + wire.tile = pip.tile; + const PipInfoPOD &pip_data = pip_info(chip_info, pip); + for (int32_t wire_index : pip_data.pseudo_cell_wires) { + wire.index = wire_index; + assign_net_to_wire(wire, net, "pseudo", /*require_empty=*/true); + } + } + + void remove_pip_pseudo_wires(PipId pip, NetInfo *net); + void unassign_wire(WireId wire); void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) final; diff --git a/fpga_interchange/chipdb.h b/fpga_interchange/chipdb.h index 2130f1b6..2f82dcc9 100644 --- a/fpga_interchange/chipdb.h +++ b/fpga_interchange/chipdb.h @@ -34,7 +34,7 @@ NEXTPNR_NAMESPACE_BEGIN * kExpectedChipInfoVersion */ -static constexpr int32_t kExpectedChipInfoVersion = 1; +static constexpr int32_t kExpectedChipInfoVersion = 2; // Flattened site indexing. // @@ -110,6 +110,7 @@ NPNR_PACKED_STRUCT(struct PipInfoPOD { int16_t site_variant; // site variant index in tile int16_t bel; // BEL this pip belongs to if site pip. int16_t extra_data; + RelSlice<int32_t> pseudo_cell_wires; }); NPNR_PACKED_STRUCT(struct ConstraintTagPOD { |