clangformat

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2021-04-12 10:26:39 +01:00
parent b5731cee02
commit fc15105643
8 changed files with 134 additions and 133 deletions

View File

@ -278,7 +278,7 @@ Arch::Arch(ArchArgs args) : args(args), disallow_site_routing(false)
auto result = lut_cells.emplace(cell_type, &lut_cell); auto result = lut_cells.emplace(cell_type, &lut_cell);
NPNR_ASSERT(result.second); NPNR_ASSERT(result.second);
if(lut_cell.input_pins.size() == 1) { if (lut_cell.input_pins.size() == 1) {
// Only really expecting 1 single input LUT type! // Only really expecting 1 single input LUT type!
NPNR_ASSERT(wire_lut == nullptr); NPNR_ASSERT(wire_lut == nullptr);
wire_lut = &lut_cell; wire_lut = &lut_cell;
@ -1495,7 +1495,7 @@ void Arch::remove_pip_pseudo_wires(PipId pip, NetInfo *net)
} }
} }
if(pip_data.pseudo_cell_wires.size() > 0) { if (pip_data.pseudo_cell_wires.size() > 0) {
get_tile_status(pip.tile).pseudo_pip_model.unbindPip(getCtx(), pip); get_tile_status(pip.tile).pseudo_pip_model.unbindPip(getCtx(), pip);
} }
} }
@ -1728,13 +1728,13 @@ bool Arch::checkPipAvailForNet(PipId pip, NetInfo *net) const
} }
} }
if(pip_data.pseudo_cell_wires.size() > 0) { if (pip_data.pseudo_cell_wires.size() > 0) {
// FIXME: This pseudo pip check is incomplete, because constraint // FIXME: This pseudo pip check is incomplete, because constraint
// failures will not be detected. However the current FPGA // failures will not be detected. However the current FPGA
// interchange schema does not provide a cell type to place. // interchange schema does not provide a cell type to place.
auto iter = tileStatus.find(pip.tile); auto iter = tileStatus.find(pip.tile);
if(iter != tileStatus.end()) { if (iter != tileStatus.end()) {
if(!iter->second.pseudo_pip_model.checkPipAvail(getCtx(), pip)) { if (!iter->second.pseudo_pip_model.checkPipAvail(getCtx(), pip)) {
return false; return false;
} }
} }
@ -1766,7 +1766,7 @@ bool Arch::checkPipAvailForNet(PipId pip, NetInfo *net) const
} }
} }
if(disallow_site_routing && !valid_pip) { if (disallow_site_routing && !valid_pip) {
// For now, if driver is not part of this site, and // For now, if driver is not part of this site, and
// disallow_site_routing is set, disallow the edge. // disallow_site_routing is set, disallow the edge.
return false; return false;
@ -1972,15 +1972,16 @@ void Arch::explain_bel_status(BelId bel) const
site.explain(getCtx()); site.explain(getCtx());
} }
DelayQuad Arch::getPipDelay(PipId pip) const { DelayQuad Arch::getPipDelay(PipId pip) const
{
// FIXME: Implement when adding timing-driven place and route. // FIXME: Implement when adding timing-driven place and route.
const auto & pip_data = pip_info(chip_info, pip); const auto &pip_data = pip_info(chip_info, pip);
// Scale pseudo-pips by the number of wires they consume to make them // Scale pseudo-pips by the number of wires they consume to make them
// more expensive than a single edge. This approximation exists soley to // more expensive than a single edge. This approximation exists soley to
// make the non-timing driven solution avoid thinking that pseudo-pips // make the non-timing driven solution avoid thinking that pseudo-pips
// are the same cost as regular pips. // are the same cost as regular pips.
return DelayQuad(100*(1+pip_data.pseudo_cell_wires.size())); return DelayQuad(100 * (1 + pip_data.pseudo_cell_wires.size()));
} }
// Instance constraint templates. // Instance constraint templates.

View File

@ -38,8 +38,8 @@
#include "chipdb.h" #include "chipdb.h"
#include "dedicated_interconnect.h" #include "dedicated_interconnect.h"
#include "lookahead.h" #include "lookahead.h"
#include "site_router.h"
#include "pseudo_pip_model.h" #include "pseudo_pip_model.h"
#include "site_router.h"
#include "site_routing_cache.h" #include "site_routing_cache.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
@ -553,7 +553,7 @@ struct Arch : ArchAPI<ArchRanges>
assign_net_to_wire(wire, net, "pseudo", /*require_empty=*/true); assign_net_to_wire(wire, net, "pseudo", /*require_empty=*/true);
} }
if(pip_data.pseudo_cell_wires.size() > 0) { if (pip_data.pseudo_cell_wires.size() > 0) {
get_tile_status(pip.tile).pseudo_pip_model.bindPip(getCtx(), pip); get_tile_status(pip.tile).pseudo_pip_model.bindPip(getCtx(), pip);
} }
} }
@ -1068,7 +1068,7 @@ struct Arch : ArchAPI<ArchRanges>
// Note: May be null in arch's without wire LUT types. Assumption is // Note: May be null in arch's without wire LUT types. Assumption is
// that these arch's don't need wire LUT's because the LUT share is simple // that these arch's don't need wire LUT's because the LUT share is simple
// enough to avoid it. // enough to avoid it.
const LutCellPOD * wire_lut; const LutCellPOD *wire_lut;
std::regex raw_bin_constant; std::regex raw_bin_constant;
std::regex verilog_bin_constant; std::regex verilog_bin_constant;

