Merge pull request #586 from litghost/add_cell_bel_mapping_only

Add Cell -> BEL Pin maps to FPGA interchange arch.
This commit is contained in:
gatecat 2021-02-17 10:16:45 +00:00 committed by GitHub
commit da1ecf0813
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 274 additions and 13 deletions

View File

@ -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<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

View File

@ -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