diff options
author | gatecat <gatecat@ds0.me> | 2021-03-22 09:30:38 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-22 09:30:38 +0000 |
commit | 68ca923bfefde24fa2b7cbc8c6f9817f1d93e1e5 (patch) | |
tree | bad29dce65cf448e36704e6d7b1773d8dfd573a2 | |
parent | f52b5229642cdb54d61b54f5ab9a7478a119298e (diff) | |
parent | 22c6754bcd08f66b6f8e87a58dc09ed260c72c25 (diff) | |
download | nextpnr-68ca923bfefde24fa2b7cbc8c6f9817f1d93e1e5.tar.gz nextpnr-68ca923bfefde24fa2b7cbc8c6f9817f1d93e1e5.tar.bz2 nextpnr-68ca923bfefde24fa2b7cbc8c6f9817f1d93e1e5.zip |
Merge pull request #635 from litghost/refactor_headers
Refactor header structures in FPGA interchange Arch.
-rw-r--r-- | common/nextpnr_namespaces.h | 3 | ||||
-rw-r--r-- | fpga_interchange/arch.cc | 294 | ||||
-rw-r--r-- | fpga_interchange/arch.h | 1036 | ||||
-rw-r--r-- | fpga_interchange/arch_iterators.h | 497 | ||||
-rw-r--r-- | fpga_interchange/archdefs.h | 5 | ||||
-rw-r--r-- | fpga_interchange/chipdb.h | 310 | ||||
-rw-r--r-- | fpga_interchange/luts.cc | 18 | ||||
-rw-r--r-- | fpga_interchange/xdc.cc | 8 | ||||
-rw-r--r-- | fpga_interchange/xdc.h | 12 | ||||
m--------- | tests | 0 |
10 files changed, 1292 insertions, 891 deletions
diff --git a/common/nextpnr_namespaces.h b/common/nextpnr_namespaces.h index 8242376c..e6985ffe 100644 --- a/common/nextpnr_namespaces.h +++ b/common/nextpnr_namespaces.h @@ -38,16 +38,19 @@ #define NPNR_NORETURN __attribute__((noreturn)) #define NPNR_DEPRECATED __attribute__((deprecated)) #define NPNR_PACKED_STRUCT(...) __VA_ARGS__ __attribute__((packed)) +#define NPNR_ALWAYS_INLINE NPNR_ATTRIBUTE(__always_inline__) #elif defined(_MSC_VER) #define NPNR_ATTRIBUTE(...) #define NPNR_NORETURN __declspec(noreturn) #define NPNR_DEPRECATED __declspec(deprecated) #define NPNR_PACKED_STRUCT(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop)) +#define NPNR_ALWAYS_INLINE #else #define NPNR_ATTRIBUTE(...) #define NPNR_NORETURN #define NPNR_DEPRECATED #define NPNR_PACKED_STRUCT(...) __VA_ARGS__ +#define NPNR_ALWAYS_INLINE #endif #endif /* NEXTPNR_NAMESPACES_H */ diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index 3839f579..4bb72ecb 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -19,6 +19,8 @@ * */ +#include "arch.h" + #include <algorithm> #include <boost/algorithm/string.hpp> #include <boost/range/adaptor/reversed.hpp> @@ -37,6 +39,9 @@ #include "util.h" #include "xdc.h" +// Include tcl.h late because it messed with defines and let them leave the +// scope of the header. +#include <tcl.h> NEXTPNR_NAMESPACE_BEGIN struct SiteBelPair { @@ -90,6 +95,10 @@ Arch::Arch(ArchArgs args) : args(args) log_error("Unable to read chipdb %s\n", args.chipdb.c_str()); } + if (chip_info->version != kExpectedChipInfoVersion) { + log_error("Expected chipdb with version %d found version %d\n", kExpectedChipInfoVersion, chip_info->version); + } + // Read strings from constids into IdString database, checking that list // is unique and matches expected constid value. const RelSlice<RelPtr<char>> &constids = *chip_info->constids; @@ -254,6 +263,8 @@ IdString Arch::archArgsToId(ArchArgs args) const { return IdString(); } void Arch::setup_byname() const { + by_name_mutex.lock(); + if (tile_by_name.empty()) { for (int i = 0; i < chip_info->tiles.ssize(); i++) { tile_by_name[id(chip_info->tiles[i].name.get())] = i; @@ -270,6 +281,8 @@ void Arch::setup_byname() const } } } + + by_name_mutex.unlock(); } BelId Arch::getBelByName(IdStringList name) const @@ -416,7 +429,8 @@ PipId Arch::getPipByName(IdStringList name) const int tile; int site; std::tie(tile, site) = site_by_name.at(site_name); - auto &tile_info = chip_info->tile_types[chip_info->tiles[tile].type]; + auto tile_type_idx = chip_info->tiles[tile].type; + auto &tile_info = chip_info->tile_types[tile_type_idx]; std::array<IdString, 2> ids{name.ids[0], belname}; BelId bel = getBelByName(IdStringList(ids)); @@ -444,7 +458,8 @@ PipId Arch::getPipByName(IdStringList name) const int tile; int site; std::tie(tile, site) = iter->second; - auto &tile_info = chip_info->tile_types[chip_info->tiles[tile].type]; + auto tile_type_idx = chip_info->tiles[tile].type; + auto &tile_info = chip_info->tile_types[tile_type_idx]; std::string pip_second = name.ids[1].str(this); auto split = pip_second.find('.'); @@ -500,7 +515,8 @@ PipId Arch::getPipByName(IdStringList name) const } } else { int tile = tile_by_name.at(name.ids[0]); - auto &tile_info = chip_info->tile_types[chip_info->tiles[tile].type]; + size_t tile_type_idx = chip_info->tiles[tile].type; + auto &tile_info = chip_info->tile_types[tile_type_idx]; std::string pip_second = name.ids[1].str(this); auto spn = split_identifier_name_dot(pip_second); @@ -618,11 +634,14 @@ ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const int dst_tile = dst.tile == -1 ? chip_info->nodes[dst.index].tile_wires[0].tile : dst.tile; int src_tile = src.tile == -1 ? chip_info->nodes[src.index].tile_wires[0].tile : src.tile; - int x0, x1, y0, y1; - x0 = src_tile % chip_info->width; - x1 = x0; - y0 = src_tile / chip_info->width; - y1 = y0; + int x0 = 0, x1 = 0, y0 = 0, y1 = 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); + auto expand = [&](int x, int y) { x0 = std::min(x0, x); x1 = std::max(x1, x); @@ -630,7 +649,8 @@ ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const y1 = std::max(y1, y); }; - expand(dst_tile % chip_info->width, dst_tile / chip_info->width); + expand(src_x, src_y); + expand(dst_x, dst_y); if (source_locs.count(src)) expand(source_locs.at(src).x, source_locs.at(src).y); @@ -1331,6 +1351,262 @@ void Arch::decode_lut_cells() } } +void Arch::assign_net_to_wire(WireId wire, NetInfo *net, const char *src, bool require_empty) +{ +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("Assigning wire %s to %s from %s\n", nameOfWire(wire), net->name.c_str(this), src); + } +#endif + NPNR_ASSERT(net != nullptr); + auto result = wire_to_net.emplace(wire, net); + if (!result.second) { + // This wire was already in the map, make sure this assignment was + // legal. + if (require_empty) { + NPNR_ASSERT(result.first->second == nullptr); + } else { + NPNR_ASSERT(result.first->second == nullptr || result.first->second == net); + } + result.first->second = net; + } +} + +void Arch::unassign_wire(WireId wire) +{ + NPNR_ASSERT(wire != WireId()); +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("unassign_wire %s\n", nameOfWire(wire)); + } +#endif + + auto iter = wire_to_net.find(wire); + NPNR_ASSERT(iter != wire_to_net.end()); + + NetInfo *net = iter->second; + NPNR_ASSERT(net != nullptr); + + auto &net_wires = net->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); + + auto pip = it->second.pip; + if (pip != PipId()) { +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("Removing pip %s because it was used to reach wire %s\n", nameOfPip(pip), nameOfWire(wire)); + } +#endif + auto pip_iter = pip_to_net.find(pip); + NPNR_ASSERT(pip_iter != pip_to_net.end()); + NPNR_ASSERT(pip_iter->second == net); + pip_iter->second = nullptr; + } + + net_wires.erase(it); +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("Removing %s from net %s in unassign_wire\n", nameOfWire(wire), net->name.c_str(this)); + } +#endif + iter->second = nullptr; +} + +void Arch::unbindPip(PipId pip) +{ + NPNR_ASSERT(pip != PipId()); +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("unbindPip %s\n", nameOfPip(pip)); + } +#endif + + auto pip_iter = pip_to_net.find(pip); + NPNR_ASSERT(pip_iter != pip_to_net.end()); + NetInfo *net = pip_iter->second; + NPNR_ASSERT(net != nullptr); + + WireId dst = getPipDstWire(pip); + auto wire_iter = wire_to_net.find(dst); + NPNR_ASSERT(wire_iter != wire_to_net.end()); + + // Clear the net now. + pip_iter->second = nullptr; +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("Removing %s from net %s in unbindPip\n", nameOfWire(dst), net->name.c_str(this)); + } +#endif + wire_iter->second = nullptr; + NPNR_ASSERT(net->wires.erase(dst) == 1); + + refreshUiPip(pip); + refreshUiWire(dst); +} + +void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength) +{ + NPNR_ASSERT(pip != PipId()); +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("bindPip %s (%d/%d) to net %s\n", nameOfPip(pip), pip.tile, pip.index, net->name.c_str(this)); + } +#endif + WireId dst = getPipDstWire(pip); + NPNR_ASSERT(dst != WireId()); + + { + // Pip should not already be assigned to anything. + auto result = pip_to_net.emplace(pip, net); + if (!result.second) { + NPNR_ASSERT(result.first->second == nullptr); + result.first->second = net; + } + } + + assign_net_to_wire(dst, net, "bindPip", /*require_empty=*/true); + + { + auto result = net->wires.emplace(dst, PipMap{pip, strength}); + NPNR_ASSERT(result.second); + } + + refreshUiPip(pip); + refreshUiWire(dst); +} + +void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength) +{ + NPNR_ASSERT(wire != WireId()); +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("bindWire %s to net %s\n", nameOfWire(wire), net->name.c_str(this)); + } +#endif + assign_net_to_wire(wire, net, "bindWire", /*require_empty=*/true); + auto &pip_map = net->wires[wire]; + pip_map.pip = PipId(); + pip_map.strength = strength; + refreshUiWire(wire); +} + +bool Arch::check_pip_avail_for_net(PipId pip, NetInfo *net) const +{ + NPNR_ASSERT(pip != PipId()); + auto pip_iter = pip_to_net.find(pip); + if (pip_iter != pip_to_net.end() && pip_iter->second != nullptr) { + bool pip_blocked = false; + if (net == nullptr) { + pip_blocked = true; + } else { + if (net != pip_iter->second) { + pip_blocked = true; + } + } + if (pip_blocked) { +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("Pip %s (%d/%d) is not available, tied to net %s\n", getCtx()->nameOfPip(pip), pip.tile, + pip.index, pip_iter->second->name.c_str(getCtx())); + } +#endif + NPNR_ASSERT(pip_iter->first == pip); + return false; + } + } + + WireId dst = getPipDstWire(pip); + + auto wire_iter = wire_to_net.find(dst); + if (wire_iter != wire_to_net.end()) { + NetInfo *wire_net = wire_iter->second; + if (wire_net != nullptr) { + auto net_iter = wire_net->wires.find(dst); + if (net_iter != wire_net->wires.end()) { + if (net == nullptr) { +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("Pip %s (%d/%d) is not available, dst wire %s is tied to net %s\n", + getCtx()->nameOfPip(pip), pip.tile, pip.index, getCtx()->nameOfWire(dst), + wire_net->name.c_str(getCtx())); + } +#endif + // dst is already driven in this net, do not allow! + return false; + } else { +#ifdef DEBUG_BINDING + if (getCtx()->verbose && net_iter->second.pip != pip) { + log_info("Pip %s (%d/%d) is not available, dst wire %s is tied to net %s\n", + getCtx()->nameOfPip(pip), pip.tile, pip.index, getCtx()->nameOfWire(dst), + wire_net->name.c_str(getCtx())); + } +#endif + // This pip is available if this pip is already bound to + // this. + return net_iter->second.pip == pip; + } + } + } + } + + const PipInfoPOD &pip_data = pip_info(chip_info, pip); + if (pip_data.site != -1 && net != nullptr) { + NPNR_ASSERT(net->driver.cell != nullptr); + NPNR_ASSERT(net->driver.cell->bel != BelId()); + + bool valid_pip = false; + if (pip.tile == net->driver.cell->bel.tile) { + auto &bel_data = bel_info(chip_info, net->driver.cell->bel); + if (bel_data.site == pip_data.site) { + valid_pip = true; + } + } + + if (!valid_pip) { + // See if one users can enter this site. + auto &tile_type = loc_info(chip_info, pip); + auto &src_wire_data = tile_type.wire_data[pip_data.src_index]; + auto &dst_wire_data = tile_type.wire_data[pip_data.dst_index]; + + if (dst_wire_data.site == -1) { + // This is an output site port, but not for the driver net. + // Disallow. + NPNR_ASSERT(src_wire_data.site == pip_data.site); + } else { + // This might be a valid pip, scan users. + for (auto &user : net->users) { + NPNR_ASSERT(user.cell != nullptr); + if (user.cell->bel == BelId()) { + continue; + } + + auto &bel_data = bel_info(chip_info, user.cell->bel); + if (bel_data.site == pip_data.site) { + valid_pip = true; + break; + } + } + } + } + + if (!valid_pip) { +#ifdef DEBUG_BINDING + if (getCtx()->verbose) { + log_info("Pip %s is within a site and not available not right now\n", getCtx()->nameOfPip(pip)); + } +#endif + return false; + } + } + + return true; +} + +bool Arch::checkPipAvail(PipId pip) const { return check_pip_avail_for_net(pip, nullptr); } + +Arch::~Arch() {} + // 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 05bc1a94..84c0b7c8 100644 --- a/fpga_interchange/arch.h +++ b/fpga_interchange/arch.h @@ -27,739 +27,19 @@ #include <iostream> #include <regex> +#include "PhysicalNetlist.capnp.h" #include "arch_api.h" #include "constraints.h" #include "nextpnr_types.h" #include "relptr.h" +#include "arch_iterators.h" +#include "chipdb.h" #include "dedicated_interconnect.h" #include "site_router.h" NEXTPNR_NAMESPACE_BEGIN -/**** Everything in this section must be kept in sync with chipdb.py ****/ - -// Flattened site indexing. -// -// To enable flat BelId.z spaces, every tile and sites within that tile are -// flattened. -// -// This has implications on BelId's, WireId's and PipId's. -// The flattened site space works as follows: -// - Objects that belong to the tile are first. BELs are always part of Sites, -// so no BEL objects are in this category. -// - All site alternative modes are exposed as a "full" site. -// - Each site appends it's BEL's, wires (site wires) and PIP's. -// - Sites add two types of pips. Sites will add pip data first for site -// pips, and then for site pin edges. -// 1. The first type is site pips, which connect site wires to other site -// wires. -// 2. The second type is site pin edges, which connect site wires to tile -// wires (or vise-versa). - -NPNR_PACKED_STRUCT(struct BelInfoPOD { - int32_t name; // bel name (in site) constid - int32_t type; // Type name constid - int32_t bel_bucket; // BEL bucket constid. - - int32_t num_bel_wires; - RelPtr<int32_t> ports; // port name constid - RelPtr<int32_t> types; // port type (IN/OUT/BIDIR) - RelPtr<int32_t> wires; // connected wire index in tile, or -1 if NA - - int16_t site; - int16_t site_variant; // some sites have alternative types - int16_t category; - int8_t synthetic; - int8_t lut_element; - - RelPtr<int32_t> pin_map; // Index into CellMapPOD::cell_bel_map -}); - -enum BELCategory -{ - // BEL is a logic element - BEL_CATEGORY_LOGIC = 0, - // BEL is a site routing mux - BEL_CATEGORY_ROUTING = 1, - // BEL is a site port, e.g. boundry between site and routing graph. - BEL_CATEGORY_SITE_PORT = 2 -}; - -NPNR_PACKED_STRUCT(struct BelPortPOD { - int32_t bel_index; - int32_t port; -}); - -NPNR_PACKED_STRUCT(struct TileWireInfoPOD { - int32_t name; // wire name constid - - // Pip index inside tile - RelSlice<int32_t> pips_uphill; - - // Pip index inside tile - RelSlice<int32_t> pips_downhill; - - // Bel index inside tile - RelSlice<BelPortPOD> bel_pins; - - int16_t site; // site index in tile - int16_t site_variant; // site variant index in tile -}); - -NPNR_PACKED_STRUCT(struct PipInfoPOD { - int32_t src_index, dst_index; - int16_t site; // site index in tile - int16_t site_variant; // site variant index in tile - int16_t bel; // BEL this pip belongs to if site pip. - int16_t extra_data; -}); - -NPNR_PACKED_STRUCT(struct ConstraintTagPOD { - int32_t tag_prefix; // constid - int32_t default_state; // constid - RelSlice<int32_t> states; // constid -}); - -NPNR_PACKED_STRUCT(struct LutBelPOD { - uint32_t name; // constid - RelSlice<int32_t> pins; // constid - uint32_t low_bit; - uint32_t high_bit; -}); - -NPNR_PACKED_STRUCT(struct LutElementPOD { - int32_t width; - RelSlice<LutBelPOD> lut_bels; -}); - -NPNR_PACKED_STRUCT(struct TileTypeInfoPOD { - int32_t name; // Tile type constid - - RelSlice<BelInfoPOD> bel_data; - - RelSlice<TileWireInfoPOD> wire_data; - - RelSlice<PipInfoPOD> pip_data; - - RelSlice<ConstraintTagPOD> tags; - - RelSlice<LutElementPOD> lut_elements; - - RelSlice<int32_t> site_types; // constid -}); - -NPNR_PACKED_STRUCT(struct SiteInstInfoPOD { - RelPtr<char> name; - RelPtr<char> site_name; - - // Which site type is this site instance? - // constid - int32_t site_type; -}); - -NPNR_PACKED_STRUCT(struct TileInstInfoPOD { - // Name of this tile. - RelPtr<char> name; - - // Index into root.tile_types. - int32_t type; - - // This array is root.tile_types[type].site_types.size() long. - // Index into root.sites - RelSlice<int32_t> sites; - - // Number of tile wires; excluding any site-internal wires - // which come after general wires and are not stored here - // as they will never be nodal - // -1 if a tile-local wire; node index if nodal wire - RelSlice<int32_t> tile_wire_to_node; -}); - -NPNR_PACKED_STRUCT(struct TileWireRefPOD { - int32_t tile; - int32_t index; -}); - -NPNR_PACKED_STRUCT(struct NodeInfoPOD { RelSlice<TileWireRefPOD> tile_wires; }); - -NPNR_PACKED_STRUCT(struct CellBelPinPOD { - int32_t cell_pin; // constid - int32_t bel_pin; // constid -}); - -NPNR_PACKED_STRUCT(struct ParameterPinsPOD { - int32_t key; // constid - int32_t value; // constid - RelSlice<CellBelPinPOD> pins; -}); - -NPNR_PACKED_STRUCT(struct CellConstraintPOD { - int32_t tag; // Tag index - int32_t constraint_type; // Constraint::ConstraintType - RelSlice<int32_t> states; // State indicies -}); - -NPNR_PACKED_STRUCT(struct CellBelMapPOD { - RelSlice<CellBelPinPOD> common_pins; - RelSlice<ParameterPinsPOD> parameter_pins; - RelSlice<CellConstraintPOD> constraints; -}); - -NPNR_PACKED_STRUCT(struct LutCellPOD { - int32_t cell; // constid - RelSlice<int32_t> input_pins; // constids - int32_t parameter; -}); - -NPNR_PACKED_STRUCT(struct CellMapPOD { - // Cell names supported in this arch. - RelSlice<int32_t> cell_names; // constids - RelSlice<int32_t> cell_bel_buckets; // constids - - RelSlice<CellBelMapPOD> cell_bel_map; - - RelSlice<LutCellPOD> lut_cells; -}); - -NPNR_PACKED_STRUCT(struct PackagePinPOD { - int32_t package_pin; // constid - int32_t site; // constid - int32_t bel; // constid -}); - -NPNR_PACKED_STRUCT(struct PackagePOD { - int32_t package; // constid - RelSlice<PackagePinPOD> pins; -}); - -NPNR_PACKED_STRUCT(struct ConstantsPOD { - // Cell type and port for the GND and VCC global source. - int32_t gnd_cell_name; // constid - int32_t gnd_cell_port; // constid - - int32_t vcc_cell_name; // constid - int32_t vcc_cell_port; // constid - - int32_t gnd_bel_tile; - int32_t gnd_bel_index; - int32_t gnd_bel_pin; // constid - - int32_t vcc_bel_tile; - int32_t vcc_bel_index; - int32_t vcc_bel_pin; // constid - - // Name to use for the global GND constant net - int32_t gnd_net_name; // constid - - // Name to use for the global VCC constant net - int32_t vcc_net_name; // constid -}); - -NPNR_PACKED_STRUCT(struct ChipInfoPOD { - RelPtr<char> name; - RelPtr<char> generator; - - int32_t version; - int32_t width, height; - - RelSlice<TileTypeInfoPOD> tile_types; - RelSlice<SiteInstInfoPOD> sites; - RelSlice<TileInstInfoPOD> tiles; - RelSlice<NodeInfoPOD> nodes; - RelSlice<PackagePOD> packages; - - // BEL bucket constids. - RelSlice<int32_t> bel_buckets; - - RelPtr<CellMapPOD> cell_map; - RelPtr<ConstantsPOD> constants; - - // Constid string data. - RelPtr<RelSlice<RelPtr<char>>> constids; -}); - -/************************ End of chipdb section. ************************/ - -inline const TileTypeInfoPOD &tile_info(const ChipInfoPOD *chip_info, int32_t tile) -{ - return chip_info->tile_types[chip_info->tiles[tile].type]; -} - -template <typename Id> const TileTypeInfoPOD &loc_info(const ChipInfoPOD *chip_info, Id &id) -{ - return chip_info->tile_types[chip_info->tiles[id.tile].type]; -} - -inline const BelInfoPOD &bel_info(const ChipInfoPOD *chip_info, BelId bel) -{ - NPNR_ASSERT(bel != BelId()); - return loc_info(chip_info, bel).bel_data[bel.index]; -} - -inline const PipInfoPOD &pip_info(const ChipInfoPOD *chip_info, PipId pip) -{ - NPNR_ASSERT(pip != PipId()); - return loc_info(chip_info, pip).pip_data[pip.index]; -} - -inline const SiteInstInfoPOD &site_inst_info(const ChipInfoPOD *chip_info, int32_t tile, int32_t site) -{ - return chip_info->sites[chip_info->tiles[tile].sites[site]]; -} - -struct BelIterator -{ - const ChipInfoPOD *chip; - int cursor_index; - int cursor_tile; - - BelIterator operator++() - { - cursor_index++; - while (cursor_tile < chip->tiles.ssize() && cursor_index >= tile_info(chip, cursor_tile).bel_data.ssize()) { - cursor_index = 0; - cursor_tile++; - } - return *this; - } - BelIterator operator++(int) - { - BelIterator prior(*this); - ++(*this); - return prior; - } - - bool operator!=(const BelIterator &other) const - { - return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; - } - - bool operator==(const BelIterator &other) const - { - return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; - } - - BelId operator*() const - { - BelId ret; - ret.tile = cursor_tile; - ret.index = cursor_index; - return ret; - } -}; - -struct BelRange -{ - BelIterator b, e; - BelIterator begin() const { return b; } - BelIterator end() const { return e; } -}; - -struct FilteredBelIterator -{ - std::function<bool(BelId)> filter; - BelIterator b, e; - - FilteredBelIterator operator++() - { - ++b; - while (b != e) { - if (filter(*b)) { - break; - } - - ++b; - } - return *this; - } - - bool operator!=(const FilteredBelIterator &other) const - { - NPNR_ASSERT(e == other.e); - return b != other.b; - } - - bool operator==(const FilteredBelIterator &other) const - { - NPNR_ASSERT(e == other.e); - return b == other.b; - } - - BelId operator*() const - { - BelId bel = *b; - NPNR_ASSERT(filter(bel)); - return bel; - } -}; - -struct FilteredBelRange -{ - FilteredBelRange(BelIterator bel_b, BelIterator bel_e, std::function<bool(BelId)> filter) - { - b.filter = filter; - b.b = bel_b; - b.e = bel_e; - - if (b.b != b.e && !filter(*b.b)) { - ++b; - } - - e.b = bel_e; - e.e = bel_e; - - if (b != e) { - NPNR_ASSERT(filter(*b.b)); - } - } - - FilteredBelIterator b, e; - FilteredBelIterator begin() const { return b; } - FilteredBelIterator end() const { return e; } -}; - -// ----------------------------------------------------------------------- - -// Iterate over TileWires for a wire (will be more than one if nodal) -struct TileWireIterator -{ - const ChipInfoPOD *chip; - WireId baseWire; - int cursor = -1; - - void operator++() { cursor++; } - - bool operator==(const TileWireIterator &other) const { return cursor == other.cursor; } - bool operator!=(const TileWireIterator &other) const { return cursor != other.cursor; } - - // Returns a *denormalised* identifier always pointing to a tile wire rather than a node - WireId operator*() const - { - if (baseWire.tile == -1) { - WireId tw; - const auto &node_wire = chip->nodes[baseWire.index].tile_wires[cursor]; - tw.tile = node_wire.tile; - tw.index = node_wire.index; - return tw; - } else { - return baseWire; - } - } -}; - -struct TileWireRange -{ - TileWireIterator b, e; - TileWireIterator begin() const { return b; } - TileWireIterator end() const { return e; } -}; - -inline WireId canonical_wire(const ChipInfoPOD *chip_info, int32_t tile, int32_t wire) -{ - WireId id; - - if (wire >= chip_info->tiles[tile].tile_wire_to_node.ssize()) { - // Cannot be a nodal wire - id.tile = tile; - id.index = wire; - } else { - int32_t node = chip_info->tiles[tile].tile_wire_to_node[wire]; - if (node == -1) { - // Not a nodal wire - id.tile = tile; - id.index = wire; - } else { - // Is a nodal wire, set tile to -1 - id.tile = -1; - id.index = node; - } - } - - return id; -} - -// ----------------------------------------------------------------------- - -struct WireIterator -{ - const ChipInfoPOD *chip; - int cursor_index = 0; - int cursor_tile = -1; - - WireIterator operator++() - { - // Iterate over nodes first, then tile wires that aren't nodes - do { - cursor_index++; - if (cursor_tile == -1 && cursor_index >= chip->nodes.ssize()) { - cursor_tile = 0; - cursor_index = 0; - } - while (cursor_tile != -1 && cursor_tile < chip->tiles.ssize() && - cursor_index >= chip->tile_types[chip->tiles[cursor_tile].type].wire_data.ssize()) { - cursor_index = 0; - cursor_tile++; - } - - } while ((cursor_tile != -1 && cursor_tile < chip->tiles.ssize() && - cursor_index < chip->tiles[cursor_tile].tile_wire_to_node.ssize() && - chip->tiles[cursor_tile].tile_wire_to_node[cursor_index] != -1)); - - return *this; - } - WireIterator operator++(int) - { - WireIterator prior(*this); - ++(*this); - return prior; - } - - bool operator!=(const WireIterator &other) const - { - return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; - } - - bool operator==(const WireIterator &other) const - { - return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; - } - - WireId operator*() const - { - WireId ret; - ret.tile = cursor_tile; - ret.index = cursor_index; - return ret; - } -}; - -struct WireRange -{ - WireIterator b, e; - WireIterator begin() const { return b; } - WireIterator end() const { return e; } -}; - -// ----------------------------------------------------------------------- -struct AllPipIterator -{ - const ChipInfoPOD *chip; - int cursor_index; - int cursor_tile; - - AllPipIterator operator++() - { - cursor_index++; - while (cursor_tile < chip->tiles.ssize() && - cursor_index >= chip->tile_types[chip->tiles[cursor_tile].type].pip_data.ssize()) { - cursor_index = 0; - cursor_tile++; - } - return *this; - } - AllPipIterator operator++(int) - { - AllPipIterator prior(*this); - ++(*this); - return prior; - } - - bool operator!=(const AllPipIterator &other) const - { - return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; - } - - bool operator==(const AllPipIterator &other) const - { - return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; - } - - PipId operator*() const - { - PipId ret; - ret.tile = cursor_tile; - ret.index = cursor_index; - return ret; - } -}; - -struct AllPipRange -{ - AllPipIterator b, e; - AllPipIterator begin() const { return b; } - AllPipIterator end() const { return e; } -}; - -// ----------------------------------------------------------------------- - -struct UphillPipIterator -{ - const ChipInfoPOD *chip; - TileWireIterator twi, twi_end; - int cursor = -1; - - void operator++() - { - cursor++; - while (true) { - if (!(twi != twi_end)) - break; - WireId w = *twi; - auto &tile = chip->tile_types[chip->tiles[w.tile].type]; - if (cursor < tile.wire_data[w.index].pips_uphill.ssize()) - break; - ++twi; - cursor = 0; - } - } - bool operator!=(const UphillPipIterator &other) const { return twi != other.twi || cursor != other.cursor; } - - PipId operator*() const - { - PipId ret; - WireId w = *twi; - ret.tile = w.tile; - ret.index = chip->tile_types[chip->tiles[w.tile].type].wire_data[w.index].pips_uphill[cursor]; - return ret; - } -}; - -struct UphillPipRange -{ - UphillPipIterator b, e; - UphillPipIterator begin() const { return b; } - UphillPipIterator end() const { return e; } -}; - -struct DownhillPipIterator -{ - const ChipInfoPOD *chip; - TileWireIterator twi, twi_end; - int cursor = -1; - - void operator++() - { - cursor++; - while (true) { - if (!(twi != twi_end)) - break; - WireId w = *twi; - auto &tile = chip->tile_types[chip->tiles[w.tile].type]; - if (cursor < tile.wire_data[w.index].pips_downhill.ssize()) - break; - ++twi; - cursor = 0; - } - } - bool operator!=(const DownhillPipIterator &other) const { return twi != other.twi || cursor != other.cursor; } - - PipId operator*() const - { - PipId ret; - WireId w = *twi; - ret.tile = w.tile; - ret.index = chip->tile_types[chip->tiles[w.tile].type].wire_data[w.index].pips_downhill[cursor]; - return ret; - } -}; - -struct DownhillPipRange -{ - DownhillPipIterator b, e; - DownhillPipIterator begin() const { return b; } - DownhillPipIterator end() const { return e; } -}; - -struct BelPinIterator -{ - const ChipInfoPOD *chip; - TileWireIterator twi, twi_end; - int cursor = -1; - - void operator++() - { - cursor++; - - while (twi != twi_end) { - WireId w = *twi; - auto &tile = tile_info(chip, w.tile); - if (cursor < tile.wire_data[w.index].bel_pins.ssize()) - break; - - ++twi; - cursor = 0; - } - } - bool operator!=(const BelPinIterator &other) const { return twi != other.twi || cursor != other.cursor; } - - BelPin operator*() const - { - BelPin ret; - WireId w = *twi; - ret.bel.tile = w.tile; - ret.bel.index = tile_info(chip, w.tile).wire_data[w.index].bel_pins[cursor].bel_index; - ret.pin.index = tile_info(chip, w.tile).wire_data[w.index].bel_pins[cursor].port; - return ret; - } -}; - -struct BelPinRange -{ - BelPinIterator b, e; - BelPinIterator begin() const { return b; } - BelPinIterator end() const { return e; } -}; - -struct IdStringIterator : std::iterator<std::forward_iterator_tag, - /*T=*/IdString, - /*Distance=*/ptrdiff_t, - /*pointer=*/IdString *, - /*reference=*/IdString> -{ - const int32_t *cursor; - - void operator++() { cursor += 1; } - - bool operator!=(const IdStringIterator &other) const { return cursor != other.cursor; } - - bool operator==(const IdStringIterator &other) const { return cursor == other.cursor; } - - IdString operator*() const { return IdString(*cursor); } -}; - -struct IdStringRange -{ - IdStringIterator b, e; - IdStringIterator begin() const { return b; } - IdStringIterator end() const { return e; } -}; - -struct BelBucketIterator -{ - IdStringIterator cursor; - - void operator++() { ++cursor; } - - bool operator!=(const BelBucketIterator &other) const { return cursor != other.cursor; } - - bool operator==(const BelBucketIterator &other) const { return cursor == other.cursor; } - - BelBucketId operator*() const - { - BelBucketId bucket; - bucket.name = IdString(*cursor); - return bucket; - } -}; - -struct BelBucketRange -{ - BelBucketIterator b, e; - BelBucketIterator begin() const { return b; } - BelBucketIterator end() const { return e; } -}; - struct ArchArgs { std::string chipdb; @@ -813,6 +93,9 @@ struct Arch : ArchAPI<ArchRanges> const ChipInfoPOD *chip_info; int32_t package_index; + // Guard initialization of "by_name" maps if accessed from multiple + // threads on a "const Context *". + mutable std::mutex by_name_mutex; mutable std::unordered_map<IdString, int> tile_by_name; mutable std::unordered_map<IdString, std::pair<int, int>> site_by_name; @@ -824,13 +107,14 @@ struct Arch : ArchAPI<ArchRanges> ArchArgs args; Arch(ArchArgs args); + virtual ~Arch(); void init(); - std::string getChipName() const override; + std::string getChipName() const final; - IdString archId() const override { return id(chip_info->name.get()); } - ArchArgs archArgs() const override { return args; } - IdString archArgsToId(ArchArgs args) const override; + IdString archId() const final { return id(chip_info->name.get()); } + ArchArgs archArgs() const final { return args; } + IdString archArgsToId(ArchArgs args) const final; // ------------------------------------------------- @@ -848,17 +132,17 @@ struct Arch : ArchAPI<ArchRanges> get_tile_x_y(tile_index, &loc->x, &loc->y); } - int getGridDimX() const override { return chip_info->width; } - int getGridDimY() const override { return chip_info->height; } - int getTileBelDimZ(int x, int y) const override + int getGridDimX() const final { return chip_info->width; } + int getGridDimY() const final { return chip_info->height; } + int getTileBelDimZ(int x, int y) const final { return chip_info->tile_types[chip_info->tiles[get_tile_index(x, y)].type].bel_data.size(); } - int getTilePipDimZ(int x, int y) const override + int getTilePipDimZ(int x, int y) const final { return chip_info->tile_types[chip_info->tiles[get_tile_index(x, y)].type].site_types.size(); } - char getNameDelimiter() const override { return '/'; } + char getNameDelimiter() const final { return '/'; } std::string get_part() const; @@ -866,9 +150,9 @@ struct Arch : ArchAPI<ArchRanges> void setup_byname() const; - BelId getBelByName(IdStringList name) const override; + BelId getBelByName(IdStringList name) const final; - IdStringList getBelName(BelId bel) const override + IdStringList getBelName(BelId bel) const final { NPNR_ASSERT(bel != BelId()); const SiteInstInfoPOD &site = get_site_inst(bel); @@ -876,7 +160,7 @@ struct Arch : ArchAPI<ArchRanges> return IdStringList(ids); } - uint32_t getBelChecksum(BelId bel) const override { return bel.index; } + uint32_t getBelChecksum(BelId bel) const final { return bel.index; } void map_cell_pins(CellInfo *cell, int32_t mapping, bool bind_constants); void map_port_pins(BelId bel, CellInfo *cell) const; @@ -926,7 +210,19 @@ struct Arch : ArchAPI<ArchRanges> return bel; } - void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) override + PhysicalNetlist::PhysNetlist::NetType get_net_type(NetInfo *net) const + { + NPNR_ASSERT(net->driver.cell != nullptr); + if (net->driver.cell->bel == get_gnd_bel()) { + return PhysicalNetlist::PhysNetlist::NetType::GND; + } else if (net->driver.cell->bel == get_vcc_bel()) { + return PhysicalNetlist::PhysNetlist::NetType::VCC; + } else { + return PhysicalNetlist::PhysNetlist::NetType::SIGNAL; + } + } + + void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) final { NPNR_ASSERT(bel != BelId()); @@ -964,7 +260,7 @@ struct Arch : ArchAPI<ArchRanges> refreshUiBel(bel); } - void unbindBel(BelId bel) override + void unbindBel(BelId bel) final { NPNR_ASSERT(bel != BelId()); @@ -990,14 +286,14 @@ struct Arch : ArchAPI<ArchRanges> refreshUiBel(bel); } - bool checkBelAvail(BelId bel) const override + bool checkBelAvail(BelId bel) const final { // FIXME: This could consult the constraint system to see if this BEL // is blocked (e.g. site type is wrong). return getBoundBelCell(bel) == nullptr; } - CellInfo *getBoundBelCell(BelId bel) const override + CellInfo *getBoundBelCell(BelId bel) const final { NPNR_ASSERT(bel != BelId()); auto iter = tileStatus.find(bel.tile); @@ -1008,7 +304,7 @@ struct Arch : ArchAPI<ArchRanges> } } - CellInfo *getConflictingBelCell(BelId bel) const override + CellInfo *getConflictingBelCell(BelId bel) const final { NPNR_ASSERT(bel != BelId()); // FIXME: This could consult the constraint system to see why this BEL @@ -1016,7 +312,7 @@ struct Arch : ArchAPI<ArchRanges> return getBoundBelCell(bel); } - BelRange getBels() const override + BelRange getBels() const final { BelRange range; range.b.cursor_tile = 0; @@ -1029,7 +325,7 @@ struct Arch : ArchAPI<ArchRanges> return range; } - Loc getBelLocation(BelId bel) const override + Loc getBelLocation(BelId bel) const final { NPNR_ASSERT(bel != BelId()); Loc loc; @@ -1038,24 +334,24 @@ struct Arch : ArchAPI<ArchRanges> return loc; } - BelId getBelByLocation(Loc loc) const override; - BelRange getBelsByTile(int x, int y) const override; + BelId getBelByLocation(Loc loc) const final; + BelRange getBelsByTile(int x, int y) const final; - bool getBelGlobalBuf(BelId bel) const override + bool getBelGlobalBuf(BelId bel) const final { // FIXME: This probably needs to be fixed! return false; } - bool getBelHidden(BelId bel) const override { return bel_info(chip_info, bel).category != BEL_CATEGORY_LOGIC; } + bool getBelHidden(BelId bel) const final { return bel_info(chip_info, bel).category != BEL_CATEGORY_LOGIC; } - IdString getBelType(BelId bel) const override + IdString getBelType(BelId bel) const final { NPNR_ASSERT(bel != BelId()); return IdString(bel_info(chip_info, bel).type); } - std::vector<std::pair<IdString, std::string>> getBelAttrs(BelId bel) const override; + std::vector<std::pair<IdString, std::string>> getBelAttrs(BelId bel) const final; int get_bel_pin_index(BelId bel, IdString pin) const { @@ -1071,10 +367,10 @@ struct Arch : ArchAPI<ArchRanges> return -1; } - WireId getBelPinWire(BelId bel, IdString pin) const override; - PortType getBelPinType(BelId bel, IdString pin) const override; + WireId getBelPinWire(BelId bel, IdString pin) const final; + PortType getBelPinType(BelId bel, IdString pin) const final; - IdStringRange getBelPins(BelId bel) const override + IdStringRange getBelPins(BelId bel) const final { NPNR_ASSERT(bel != BelId()); @@ -1088,11 +384,11 @@ struct Arch : ArchAPI<ArchRanges> return str_range; } - const std::vector<IdString> &getBelPinsForCellPin(const CellInfo *cell_info, IdString pin) const override; + const std::vector<IdString> &getBelPinsForCellPin(const CellInfo *cell_info, IdString pin) const final; // ------------------------------------------------- - WireId getWireByName(IdStringList name) const override; + WireId getWireByName(IdStringList name) const final; const TileWireInfoPOD &wire_info(WireId wire) const { @@ -1104,7 +400,7 @@ struct Arch : ArchAPI<ArchRanges> } } - IdStringList getWireName(WireId wire) const override + IdStringList getWireName(WireId wire) const final { NPNR_ASSERT(wire != WireId()); if (wire.tile != -1) { @@ -1122,64 +418,44 @@ struct Arch : ArchAPI<ArchRanges> return IdStringList(ids); } - IdString getWireType(WireId wire) const override; - std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId wire) const override; + IdString getWireType(WireId wire) const final; + std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId wire) const final; - uint32_t getWireChecksum(WireId wire) const override { return wire.index; } + uint32_t getWireChecksum(WireId wire) const final { return wire.index; } - void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) override - { - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire] == nullptr); - wire_to_net[wire] = net; - net->wires[wire].pip = PipId(); - net->wires[wire].strength = strength; - refreshUiWire(wire); - } + void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) final; - void unbindWire(WireId wire) override + void unbindWire(WireId wire) final { NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire] != nullptr); - - auto &net_wires = wire_to_net[wire]->wires; - auto it = net_wires.find(wire); - NPNR_ASSERT(it != net_wires.end()); - - auto pip = it->second.pip; - if (pip != PipId()) { - pip_to_net[pip] = nullptr; - } - - net_wires.erase(it); - wire_to_net[wire] = nullptr; + unassign_wire(wire); refreshUiWire(wire); } - bool checkWireAvail(WireId wire) const override + bool checkWireAvail(WireId wire) const final { NPNR_ASSERT(wire != WireId()); auto w2n = wire_to_net.find(wire); return w2n == wire_to_net.end() || w2n->second == nullptr; } - NetInfo *getBoundWireNet(WireId wire) const override + NetInfo *getBoundWireNet(WireId wire) const final { NPNR_ASSERT(wire != WireId()); auto w2n = wire_to_net.find(wire); return w2n == wire_to_net.end() ? nullptr : w2n->second; } - WireId getConflictingWireWire(WireId wire) const override { return wire; } + WireId getConflictingWireWire(WireId wire) const final { return wire; } - NetInfo *getConflictingWireNet(WireId wire) const override + NetInfo *getConflictingWireNet(WireId wire) const final { NPNR_ASSERT(wire != WireId()); auto w2n = wire_to_net.find(wire); return w2n == wire_to_net.end() ? nullptr : w2n->second; } - DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); } + DelayQuad getWireDelay(WireId wire) const final { return DelayQuad(0); } TileWireRange get_tile_wire_range(WireId wire) const { @@ -1199,7 +475,7 @@ struct Arch : ArchAPI<ArchRanges> return range; } - BelPinRange getWireBelPins(WireId wire) const override + BelPinRange getWireBelPins(WireId wire) const final { BelPinRange range; NPNR_ASSERT(wire != WireId()); @@ -1218,7 +494,7 @@ struct Arch : ArchAPI<ArchRanges> return range; } - WireRange getWires() const override + WireRange getWires() const final { WireRange range; range.b.chip = chip_info; @@ -1232,65 +508,43 @@ struct Arch : ArchAPI<ArchRanges> // ------------------------------------------------- - PipId getPipByName(IdStringList name) const override; - IdStringList getPipName(PipId pip) const override; - IdString getPipType(PipId pip) const override; - std::vector<std::pair<IdString, std::string>> getPipAttrs(PipId pip) const override; - - void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) override - { - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip] == nullptr); - - WireId dst = getPipDstWire(pip); - NPNR_ASSERT(wire_to_net[dst] == nullptr || wire_to_net[dst] == net); + PipId getPipByName(IdStringList name) const final; + IdStringList getPipName(PipId pip) const final; + IdString getPipType(PipId pip) const final; + std::vector<std::pair<IdString, std::string>> getPipAttrs(PipId pip) const final; - pip_to_net[pip] = net; - - wire_to_net[dst] = net; - net->wires[dst].pip = pip; - net->wires[dst].strength = strength; - refreshUiPip(pip); - refreshUiWire(dst); - } + void assign_net_to_wire(WireId wire, NetInfo *net, const char *src, bool require_empty); - void unbindPip(PipId pip) override - { - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip] != nullptr); + void unassign_wire(WireId wire); - WireId dst = getPipDstWire(pip); - NPNR_ASSERT(wire_to_net[dst] != nullptr); - wire_to_net[dst] = nullptr; - pip_to_net[pip]->wires.erase(dst); + void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) final; - pip_to_net[pip] = nullptr; - refreshUiPip(pip); - refreshUiWire(dst); - } + void unbindPip(PipId pip) final; - bool checkPipAvail(PipId pip) const override - { - NPNR_ASSERT(pip != PipId()); - return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == nullptr; - } + bool checkPipAvail(PipId pip) const final; + bool check_pip_avail_for_net(PipId pip, NetInfo *) const; - NetInfo *getBoundPipNet(PipId pip) const override + NetInfo *getBoundPipNet(PipId pip) const final { NPNR_ASSERT(pip != PipId()); auto p2n = pip_to_net.find(pip); return p2n == pip_to_net.end() ? nullptr : p2n->second; } - WireId getConflictingPipWire(PipId pip) const override { return getPipDstWire(pip); } + WireId getConflictingPipWire(PipId pip) const final + { + // FIXME: This doesn't account for pseudo pips. + return getPipDstWire(pip); + } - NetInfo *getConflictingPipNet(PipId pip) const override + NetInfo *getConflictingPipNet(PipId pip) const final { + // FIXME: This doesn't account for pseudo pips. auto p2n = pip_to_net.find(pip); return p2n == pip_to_net.end() ? nullptr : p2n->second; } - AllPipRange getPips() const override + AllPipRange getPips() const final { AllPipRange range; range.b.cursor_tile = 0; @@ -1303,7 +557,7 @@ struct Arch : ArchAPI<ArchRanges> return range; } - Loc getPipLocation(PipId pip) const override + Loc getPipLocation(PipId pip) const final { Loc loc; get_tile_loc(pip.tile, &loc); @@ -1311,21 +565,25 @@ struct Arch : ArchAPI<ArchRanges> return loc; } - uint32_t getPipChecksum(PipId pip) const override { return pip.index; } + uint32_t getPipChecksum(PipId pip) const final { return pip.index; } - WireId getPipSrcWire(PipId pip) const override + WireId getPipSrcWire(PipId pip) const final NPNR_ALWAYS_INLINE { return canonical_wire(chip_info, pip.tile, loc_info(chip_info, pip).pip_data[pip.index].src_index); } - WireId getPipDstWire(PipId pip) const override + WireId getPipDstWire(PipId pip) const final NPNR_ALWAYS_INLINE { return canonical_wire(chip_info, pip.tile, loc_info(chip_info, pip).pip_data[pip.index].dst_index); } - DelayQuad getPipDelay(PipId pip) const override { return DelayQuad(0); } + DelayQuad getPipDelay(PipId pip) const final + { + // FIXME: Implement when adding timing-driven place and route. + return DelayQuad(100); + } - DownhillPipRange getPipsDownhill(WireId wire) const override + DownhillPipRange getPipsDownhill(WireId wire) const final { DownhillPipRange range; NPNR_ASSERT(wire != WireId()); @@ -1342,7 +600,7 @@ struct Arch : ArchAPI<ArchRanges> return range; } - UphillPipRange getPipsUphill(WireId wire) const override + UphillPipRange getPipsUphill(WireId wire) const final { UphillPipRange range; NPNR_ASSERT(wire != WireId()); @@ -1362,24 +620,24 @@ struct Arch : ArchAPI<ArchRanges> // ------------------------------------------------- // FIXME: Use groups to get access to sites. - GroupId getGroupByName(IdStringList name) const override { return GroupId(); } - IdStringList getGroupName(GroupId group) const override { return IdStringList(); } - std::vector<GroupId> getGroups() const override { return {}; } - std::vector<BelId> getGroupBels(GroupId group) const override { return {}; } - std::vector<WireId> getGroupWires(GroupId group) const override { return {}; } - std::vector<PipId> getGroupPips(GroupId group) const override { return {}; } - std::vector<GroupId> getGroupGroups(GroupId group) const override { return {}; } + GroupId getGroupByName(IdStringList name) const final { return GroupId(); } + IdStringList getGroupName(GroupId group) const final { return IdStringList(); } + std::vector<GroupId> getGroups() const final { return {}; } + std::vector<BelId> getGroupBels(GroupId group) const final { return {}; } + std::vector<WireId> getGroupWires(GroupId group) const final { return {}; } + std::vector<PipId> getGroupPips(GroupId group) const final { return {}; } + std::vector<GroupId> getGroupGroups(GroupId group) const final { return {}; } // ------------------------------------------------- - delay_t estimateDelay(WireId src, WireId dst) const override; - delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const override; - ArcBounds getRouteBoundingBox(WireId src, WireId dst) const override; - delay_t getDelayEpsilon() const override { return 20; } - delay_t getRipupDelayPenalty() const override { return 120; } - float getDelayNS(delay_t v) const override { return v * 0.001; } - delay_t getDelayFromNS(float ns) const override { return delay_t(ns * 1000); } - uint32_t getDelayChecksum(delay_t v) const override { return v; } - bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const override; + delay_t estimateDelay(WireId src, WireId dst) const final; + delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const final; + ArcBounds getRouteBoundingBox(WireId src, WireId dst) const final; + delay_t getDelayEpsilon() const final { return 20; } + delay_t getRipupDelayPenalty() const final { return 120; } + float getDelayNS(delay_t v) const final { return v * 0.001; } + delay_t getDelayFromNS(float ns) const final { return delay_t(ns * 1000); } + uint32_t getDelayChecksum(delay_t v) const final { return v; } + bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const final; // ------------------------------------------------- @@ -1387,31 +645,31 @@ struct Arch : ArchAPI<ArchRanges> std::unordered_set<CellInfo *> *placed_cells); void pack_ports(); void decode_lut_cells(); - bool pack() override; - bool place() override; - bool route() override; + bool pack() final; + bool place() final; + bool route() final; // ------------------------------------------------- - std::vector<GraphicElement> getDecalGraphics(DecalId decal) const override; + std::vector<GraphicElement> getDecalGraphics(DecalId decal) const final; - DecalXY getBelDecal(BelId bel) const override; - DecalXY getWireDecal(WireId wire) const override; - DecalXY getPipDecal(PipId pip) const override; - DecalXY getGroupDecal(GroupId group) const override; + DecalXY getBelDecal(BelId bel) const final; + DecalXY getWireDecal(WireId wire) const final; + DecalXY getPipDecal(PipId pip) const final; + DecalXY getGroupDecal(GroupId group) const final; // ------------------------------------------------- // Get the delay through a cell from one port to another, returning false // if no path exists. This only considers combinational delays, as required by the Arch API - bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override; + bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const final; // Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port - TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override; + TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const final; // Get the TimingClockingInfo of a port - TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const override; + TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const final; // ------------------------------------------------- - const BelBucketRange getBelBuckets() const override + const BelBucketRange getBelBuckets() const final { BelBucketRange bel_bucket_range; bel_bucket_range.b.cursor.cursor = chip_info->bel_buckets.begin(); @@ -1419,14 +677,14 @@ struct Arch : ArchAPI<ArchRanges> return bel_bucket_range; } - BelBucketId getBelBucketForBel(BelId bel) const override + BelBucketId getBelBucketForBel(BelId bel) const final { BelBucketId bel_bucket; bel_bucket.name = IdString(bel_info(chip_info, bel).bel_bucket); return bel_bucket; } - const IdStringRange getCellTypes() const override + const IdStringRange getCellTypes() const final { const CellMapPOD &cell_map = *chip_info->cell_map; @@ -1437,9 +695,9 @@ struct Arch : ArchAPI<ArchRanges> return id_range; } - IdString getBelBucketName(BelBucketId bucket) const override { return bucket.name; } + IdString getBelBucketName(BelBucketId bucket) const final { return bucket.name; } - BelBucketId getBelBucketByName(IdString name) const override + BelBucketId getBelBucketByName(IdString name) const final { for (BelBucketId bel_bucket : getBelBuckets()) { if (bel_bucket.name == name) { @@ -1453,7 +711,7 @@ struct Arch : ArchAPI<ArchRanges> size_t get_cell_type_index(IdString cell_type) const; - BelBucketId getBelBucketForCellType(IdString cell_type) const override + BelBucketId getBelBucketForCellType(IdString cell_type) const final { if (io_port_types.count(cell_type)) { BelBucketId bucket; @@ -1467,7 +725,7 @@ struct Arch : ArchAPI<ArchRanges> return bucket; } - FilteredBelRange getBelsInBucket(BelBucketId bucket) const override + FilteredBelRange getBelsInBucket(BelBucketId bucket) const final { BelRange range = getBels(); FilteredBelRange filtered_range(range.begin(), range.end(), @@ -1476,7 +734,7 @@ struct Arch : ArchAPI<ArchRanges> return filtered_range; } - bool isValidBelForCellType(IdString cell_type, BelId bel) const override + bool isValidBelForCellType(IdString cell_type, BelId bel) const final { if (io_port_types.count(cell_type)) { return pads.count(bel) > 0; @@ -1506,7 +764,7 @@ struct Arch : ArchAPI<ArchRanges> } // Return true whether all Bels at a given location are valid - bool isBelLocationValid(BelId bel) const override + bool isBelLocationValid(BelId bel) const final { auto iter = tileStatus.find(bel.tile); if (iter == tileStatus.end()) { @@ -1541,7 +799,7 @@ struct Arch : ArchAPI<ArchRanges> std::unordered_map<WireId, Loc> sink_locs, source_locs; // ------------------------------------------------- - void assignArchInfo() override {} + void assignArchInfo() final {} // ------------------------------------------------- @@ -1599,21 +857,21 @@ struct Arch : ArchAPI<ArchRanges> const CellConstraintPOD *constraint; Constraint(const CellConstraintPOD *constraint) : constraint(constraint) {} - size_t tag() const override { return constraint->tag; } + size_t tag() const final { return constraint->tag; } - ArchConstraints::ConstraintType constraint_type() const override + ArchConstraints::ConstraintType constraint_type() const final { return Constraints<kMaxState>::ConstraintType(constraint->constraint_type); } - ArchConstraints::ConstraintStateType state() const override + ArchConstraints::ConstraintStateType state() const final { NPNR_ASSERT(constraint_type() == Constraints<kMaxState>::CONSTRAINT_TAG_IMPLIES); NPNR_ASSERT(constraint->states.size() == 1); return constraint->states[0]; } - StateRange states() const override + StateRange states() const final { StateRange range; range.b = constraint->states.get(); @@ -1725,6 +983,32 @@ struct Arch : ArchAPI<ArchRanges> } } + bool is_same_site(WireId wire_a, WireId wire_b) const + { + if (wire_a.tile == -1) { + return false; + } + + if (wire_a.tile != wire_b.tile) { + return false; + } + + auto &wire_a_data = wire_info(wire_a); + auto &wire_b_data = wire_info(wire_b); + + return wire_a_data.site == wire_b_data.site && wire_a_data.site != -1; + } + + bool is_wire_in_site(WireId wire) const + { + if (wire.tile == -1) { + return false; + } + + auto &wire_data = wire_info(wire); + return wire_data.site != -1; + } + void merge_constant_nets(); void report_invalid_bel(BelId bel, CellInfo *cell) const; diff --git a/fpga_interchange/arch_iterators.h b/fpga_interchange/arch_iterators.h new file mode 100644 index 00000000..c59a7d18 --- /dev/null +++ b/fpga_interchange/arch_iterators.h @@ -0,0 +1,497 @@ +/* + * 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 ARCH_ITERATORS_H +#define ARCH_ITERATORS_H + +#include "chipdb.h" +#include "nextpnr_namespaces.h" +#include "nextpnr_types.h" + +NEXTPNR_NAMESPACE_BEGIN + +struct BelIterator +{ + const ChipInfoPOD *chip; + int cursor_index; + int cursor_tile; + + BelIterator operator++() + { + cursor_index++; + while (cursor_tile < chip->tiles.ssize() && cursor_index >= tile_info(chip, cursor_tile).bel_data.ssize()) { + cursor_index = 0; + cursor_tile++; + } + return *this; + } + BelIterator operator++(int) + { + BelIterator prior(*this); + ++(*this); + return prior; + } + + bool operator!=(const BelIterator &other) const + { + return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; + } + + bool operator==(const BelIterator &other) const + { + return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; + } + + BelId operator*() const + { + BelId ret; + ret.tile = cursor_tile; + ret.index = cursor_index; + return ret; + } +}; + +struct BelRange +{ + BelIterator b, e; + BelIterator begin() const { return b; } + BelIterator end() const { return e; } +}; + +struct FilteredBelIterator +{ + std::function<bool(BelId)> filter; + BelIterator b, e; + + FilteredBelIterator operator++() + { + ++b; + while (b != e) { + if (filter(*b)) { + break; + } + + ++b; + } + return *this; + } + + bool operator!=(const FilteredBelIterator &other) const + { + NPNR_ASSERT(e == other.e); + return b != other.b; + } + + bool operator==(const FilteredBelIterator &other) const + { + NPNR_ASSERT(e == other.e); + return b == other.b; + } + + BelId operator*() const + { + BelId bel = *b; + NPNR_ASSERT(filter(bel)); + return bel; + } +}; + +struct FilteredBelRange +{ + FilteredBelRange(BelIterator bel_b, BelIterator bel_e, std::function<bool(BelId)> filter) + { + b.filter = filter; + b.b = bel_b; + b.e = bel_e; + + if (b.b != b.e && !filter(*b.b)) { + ++b; + } + + e.b = bel_e; + e.e = bel_e; + + if (b != e) { + NPNR_ASSERT(filter(*b.b)); + } + } + + FilteredBelIterator b, e; + FilteredBelIterator begin() const { return b; } + FilteredBelIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +// Iterate over TileWires for a wire (will be more than one if nodal) +struct TileWireIterator +{ + const ChipInfoPOD *chip; + WireId baseWire; + int cursor = -1; + + void operator++() { cursor++; } + + bool operator==(const TileWireIterator &other) const { return cursor == other.cursor; } + bool operator!=(const TileWireIterator &other) const { return cursor != other.cursor; } + + // Returns a *denormalised* identifier always pointing to a tile wire rather than a node + WireId operator*() const + { + if (baseWire.tile == -1) { + WireId tw; + const auto &node_wire = chip->nodes[baseWire.index].tile_wires[cursor]; + tw.tile = node_wire.tile; + tw.index = node_wire.index; + return tw; + } else { + return baseWire; + } + } +}; + +struct TileWireRange +{ + TileWireIterator b, e; + TileWireIterator begin() const { return b; } + TileWireIterator end() const { return e; } +}; + +NPNR_ALWAYS_INLINE inline WireId canonical_wire(const ChipInfoPOD *chip_info, int32_t tile, int32_t wire) +{ + WireId id; + + if (wire >= chip_info->tiles[tile].tile_wire_to_node.ssize()) { + // Cannot be a nodal wire + id.tile = tile; + id.index = wire; + } else { + int32_t node = chip_info->tiles[tile].tile_wire_to_node[wire]; + if (node == -1) { + // Not a nodal wire + id.tile = tile; + id.index = wire; + } else { + // Is a nodal wire, set tile to -1 + id.tile = -1; + id.index = node; + } + } + + return id; +} + +// ----------------------------------------------------------------------- + +struct WireIterator +{ + const ChipInfoPOD *chip; + int cursor_index = 0; + int cursor_tile = -1; + + WireIterator operator++() + { + // Iterate over nodes first, then tile wires that aren't nodes + do { + cursor_index++; + if (cursor_tile == -1 && cursor_index >= chip->nodes.ssize()) { + cursor_tile = 0; + cursor_index = 0; + } + while (cursor_tile != -1 && cursor_tile < chip->tiles.ssize() && + cursor_index >= chip->tile_types[chip->tiles[cursor_tile].type].wire_data.ssize()) { + cursor_index = 0; + cursor_tile++; + } + + } while ((cursor_tile != -1 && cursor_tile < chip->tiles.ssize() && + cursor_index < chip->tiles[cursor_tile].tile_wire_to_node.ssize() && + chip->tiles[cursor_tile].tile_wire_to_node[cursor_index] != -1)); + + return *this; + } + WireIterator operator++(int) + { + WireIterator prior(*this); + ++(*this); + return prior; + } + + bool operator!=(const WireIterator &other) const + { + return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; + } + + bool operator==(const WireIterator &other) const + { + return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; + } + + WireId operator*() const + { + WireId ret; + ret.tile = cursor_tile; + ret.index = cursor_index; + return ret; + } +}; + +struct WireRange +{ + WireIterator b, e; + WireIterator begin() const { return b; } + WireIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- +struct AllPipIterator +{ + const ChipInfoPOD *chip; + int cursor_index; + int cursor_tile; + + AllPipIterator operator++() + { + cursor_index++; + while (cursor_tile < chip->tiles.ssize() && + cursor_index >= chip->tile_types[chip->tiles[cursor_tile].type].pip_data.ssize()) { + cursor_index = 0; + cursor_tile++; + } + return *this; + } + AllPipIterator operator++(int) + { + AllPipIterator prior(*this); + ++(*this); + return prior; + } + + bool operator!=(const AllPipIterator &other) const + { + return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; + } + + bool operator==(const AllPipIterator &other) const + { + return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; + } + + PipId operator*() const + { + PipId ret; + ret.tile = cursor_tile; + ret.index = cursor_index; + return ret; + } +}; + +struct AllPipRange +{ + AllPipIterator b, e; + AllPipIterator begin() const { return b; } + AllPipIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct UphillPipIterator +{ + const ChipInfoPOD *chip; + TileWireIterator twi, twi_end; + int cursor = -1; + + void operator++() + { + cursor++; + while (true) { + if (!(twi != twi_end)) + break; + WireId w = *twi; + auto &tile = chip->tile_types[chip->tiles[w.tile].type]; + if (cursor < tile.wire_data[w.index].pips_uphill.ssize()) + break; + ++twi; + cursor = 0; + } + } + bool operator!=(const UphillPipIterator &other) const { return twi != other.twi || cursor != other.cursor; } + + PipId operator*() const + { + PipId ret; + WireId w = *twi; + ret.tile = w.tile; + ret.index = chip->tile_types[chip->tiles[w.tile].type].wire_data[w.index].pips_uphill[cursor]; + return ret; + } +}; + +struct UphillPipRange +{ + UphillPipIterator b, e; + UphillPipIterator begin() const { return b; } + UphillPipIterator end() const { return e; } +}; + +struct DownhillPipIterator +{ + const ChipInfoPOD *chip; + TileWireIterator twi, twi_end; + int cursor = -1; + + int32_t tile; + int32_t tile_type; + const RelSlice<int32_t> *pips_downhill = nullptr; + + void operator++() + { + cursor++; + while (true) { + if (!(twi != twi_end)) + break; + + if (pips_downhill == nullptr) { + WireId w = *twi; + tile_type = chip->tiles[w.tile].type; + const TileTypeInfoPOD &type = chip->tile_types[tile_type]; + + tile = w.tile; + pips_downhill = &type.wire_data[w.index].pips_downhill; + } + + if (cursor < pips_downhill->ssize()) + break; + + ++twi; + cursor = 0; + pips_downhill = nullptr; + } + } + bool operator!=(const DownhillPipIterator &other) const { return twi != other.twi || cursor != other.cursor; } + + PipId operator*() const + { + PipId ret; + ret.tile = tile; + ret.index = (*pips_downhill)[cursor]; + return ret; + } +}; + +struct DownhillPipRange +{ + DownhillPipIterator b, e; + DownhillPipIterator begin() const { return b; } + DownhillPipIterator end() const { return e; } +}; + +struct BelPinIterator +{ + const ChipInfoPOD *chip; + TileWireIterator twi, twi_end; + int cursor = -1; + + void operator++() + { + cursor++; + + while (twi != twi_end) { + WireId w = *twi; + auto &tile = tile_info(chip, w.tile); + if (cursor < tile.wire_data[w.index].bel_pins.ssize()) + break; + + ++twi; + cursor = 0; + } + } + bool operator!=(const BelPinIterator &other) const { return twi != other.twi || cursor != other.cursor; } + + BelPin operator*() const + { + BelPin ret; + WireId w = *twi; + ret.bel.tile = w.tile; + ret.bel.index = tile_info(chip, w.tile).wire_data[w.index].bel_pins[cursor].bel_index; + ret.pin.index = tile_info(chip, w.tile).wire_data[w.index].bel_pins[cursor].port; + return ret; + } +}; + +struct BelPinRange +{ + BelPinIterator b, e; + BelPinIterator begin() const { return b; } + BelPinIterator end() const { return e; } +}; + +struct IdStringIterator : std::iterator<std::forward_iterator_tag, + /*T=*/IdString, + /*Distance=*/ptrdiff_t, + /*pointer=*/IdString *, + /*reference=*/IdString> +{ + const int32_t *cursor; + + void operator++() { cursor += 1; } + + bool operator!=(const IdStringIterator &other) const { return cursor != other.cursor; } + + bool operator==(const IdStringIterator &other) const { return cursor == other.cursor; } + + IdString operator*() const { return IdString(*cursor); } +}; + +struct IdStringRange +{ + IdStringIterator b, e; + IdStringIterator begin() const { return b; } + IdStringIterator end() const { return e; } +}; + +struct BelBucketIterator +{ + IdStringIterator cursor; + + void operator++() { ++cursor; } + + bool operator!=(const BelBucketIterator &other) const { return cursor != other.cursor; } + + bool operator==(const BelBucketIterator &other) const { return cursor == other.cursor; } + + BelBucketId operator*() const + { + BelBucketId bucket; + bucket.name = IdString(*cursor); + return bucket; + } +}; + +struct BelBucketRange +{ + BelBucketIterator b, e; + BelBucketIterator begin() const { return b; } + BelBucketIterator end() const { return e; } +}; + +NEXTPNR_NAMESPACE_END + +#endif /* ARCH_ITERATORS_H */ diff --git a/fpga_interchange/archdefs.h b/fpga_interchange/archdefs.h index c9c0bc4f..d20c5ea4 100644 --- a/fpga_interchange/archdefs.h +++ b/fpga_interchange/archdefs.h @@ -24,6 +24,7 @@ #include <boost/functional/hash.hpp> #include <cstdint> +#include "hash_table.h" #include "luts.h" #include "nextpnr_namespaces.h" @@ -108,8 +109,8 @@ struct ArchCellInfo ArchCellInfo() : cell_mapping(-1) {} int32_t cell_mapping; - std::unordered_map<IdString, std::vector<IdString>> cell_bel_pins; - std::unordered_set<IdString> const_ports; + HashTables::HashMap<IdString, std::vector<IdString>> cell_bel_pins; + HashTables::HashSet<IdString> const_ports; LutCell lut_cell; }; diff --git a/fpga_interchange/chipdb.h b/fpga_interchange/chipdb.h new file mode 100644 index 00000000..2130f1b6 --- /dev/null +++ b/fpga_interchange/chipdb.h @@ -0,0 +1,310 @@ +/* + * 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 CHIPDB_H +#define CHIPDB_H + +#include "archdefs.h" +#include "nextpnr_namespaces.h" +#include "relptr.h" + +NEXTPNR_NAMESPACE_BEGIN + +/* !!! Everything in this section must be kept in sync !!! + * !!! with fpga_interchange/chip_info.py !!! + * + * When schema changes, bump version number in chip_info.py and + * kExpectedChipInfoVersion + */ + +static constexpr int32_t kExpectedChipInfoVersion = 1; + +// Flattened site indexing. +// +// To enable flat BelId.z spaces, every tile and sites within that tile are +// flattened. +// +// This has implications on BelId's, WireId's and PipId's. +// The flattened site space works as follows: +// - Objects that belong to the tile are first. BELs are always part of Sites, +// so no BEL objects are in this category. +// - All site alternative modes are exposed as a "full" site. +// - Each site appends it's BEL's, wires (site wires) and PIP's. +// - Sites add two types of pips. Sites will add pip data first for site +// pips, and then for site pin edges. +// 1. The first type is site pips, which connect site wires to other site +// wires. +// 2. The second type is site pin edges, which connect site wires to tile +// wires (or vise-versa). + +NPNR_PACKED_STRUCT(struct BelInfoPOD { + int32_t name; // bel name (in site) constid + int32_t type; // Type name constid + int32_t bel_bucket; // BEL bucket constid. + + int32_t num_bel_wires; + RelPtr<int32_t> ports; // port name constid + RelPtr<int32_t> types; // port type (IN/OUT/BIDIR) + RelPtr<int32_t> wires; // connected wire index in tile, or -1 if NA + + int16_t site; + int16_t site_variant; // some sites have alternative types + int16_t category; + int8_t synthetic; + int8_t lut_element; + + RelPtr<int32_t> pin_map; // Index into CellMapPOD::cell_bel_map +}); + +enum BELCategory +{ + // BEL is a logic element + BEL_CATEGORY_LOGIC = 0, + // BEL is a site routing mux + BEL_CATEGORY_ROUTING = 1, + // BEL is a site port, e.g. boundry between site and routing graph. + BEL_CATEGORY_SITE_PORT = 2 +}; + +NPNR_PACKED_STRUCT(struct BelPortPOD { + int32_t bel_index; + int32_t port; +}); + +NPNR_PACKED_STRUCT(struct TileWireInfoPOD { + int32_t name; // wire name constid + + // Pip index inside tile + RelSlice<int32_t> pips_uphill; + + // Pip index inside tile + RelSlice<int32_t> pips_downhill; + + // Bel index inside tile + RelSlice<BelPortPOD> bel_pins; + + int16_t site; // site index in tile + int16_t site_variant; // site variant index in tile +}); + +NPNR_PACKED_STRUCT(struct PipInfoPOD { + int32_t src_index, dst_index; + int16_t site; // site index in tile + int16_t site_variant; // site variant index in tile + int16_t bel; // BEL this pip belongs to if site pip. + int16_t extra_data; +}); + +NPNR_PACKED_STRUCT(struct ConstraintTagPOD { + int32_t tag_prefix; // constid + int32_t default_state; // constid + RelSlice<int32_t> states; // constid +}); + +NPNR_PACKED_STRUCT(struct LutBelPOD { + uint32_t name; // constid + RelSlice<int32_t> pins; // constid + uint32_t low_bit; + uint32_t high_bit; +}); + +NPNR_PACKED_STRUCT(struct LutElementPOD { + int32_t width; + RelSlice<LutBelPOD> lut_bels; +}); + +NPNR_PACKED_STRUCT(struct TileTypeInfoPOD { + int32_t name; // Tile type constid + + RelSlice<BelInfoPOD> bel_data; + + RelSlice<TileWireInfoPOD> wire_data; + + RelSlice<PipInfoPOD> pip_data; + + RelSlice<ConstraintTagPOD> tags; + + RelSlice<LutElementPOD> lut_elements; + + RelSlice<int32_t> site_types; // constid +}); + +NPNR_PACKED_STRUCT(struct SiteInstInfoPOD { + RelPtr<char> name; + RelPtr<char> site_name; + + // Which site type is this site instance? + // constid + int32_t site_type; +}); + +NPNR_PACKED_STRUCT(struct TileInstInfoPOD { + // Name of this tile. + RelPtr<char> name; + + // Index into root.tile_types. + int32_t type; + + // This array is root.tile_types[type].site_types.size() long. + // Index into root.sites + RelSlice<int32_t> sites; + + // Number of tile wires; excluding any site-internal wires + // which come after general wires and are not stored here + // as they will never be nodal + // -1 if a tile-local wire; node index if nodal wire + RelSlice<int32_t> tile_wire_to_node; +}); + +NPNR_PACKED_STRUCT(struct TileWireRefPOD { + int32_t tile; + int32_t index; +}); + +NPNR_PACKED_STRUCT(struct NodeInfoPOD { RelSlice<TileWireRefPOD> tile_wires; }); + +NPNR_PACKED_STRUCT(struct CellBelPinPOD { + int32_t cell_pin; // constid + int32_t bel_pin; // constid +}); + +NPNR_PACKED_STRUCT(struct ParameterPinsPOD { + int32_t key; // constid + int32_t value; // constid + RelSlice<CellBelPinPOD> pins; +}); + +NPNR_PACKED_STRUCT(struct CellConstraintPOD { + int32_t tag; // Tag index + int32_t constraint_type; // Constraint::ConstraintType + RelSlice<int32_t> states; // State indicies +}); + +NPNR_PACKED_STRUCT(struct CellBelMapPOD { + RelSlice<CellBelPinPOD> common_pins; + RelSlice<ParameterPinsPOD> parameter_pins; + RelSlice<CellConstraintPOD> constraints; +}); + +NPNR_PACKED_STRUCT(struct LutCellPOD { + int32_t cell; // constid + RelSlice<int32_t> input_pins; // constids + int32_t parameter; +}); + +NPNR_PACKED_STRUCT(struct CellMapPOD { + // Cell names supported in this arch. + RelSlice<int32_t> cell_names; // constids + RelSlice<int32_t> cell_bel_buckets; // constids + + RelSlice<CellBelMapPOD> cell_bel_map; + + RelSlice<LutCellPOD> lut_cells; +}); + +NPNR_PACKED_STRUCT(struct PackagePinPOD { + int32_t package_pin; // constid + int32_t site; // constid + int32_t bel; // constid +}); + +NPNR_PACKED_STRUCT(struct PackagePOD { + int32_t package; // constid + RelSlice<PackagePinPOD> pins; +}); + +NPNR_PACKED_STRUCT(struct ConstantsPOD { + // Cell type and port for the GND and VCC global source. + int32_t gnd_cell_name; // constid + int32_t gnd_cell_port; // constid + + int32_t vcc_cell_name; // constid + int32_t vcc_cell_port; // constid + + int32_t gnd_bel_tile; + int32_t gnd_bel_index; + int32_t gnd_bel_pin; // constid + + int32_t vcc_bel_tile; + int32_t vcc_bel_index; + int32_t vcc_bel_pin; // constid + + // Name to use for the global GND constant net + int32_t gnd_net_name; // constid + + // Name to use for the global VCC constant net + int32_t vcc_net_name; // constid +}); + +NPNR_PACKED_STRUCT(struct ChipInfoPOD { + RelPtr<char> name; + RelPtr<char> generator; + + int32_t version; + int32_t width, height; + + RelSlice<TileTypeInfoPOD> tile_types; + RelSlice<SiteInstInfoPOD> sites; + RelSlice<TileInstInfoPOD> tiles; + RelSlice<NodeInfoPOD> nodes; + RelSlice<PackagePOD> packages; + + // BEL bucket constids. + RelSlice<int32_t> bel_buckets; + + RelPtr<CellMapPOD> cell_map; + RelPtr<ConstantsPOD> constants; + + // Constid string data. + RelPtr<RelSlice<RelPtr<char>>> constids; +}); + +/************************ End of chipdb section. ************************/ + +inline const TileTypeInfoPOD &tile_info(const ChipInfoPOD *chip_info, int32_t tile) +{ + return chip_info->tile_types[chip_info->tiles[tile].type]; +} + +template <typename Id> const TileTypeInfoPOD &loc_info(const ChipInfoPOD *chip_info, Id &id) +{ + return chip_info->tile_types[chip_info->tiles[id.tile].type]; +} + +NPNR_ALWAYS_INLINE inline const BelInfoPOD &bel_info(const ChipInfoPOD *chip_info, BelId bel) +{ + NPNR_ASSERT(bel != BelId()); + return loc_info(chip_info, bel).bel_data[bel.index]; +} + +inline const PipInfoPOD &pip_info(const ChipInfoPOD *chip_info, PipId pip) +{ + NPNR_ASSERT(pip != PipId()); + return loc_info(chip_info, pip).pip_data[pip.index]; +} + +inline const SiteInstInfoPOD &site_inst_info(const ChipInfoPOD *chip_info, int32_t tile, int32_t site) +{ + return chip_info->sites[chip_info->tiles[tile].sites[site]]; +} + +NEXTPNR_NAMESPACE_END + +#endif /* CHIPDB_H */ diff --git a/fpga_interchange/luts.cc b/fpga_interchange/luts.cc index 6e24847f..bdf728fd 100644 --- a/fpga_interchange/luts.cc +++ b/fpga_interchange/luts.cc @@ -122,6 +122,8 @@ struct LutPin bool operator<(const LutPin &other) const { return max_pin < other.max_pin; } }; +//#define DEBUG_LUT_ROTATION + bool LutMapper::remap_luts(const Context *ctx) { std::unordered_map<NetInfo *, LutPin> lut_pin_map; @@ -262,11 +264,25 @@ bool LutMapper::remap_luts(const Context *ctx) for (size_t bel_pin_idx = 0; bel_pin_idx < lut_bel.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->lut_cell.vcc_pins.emplace(lut_bel.pins[bel_pin_idx]); + cell->lut_cell.vcc_pins.emplace(lut_bel.pins.at(bel_pin_idx)); } } } +#ifdef DEBUG_LUT_ROTATION + log_info("Final mapping:\n"); + for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { + CellInfo *cell = cells[cell_idx]; + for (auto &cell_pin_pair : cell->cell_bel_pins) { + log_info("%s %s %s =>", cell->type.c_str(ctx), cell->name.c_str(ctx), cell_pin_pair.first.c_str(ctx)); + for (auto bel_pin : cell_pin_pair.second) { + log(" %s", bel_pin.c_str(ctx)); + } + log("\n"); + } + } +#endif + return true; } diff --git a/fpga_interchange/xdc.cc b/fpga_interchange/xdc.cc index 584a1777..6e22ce8b 100644 --- a/fpga_interchange/xdc.cc +++ b/fpga_interchange/xdc.cc @@ -19,9 +19,15 @@ */ #include "xdc.h" + #include <string> + +#include "context.h" #include "log.h" -#include "nextpnr.h" + +// Include tcl.h late because it messed with #define's and lets them leave the +// scope of the header. +#include <tcl.h> NEXTPNR_NAMESPACE_BEGIN diff --git a/fpga_interchange/xdc.h b/fpga_interchange/xdc.h index c6b80870..bafd1235 100644 --- a/fpga_interchange/xdc.h +++ b/fpga_interchange/xdc.h @@ -17,11 +17,17 @@ * */ -#include <tcl.h> -#include "nextpnr.h" +#ifndef XDC_H +#define XDC_H + +#include "nextpnr_namespaces.h" + +struct Tcl_Interp; NEXTPNR_NAMESPACE_BEGIN +struct Context; + struct TclInterp { TclInterp(Context *ctx); @@ -31,3 +37,5 @@ struct TclInterp }; NEXTPNR_NAMESPACE_END + +#endif diff --git a/tests b/tests -Subproject a751e0d9081477e33c620b5224ccd2026f2fa0c +Subproject caf7261be7b34b365ab6d8449455891c2ed28fa |