aboutsummaryrefslogtreecommitdiffstats
path: root/fpga_interchange
diff options
context:
space:
mode:
Diffstat (limited to 'fpga_interchange')
-rw-r--r--fpga_interchange/arch.cc3
-rw-r--r--fpga_interchange/luts.cc178
-rw-r--r--fpga_interchange/luts.h41
3 files changed, 108 insertions, 114 deletions
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc
index 3b603e5e..e9dee580 100644
--- a/fpga_interchange/arch.cc
+++ b/fpga_interchange/arch.cc
@@ -723,7 +723,8 @@ bool Arch::route()
return result;
}
-bool Arch::route_vcc_to_unused_lut_pins() {
+bool Arch::route_vcc_to_unused_lut_pins()
+{
std::string router = str_or_default(settings, id("router"), defaultRouter);
// Fixup LUT vcc pins.
diff --git a/fpga_interchange/luts.cc b/fpga_interchange/luts.cc
index dc4e0531..49f934a4 100644
--- a/fpga_interchange/luts.cc
+++ b/fpga_interchange/luts.cc
@@ -19,16 +19,15 @@
#include "nextpnr.h"
-#include "luts.h"
#include "log.h"
+#include "luts.h"
NEXTPNR_NAMESPACE_BEGIN
-bool rotate_and_merge_lut_equation(std::vector<LogicLevel> * result,
- const LutBel & lut_bel,
- const nextpnr::DynamicBitarray<> &old_equation,
- const std::vector<int32_t> &pin_map,
- uint32_t used_pins) {
+bool rotate_and_merge_lut_equation(std::vector<LogicLevel> *result, const LutBel &lut_bel,
+ const nextpnr::DynamicBitarray<> &old_equation, const std::vector<int32_t> &pin_map,
+ uint32_t used_pins)
+{
// pin_map maps pin indicies from the old pin to the new pin.
// So a reversal of a LUT4 would have a pin map of:
// pin_map[0] = 3;
@@ -37,16 +36,16 @@ bool rotate_and_merge_lut_equation(std::vector<LogicLevel> * result,
// pin_map[3] = 0;
size_t bel_width = 1 << lut_bel.pins.size();
- for(size_t bel_address = 0; bel_address < bel_width; ++bel_address) {
+ for (size_t bel_address = 0; bel_address < bel_width; ++bel_address) {
bool address_reachable = true;
size_t cell_address = 0;
- for(size_t bel_pin_idx = 0; bel_pin_idx < lut_bel.pins.size(); ++bel_pin_idx) {
+ for (size_t bel_pin_idx = 0; bel_pin_idx < lut_bel.pins.size(); ++bel_pin_idx) {
// This address line is 0, so don't translate this bit to the cell
// address.
- if((bel_address & (1 << bel_pin_idx)) == 0) {
+ if ((bel_address & (1 << bel_pin_idx)) == 0) {
// This pin is unused, so the line will be tied high, this
// address is unreachable.
- if((used_pins & (1 << bel_pin_idx)) == 0) {
+ if ((used_pins & (1 << bel_pin_idx)) == 0) {
address_reachable = false;
break;
}
@@ -54,11 +53,10 @@ bool rotate_and_merge_lut_equation(std::vector<LogicLevel> * result,
continue;
}
-
auto cell_pin_idx = pin_map[bel_pin_idx];
// Is this BEL pin used for this cell?
- if(cell_pin_idx < 0) {
+ if (cell_pin_idx < 0) {
// This BEL pin is not used for the LUT cell, skip
continue;
}
@@ -66,20 +64,20 @@ bool rotate_and_merge_lut_equation(std::vector<LogicLevel> * result,
cell_address |= (1 << cell_pin_idx);
}
- if(!address_reachable) {
+ if (!address_reachable) {
continue;
}
bel_address += lut_bel.low_bit;
- if(old_equation.get(cell_address)) {
- if((*result)[bel_address] == LL_Zero) {
+ if (old_equation.get(cell_address)) {
+ if ((*result)[bel_address] == LL_Zero) {
// Output equation has a conflict!
return false;
}
(*result)[bel_address] = LL_One;
} else {
- if((*result)[bel_address] == LL_One) {
+ if ((*result)[bel_address] == LL_One) {
// Output equation has a conflict!
return false;
}
@@ -92,20 +90,23 @@ bool rotate_and_merge_lut_equation(std::vector<LogicLevel> * result,
static constexpr bool kCheckOutputEquation = true;
-struct LutPin {
- struct LutPinUser {
+struct LutPin
+{
+ struct LutPinUser
+ {
size_t cell_idx;
size_t cell_pin_idx;
};
- const NetInfo * net = nullptr;
+ const NetInfo *net = nullptr;
std::vector<LutPinUser> users;
int32_t min_pin = -1;
int32_t max_pin = -1;
- void add_user(const LutBel & lut_bel, size_t cell_idx, size_t cell_pin_idx) {
- if(min_pin < 0) {
+ void add_user(const LutBel &lut_bel, size_t cell_idx, size_t cell_pin_idx)
+ {
+ if (min_pin < 0) {
min_pin = lut_bel.min_pin;
max_pin = lut_bel.max_pin;
}
@@ -118,52 +119,52 @@ struct LutPin {
users.back().cell_pin_idx = cell_pin_idx;
}
- bool operator < (const LutPin & other) const {
- return max_pin < other.max_pin;
- }
+ bool operator<(const LutPin &other) const { return max_pin < other.max_pin; }
};
-bool LutMapper::remap_luts(const Context *ctx) {
- std::unordered_map<NetInfo*, LutPin> lut_pin_map;
- std::vector<const LutBel*> lut_bels;
+bool LutMapper::remap_luts(const Context *ctx)
+{
+ std::unordered_map<NetInfo *, LutPin> lut_pin_map;
+ std::vector<const LutBel *> lut_bels;
lut_bels.resize(cells.size());
- for(size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
- const CellInfo * cell = cells[cell_idx];
+ for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
+ const CellInfo *cell = cells[cell_idx];
#ifdef DEBUG_LUT_ROTATION
- log_info("Mapping %s %s eq = %s at %s\n", cell->type.c_str(ctx), cell->name.c_str(ctx), cell->params.at(ctx->id("INIT")).c_str(), ctx->nameOfBel(cell->bel));
+ log_info("Mapping %s %s eq = %s at %s\n", cell->type.c_str(ctx), cell->name.c_str(ctx),
+ cell->params.at(ctx->id("INIT")).c_str(), ctx->nameOfBel(cell->bel));
#endif
- 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);
- auto & lut_bel = element.lut_bels.at(bel_name);
+ auto &lut_bel = element.lut_bels.at(bel_name);
lut_bels[cell_idx] = &lut_bel;
- for(size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) {
+ for (size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) {
IdString lut_pin_name = cell->lut_cell.pins[pin_idx];
- const PortInfo & port_info = cell->ports.at(lut_pin_name);
+ const PortInfo &port_info = cell->ports.at(lut_pin_name);
NPNR_ASSERT(port_info.net != nullptr);
auto result = lut_pin_map.emplace(port_info.net, LutPin());
- LutPin & lut_pin = result.first->second;
+ LutPin &lut_pin = result.first->second;
lut_pin.net = port_info.net;
lut_pin.add_user(lut_bel, cell_idx, pin_idx);
}
}
- if(lut_pin_map.size() > element.pins.size()) {
+ if (lut_pin_map.size() > element.pins.size()) {
// Trival conflict, more nets entering element than pins are
// available!
#ifdef DEBUG_LUT_ROTATION
- log_info("Trival failure %zu > %zu, %zu %zu\n",
- lut_pin_map.size(), element.pins.size(), element.width, element.lut_bels.size());
+ log_info("Trival failure %zu > %zu, %zu %zu\n", lut_pin_map.size(), element.pins.size(), element.width,
+ element.lut_bels.size());
#endif
return false;
}
std::vector<LutPin> lut_pins;
lut_pins.reserve(lut_pin_map.size());
- for(auto lut_pin_pair : lut_pin_map) {
+ for (auto lut_pin_pair : lut_pin_map) {
lut_pins.push_back(std::move(lut_pin_pair.second));
}
lut_pin_map.clear();
@@ -173,7 +174,7 @@ bool LutMapper::remap_luts(const Context *ctx) {
std::vector<std::vector<int32_t>> bel_to_cell_pin_remaps;
cell_to_bel_pin_remaps.resize(cells.size());
bel_to_cell_pin_remaps.resize(cells.size());
- for(size_t i = 0; i < cells.size(); ++i) {
+ for (size_t i = 0; i < cells.size(); ++i) {
cell_to_bel_pin_remaps[i].resize(cells[i]->lut_cell.pins.size());
bel_to_cell_pin_remaps[i].resize(lut_bels[i]->pins.size(), -1);
}
@@ -181,23 +182,20 @@ bool LutMapper::remap_luts(const Context *ctx) {
uint32_t used_pins = 0;
size_t idx = 0;
std::vector<IdString> net_pins(lut_pins.size());
- for(auto &lut_pin : lut_pins) {
+ for (auto &lut_pin : lut_pins) {
size_t net_idx = idx++;
used_pins |= (1 << net_idx);
- for(auto cell_pin_idx : lut_pin.users) {
+ for (auto cell_pin_idx : lut_pin.users) {
size_t cell_idx = cell_pin_idx.cell_idx;
size_t pin_idx = cell_pin_idx.cell_pin_idx;
IdString bel_pin = lut_bels[cell_idx]->pins[net_idx];
#ifdef DEBUG_LUT_ROTATION
- log_info("%s %s %s => %s (%s)\n",
- cells[cell_idx]->type.c_str(ctx),
- cells[cell_idx]->name.c_str(ctx),
- cells[cell_idx]->lut_cell.pins[pin_idx].c_str(ctx),
- bel_pin.c_str(ctx),
- lut_pin.net->name.c_str(ctx));
+ log_info("%s %s %s => %s (%s)\n", cells[cell_idx]->type.c_str(ctx), cells[cell_idx]->name.c_str(ctx),
+ cells[cell_idx]->lut_cell.pins[pin_idx].c_str(ctx), bel_pin.c_str(ctx),
+ lut_pin.net->name.c_str(ctx));
#endif
- if(net_pins[net_idx] == IdString()) {
+ if (net_pins[net_idx] == IdString()) {
net_pins[net_idx] = bel_pin;
} else {
NPNR_ASSERT(net_pins[net_idx] == bel_pin);
@@ -211,18 +209,16 @@ bool LutMapper::remap_luts(const Context *ctx) {
// Try to see if the equations are mergable!
std::vector<LogicLevel> equation_result;
equation_result.resize(element.width, LL_DontCare);
- for(size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
- const CellInfo * cell = cells[cell_idx];
- auto & lut_bel = *lut_bels[cell_idx];
- if(!rotate_and_merge_lut_equation(&equation_result,
- lut_bel, cell->lut_cell.equation, bel_to_cell_pin_remaps[cell_idx], used_pins)) {
+ for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
+ const CellInfo *cell = cells[cell_idx];
+ auto &lut_bel = *lut_bels[cell_idx];
+ if (!rotate_and_merge_lut_equation(&equation_result, lut_bel, cell->lut_cell.equation,
+ bel_to_cell_pin_remaps[cell_idx], used_pins)) {
#ifdef DEBUG_LUT_ROTATION
log_info("Failed to find a solution!\n");
- for(auto *cell : cells) {
- log_info("%s %s : %s\b\n",
- cell->type.c_str(ctx),
- cell->name.c_str(ctx),
- cell->params.at(ctx->id("INIT")).c_str());
+ for (auto *cell : cells) {
+ log_info("%s %s : %s\b\n", cell->type.c_str(ctx), cell->name.c_str(ctx),
+ cell->params.at(ctx->id("INIT")).c_str());
}
#endif
return false;
@@ -234,13 +230,13 @@ bool LutMapper::remap_luts(const Context *ctx) {
#endif
// Sanity check final equation to make sure no assumptions are violated.
- if(kCheckOutputEquation) {
- for(size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
- CellInfo * cell = cells[cell_idx];
- auto & lut_bel = *lut_bels[cell_idx];
+ if (kCheckOutputEquation) {
+ for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
+ CellInfo *cell = cells[cell_idx];
+ auto &lut_bel = *lut_bels[cell_idx];
std::unordered_map<IdString, IdString> cell_to_bel_map;
- for(size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) {
+ for (size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) {
size_t bel_pin_idx = cell_to_bel_pin_remaps[cell_idx][pin_idx];
NPNR_ASSERT(bel_pin_idx < lut_bel.pins.size());
cell_to_bel_map[cell->lut_cell.pins[pin_idx]] = lut_bel.pins[bel_pin_idx];
@@ -252,19 +248,19 @@ bool LutMapper::remap_luts(const Context *ctx) {
// Push new cell -> BEL pin maps out to cells now that equations have been
// verified!
- for(size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
- CellInfo * cell = cells[cell_idx];
- auto & lut_bel = *lut_bels[cell_idx];
+ for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
+ CellInfo *cell = cells[cell_idx];
+ auto &lut_bel = *lut_bels[cell_idx];
- for(size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) {
+ for (size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) {
auto &bel_pins = cell->cell_bel_pins[cell->lut_cell.pins[pin_idx]];
bel_pins.clear();
bel_pins.push_back(lut_bel.pins[cell_to_bel_pin_remaps[cell_idx][pin_idx]]);
}
cell->lut_cell.vcc_pins.clear();
- for(size_t bel_pin_idx = 0; bel_pin_idx < lut_bel.pins.size(); ++bel_pin_idx) {
- if((used_pins & (1 << bel_pin_idx)) == 0) {
+ for (size_t bel_pin_idx = 0; bel_pin_idx < lut_bel.pins.size(); ++bel_pin_idx) {
+ if ((used_pins & (1 << bel_pin_idx)) == 0) {
NPNR_ASSERT(bel_to_cell_pin_remaps[cell_idx][bel_pin_idx] == -1);
cell->lut_cell.vcc_pins.emplace(lut_bel.pins[bel_pin_idx]);
}
@@ -274,18 +270,15 @@ bool LutMapper::remap_luts(const Context *ctx) {
return true;
}
-void check_equation(
- const LutCell & lut_cell,
- const std::unordered_map<IdString, IdString> &cell_to_bel_map,
- const LutBel & lut_bel,
- const std::vector<LogicLevel> &equation,
- uint32_t used_pins) {
+void check_equation(const LutCell &lut_cell, const std::unordered_map<IdString, IdString> &cell_to_bel_map,
+ const LutBel &lut_bel, const std::vector<LogicLevel> &equation, uint32_t used_pins)
+{
std::vector<int8_t> pin_map;
pin_map.resize(lut_bel.pins.size(), -1);
NPNR_ASSERT(lut_cell.pins.size() < std::numeric_limits<decltype(pin_map)::value_type>::max());
- for(size_t cell_pin_idx = 0; cell_pin_idx < lut_cell.pins.size(); ++cell_pin_idx) {
+ for (size_t cell_pin_idx = 0; cell_pin_idx < lut_cell.pins.size(); ++cell_pin_idx) {
IdString cell_pin = lut_cell.pins[cell_pin_idx];
IdString bel_pin = cell_to_bel_map.at(cell_pin);
size_t bel_pin_idx = lut_bel.pin_to_index.at(bel_pin);
@@ -297,18 +290,18 @@ void check_equation(
// LUT equation is respected.
size_t bel_width = 1 << lut_bel.pins.size();
NPNR_ASSERT(lut_bel.low_bit + bel_width == lut_bel.high_bit + 1);
- for(size_t bel_address = 0; bel_address < bel_width; ++bel_address) {
+ for (size_t bel_address = 0; bel_address < bel_width; ++bel_address) {
LogicLevel level = equation[bel_address + lut_bel.low_bit];
bool address_reachable = true;
size_t cell_address = 0;
- for(size_t bel_pin_idx = 0; bel_pin_idx < lut_bel.pins.size(); ++bel_pin_idx) {
+ for (size_t bel_pin_idx = 0; bel_pin_idx < lut_bel.pins.size(); ++bel_pin_idx) {
// This address line is 0, so don't translate this bit to the cell
// address.
- if((bel_address & (1 << bel_pin_idx)) == 0) {
+ if ((bel_address & (1 << bel_pin_idx)) == 0) {
// This pin is unused, so the line will be tied high, this
// address is unreachable.
- if((used_pins & (1 << bel_pin_idx)) == 0) {
+ if ((used_pins & (1 << bel_pin_idx)) == 0) {
address_reachable = false;
break;
}
@@ -318,7 +311,7 @@ void check_equation(
auto cell_pin_idx = pin_map[bel_pin_idx];
// Is this BEL pin used for this cell?
- if(cell_pin_idx < 0) {
+ if (cell_pin_idx < 0) {
// This BEL pin is not used for the LUT cell, skip
continue;
}
@@ -326,11 +319,11 @@ void check_equation(
cell_address |= (1 << cell_pin_idx);
}
- if(!address_reachable) {
+ if (!address_reachable) {
continue;
}
- if(lut_cell.equation.get(cell_address)) {
+ if (lut_cell.equation.get(cell_address)) {
NPNR_ASSERT(level == LL_One);
} else {
NPNR_ASSERT(level == LL_Zero);
@@ -338,17 +331,18 @@ void check_equation(
}
}
-void LutElement::compute_pin_order() {
+void LutElement::compute_pin_order()
+{
pins.clear();
pin_to_index.clear();
- for(auto & lut_bel_pair : lut_bels) {
- auto & lut_bel = lut_bel_pair.second;
+ for (auto &lut_bel_pair : lut_bels) {
+ auto &lut_bel = lut_bel_pair.second;
- for(size_t pin_idx = 0; pin_idx < lut_bel.pins.size(); ++pin_idx) {
+ for (size_t pin_idx = 0; pin_idx < lut_bel.pins.size(); ++pin_idx) {
IdString pin = lut_bel.pins[pin_idx];
auto result = pin_to_index.emplace(pin, pin_idx);
- if(!result.second) {
+ if (!result.second) {
// Not sure when this isn't true, but check it for now!
NPNR_ASSERT(result.first->second == pin_idx);
}
@@ -356,12 +350,12 @@ void LutElement::compute_pin_order() {
}
pins.resize(pin_to_index.size());
- for(auto &pin_pair : pin_to_index) {
+ for (auto &pin_pair : pin_to_index) {
pins.at(pin_pair.second) = pin_pair.first;
}
- for(auto & lut_bel_pair : lut_bels) {
- auto & lut_bel = lut_bel_pair.second;
+ for (auto &lut_bel_pair : lut_bels) {
+ auto &lut_bel = lut_bel_pair.second;
lut_bel.min_pin = pin_to_index.at(lut_bel.pins.front());
lut_bel.max_pin = pin_to_index.at(lut_bel.pins.back());
}
diff --git a/fpga_interchange/luts.h b/fpga_interchange/luts.h
index 0218653a..a5d3b1d0 100644
--- a/fpga_interchange/luts.h
+++ b/fpga_interchange/luts.h
@@ -31,13 +31,15 @@ NEXTPNR_NAMESPACE_BEGIN
struct CellInfo;
struct Context;
-enum LogicLevel {
+enum LogicLevel
+{
LL_Zero,
LL_One,
LL_DontCare
};
-struct LutCell {
+struct LutCell
+{
// LUT cell pins for equation, LSB first.
std::vector<IdString> pins;
std::unordered_set<IdString> lut_pins;
@@ -45,7 +47,8 @@ struct LutCell {
nextpnr::DynamicBitarray<> equation;
};
-struct LutBel {
+struct LutBel
+{
// LUT BEL pins to LUT array index.
std::vector<IdString> pins;
std::unordered_map<IdString, size_t> pin_to_index;
@@ -59,16 +62,13 @@ struct LutBel {
int32_t max_pin;
};
-// Work forward from cell definition and cell -> bel pin map and check that
+// Work forward from cell definition and cell -> bel pin map and check that
// equation is valid.
-void check_equation(
- const LutCell & lut_cell,
- const std::unordered_map<IdString, IdString> &cell_to_bel_map,
- const LutBel & lut_bel,
- const std::vector<LogicLevel> &equation,
- uint32_t used_pins);
-
-struct LutElement {
+void check_equation(const LutCell &lut_cell, const std::unordered_map<IdString, IdString> &cell_to_bel_map,
+ const LutBel &lut_bel, const std::vector<LogicLevel> &equation, uint32_t used_pins);
+
+struct LutElement
+{
size_t width;
std::unordered_map<IdString, LutBel> lut_bels;
@@ -78,11 +78,12 @@ struct LutElement {
std::unordered_map<IdString, size_t> pin_to_index;
};
-struct LutMapper {
- LutMapper(const LutElement & element) : element(element) {}
- const LutElement & element;
+struct LutMapper
+{
+ LutMapper(const LutElement &element) : element(element) {}
+ const LutElement &element;
- std::vector<CellInfo*> cells;
+ std::vector<CellInfo *> cells;
bool remap_luts(const Context *ctx);
};
@@ -90,11 +91,9 @@ struct LutMapper {
// Rotate and merge a LUT equation into an array of levels.
//
// If a conflict arises, return false and result is in an indeterminate state.
-bool rotate_and_merge_lut_equation(std::vector<LogicLevel> * result,
- const LutBel & lut_bel,
- const nextpnr::DynamicBitarray<> &old_equation,
- const std::vector<size_t> &pin_map,
- uint32_t used_pins);
+bool rotate_and_merge_lut_equation(std::vector<LogicLevel> *result, const LutBel &lut_bel,
+ const nextpnr::DynamicBitarray<> &old_equation, const std::vector<size_t> &pin_map,
+ uint32_t used_pins);
NEXTPNR_NAMESPACE_END