diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index 814e4f85..8c8224ca 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -36,6 +36,30 @@ #include "util.h" #include "xdc.h" +NEXTPNR_NAMESPACE_BEGIN +struct SiteBelPair +{ + std::string site; + IdString bel; + + SiteBelPair() {} + SiteBelPair(std::string site, IdString bel) : site(site), bel(bel) {} + + bool operator==(const SiteBelPair &other) const { return site == other.site && bel == other.bel; } +}; +NEXTPNR_NAMESPACE_END + +template <> struct std::hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX SiteBelPair &site_bel) const noexcept + { + std::size_t seed = 0; + boost::hash_combine(seed, std::hash()(site_bel.site)); + boost::hash_combine(seed, std::hash()(site_bel.bel)); + return seed; + } +}; + NEXTPNR_NAMESPACE_BEGIN static std::pair split_identifier_name_dot(const std::string &name) @@ -65,18 +89,16 @@ Arch::Arch(ArchArgs args) : args(args) log_error("Unable to read chipdb %s\n", args.chipdb.c_str()); } - // Read strings from constids into IdString database, checking that list - // is unique and matches expected constid value. - int id = 1; - for (const auto &constid : *chip_info->constids) { - IdString::initialize_add(this, constid.get(), id++); - } - tileStatus.resize(chip_info->tiles.size()); for (int i = 0; i < chip_info->tiles.ssize(); i++) { tileStatus[i].boundcells.resize(chip_info->tile_types[chip_info->tiles[i].type].bel_data.size()); } + const RelSlice> &constids = *chip_info->constids; + for (size_t i = 0; i < constids.size(); ++i) { + IdString::initialize_add(this, constids[i].get(), i + 1); + } + // Sanity check cell name ids. const CellMapPOD &cell_map = *chip_info->cell_map; int32_t first_cell_id = cell_map.cell_names[0]; @@ -87,6 +109,43 @@ Arch::Arch(ArchArgs args) : args(args) io_port_types.emplace(this->id("$nextpnr_ibuf")); io_port_types.emplace(this->id("$nextpnr_obuf")); io_port_types.emplace(this->id("$nextpnr_iobuf")); + + if (!this->args.package.empty()) { + IdString package = this->id(this->args.package); + package_index = -1; + for (size_t i = 0; i < chip_info->packages.size(); ++i) { + if (IdString(chip_info->packages[i].package) == package) { + NPNR_ASSERT(package_index == -1); + package_index = i; + } + } + + if (package_index == -1) { + log_error("Could not find package '%s' in chipdb.\n", this->args.package.c_str()); + } + } else { + // Default to first package. + NPNR_ASSERT(chip_info->packages.size() > 0); + IdString package_name(chip_info->packages[0].package); + this->args.package = package_name.str(this); + package_index = 0; + } + + std::unordered_set site_bel_pads; + for (const auto &package_pin : chip_info->packages[package_index].pins) { + IdString site(package_pin.site); + IdString bel(package_pin.bel); + site_bel_pads.emplace(SiteBelPair(site.str(this), bel)); + } + + for (BelId bel : getBels()) { + auto &bel_data = bel_info(chip_info, bel); + const SiteInstInfoPOD &site = chip_info->sites[chip_info->tiles[bel.tile].sites[bel_data.site]]; + auto iter = site_bel_pads.find(SiteBelPair(site.site_name.get(), IdString(bel_data.name))); + if (iter != site_bel_pads.end()) { + pads.emplace(bel); + } + } } // ----------------------------------------------------------------------- @@ -608,4 +667,99 @@ const std::vector Arch::availablePlacers = {"sa", const std::string Arch::defaultRouter = "router2"; const std::vector Arch::availableRouters = {"router1", "router2"}; +void Arch::map_cell_pins(CellInfo *cell, int32_t mapping) const +{ + cell->cell_mapping = mapping; + cell->cell_bel_pins.clear(); + + const CellBelMapPOD &cell_pin_map = chip_info->cell_map->cell_bel_map[mapping]; + + 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") { + // FIXME: Tie this pin to the GND net + continue; + } + if (cell_pin.str(this) == "VCC") { + // FIXME: Tie this pin to the VCC net + continue; + } + + cell->cell_bel_pins[cell_pin].push_back(bel_pin); + } + + for (const auto ¶meter_pin_map : cell_pin_map.parameter_pins) { + IdString param_key(parameter_pin_map.key); + std::string param_value = IdString(parameter_pin_map.value).c_str(this); + + auto iter = cell->params.find(param_key); + if (iter == cell->params.end()) { + continue; + } + + if (param_value != iter->second.as_string()) { + continue; + } + + for (const auto &pin_map : parameter_pin_map.pins) { + IdString cell_pin(pin_map.cell_pin); + IdString bel_pin(pin_map.bel_pin); + + if (cell_pin.str(this) == "GND") { + // FIXME: Tie this pin to the GND net + continue; + } + if (cell_pin.str(this) == "VCC") { + // FIXME: Tie this pin to the VCC net + continue; + } + + cell->cell_bel_pins[cell_pin].push_back(bel_pin); + } + } +} + +void Arch::map_port_pins(BelId bel, CellInfo *cell) const +{ + IdStringRange pins = getBelPins(bel); + NPNR_ASSERT(pins.begin() != pins.end()); + auto b = pins.begin(); + IdString pin = *b; + ++b; + NPNR_ASSERT(b == pins.end()); + NPNR_ASSERT(cell->ports.size() == 1); + cell->cell_bel_pins[cell->ports.begin()->first].clear(); + cell->cell_bel_pins[cell->ports.begin()->first].push_back(pin); +} + +bool Arch::is_net_within_site(const NetInfo &net) const +{ + if (net.driver.cell == nullptr || net.driver.cell->bel == BelId()) { + return false; + } + + BelId driver = net.driver.cell->bel; + int32_t site = bel_info(chip_info, driver).site; + NPNR_ASSERT(site >= 0); + + for (const auto &user : net.users) { + if (user.cell == nullptr || user.cell->bel == BelId()) { + return false; + } + BelId user_bel = user.cell->bel; + + if (user_bel.tile != driver.tile) { + return false; + } + + if (bel_info(chip_info, user_bel).site != site) { + return false; + } + } + + return true; +} + NEXTPNR_NAMESPACE_END diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h index b152bd0e..1aa58761 100644 --- a/fpga_interchange/arch.h +++ b/fpga_interchange/arch.h @@ -67,7 +67,7 @@ NPNR_PACKED_STRUCT(struct BelInfoPOD { int16_t category; int16_t padding; - RelPtr valid_cells; // Bool array, length of number_cells. + RelPtr pin_map; // Index into CellMapPOD::cell_bel_map }); enum BELCategory @@ -109,6 +109,12 @@ NPNR_PACKED_STRUCT(struct PipInfoPOD { int16_t extra_data; }); +NPNR_PACKED_STRUCT(struct ConstraintTagPOD { + int32_t tag_prefix; // constid + int32_t default_state; // constid + RelSlice states; // constid +}); + NPNR_PACKED_STRUCT(struct TileTypeInfoPOD { int32_t name; // Tile type constid @@ -119,10 +125,13 @@ NPNR_PACKED_STRUCT(struct TileTypeInfoPOD { RelSlice wire_data; RelSlice pip_data; + + RelSlice tags; }); NPNR_PACKED_STRUCT(struct SiteInstInfoPOD { RelPtr name; + RelPtr site_name; // Which site type is this site instance? // constid @@ -138,7 +147,7 @@ NPNR_PACKED_STRUCT(struct TileInstInfoPOD { // This array is root.tile_types[type].number_sites long. // Index into root.sites - RelPtr sites; + RelSlice sites; // Number of tile wires; excluding any site-internal wires // which come after general wires and are not stored here @@ -154,10 +163,46 @@ NPNR_PACKED_STRUCT(struct TileWireRefPOD { NPNR_PACKED_STRUCT(struct NodeInfoPOD { RelSlice 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 pins; +}); + +NPNR_PACKED_STRUCT(struct CellConstraintPOD { + int32_t tag; // Tag index + int32_t constraint_type; // Constraint::ConstraintType + RelSlice states; // State indicies +}); + +NPNR_PACKED_STRUCT(struct CellBelMapPOD { + RelSlice common_pins; + RelSlice parameter_pins; + RelSlice constraints; +}); + NPNR_PACKED_STRUCT(struct CellMapPOD { // Cell names supported in this arch. RelSlice cell_names; // constids RelSlice cell_bel_buckets; // constids + + RelSlice cell_bel_map; +}); + +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 pins; }); NPNR_PACKED_STRUCT(struct ChipInfoPOD { @@ -171,6 +216,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { RelSlice sites; RelSlice tiles; RelSlice nodes; + RelSlice packages; // BEL bucket constids. RelSlice bel_buckets; @@ -667,7 +713,7 @@ struct ArchRanges using TileBelsRangeT = BelRange; using BelAttrsRangeT = std::vector>; using BelPinsRangeT = IdStringRange; - using CellBelPinRangeT = std::array; + using CellBelPinRangeT = const std::vector &; // Wires using AllWiresRangeT = WireRange; using DownhillPipRangeT = DownhillPipRange; @@ -695,6 +741,7 @@ struct Arch : ArchAPI { boost::iostreams::mapped_file_source blob_file; const ChipInfoPOD *chip_info; + int32_t package_index; mutable std::unordered_map tile_by_name; mutable std::unordered_map> site_by_name; @@ -768,12 +815,29 @@ struct Arch : ArchAPI uint32_t getBelChecksum(BelId bel) const override { return bel.index; } + void map_cell_pins(CellInfo *cell, int32_t mapping) const; + void map_port_pins(BelId bel, CellInfo *cell) const; + void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) override { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(tileStatus[bel.tile].boundcells[bel.index] == nullptr); tileStatus[bel.tile].boundcells[bel.index] = cell; + + const auto &bel_data = bel_info(chip_info, bel); + NPNR_ASSERT(bel_data.category == BEL_CATEGORY_LOGIC); + + if (io_port_types.count(cell->type) == 0) { + int32_t mapping = bel_info(chip_info, bel).pin_map[get_cell_type_index(cell->type)]; + NPNR_ASSERT(mapping >= 0); + + if (cell->cell_mapping != mapping) { + map_cell_pins(cell, mapping); + } + } else { + map_port_pins(bel, cell); + } cell->bel = bel; cell->belStrength = strength; refreshUiBel(bel); @@ -870,12 +934,15 @@ struct Arch : ArchAPI IdStringRange str_range; str_range.b.cursor = &ports[0]; - str_range.e.cursor = &ports[num_bel_wires - 1]; + str_range.e.cursor = &ports[num_bel_wires]; return str_range; } - std::array getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const override { return {pin}; } + const std::vector &getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const override + { + return cell_info->cell_bel_pins.at(pin); + } // ------------------------------------------------- @@ -1260,6 +1327,12 @@ struct Arch : ArchAPI BelBucketId getBelBucketForCellType(IdString cell_type) const override { + if (io_port_types.count(cell_type)) { + BelBucketId bucket; + bucket.name = id("IOPORTS"); + return bucket; + } + BelBucketId bucket; const CellMapPOD &cell_map = *chip_info->cell_map; bucket.name = IdString(cell_map.cell_bel_buckets[get_cell_type_index(cell_type)]); @@ -1277,7 +1350,11 @@ struct Arch : ArchAPI bool isValidBelForCellType(IdString cell_type, BelId bel) const override { - return bel_info(chip_info, bel).valid_cells[get_cell_type_index(cell_type)]; + if (io_port_types.count(cell_type)) { + return pads.count(bel) > 0; + } else { + return bel_info(chip_info, bel).pin_map[get_cell_type_index(cell_type)] > 0; + } } // Whether or not a given cell can be placed at a given Bel @@ -1318,6 +1395,28 @@ struct Arch : ArchAPI void parse_xdc(const std::string &filename); std::unordered_set io_port_types; + std::unordered_set pads; + + bool is_site_port(PipId pip) const + { + const PipInfoPOD &pip_data = pip_info(chip_info, pip); + if (pip_data.site == -1) { + return false; + } + + BelId bel; + bel.tile = pip.tile; + bel.index = pip_data.bel; + + const BelInfoPOD &bel_data = bel_info(chip_info, bel); + + return bel_data.category == BEL_CATEGORY_SITE_PORT; + } + + // Is the driver and all users of this net located within the same site? + // + // Returns false if any element of the net is not placed. + bool is_net_within_site(const NetInfo &net) const; }; NEXTPNR_NAMESPACE_END