aboutsummaryrefslogtreecommitdiffstats
path: root/fpga_interchange/arch.h
diff options
context:
space:
mode:
Diffstat (limited to 'fpga_interchange/arch.h')
-rw-r--r--fpga_interchange/arch.h304
1 files changed, 275 insertions, 29 deletions
diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h
index 638855cd..76497d6d 100644
--- a/fpga_interchange/arch.h
+++ b/fpga_interchange/arch.h
@@ -28,6 +28,8 @@
#include <iostream>
+#include "constraints.h"
+
NEXTPNR_NAMESPACE_BEGIN
/**** Everything in this section must be kept in sync with chipdb.py ****/
@@ -251,6 +253,11 @@ inline const PipInfoPOD &pip_info(const ChipInfoPOD *chip_info, PipId pip)
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;
@@ -654,7 +661,11 @@ struct BelPinRange
BelPinIterator end() const { return e; }
};
-struct IdStringIterator
+struct IdStringIterator : std::iterator<std::forward_iterator_tag,
+ /*T=*/IdString,
+ /*Distance=*/ptrdiff_t,
+ /*pointer=*/IdString *,
+ /*reference=*/IdString>
{
const int32_t *cursor;
@@ -751,12 +762,32 @@ struct Arch : ArchAPI<ArchRanges>
std::unordered_map<WireId, std::pair<int, int>> driving_pip_loc;
std::unordered_map<WireId, NetInfo *> reserved_wires;
+ static constexpr size_t kMaxState = 8;
+
+ struct TileStatus;
+ struct SiteRouter
+ {
+ SiteRouter(int16_t site) : site(site), dirty(false), site_ok(true) {}
+
+ std::unordered_set<CellInfo *> cells_in_site;
+ const int16_t site;
+
+ mutable bool dirty;
+ mutable bool site_ok;
+
+ void bindBel(CellInfo *cell);
+ void unbindBel(CellInfo *cell);
+ bool checkSiteRouting(const Context *ctx, const TileStatus &tile_status) const;
+ };
+
struct TileStatus
{
+ std::vector<ExclusiveStateGroup<kMaxState>> tags;
std::vector<CellInfo *> boundcells;
+ std::vector<SiteRouter> sites;
};
- std::vector<TileStatus> tileStatus;
+ std::unordered_map<int32_t, TileStatus> tileStatus;
ArchArgs args;
Arch(ArchArgs args);
@@ -806,9 +837,7 @@ struct Arch : ArchAPI<ArchRanges>
IdStringList getBelName(BelId bel) const override
{
NPNR_ASSERT(bel != BelId());
- int site_index = bel_info(chip_info, bel).site;
- NPNR_ASSERT(site_index >= 0);
- const SiteInstInfoPOD &site = chip_info->sites[chip_info->tiles[bel.tile].sites[site_index]];
+ const SiteInstInfoPOD &site = get_site_inst(bel);
std::array<IdString, 2> ids{id(site.name.get()), IdString(bel_info(chip_info, bel).name)};
return IdStringList(ids);
}
@@ -818,12 +847,39 @@ struct Arch : ArchAPI<ArchRanges>
void map_cell_pins(CellInfo *cell, int32_t mapping) const;
void map_port_pins(BelId bel, CellInfo *cell) const;
+ TileStatus &get_tile_status(int32_t tile)
+ {
+ auto result = tileStatus.emplace(tile, TileStatus());
+ if (result.second) {
+ auto &tile_type = chip_info->tile_types[chip_info->tiles[tile].type];
+ result.first->second.boundcells.resize(tile_type.bel_data.size());
+ result.first->second.tags.resize(default_tags.size());
+
+ result.first->second.sites.reserve(tile_type.number_sites);
+ for (size_t i = 0; i < (size_t)tile_type.number_sites; ++i) {
+ result.first->second.sites.push_back(SiteRouter(i));
+ }
+ }
+
+ return result.first->second;
+ }
+
+ const SiteRouter &get_site_status(const TileStatus &tile_status, const BelInfoPOD &bel_data) const
+ {
+ return tile_status.sites.at(bel_data.site);
+ }
+
+ SiteRouter &get_site_status(TileStatus &tile_status, const BelInfoPOD &bel_data)
+ {
+ return tile_status.sites.at(bel_data.site);
+ }
+
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;
+ TileStatus &tile_status = get_tile_status(bel.tile);
+ NPNR_ASSERT(tile_status.boundcells[bel.index] == nullptr);
const auto &bel_data = bel_info(chip_info, bel);
NPNR_ASSERT(bel_data.category == BEL_CATEGORY_LOGIC);
@@ -835,36 +891,74 @@ struct Arch : ArchAPI<ArchRanges>
if (cell->cell_mapping != mapping) {
map_cell_pins(cell, mapping);
}
+ constraints.bindBel(tile_status.tags.data(), get_cell_constraints(bel, cell->type));
} else {
map_port_pins(bel, cell);
+ // FIXME: Probably need to actually constraint io port cell/bel,
+ // but the current BBA emission doesn't support that. This only
+ // really matters if the placer can choose IO port locations.
}
+
+ get_site_status(tile_status, bel_data).bindBel(cell);
+
+ tile_status.boundcells[bel.index] = cell;
+
cell->bel = bel;
cell->belStrength = strength;
+
refreshUiBel(bel);
}
void unbindBel(BelId bel) override
{
NPNR_ASSERT(bel != BelId());
- NPNR_ASSERT(tileStatus[bel.tile].boundcells[bel.index] != nullptr);
- tileStatus[bel.tile].boundcells[bel.index]->bel = BelId();
- tileStatus[bel.tile].boundcells[bel.index]->belStrength = STRENGTH_NONE;
- tileStatus[bel.tile].boundcells[bel.index] = nullptr;
+
+ TileStatus &tile_status = get_tile_status(bel.tile);
+ NPNR_ASSERT(tile_status.boundcells[bel.index] != nullptr);
+
+ CellInfo *cell = tile_status.boundcells[bel.index];
+ tile_status.boundcells[bel.index] = nullptr;
+
+ cell->bel = BelId();
+ cell->belStrength = STRENGTH_NONE;
+
+ // FIXME: Probably need to actually constraint io port cell/bel,
+ // but the current BBA emission doesn't support that. This only
+ // really matters if the placer can choose IO port locations.
+ if (io_port_types.count(cell->type) == 0) {
+ constraints.unbindBel(tile_status.tags.data(), get_cell_constraints(bel, cell->type));
+ }
+
+ const auto &bel_data = bel_info(chip_info, bel);
+ get_site_status(tile_status, bel_data).unbindBel(cell);
+
refreshUiBel(bel);
}
- bool checkBelAvail(BelId bel) const override { return tileStatus[bel.tile].boundcells[bel.index] == nullptr; }
+ bool checkBelAvail(BelId bel) const override
+ {
+ // 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
{
NPNR_ASSERT(bel != BelId());
- return tileStatus[bel.tile].boundcells[bel.index];
+ auto iter = tileStatus.find(bel.tile);
+ if (iter == tileStatus.end()) {
+ return nullptr;
+ } else {
+ return iter->second.boundcells[bel.index];
+ }
}
CellInfo *getConflictingBelCell(BelId bel) const override
{
NPNR_ASSERT(bel != BelId());
- return tileStatus[bel.tile].boundcells[bel.index];
+ // FIXME: This could consult the constraint system to see why this BEL
+ // is blocked.
+ return getBoundBelCell(bel);
}
BelRange getBels() const override
@@ -964,8 +1058,7 @@ struct Arch : ArchAPI<ArchRanges>
if (wire.tile != -1) {
const auto &tile_type = loc_info(chip_info, wire);
if (tile_type.wire_data[wire.index].site != -1) {
- int site_index = tile_type.wire_data[wire.index].site;
- const SiteInstInfoPOD &site = chip_info->sites[chip_info->tiles[wire.tile].sites[site_index]];
+ const SiteInstInfoPOD &site = get_site_inst(wire);
std::array<IdString, 2> ids{id(site.name.get()), IdString(tile_type.wire_data[wire.index].name)};
return IdStringList(ids);
}
@@ -1251,6 +1344,9 @@ struct Arch : ArchAPI<ArchRanges>
// -------------------------------------------------
+ void place_iobufs(WireId pad_wire, NetInfo *net, const std::unordered_set<CellInfo *> &tightly_attached_bels,
+ std::unordered_set<CellInfo *> *placed_cells);
+ void pack_ports();
bool pack() override;
bool place() override;
bool route() override;
@@ -1315,15 +1411,7 @@ struct Arch : ArchAPI<ArchRanges>
return BelBucketId();
}
- size_t get_cell_type_index(IdString cell_type) const
- {
- const CellMapPOD &cell_map = *chip_info->cell_map;
- int cell_offset = cell_type.index - cell_map.cell_names[0];
- NPNR_ASSERT(cell_offset >= 0 && cell_offset < cell_map.cell_names.ssize());
- NPNR_ASSERT(cell_map.cell_names[cell_offset] == cell_type.index);
-
- return cell_offset;
- }
+ size_t get_cell_type_index(IdString cell_type) const;
BelBucketId getBelBucketForCellType(IdString cell_type) const override
{
@@ -1352,16 +1440,57 @@ struct Arch : ArchAPI<ArchRanges>
{
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;
}
+
+ const auto &bel_data = bel_info(chip_info, bel);
+ if (bel_data.category != BEL_CATEGORY_LOGIC) {
+ return false;
+ }
+
+ auto cell_type_index = get_cell_type_index(cell_type);
+ return bel_data.pin_map[cell_type_index] != -1;
+ }
+
+ bool is_cell_valid_constraints(const CellInfo *cell, const TileStatus &tile_status, bool explain) const
+ {
+ if (io_port_types.count(cell->type)) {
+ return true;
+ }
+
+ BelId bel = cell->bel;
+ NPNR_ASSERT(bel != BelId());
+
+ return constraints.isValidBelForCellType(getCtx(), get_constraint_prototype(bel), tile_status.tags.data(),
+ get_cell_constraints(bel, cell->type),
+ id(chip_info->tiles[bel.tile].name.get()), cell->name, bel, explain);
}
// Return true whether all Bels at a given location are valid
bool isBelLocationValid(BelId bel) const override
{
- // FIXME: Implement this
- return true;
+ auto iter = tileStatus.find(bel.tile);
+ if (iter == tileStatus.end()) {
+ return true;
+ }
+ const TileStatus &tile_status = iter->second;
+ const CellInfo *cell = tile_status.boundcells[bel.index];
+ if (cell == nullptr) {
+ return true;
+ } else {
+ if (io_port_types.count(cell->type)) {
+ // FIXME: Probably need to actually constraint io port cell/bel,
+ // but the current BBA emission doesn't support that. This only
+ // really matters if the placer can choose IO port locations.
+ return true;
+ }
+
+ if (!is_cell_valid_constraints(cell, tile_status, explain_constraints)) {
+ return false;
+ }
+
+ auto &bel_data = bel_info(chip_info, bel);
+ return get_site_status(tile_status, bel_data).checkSiteRouting(getCtx(), tile_status);
+ }
}
IdString get_bel_tiletype(BelId bel) const { return IdString(loc_info(chip_info, bel).name); }
@@ -1406,6 +1535,123 @@ struct Arch : ArchAPI<ArchRanges>
//
// Returns false if any element of the net is not placed.
bool is_net_within_site(const NetInfo &net) const;
+
+ using ArchConstraints = Constraints<kMaxState>;
+ ArchConstraints constraints;
+ std::vector<ArchConstraints::TagState> default_tags;
+ bool explain_constraints;
+
+ struct StateRange
+ {
+ const int32_t *b;
+ const int32_t *e;
+
+ const int32_t *begin() const { return b; }
+ const int32_t *end() const { return e; }
+ };
+
+ struct Constraint : ArchConstraints::Constraint<StateRange>
+ {
+ const CellConstraintPOD *constraint;
+ Constraint(const CellConstraintPOD *constraint) : constraint(constraint) {}
+
+ size_t tag() const override { return constraint->tag; }
+
+ ArchConstraints::ConstraintType constraint_type() const override
+ {
+ return Constraints<kMaxState>::ConstraintType(constraint->constraint_type);
+ }
+
+ ArchConstraints::ConstraintStateType state() const override
+ {
+ NPNR_ASSERT(constraint_type() == Constraints<kMaxState>::CONSTRAINT_TAG_IMPLIES);
+ NPNR_ASSERT(constraint->states.size() == 1);
+ return constraint->states[0];
+ }
+
+ StateRange states() const override
+ {
+ StateRange range;
+ range.b = constraint->states.get();
+ range.e = range.b + constraint->states.size();
+
+ return range;
+ }
+ };
+
+ struct ConstraintIterator
+ {
+ const CellConstraintPOD *constraint;
+ ConstraintIterator() {}
+
+ ConstraintIterator operator++()
+ {
+ ++constraint;
+ return *this;
+ }
+
+ bool operator!=(const ConstraintIterator &other) const { return constraint != other.constraint; }
+
+ bool operator==(const ConstraintIterator &other) const { return constraint == other.constraint; }
+
+ Constraint operator*() const { return Constraint(constraint); }
+ };
+
+ struct ConstraintRange
+ {
+ ConstraintIterator b, e;
+
+ ConstraintIterator begin() const { return b; }
+ ConstraintIterator end() const { return e; }
+ };
+
+ uint32_t get_constraint_prototype(BelId bel) const { return chip_info->tiles[bel.tile].type; }
+
+ ConstraintRange get_cell_constraints(BelId bel, IdString cell_type) const
+ {
+ const auto &bel_data = bel_info(chip_info, bel);
+ NPNR_ASSERT(bel_data.category == BEL_CATEGORY_LOGIC);
+
+ int32_t mapping = bel_data.pin_map[get_cell_type_index(cell_type)];
+ NPNR_ASSERT(mapping >= 0);
+
+ auto &cell_bel_map = chip_info->cell_map->cell_bel_map[mapping];
+ ConstraintRange range;
+ range.b.constraint = cell_bel_map.constraints.get();
+ range.e.constraint = range.b.constraint + cell_bel_map.constraints.size();
+
+ return range;
+ }
+
+ const char *get_site_name(int32_t tile, size_t site) const
+ {
+ return site_inst_info(chip_info, tile, site).name.get();
+ }
+
+ const char *get_site_name(BelId bel) const
+ {
+ auto &bel_data = bel_info(chip_info, bel);
+ return get_site_name(bel.tile, bel_data.site);
+ }
+
+ const SiteInstInfoPOD &get_site_inst(BelId bel) const
+ {
+ auto &bel_data = bel_info(chip_info, bel);
+ return site_inst_info(chip_info, bel.tile, bel_data.site);
+ }
+
+ const SiteInstInfoPOD &get_site_inst(WireId wire) const
+ {
+ auto &wire_data = wire_info(wire);
+ NPNR_ASSERT(wire_data.site != -1);
+ return site_inst_info(chip_info, wire.tile, wire_data.site);
+ }
+
+ const SiteInstInfoPOD &get_site_inst(PipId pip) const
+ {
+ auto &pip_data = pip_info(chip_info, pip);
+ return site_inst_info(chip_info, pip.tile, pip_data.site);
+ }
};
NEXTPNR_NAMESPACE_END