[FPGA Interchange] Add Cell -> BEL Pin maps.
This also expands the FPGA interchange Arch BBA to include placement constraints, but doesn't implement them yet. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
parent
a74d1a8b32
commit
bb4fa7af5b
@ -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,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<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 +667,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 ¶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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
// Whether or not a given cell can be placed at a given Bel
|
||||
@ -1318,6 +1395,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
|
||||
|
Loading…
Reference in New Issue
Block a user