diff options
Diffstat (limited to 'fpga_interchange/arch.h')
-rw-r--r-- | fpga_interchange/arch.h | 304 |
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 |