clangformat
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
parent
b5731cee02
commit
fc15105643
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
|
@ -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.
|
||||||
|
@ -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 */
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user