View File

@ -17,11 +17,10 @@
* *
*/ */
#include "luts.h" #include "luts.h"
#include "nextpnr.h"
#include "log.h" #include "log.h"
#include "nextpnr.h"
//#define DEBUG_LUT_ROTATION //#define DEBUG_LUT_ROTATION
@ -131,8 +130,8 @@ struct LutPin
bool operator<(const LutPin &other) const { return max_pin < other.max_pin; } bool operator<(const LutPin &other) const { return max_pin < other.max_pin; }
}; };
uint32_t LutMapper::check_wires(const Context *ctx) const
uint32_t LutMapper::check_wires(const Context *ctx) const { {
// Unlike the 3 argument version of check_wires, this version needs to // Unlike the 3 argument version of check_wires, this version needs to
// calculate following data based on current cell pin mapping, etc: // calculate following data based on current cell pin mapping, etc:
// //
@ -149,7 +148,6 @@ uint32_t LutMapper::check_wires(const Context *ctx) const {
for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) { for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
const CellInfo *cell = cells[cell_idx]; const CellInfo *cell = cells[cell_idx];
auto &bel_data = bel_info(ctx->chip_info, cell->bel); auto &bel_data = bel_info(ctx->chip_info, cell->bel);
IdString bel_name(bel_data.name); IdString bel_name(bel_data.name);
auto &lut_bel = element.lut_bels.at(bel_name); auto &lut_bel = element.lut_bels.at(bel_name);
@ -169,8 +167,7 @@ uint32_t LutMapper::check_wires(const Context *ctx) const {
} }
HashTables::HashSet<const LutBel *> blocked_luts; HashTables::HashSet<const LutBel *> blocked_luts;
return check_wires(bel_to_cell_pin_remaps, lut_bels, used_pins, return check_wires(bel_to_cell_pin_remaps, lut_bels, used_pins, &blocked_luts);
&blocked_luts);
} }
uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_cell_pin_remaps, uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_cell_pin_remaps,

View File

@ -101,7 +101,7 @@ struct LutMapper
// the pin is free to be a signal. // the pin is free to be a signal.
uint32_t check_wires(const std::vector<std::vector<int32_t>> &bel_to_cell_pin_remaps, uint32_t check_wires(const std::vector<std::vector<int32_t>> &bel_to_cell_pin_remaps,
const std::vector<const LutBel *> &lut_bels, uint32_t used_pins, const std::vector<const LutBel *> &lut_bels, uint32_t used_pins,
HashTables::HashSet<const LutBel *> *blocked_luts) const; HashTables::HashSet<const LutBel *> *blocked_luts) const;
// Version of check_wires that uses current state of cells based on pin // Version of check_wires that uses current state of cells based on pin
// mapping in cells variable. // mapping in cells variable.

View File

