aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-02-17 10:16:45 +0000
committerGitHub <noreply@github.com>2021-02-17 10:16:45 +0000
commitda1ecf0813cb07a65bc1ca498d0f9c896cc3a675 (patch)
tree5b9625b3852b79acb73ae55cd39078b18ab29019
parenta77ceec5cf5603542d87724d9fdc51d48fa29327 (diff)
parent26a187e5ebcd1bdb6e079a91e25b610dc603aab2 (diff)
downloadnextpnr-da1ecf0813cb07a65bc1ca498d0f9c896cc3a675.tar.gz
nextpnr-da1ecf0813cb07a65bc1ca498d0f9c896cc3a675.tar.bz2
nextpnr-da1ecf0813cb07a65bc1ca498d0f9c896cc3a675.zip
Merge pull request #586 from litghost/add_cell_bel_mapping_only
Add Cell -> BEL Pin maps to FPGA interchange arch.
-rw-r--r--fpga_interchange/arch.cc176
-rw-r--r--fpga_interchange/arch.h111
2 files changed, 274 insertions, 13 deletions
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc
index 814e4f85..dc5b5c77 100644
--- a/fpga_interchange/arch.cc
+++ b/fpga_interchange/arch.cc
@@ -37,6 +37,30 @@
#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<NEXTPNR_NAMESPACE_PREFIX SiteBelPair>
+{
+ std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX SiteBelPair &site_bel) const noexcept
+ {
+ std::size_t seed = 0;
+ boost::hash_combine(seed, std::hash<std::string>()(site_bel.site));
+ boost::hash_combine(seed, std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(site_bel.bel));
+ return seed;
+ }
+};
+
+NEXTPNR_NAMESPACE_BEGIN
static std::pair<std::string, std::string> 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<RelPtr<char>> &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,51 @@ 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);
+ if(chip_info->packages.size() == 1) {
+ IdString package_name(chip_info->packages[0].package);
+ this->args.package = package_name.str(this);
+ package_index = 0;
+ } else {
+ log_info("Package must be specified (with --package arg) when multiple packages are available, packages:\n");
+ for(const auto &package : chip_info->packages) {
+ log_info(" - %s\n", IdString(package.package).c_str(this));
+ }
+ log_error("--package is required!\n");
+ }
+ }
+
+ std::unordered_set<SiteBelPair> 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 +675,99 @@ const std::vector<std::string> Arch::availablePlacers = {"sa",
const std::string Arch::defaultRouter = "router2";
const std::vector<std::string> Arch::availableRouters = {"router1", "router2"};
+void Arch::map_cell_pins(CellInfo *cell, int32_t mapping) 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 &parameter_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 80eada4e..638855cd 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<int8_t> valid_cells; // Bool array, length of number_cells.
+ RelPtr<int32_t> 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<int32_t> states; // constid
+});
+
NPNR_PACKED_STRUCT(struct TileTypeInfoPOD {
int32_t name; // Tile type constid
@@ -119,10 +125,13 @@ NPNR_PACKED_STRUCT(struct TileTypeInfoPOD {
RelSlice<TileWireInfoPOD> wire_data;
RelSlice<PipInfoPOD> pip_data;
+
+ RelSlice<ConstraintTagPOD> tags;
});
NPNR_PACKED_STRUCT(struct SiteInstInfoPOD {
RelPtr<char> name;
+ RelPtr<char> 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<int32_t> sites;
+ RelSlice<int32_t> 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<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 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;
+});
+
+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 ChipInfoPOD {
@@ -171,6 +216,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD {
RelSlice<SiteInstInfoPOD> sites;
RelSlice<TileInstInfoPOD> tiles;
RelSlice<NodeInfoPOD> nodes;
+ RelSlice<PackagePOD> packages;
// BEL bucket constids.
RelSlice<int32_t> bel_buckets;
@@ -667,7 +713,7 @@ struct ArchRanges
using TileBelsRangeT = BelRange;
using BelAttrsRangeT = std::vector<std::pair<IdString, std::string>>;
using BelPinsRangeT = IdStringRange;
- using CellBelPinRangeT = std::array<IdString, 1>;
+ using CellBelPinRangeT = const std::vector<IdString> &;
// Wires
using AllWiresRangeT = WireRange;
using DownhillPipRangeT = DownhillPipRange;
@@ -695,6 +741,7 @@ struct Arch : ArchAPI<ArchRanges>
{
boost::iostreams::mapped_file_source blob_file;
const ChipInfoPOD *chip_info;
+ int32_t package_index;
mutable std::unordered_map<IdString, int> tile_by_name;
mutable std::unordered_map<IdString, std::pair<int, int>> site_by_name;
@@ -768,12 +815,29 @@ struct Arch : ArchAPI<ArchRanges>
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<ArchRanges>
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<IdString, 1> getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const override { return {pin}; }
+ const std::vector<IdString> &getBelPinsForCellPin(CellInfo *cell_info, IdString pin) const override
+ {
+ return cell_info->cell_bel_pins.at(pin);
+ }
// -------------------------------------------------
@@ -1260,6 +1327,12 @@ struct Arch : ArchAPI<ArchRanges>
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<ArchRanges>
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;
+ }
}
// Return true whether all Bels at a given location are valid
@@ -1307,6 +1384,28 @@ struct Arch : ArchAPI<ArchRanges>
void parse_xdc(const std::string &filename);
std::unordered_set<IdString> io_port_types;
+ std::unordered_set<BelId> 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