@ -26,28 +26,29 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
void PseudoPipData::init_tile_type(const Context *ctx, int32_t tile_type) { void PseudoPipData::init_tile_type(const Context *ctx, int32_t tile_type)
if(max_pseudo_pip_for_tile_type.count(tile_type)) { {
if (max_pseudo_pip_for_tile_type.count(tile_type)) {
return; return;
} }
const TileTypeInfoPOD & type_data = ctx->chip_info->tile_types[tile_type]; const TileTypeInfoPOD &type_data = ctx->chip_info->tile_types[tile_type];
int32_t max_pseudo_pip_index = -1; int32_t max_pseudo_pip_index = -1;
for(int32_t pip_idx = 0; pip_idx < type_data.pip_data.ssize(); ++pip_idx) { for (int32_t pip_idx = 0; pip_idx < type_data.pip_data.ssize(); ++pip_idx) {
const PipInfoPOD & pip_data = type_data.pip_data[pip_idx]; const PipInfoPOD &pip_data = type_data.pip_data[pip_idx];
if(pip_data.pseudo_cell_wires.size() == 0) { if (pip_data.pseudo_cell_wires.size() == 0) {
continue; continue;
} }
if(pip_idx > max_pseudo_pip_index) { if (pip_idx > max_pseudo_pip_index) {
max_pseudo_pip_index = pip_idx; max_pseudo_pip_index = pip_idx;
} }
HashTables::HashSet<size_t> sites; HashTables::HashSet<size_t> sites;
std::vector<PseudoPipBel> pseudo_pip_bels; std::vector<PseudoPipBel> pseudo_pip_bels;
for(int32_t wire_index : pip_data.pseudo_cell_wires) { for (int32_t wire_index : pip_data.pseudo_cell_wires) {
const TileWireInfoPOD &wire_data = type_data.wire_data[wire_index]; const TileWireInfoPOD &wire_data = type_data.wire_data[wire_index];
if(wire_data.site == -1) { if (wire_data.site == -1) {
continue; continue;
} }
@ -56,7 +57,7 @@ void PseudoPipData::init_tile_type(const Context *ctx, int32_t tile_type) {
// Note: This assumption may be too restrictive. If so, then // Note: This assumption may be too restrictive. If so, then
// need to update database generators to provide // need to update database generators to provide
// pseudo_cell_wires for each site type, not just the primary. // pseudo_cell_wires for each site type, not just the primary.
if(wire_data.site_variant != -1) { if (wire_data.site_variant != -1) {
continue; continue;
} }
@ -64,28 +65,28 @@ void PseudoPipData::init_tile_type(const Context *ctx, int32_t tile_type) {
int32_t driver_bel = -1; int32_t driver_bel = -1;
int32_t output_pin = -1; int32_t output_pin = -1;
for(const BelPortPOD & bel_pin : wire_data.bel_pins) { for (const BelPortPOD &bel_pin : wire_data.bel_pins) {
const BelInfoPOD & bel_data = type_data.bel_data[bel_pin.bel_index]; const BelInfoPOD &bel_data = type_data.bel_data[bel_pin.bel_index];
if(bel_data.synthetic != NOT_SYNTH) { if (bel_data.synthetic != NOT_SYNTH) {
// Ignore synthetic BELs // Ignore synthetic BELs
continue; continue;
} }
if(bel_data.category != BEL_CATEGORY_LOGIC) { if (bel_data.category != BEL_CATEGORY_LOGIC) {
// Ignore site ports and site routing // Ignore site ports and site routing
continue; continue;
} }
int32_t bel_pin_idx = -1; int32_t bel_pin_idx = -1;
for(int32_t i = 0; i < bel_data.num_bel_wires; ++i) { for (int32_t i = 0; i < bel_data.num_bel_wires; ++i) {
if(bel_data.ports[i] == bel_pin.port) { if (bel_data.ports[i] == bel_pin.port) {
bel_pin_idx = i; bel_pin_idx = i;
break; break;
} }
} }
NPNR_ASSERT(bel_pin_idx != -1); NPNR_ASSERT(bel_pin_idx != -1);
if(bel_data.types[bel_pin_idx] != PORT_OUT) { if (bel_data.types[bel_pin_idx] != PORT_OUT) {
// Only care about output ports. Input ports may not be // Only care about output ports. Input ports may not be
// part of the pseudo pip. // part of the pseudo pip.
continue; continue;
@ -97,7 +98,7 @@ void PseudoPipData::init_tile_type(const Context *ctx, int32_t tile_type) {
output_pin = bel_pin_idx; output_pin = bel_pin_idx;
} }
if(driver_bel != -1) { if (driver_bel != -1) {
NPNR_ASSERT(output_pin != -1); NPNR_ASSERT(output_pin != -1);
PseudoPipBel bel; PseudoPipBel bel;
bel.bel_index = driver_bel; bel.bel_index = driver_bel;
@ -116,11 +117,11 @@ void PseudoPipData::init_tile_type(const Context *ctx, int32_t tile_type) {
// Initialize "logic_bels_for_pip" for every site that this pseudo pip // Initialize "logic_bels_for_pip" for every site that this pseudo pip
// appears. This means that if there are no pseudo_pip_bels, those // appears. This means that if there are no pseudo_pip_bels, those
// vectors will be empty. // vectors will be empty.
for(int32_t site : sites_for_pseudo_pip) { for (int32_t site : sites_for_pseudo_pip) {
logic_bels_for_pip[LogicBelKey{tile_type, pip_idx, site}].clear(); logic_bels_for_pip[LogicBelKey{tile_type, pip_idx, site}].clear();
} }
if(!pseudo_pip_bels.empty()) { if (!pseudo_pip_bels.empty()) {
HashTables::HashSet<int32_t> pseudo_cell_wires; HashTables::HashSet<int32_t> pseudo_cell_wires;
pseudo_cell_wires.insert(pip_data.pseudo_cell_wires.begin(), pip_data.pseudo_cell_wires.end()); pseudo_cell_wires.insert(pip_data.pseudo_cell_wires.begin(), pip_data.pseudo_cell_wires.end());
@ -129,23 +130,23 @@ void PseudoPipData::init_tile_type(const Context *ctx, int32_t tile_type) {
// //
// Note: Intentially copying the bel for mutation, and then // Note: Intentially copying the bel for mutation, and then
// pushing onto vector. // pushing onto vector.
for(PseudoPipBel bel : pseudo_pip_bels) { for (PseudoPipBel bel : pseudo_pip_bels) {
const BelInfoPOD & bel_data = type_data.bel_data[bel.bel_index]; const BelInfoPOD &bel_data = type_data.bel_data[bel.bel_index];
int32_t site = bel_data.site; int32_t site = bel_data.site;
int32_t input_bel_pin = -1; int32_t input_bel_pin = -1;
int32_t output_bel_pin = -1; int32_t output_bel_pin = -1;
for(int32_t i = 0; i < bel_data.num_bel_wires; ++i) { for (int32_t i = 0; i < bel_data.num_bel_wires; ++i) {
if(!pseudo_cell_wires.count(bel_data.wires[i])) { if (!pseudo_cell_wires.count(bel_data.wires[i])) {
continue; continue;
} }
if(bel_data.types[i] == PORT_OUT) { if (bel_data.types[i] == PORT_OUT) {
NPNR_ASSERT(output_bel_pin == -1); NPNR_ASSERT(output_bel_pin == -1);
output_bel_pin = i; output_bel_pin = i;
} }
if(bel_data.types[i] == PORT_IN && input_bel_pin == -1) { if (bel_data.types[i] == PORT_IN && input_bel_pin == -1) {
// Take first input BEL pin // Take first input BEL pin
// //
// FIXME: This heuristic feels fragile. // FIXME: This heuristic feels fragile.
@ -166,35 +167,38 @@ void PseudoPipData::init_tile_type(const Context *ctx, int32_t tile_type) {
max_pseudo_pip_for_tile_type[tile_type] = max_pseudo_pip_index; max_pseudo_pip_for_tile_type[tile_type] = max_pseudo_pip_index;
} }
const std::vector<size_t> &PseudoPipData::get_possible_sites_for_pip(const Context *ctx, PipId pip) const { const std::vector<size_t> &PseudoPipData::get_possible_sites_for_pip(const Context *ctx, PipId pip) const
{
int32_t tile_type = ctx->chip_info->tiles[pip.tile].type; int32_t tile_type = ctx->chip_info->tiles[pip.tile].type;
return possibles_sites_for_pip.at(std::make_pair(tile_type, pip.index)); return possibles_sites_for_pip.at(std::make_pair(tile_type, pip.index));
} }
size_t PseudoPipData::get_max_pseudo_pip(int32_t tile_type) const { size_t PseudoPipData::get_max_pseudo_pip(int32_t tile_type) const { return max_pseudo_pip_for_tile_type.at(tile_type); }
return max_pseudo_pip_for_tile_type.at(tile_type);
}
const std::vector<PseudoPipBel> &PseudoPipData::get_logic_bels_for_pip(const Context *ctx, int32_t site, PipId pip) const { const std::vector<PseudoPipBel> &PseudoPipData::get_logic_bels_for_pip(const Context *ctx, int32_t site,
PipId pip) const
{
int32_t tile_type = ctx->chip_info->tiles[pip.tile].type; int32_t tile_type = ctx->chip_info->tiles[pip.tile].type;
return logic_bels_for_pip.at(LogicBelKey{tile_type, pip.index, site}); return logic_bels_for_pip.at(LogicBelKey{tile_type, pip.index, site});
} }
void PseudoPipModel::init(Context *ctx, int32_t tile_idx) { void PseudoPipModel::init(Context *ctx, int32_t tile_idx)
{
int32_t tile_type = ctx->chip_info->tiles[tile_idx].type; int32_t tile_type = ctx->chip_info->tiles[tile_idx].type;
this->tile = tile_idx; this->tile = tile_idx;
allowed_pseudo_pips.resize(ctx->pseudo_pip_data.get_max_pseudo_pip(tile_type)+1); allowed_pseudo_pips.resize(ctx->pseudo_pip_data.get_max_pseudo_pip(tile_type) + 1);
allowed_pseudo_pips.fill(true); allowed_pseudo_pips.fill(true);
} }
void PseudoPipModel::prepare_for_routing(const Context *ctx, const std::vector<SiteRouter> & sites) { void PseudoPipModel::prepare_for_routing(const Context *ctx, const std::vector<SiteRouter> &sites)
{
// First determine which sites have placed cells, these sites are consider // First determine which sites have placed cells, these sites are consider
// active. // active.
HashTables::HashSet<size_t> active_sites; HashTables::HashSet<size_t> active_sites;
for(size_t site = 0; site < sites.size(); ++site) { for (size_t site = 0; site < sites.size(); ++site) {
if(!sites[site].cells_in_site.empty()) { if (!sites[site].cells_in_site.empty()) {
active_sites.emplace(site); active_sites.emplace(site);
} }
} }
@ -203,14 +207,14 @@ void PseudoPipModel::prepare_for_routing(const Context *ctx, const std::vector<S
// site (if the site / alt site is in use) or the first site that pseudo // site (if the site / alt site is in use) or the first site that pseudo
// pip appears in. // pip appears in.
int32_t tile_type = ctx->chip_info->tiles[tile].type; int32_t tile_type = ctx->chip_info->tiles[tile].type;
const TileTypeInfoPOD & type_data = ctx->chip_info->tile_types[tile_type]; const TileTypeInfoPOD &type_data = ctx->chip_info->tile_types[tile_type];
pseudo_pip_sites.clear(); pseudo_pip_sites.clear();
site_to_pseudo_pips.clear(); site_to_pseudo_pips.clear();
for(size_t pip_idx = 0; pip_idx < type_data.pip_data.size(); ++pip_idx) { for (size_t pip_idx = 0; pip_idx < type_data.pip_data.size(); ++pip_idx) {
const PipInfoPOD & pip_data = type_data.pip_data[pip_idx]; const PipInfoPOD &pip_data = type_data.pip_data[pip_idx];
if(pip_data.pseudo_cell_wires.size() == 0) { if (pip_data.pseudo_cell_wires.size() == 0) {
continue; continue;
} }
@ -220,14 +224,14 @@ void PseudoPipModel::prepare_for_routing(const Context *ctx, const std::vector<S
const std::vector<size_t> &sites = ctx->pseudo_pip_data.get_possible_sites_for_pip(ctx, pip); const std::vector<size_t> &sites = ctx->pseudo_pip_data.get_possible_sites_for_pip(ctx, pip);
int32_t site_for_pip = -1; int32_t site_for_pip = -1;
for(size_t possible_site : sites) { for (size_t possible_site : sites) {
if(active_sites.count(possible_site)) { if (active_sites.count(possible_site)) {
site_for_pip = possible_site; site_for_pip = possible_site;
break; break;
} }
} }
if(site_for_pip < 0) { if (site_for_pip < 0) {
site_for_pip = sites.at(0); site_for_pip = sites.at(0);
} }
@ -235,16 +239,17 @@ void PseudoPipModel::prepare_for_routing(const Context *ctx, const std::vector<S
site_to_pseudo_pips[site_for_pip].push_back(pip_idx); site_to_pseudo_pips[site_for_pip].push_back(pip_idx);
} }
for(auto & site_pair : site_to_pseudo_pips) { for (auto &site_pair : site_to_pseudo_pips) {
update_site(ctx, site_pair.first); update_site(ctx, site_pair.first);
} }
} }
bool PseudoPipModel::checkPipAvail(const Context *ctx, PipId pip) const { bool PseudoPipModel::checkPipAvail(const Context *ctx, PipId pip) const
{
bool allowed = allowed_pseudo_pips.get(pip.index); bool allowed = allowed_pseudo_pips.get(pip.index);
if(!allowed) { if (!allowed) {
#ifdef DEBUG_PSEUDO_PIP #ifdef DEBUG_PSEUDO_PIP
if(ctx->verbose) { if (ctx->verbose) {
log_info("Pseudo pip %s not allowed\n", ctx->nameOfPip(pip)); log_info("Pseudo pip %s not allowed\n", ctx->nameOfPip(pip));
} }
#endif #endif
@ -253,11 +258,12 @@ bool PseudoPipModel::checkPipAvail(const Context *ctx, PipId pip) const {
return allowed; return allowed;
} }
void PseudoPipModel::bindPip(const Context *ctx, PipId pip) { void PseudoPipModel::bindPip(const Context *ctx, PipId pip)
{
// If pseudo_pip_sites is empty, then prepare_for_routing was never // If pseudo_pip_sites is empty, then prepare_for_routing was never
// invoked. This is likely because PseudoPipModel was constructed during // invoked. This is likely because PseudoPipModel was constructed during
// routing. // routing.
if(pseudo_pip_sites.empty()) { if (pseudo_pip_sites.empty()) {
prepare_for_routing(ctx, ctx->tileStatus.at(tile).sites); prepare_for_routing(ctx, ctx->tileStatus.at(tile).sites);
} }
@ -273,7 +279,8 @@ void PseudoPipModel::bindPip(const Context *ctx, PipId pip) {
update_site(ctx, site); update_site(ctx, site);
} }
void PseudoPipModel::unbindPip(const Context *ctx, PipId pip) { void PseudoPipModel::unbindPip(const Context *ctx, PipId pip)
{
// It should not be possible for unbindPip to be invoked with // It should not be possible for unbindPip to be invoked with
// pseudo_pip_sites being empty. // pseudo_pip_sites being empty.
NPNR_ASSERT(!pseudo_pip_sites.empty()); NPNR_ASSERT(!pseudo_pip_sites.empty());
@ -285,7 +292,8 @@ void PseudoPipModel::unbindPip(const Context *ctx, PipId pip) {
update_site(ctx, site); update_site(ctx, site);
} }
void PseudoPipModel::update_site(const Context *ctx, size_t site) { void PseudoPipModel::update_site(const Context *ctx, size_t site)
{
// update_site consists of several steps: // update_site consists of several steps:
// //
// - Find all BELs within the site used by pseudo pips. // - Find all BELs within the site used by pseudo pips.
@ -303,8 +311,8 @@ void PseudoPipModel::update_site(const Context *ctx, size_t site) {
unused_pseudo_pips.reserve(pseudo_pips_for_site.size()); unused_pseudo_pips.reserve(pseudo_pips_for_site.size());
HashTables::HashMap<int32_t, PseudoPipBel> used_bels; HashTables::HashMap<int32_t, PseudoPipBel> used_bels;
for(int32_t pseudo_pip : pseudo_pips_for_site) { for (int32_t pseudo_pip : pseudo_pips_for_site) {
if(!active_pseudo_pips.count(pseudo_pip)) { if (!active_pseudo_pips.count(pseudo_pip)) {
unused_pseudo_pips.push_back(pseudo_pip); unused_pseudo_pips.push_back(pseudo_pip);
continue; continue;
} }
@ -312,17 +320,17 @@ void PseudoPipModel::update_site(const Context *ctx, size_t site) {
PipId pip; PipId pip;
pip.tile = tile; pip.tile = tile;
pip.index = pseudo_pip; pip.index = pseudo_pip;
for(const PseudoPipBel & bel: ctx->pseudo_pip_data.get_logic_bels_for_pip(ctx, site, pip)) { for (const PseudoPipBel &bel : ctx->pseudo_pip_data.get_logic_bels_for_pip(ctx, site, pip)) {
used_bels.emplace(bel.bel_index, bel); used_bels.emplace(bel.bel_index, bel);
} }
} }
if(unused_pseudo_pips.empty()) { if (unused_pseudo_pips.empty()) {
return; return;
} }
int32_t tile_type = ctx->chip_info->tiles[tile].type; int32_t tile_type = ctx->chip_info->tiles[tile].type;
const TileTypeInfoPOD & type_data = ctx->chip_info->tile_types[tile_type]; const TileTypeInfoPOD &type_data = ctx->chip_info->tile_types[tile_type];
// This section builds up LUT mapping logic to determine which LUT wires // This section builds up LUT mapping logic to determine which LUT wires
// are availble and which are not. // are availble and which are not.
@ -333,7 +341,7 @@ void PseudoPipModel::update_site(const Context *ctx, size_t site) {
lut_mappers.push_back(LutMapper(lut_elements[i])); lut_mappers.push_back(LutMapper(lut_elements[i]));
} }
const TileStatus & tile_status = ctx->tileStatus.at(tile); const TileStatus &tile_status = ctx->tileStatus.at(tile);
for (CellInfo *cell : tile_status.sites[site].cells_in_site) { for (CellInfo *cell : tile_status.sites[site].cells_in_site) {
if (cell->lut_cell.pins.empty()) { if (cell->lut_cell.pins.empty()) {
continue; continue;
@ -348,12 +356,12 @@ void PseudoPipModel::update_site(const Context *ctx, size_t site) {
std::vector<CellInfo> lut_cells; std::vector<CellInfo> lut_cells;
lut_cells.reserve(used_bels.size()); lut_cells.reserve(used_bels.size());
for(const auto & bel_pair : used_bels) { for (const auto &bel_pair : used_bels) {
const PseudoPipBel &bel = bel_pair.second; const PseudoPipBel &bel = bel_pair.second;
const BelInfoPOD & bel_data = type_data.bel_data[bel.bel_index]; const BelInfoPOD &bel_data = type_data.bel_data[bel.bel_index];
// This used BEL isn't a LUT, skip it! // This used BEL isn't a LUT, skip it!
if(bel_data.lut_element == -1) { if (bel_data.lut_element == -1) {
continue; continue;
} }
@ -363,7 +371,7 @@ void PseudoPipModel::update_site(const Context *ctx, size_t site) {
cell.bel.tile = tile; cell.bel.tile = tile;
cell.bel.index = bel_pair.first; cell.bel.index = bel_pair.first;
if(ctx->wire_lut == nullptr) { if (ctx->wire_lut == nullptr) {
continue; continue;
} }
@ -383,39 +391,37 @@ void PseudoPipModel::update_site(const Context *ctx, size_t site) {
std::vector<uint32_t> lut_wires_unavailable; std::vector<uint32_t> lut_wires_unavailable;
lut_wires_unavailable.reserve(lut_elements.size()); lut_wires_unavailable.reserve(lut_elements.size());
for(LutMapper &lut_mapper : lut_mappers) { for (LutMapper &lut_mapper : lut_mappers) {
lut_wires_unavailable.push_back(lut_mapper.check_wires(ctx)); lut_wires_unavailable.push_back(lut_mapper.check_wires(ctx));
} }
// For unused pseudo pips, see if the BEL used is idle. // For unused pseudo pips, see if the BEL used is idle.
for(int32_t pseudo_pip : unused_pseudo_pips) { for (int32_t pseudo_pip : unused_pseudo_pips) {
PipId pip; PipId pip;
pip.tile = tile; pip.tile = tile;
pip.index = pseudo_pip; pip.index = pseudo_pip;
bool blocked_by_bel = false; bool blocked_by_bel = false;
const std::vector<PseudoPipBel> & bels = ctx->pseudo_pip_data.get_logic_bels_for_pip(ctx, site, pip); const std::vector<PseudoPipBel> &bels = ctx->pseudo_pip_data.get_logic_bels_for_pip(ctx, site, pip);
for(const PseudoPipBel & bel: bels) { for (const PseudoPipBel &bel : bels) {
if(tile_status.boundcells[bel.bel_index] != nullptr) { if (tile_status.boundcells[bel.bel_index] != nullptr) {
blocked_by_bel = true; blocked_by_bel = true;
#ifdef DEBUG_PSEUDO_PIP #ifdef DEBUG_PSEUDO_PIP
if(ctx->verbose) { if (ctx->verbose) {
BelId abel; BelId abel;
abel.tile = tile; abel.tile = tile;
abel.index = bel.bel_index; abel.index = bel.bel_index;
log_info("Pseudo pip %s is block by a bound BEL %s\n", log_info("Pseudo pip %s is block by a bound BEL %s\n", ctx->nameOfPip(pip), ctx->nameOfBel(abel));
ctx->nameOfPip(pip), ctx->nameOfBel(abel));
} }
#endif #endif
break; break;
} }
if(used_bels.count(bel.bel_index)) { if (used_bels.count(bel.bel_index)) {
#ifdef DEBUG_PSEUDO_PIP #ifdef DEBUG_PSEUDO_PIP
if(ctx->verbose) { if (ctx->verbose) {
log_info("Pseudo pip %s is block by another pseudo pip\n", log_info("Pseudo pip %s is block by another pseudo pip\n", ctx->nameOfPip(pip));
ctx->nameOfPip(pip));
} }
#endif #endif
blocked_by_bel = true; blocked_by_bel = true;
@ -423,7 +429,7 @@ void PseudoPipModel::update_site(const Context *ctx, size_t site) {
} }
} }
if(blocked_by_bel) { if (blocked_by_bel) {
allowed_pseudo_pips.set(pseudo_pip, false); allowed_pseudo_pips.set(pseudo_pip, false);
continue; continue;
} }
@ -432,9 +438,9 @@ void PseudoPipModel::update_site(const Context *ctx, size_t site) {
// See if any BELs are part of a LUT element. If so, see if using // See if any BELs are part of a LUT element. If so, see if using
// that pseudo pip violates the LUT element equation. // that pseudo pip violates the LUT element equation.
for(const PseudoPipBel & bel: bels) { for (const PseudoPipBel &bel : bels) {
const BelInfoPOD & bel_data = type_data.bel_data[bel.bel_index]; const BelInfoPOD &bel_data = type_data.bel_data[bel.bel_index];
if(bel_data.lut_element == -1) { if (bel_data.lut_element == -1) {
continue; continue;
} }
@ -447,17 +453,16 @@ void PseudoPipModel::update_site(const Context *ctx, size_t site) {
size_t pin_idx = lut_elements.at(bel_data.lut_element).lut_bels.at(bel_name).pin_to_index.at(input_bel_pin); size_t pin_idx = lut_elements.at(bel_data.lut_element).lut_bels.at(bel_name).pin_to_index.at(input_bel_pin);
uint32_t blocked_inputs = lut_wires_unavailable.at(bel_data.lut_element); uint32_t blocked_inputs = lut_wires_unavailable.at(bel_data.lut_element);
if((blocked_inputs & (1 << pin_idx)) != 0) { if ((blocked_inputs & (1 << pin_idx)) != 0) {
blocked_by_lut_eq = true; blocked_by_lut_eq = true;
break; break;
} }
} }
if(blocked_by_lut_eq) { if (blocked_by_lut_eq) {
#ifdef DEBUG_PSEUDO_PIP #ifdef DEBUG_PSEUDO_PIP
if(ctx->verbose) { if (ctx->verbose) {
log_info("Pseudo pip %s is blocked by lut eq\n", log_info("Pseudo pip %s is blocked by lut eq\n", ctx->nameOfPip(pip));
ctx->nameOfPip(pip));
} }
#endif #endif
allowed_pseudo_pips.set(pseudo_pip, false); allowed_pseudo_pips.set(pseudo_pip, false);

View File

@ -23,15 +23,16 @@
#include <tuple> #include <tuple>
#include "dynamic_bitarray.h"
#include "hash_table.h"
#include "nextpnr_namespaces.h" #include "nextpnr_namespaces.h"
#include "nextpnr_types.h" #include "nextpnr_types.h"
#include "site_router.h" #include "site_router.h"
#include "dynamic_bitarray.h"
#include "hash_table.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
struct PseudoPipBel { struct PseudoPipBel
{
// Which BEL in the tile does the pseudo pip use? // Which BEL in the tile does the pseudo pip use?
int32_t bel_index; int32_t bel_index;
@ -46,22 +47,17 @@ struct PseudoPipBel {
int32_t output_bel_pin; int32_t output_bel_pin;
}; };
struct LogicBelKey { struct LogicBelKey
{
int32_t tile_type; int32_t tile_type;
int32_t pip_index; int32_t pip_index;
int32_t site; int32_t site;
std::tuple<int32_t, int32_t, int32_t> make_tuple() const { std::tuple<int32_t, int32_t, int32_t> make_tuple() const { return std::make_tuple(tile_type, pip_index, site); }
return std::make_tuple(tile_type, pip_index, site);
}
bool operator == (const LogicBelKey & other) const { bool operator==(const LogicBelKey &other) const { return make_tuple() == other.make_tuple(); }
return make_tuple() == other.make_tuple();
}
bool operator < (const LogicBelKey & other) const { bool operator<(const LogicBelKey &other) const { return make_tuple() < other.make_tuple(); }
return make_tuple() < other.make_tuple();
}
}; };
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END
@ -80,13 +76,13 @@ template <> struct hash<NEXTPNR_NAMESPACE_PREFIX LogicBelKey>
} }
}; };
}; }; // namespace std
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
// Storage for tile type generic pseudo pip data and lookup. // Storage for tile type generic pseudo pip data and lookup.
struct PseudoPipData { struct PseudoPipData
{
// Initial data for specified tile type, if not already initialized. // Initial data for specified tile type, if not already initialized.
void init_tile_type(const Context *ctx, int32_t tile_type); void init_tile_type(const Context *ctx, int32_t tile_type);
@ -107,7 +103,8 @@ struct PseudoPipData {
}; };
// Tile instance fast pseudo pip lookup. // Tile instance fast pseudo pip lookup.
struct PseudoPipModel { struct PseudoPipModel
{
int32_t tile; int32_t tile;
DynamicBitarray<> allowed_pseudo_pips; DynamicBitarray<> allowed_pseudo_pips;
HashTables::HashMap<int32_t, size_t> pseudo_pip_sites; HashTables::HashMap<int32_t, size_t> pseudo_pip_sites;
@ -124,7 +121,7 @@ struct PseudoPipModel {
// //
// If the tile has no placed elements, then prepare_for_routing does not // If the tile has no placed elements, then prepare_for_routing does not
// need to be called after init. // need to be called after init.
void prepare_for_routing(const Context *ctx, const std::vector<SiteRouter> & sites); void prepare_for_routing(const Context *ctx, const std::vector<SiteRouter> &sites);
// Returns true if the pseudo pip is allowed given current site placements // Returns true if the pseudo pip is allowed given current site placements
// and other pseudo pips. // and other pseudo pips.

View File

@ -322,7 +322,6 @@ inline SiteWire SiteArch::getBelPinWire(BelId bel, IdString pin) const
inline PortType SiteArch::getBelPinType(BelId bel, IdString pin) const { return ctx->getBelPinType(bel, pin); } inline PortType SiteArch::getBelPinType(BelId bel, IdString pin) const { return ctx->getBelPinType(bel, pin); }
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END
#endif /* SITE_ARCH_H */ #endif /* SITE_ARCH_H */

View File

@ -675,7 +675,8 @@ static bool find_solution_via_backtrack(SiteArch *ctx, std::vector<PossibleSolut
NPNR_ASSERT(false); NPNR_ASSERT(false);
} }
static bool route_site(SiteArch *ctx, SiteRoutingCache *site_routing_cache, RouteNodeStorage *node_storage, bool explain) static bool route_site(SiteArch *ctx, SiteRoutingCache *site_routing_cache, RouteNodeStorage *node_storage,
bool explain)
{ {
// Overview: // Overview:
// - Starting from each site net source, expand the site routing graph // - Starting from each site net source, expand the site routing graph
@ -987,7 +988,8 @@ static void apply_routing(Context *ctx, const SiteArch &site_arch)
} }
static bool map_luts_in_site(const SiteInformation &site_info, static bool map_luts_in_site(const SiteInformation &site_info,
HashTables::HashSet<std::pair<IdString, IdString>> *blocked_wires) { HashTables::HashSet<std::pair<IdString, IdString>> *blocked_wires)
{
const Context *ctx = site_info.ctx; const Context *ctx = site_info.ctx;
const std::vector<LutElement> &lut_elements = ctx->lut_elements.at(site_info.tile_type); const std::vector<LutElement> &lut_elements = ctx->lut_elements.at(site_info.tile_type);
std::vector<LutMapper> lut_mappers; std::vector<LutMapper> lut_mappers;
@ -1019,7 +1021,7 @@ static bool map_luts_in_site(const SiteInformation &site_info,
return false; return false;
} }
for(const LutBel * lut_bel : blocked_luts) { for (const LutBel *lut_bel : blocked_luts) {
blocked_wires->emplace(std::make_pair(lut_bel->name, lut_bel->output_pin)); blocked_wires->emplace(std::make_pair(lut_bel->name, lut_bel->output_pin));
} }
} }
@ -1027,19 +1029,20 @@ static bool map_luts_in_site(const SiteInformation &site_info,
return true; return true;
} }
// Block outputs of unavailable LUTs to prevent site router from using them. // Block outputs of unavailable LUTs to prevent site router from using them.
static void block_lut_outputs(SiteArch *site_arch, static void block_lut_outputs(SiteArch *site_arch,
const HashTables::HashSet<std::pair<IdString, IdString>> &blocked_wires) { const HashTables::HashSet<std::pair<IdString, IdString>> &blocked_wires)
const Context * ctx = site_arch->site_info->ctx; {
const Context *ctx = site_arch->site_info->ctx;
auto &tile_info = ctx->chip_info->tile_types[site_arch->site_info->tile_type]; auto &tile_info = ctx->chip_info->tile_types[site_arch->site_info->tile_type];
for(const auto & bel_pin_pair : blocked_wires) { for (const auto &bel_pin_pair : blocked_wires) {
IdString bel_name = bel_pin_pair.first; IdString bel_name = bel_pin_pair.first;
IdString bel_pin = bel_pin_pair.second; IdString bel_pin = bel_pin_pair.second;
int32_t bel_index = -1; int32_t bel_index = -1;
for (int32_t i = 0; i < tile_info.bel_data.ssize(); i++) { for (int32_t i = 0; i < tile_info.bel_data.ssize(); i++) {
if (tile_info.bel_data[i].site == site_arch->site_info->site && tile_info.bel_data[i].name == bel_name.index) { if (tile_info.bel_data[i].site == site_arch->site_info->site &&
tile_info.bel_data[i].name == bel_name.index) {
bel_index = i; bel_index = i;
break; break;
} }
@ -1062,7 +1065,6 @@ bool SiteRouter::checkSiteRouting(const Context *ctx, const TileStatus &tile_sta
// - Ensure that the LUT equation elements in the site are legal // - Ensure that the LUT equation elements in the site are legal
// - Check that the site is routable. // - Check that the site is routable.
// Because site routing checks are expensive, cache them. // Because site routing checks are expensive, cache them.
// SiteRouter::bindBel/unbindBel should correctly invalid the cache by // SiteRouter::bindBel/unbindBel should correctly invalid the cache by
// setting dirty=true. // setting dirty=true.
@ -1111,7 +1113,7 @@ bool SiteRouter::checkSiteRouting(const Context *ctx, const TileStatus &tile_sta
SiteInformation site_info(ctx, tile, site, cells_in_site); SiteInformation site_info(ctx, tile, site, cells_in_site);
HashTables::HashSet<std::pair<IdString, IdString>> blocked_wires; HashTables::HashSet<std::pair<IdString, IdString>> blocked_wires;
if(!map_luts_in_site(site_info, &blocked_wires)) { if (!map_luts_in_site(site_info, &blocked_wires)) {
site_ok = false; site_ok = false;
return site_ok; return site_ok;
} }