2021-02-25 06:02:21 +08:00
|
|
|
/*
|
|
|
|
* nextpnr -- Next Generation Place and Route
|
|
|
|
*
|
|
|
|
* Copyright (C) 2021 Symbiflow Authors
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
#include "luts.h"
|
2021-02-25 06:02:21 +08:00
|
|
|
|
2021-04-02 06:19:21 +08:00
|
|
|
#include "log.h"
|
2021-04-12 17:26:39 +08:00
|
|
|
#include "nextpnr.h"
|
2021-04-02 06:19:21 +08:00
|
|
|
|
2021-07-09 21:40:06 +08:00
|
|
|
#include "site_lut_mapping_cache.h"
|
|
|
|
|
2021-04-02 04:18:07 +08:00
|
|
|
//#define DEBUG_LUT_ROTATION
|
|
|
|
|
2021-02-25 06:02:21 +08:00
|
|
|
NEXTPNR_NAMESPACE_BEGIN
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
bool rotate_and_merge_lut_equation(std::vector<LogicLevel> *result, const LutBel &lut_bel,
|
2021-03-16 01:25:46 +08:00
|
|
|
const DynamicBitarray<> &old_equation, const std::vector<int32_t> &pin_map,
|
2021-03-03 18:39:47 +08:00
|
|
|
uint32_t used_pins)
|
|
|
|
{
|
2021-02-25 06:02:21 +08:00
|
|
|
// 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;
|
|
|
|
// pin_map[1] = 2;
|
|
|
|
// pin_map[2] = 1;
|
|
|
|
// pin_map[3] = 0;
|
|
|
|
|
|
|
|
size_t bel_width = 1 << lut_bel.pins.size();
|
2021-03-03 18:39:47 +08:00
|
|
|
for (size_t bel_address = 0; bel_address < bel_width; ++bel_address) {
|
2021-02-25 06:02:21 +08:00
|
|
|
bool address_reachable = true;
|
|
|
|
size_t cell_address = 0;
|
2021-03-03 18:39:47 +08:00
|
|
|
for (size_t bel_pin_idx = 0; bel_pin_idx < lut_bel.pins.size(); ++bel_pin_idx) {
|
2021-02-25 06:02:21 +08:00
|
|
|
// This address line is 0, so don't translate this bit to the cell
|
|
|
|
// address.
|
2021-03-03 18:39:47 +08:00
|
|
|
if ((bel_address & (1 << bel_pin_idx)) == 0) {
|
2021-02-25 06:02:21 +08:00
|
|
|
// This pin is unused, so the line will be tied high, this
|
|
|
|
// address is unreachable.
|
2021-03-26 04:36:11 +08:00
|
|
|
//
|
|
|
|
// FIXME: The assumption is that unused pins are tied VCC.
|
|
|
|
// This is not generally true.
|
|
|
|
//
|
|
|
|
// Use Arch::prefered_constant_net_type to determine what
|
|
|
|
// constant net should be used for unused pins.
|
2021-03-03 18:39:47 +08:00
|
|
|
if ((used_pins & (1 << bel_pin_idx)) == 0) {
|
2021-02-25 06:02:21 +08:00
|
|
|
address_reachable = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto cell_pin_idx = pin_map[bel_pin_idx];
|
|
|
|
|
|
|
|
// Is this BEL pin used for this cell?
|
2021-03-03 18:39:47 +08:00
|
|
|
if (cell_pin_idx < 0) {
|
2021-02-25 06:02:21 +08:00
|
|
|
// This BEL pin is not used for the LUT cell, skip
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell_address |= (1 << cell_pin_idx);
|
|
|
|
}
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
if (!address_reachable) {
|
2021-02-25 06:02:21 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bel_address += lut_bel.low_bit;
|
2021-03-03 18:39:47 +08:00
|
|
|
if (old_equation.get(cell_address)) {
|
|
|
|
if ((*result)[bel_address] == LL_Zero) {
|
2021-02-25 06:02:21 +08:00
|
|
|
// Output equation has a conflict!
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*result)[bel_address] = LL_One;
|
|
|
|
} else {
|
2021-03-03 18:39:47 +08:00
|
|
|
if ((*result)[bel_address] == LL_One) {
|
2021-02-25 06:02:21 +08:00
|
|
|
// Output equation has a conflict!
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
(*result)[bel_address] = LL_Zero;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr bool kCheckOutputEquation = true;
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
struct LutPin
|
|
|
|
{
|
|
|
|
struct LutPinUser
|
|
|
|
{
|
2021-02-25 06:02:21 +08:00
|
|
|
size_t cell_idx;
|
|
|
|
size_t cell_pin_idx;
|
|
|
|
};
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
const NetInfo *net = nullptr;
|
2021-02-25 06:02:21 +08:00
|
|
|
std::vector<LutPinUser> users;
|
|
|
|
|
|
|
|
int32_t min_pin = -1;
|
|
|
|
int32_t max_pin = -1;
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
void add_user(const LutBel &lut_bel, size_t cell_idx, size_t cell_pin_idx)
|
|
|
|
{
|
|
|
|
if (min_pin < 0) {
|
2021-02-25 06:02:21 +08:00
|
|
|
min_pin = lut_bel.min_pin;
|
|
|
|
max_pin = lut_bel.max_pin;
|
|
|
|
}
|
|
|
|
|
|
|
|
min_pin = std::max(min_pin, lut_bel.min_pin);
|
|
|
|
max_pin = std::min(max_pin, lut_bel.max_pin);
|
|
|
|
|
|
|
|
users.emplace_back();
|
|
|
|
users.back().cell_idx = cell_idx;
|
|
|
|
users.back().cell_pin_idx = cell_pin_idx;
|
|
|
|
}
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
bool operator<(const LutPin &other) const { return max_pin < other.max_pin; }
|
2021-02-25 06:02:21 +08:00
|
|
|
};
|
|
|
|
|
2021-04-12 17:26:39 +08:00
|
|
|
uint32_t LutMapper::check_wires(const Context *ctx) const
|
|
|
|
{
|
2021-04-02 04:18:07 +08:00
|
|
|
// Unlike the 3 argument version of check_wires, this version needs to
|
|
|
|
// calculate following data based on current cell pin mapping, etc:
|
|
|
|
//
|
|
|
|
// - Index map from bel pins to cell pins, -1 for unmapped
|
|
|
|
// - Mask of used pins
|
|
|
|
// - Vector of unused LUT BELs.
|
|
|
|
|
|
|
|
uint32_t used_pins = 0;
|
|
|
|
|
|
|
|
std::vector<std::vector<int32_t>> bel_to_cell_pin_remaps;
|
|
|
|
std::vector<const LutBel *> lut_bels;
|
|
|
|
bel_to_cell_pin_remaps.resize(cells.size());
|
|
|
|
lut_bels.resize(cells.size());
|
|
|
|
for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
|
|
|
|
const CellInfo *cell = cells[cell_idx];
|
|
|
|
|
|
|
|
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);
|
|
|
|
lut_bels[cell_idx] = &lut_bel;
|
|
|
|
|
|
|
|
bel_to_cell_pin_remaps[cell_idx].resize(lut_bel.pins.size(), -1);
|
|
|
|
|
|
|
|
for (size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) {
|
|
|
|
IdString lut_cell_pin = cell->lut_cell.pins[pin_idx];
|
|
|
|
const std::vector<IdString> bel_pins = cell->cell_bel_pins.at(lut_cell_pin);
|
|
|
|
NPNR_ASSERT(bel_pins.size() == 1);
|
|
|
|
|
|
|
|
size_t bel_pin_idx = lut_bel.pin_to_index.at(bel_pins[0]);
|
|
|
|
bel_to_cell_pin_remaps[cell_idx][bel_pin_idx] = pin_idx;
|
|
|
|
used_pins |= (1 << bel_pin_idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-02 17:01:36 +08:00
|
|
|
pool<const LutBel *, hash_ptr_ops> blocked_luts;
|
2021-04-12 17:26:39 +08:00
|
|
|
return check_wires(bel_to_cell_pin_remaps, lut_bels, used_pins, &blocked_luts);
|
2021-04-02 04:18:07 +08:00
|
|
|
}
|
2021-03-20 08:35:29 +08:00
|
|
|
|
2021-03-25 07:25:15 +08:00
|
|
|
uint32_t LutMapper::check_wires(const std::vector<std::vector<int32_t>> &bel_to_cell_pin_remaps,
|
2021-04-02 06:19:21 +08:00
|
|
|
const std::vector<const LutBel *> &lut_bels, uint32_t used_pins,
|
2021-06-02 17:01:36 +08:00
|
|
|
pool<const LutBel *, hash_ptr_ops> *blocked_luts) const
|
2021-03-25 07:25:15 +08:00
|
|
|
{
|
|
|
|
std::vector<const LutBel *> unused_luts;
|
|
|
|
for (auto &lut_bel_pair : element.lut_bels) {
|
|
|
|
if (std::find(lut_bels.begin(), lut_bels.end(), &lut_bel_pair.second) == lut_bels.end()) {
|
|
|
|
unused_luts.push_back(&lut_bel_pair.second);
|
2021-04-02 06:19:21 +08:00
|
|
|
blocked_luts->emplace(&lut_bel_pair.second);
|
2021-03-25 07:25:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-26 04:36:11 +08:00
|
|
|
// FIXME: The assumption is that unused pins are tied VCC.
|
|
|
|
// This is not generally true.
|
|
|
|
//
|
|
|
|
// Use Arch::prefered_constant_net_type to determine what
|
|
|
|
// constant net should be used for unused pins.
|
2021-03-25 07:25:15 +08:00
|
|
|
uint32_t vcc_mask = 0;
|
|
|
|
|
|
|
|
DynamicBitarray<> wire_equation;
|
|
|
|
wire_equation.resize(2);
|
|
|
|
wire_equation.set(0, false);
|
|
|
|
wire_equation.set(1, true);
|
|
|
|
|
|
|
|
std::vector<int32_t> wire_bel_to_cell_pin_map;
|
|
|
|
std::vector<LogicLevel> equation_result;
|
|
|
|
for (int32_t pin_idx = 0; pin_idx < (int32_t)element.pins.size(); ++pin_idx) {
|
|
|
|
if (used_pins & (1 << pin_idx)) {
|
|
|
|
// This pin is already used, so it cannot be used for a wire.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool valid_pin_for_wire = false;
|
|
|
|
bool invalid_pin_for_wire = false;
|
|
|
|
|
|
|
|
for (const LutBel *lut_bel : unused_luts) {
|
|
|
|
if (pin_idx < lut_bel->min_pin) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pin_idx > lut_bel->max_pin) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
wire_bel_to_cell_pin_map.clear();
|
|
|
|
wire_bel_to_cell_pin_map.resize(lut_bel->pins.size(), -1);
|
|
|
|
wire_bel_to_cell_pin_map[lut_bel->pin_to_index.at(element.pins[pin_idx])] = 0;
|
|
|
|
|
|
|
|
equation_result.clear();
|
|
|
|
equation_result.resize(element.width, LL_DontCare);
|
|
|
|
|
|
|
|
uint32_t used_pins_with_wire = used_pins | (1 << pin_idx);
|
|
|
|
|
|
|
|
for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
|
|
|
|
const CellInfo *cell = cells[cell_idx];
|
|
|
|
auto &lut_bel_for_cell = *lut_bels[cell_idx];
|
|
|
|
if (!rotate_and_merge_lut_equation(&equation_result, lut_bel_for_cell, cell->lut_cell.equation,
|
|
|
|
bel_to_cell_pin_remaps[cell_idx], used_pins_with_wire)) {
|
|
|
|
invalid_pin_for_wire = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (invalid_pin_for_wire) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rotate_and_merge_lut_equation(&equation_result, *lut_bel, wire_equation, wire_bel_to_cell_pin_map,
|
|
|
|
used_pins_with_wire)) {
|
|
|
|
valid_pin_for_wire = true;
|
2021-04-02 06:19:21 +08:00
|
|
|
blocked_luts->erase(lut_bel);
|
2021-03-25 07:25:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool good_for_wire = valid_pin_for_wire && !invalid_pin_for_wire;
|
|
|
|
if (!good_for_wire) {
|
|
|
|
vcc_mask |= (1 << pin_idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return vcc_mask;
|
|
|
|
}
|
|
|
|
|
2021-07-09 21:40:06 +08:00
|
|
|
bool LutMapper::remap_luts(const Context *ctx, SiteLutMappingResult* lut_mapping, pool<const LutBel *, hash_ptr_ops> *blocked_luts)
|
2021-03-03 18:39:47 +08:00
|
|
|
{
|
2021-06-02 17:01:36 +08:00
|
|
|
dict<NetInfo *, LutPin, hash_ptr_ops> lut_pin_map;
|
2021-03-03 18:39:47 +08:00
|
|
|
std::vector<const LutBel *> lut_bels;
|
2021-02-25 06:02:21 +08:00
|
|
|
lut_bels.resize(cells.size());
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
|
|
|
|
const CellInfo *cell = cells[cell_idx];
|
2021-02-25 06:02:21 +08:00
|
|
|
#ifdef DEBUG_LUT_ROTATION
|
2021-03-03 18:39:47 +08:00
|
|
|
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));
|
2021-02-25 06:02:21 +08:00
|
|
|
#endif
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
auto &bel_data = bel_info(ctx->chip_info, cell->bel);
|
2021-02-25 06:02:21 +08:00
|
|
|
IdString bel_name(bel_data.name);
|
2021-03-03 18:39:47 +08:00
|
|
|
auto &lut_bel = element.lut_bels.at(bel_name);
|
2021-02-25 06:02:21 +08:00
|
|
|
lut_bels[cell_idx] = &lut_bel;
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
for (size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) {
|
2021-02-25 06:02:21 +08:00
|
|
|
IdString lut_pin_name = cell->lut_cell.pins[pin_idx];
|
2021-03-03 18:39:47 +08:00
|
|
|
const PortInfo &port_info = cell->ports.at(lut_pin_name);
|
2021-02-25 06:02:21 +08:00
|
|
|
NPNR_ASSERT(port_info.net != nullptr);
|
|
|
|
|
|
|
|
auto result = lut_pin_map.emplace(port_info.net, LutPin());
|
2021-03-03 18:39:47 +08:00
|
|
|
LutPin &lut_pin = result.first->second;
|
2021-02-25 06:02:21 +08:00
|
|
|
lut_pin.net = port_info.net;
|
|
|
|
lut_pin.add_user(lut_bel, cell_idx, pin_idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
if (lut_pin_map.size() > element.pins.size()) {
|
2021-02-25 06:02:21 +08:00
|
|
|
// Trival conflict, more nets entering element than pins are
|
|
|
|
// available!
|
|
|
|
#ifdef DEBUG_LUT_ROTATION
|
2021-03-03 18:39:47 +08:00
|
|
|
log_info("Trival failure %zu > %zu, %zu %zu\n", lut_pin_map.size(), element.pins.size(), element.width,
|
|
|
|
element.lut_bels.size());
|
2021-02-25 06:02:21 +08:00
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<LutPin> lut_pins;
|
|
|
|
lut_pins.reserve(lut_pin_map.size());
|
2021-03-03 18:39:47 +08:00
|
|
|
for (auto lut_pin_pair : lut_pin_map) {
|
2021-02-25 06:02:21 +08:00
|
|
|
lut_pins.push_back(std::move(lut_pin_pair.second));
|
|
|
|
}
|
|
|
|
lut_pin_map.clear();
|
|
|
|
std::sort(lut_pins.begin(), lut_pins.end());
|
|
|
|
|
|
|
|
std::vector<std::vector<size_t>> cell_to_bel_pin_remaps;
|
|
|
|
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());
|
2021-03-03 18:39:47 +08:00
|
|
|
for (size_t i = 0; i < cells.size(); ++i) {
|
2021-02-25 06:02:21 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t used_pins = 0;
|
|
|
|
size_t idx = 0;
|
|
|
|
std::vector<IdString> net_pins(lut_pins.size());
|
2021-03-03 18:39:47 +08:00
|
|
|
for (auto &lut_pin : lut_pins) {
|
2021-02-25 06:02:21 +08:00
|
|
|
size_t net_idx = idx++;
|
|
|
|
used_pins |= (1 << net_idx);
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
for (auto cell_pin_idx : lut_pin.users) {
|
2021-02-25 06:02:21 +08:00
|
|
|
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
|
2021-03-03 18:39:47 +08:00
|
|
|
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));
|
2021-02-25 06:02:21 +08:00
|
|
|
#endif
|
2021-03-03 18:39:47 +08:00
|
|
|
if (net_pins[net_idx] == IdString()) {
|
2021-02-25 06:02:21 +08:00
|
|
|
net_pins[net_idx] = bel_pin;
|
|
|
|
} else {
|
|
|
|
NPNR_ASSERT(net_pins[net_idx] == bel_pin);
|
|
|
|
}
|
|
|
|
|
|
|
|
cell_to_bel_pin_remaps[cell_idx][pin_idx] = net_idx;
|
|
|
|
bel_to_cell_pin_remaps[cell_idx][net_idx] = pin_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to see if the equations are mergable!
|
|
|
|
std::vector<LogicLevel> equation_result;
|
|
|
|
equation_result.resize(element.width, LL_DontCare);
|
2021-03-03 18:39:47 +08:00
|
|
|
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)) {
|
2021-02-25 06:02:21 +08:00
|
|
|
#ifdef DEBUG_LUT_ROTATION
|
|
|
|
log_info("Failed to find a solution!\n");
|
2021-03-03 18:39:47 +08:00
|
|
|
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());
|
2021-02-25 06:02:21 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_LUT_ROTATION
|
|
|
|
log_info("Found a solution!\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Sanity check final equation to make sure no assumptions are violated.
|
2021-03-03 18:39:47 +08:00
|
|
|
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];
|
2021-02-25 06:02:21 +08:00
|
|
|
|
2021-06-02 17:01:36 +08:00
|
|
|
dict<IdString, IdString> cell_to_bel_map;
|
2021-03-03 18:39:47 +08:00
|
|
|
for (size_t pin_idx = 0; pin_idx < cell->lut_cell.pins.size(); ++pin_idx) {
|
2021-02-25 06:02:21 +08:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
|
|
|
check_equation(cell->lut_cell, cell_to_bel_map, lut_bel, equation_result, used_pins);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-09 21:40:06 +08:00
|
|
|
// Not all LUT inputs are used
|
|
|
|
uint32_t vcc_pins = 0;
|
|
|
|
if (cells.size() != element.lut_bels.size()) {
|
|
|
|
// Look to see if wires can be run from element inputs to unused
|
|
|
|
// outputs. If not, block the BEL pin by tying to VCC.
|
|
|
|
//
|
|
|
|
// FIXME: The assumption is that unused pins are tied VCC.
|
|
|
|
// This is not generally true.
|
|
|
|
//
|
|
|
|
// Use Arch::prefered_constant_net_type to determine what
|
|
|
|
// constant net should be used for unused pins.
|
|
|
|
vcc_pins = check_wires(bel_to_cell_pin_remaps, lut_bels, used_pins, blocked_luts);
|
|
|
|
#if defined(DEBUG_LUT_ROTATION)
|
|
|
|
log_info("vcc_pins = 0x%x", vcc_pins);
|
|
|
|
for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
|
|
|
|
CellInfo *cell = cells[cell_idx];
|
|
|
|
log(", %s => %s", ctx->nameOfBel(cell->bel), cell->name.c_str(ctx));
|
|
|
|
}
|
|
|
|
log("\n");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fill in the LUT mapping result
|
|
|
|
|
|
|
|
// Push new cell -> BEL pin maps out to cells now that equations have been
|
|
|
|
// verified!
|
|
|
|
lut_mapping->cells.reserve(cells.size());
|
|
|
|
for (size_t cell_idx = 0; cell_idx < cells.size(); ++cell_idx) {
|
|
|
|
CellInfo *cellInfo = cells[cell_idx];
|
|
|
|
auto &lutBel = *lut_bels[cell_idx];
|
|
|
|
|
|
|
|
// Add the cell data
|
|
|
|
SiteLutMappingResult::Cell cell;
|
|
|
|
cell.belIndex = cellInfo->bel.index;
|
|
|
|
|
|
|
|
// Cell to BEL pin map
|
|
|
|
for (size_t pin_idx = 0; pin_idx < cellInfo->lut_cell.pins.size(); ++pin_idx) {
|
|
|
|
IdString cellPin = cellInfo->lut_cell.pins[pin_idx];
|
|
|
|
IdString belPin = lutBel.pins[cell_to_bel_pin_remaps[cell_idx][pin_idx]];
|
|
|
|
cell.belPins[cellPin] = belPin;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell.lutCell.vcc_pins.clear();
|
|
|
|
|
|
|
|
// All LUT inputs used
|
|
|
|
if (cells.size() == element.lut_bels.size()) {
|
|
|
|
for (size_t bel_pin_idx = 0; bel_pin_idx < lutBel.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.lutCell.vcc_pins.emplace(lutBel.pins.at(bel_pin_idx));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Only some LUT inputs used
|
|
|
|
else {
|
|
|
|
for (size_t bel_pin_idx = 0; bel_pin_idx < lutBel.pins.size(); ++bel_pin_idx) {
|
|
|
|
if ((vcc_pins & (1 << bel_pin_idx)) != 0) {
|
|
|
|
NPNR_ASSERT(bel_to_cell_pin_remaps[cell_idx][bel_pin_idx] == -1);
|
|
|
|
auto pin = lutBel.pins.at(bel_pin_idx);
|
|
|
|
cell.lutCell.vcc_pins.emplace(pin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lut_mapping->cells.push_back(cell);
|
|
|
|
}
|
|
|
|
|
2021-02-25 06:02:21 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-02 17:01:36 +08:00
|
|
|
void check_equation(const LutCell &lut_cell, const dict<IdString, IdString> &cell_to_bel_map, const LutBel &lut_bel,
|
|
|
|
const std::vector<LogicLevel> &equation, uint32_t used_pins)
|
2021-03-03 18:39:47 +08:00
|
|
|
{
|
2021-02-25 06:02:21 +08:00
|
|
|
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());
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
for (size_t cell_pin_idx = 0; cell_pin_idx < lut_cell.pins.size(); ++cell_pin_idx) {
|
2021-02-25 06:02:21 +08:00
|
|
|
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);
|
|
|
|
|
|
|
|
pin_map[bel_pin_idx] = cell_pin_idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate over all BEL addresses in the LUT, and ensure that the original
|
|
|
|
// 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);
|
2021-03-03 18:39:47 +08:00
|
|
|
for (size_t bel_address = 0; bel_address < bel_width; ++bel_address) {
|
2021-02-25 06:02:21 +08:00
|
|
|
LogicLevel level = equation[bel_address + lut_bel.low_bit];
|
|
|
|
|
|
|
|
bool address_reachable = true;
|
|
|
|
size_t cell_address = 0;
|
2021-03-03 18:39:47 +08:00
|
|
|
for (size_t bel_pin_idx = 0; bel_pin_idx < lut_bel.pins.size(); ++bel_pin_idx) {
|
2021-02-25 06:02:21 +08:00
|
|
|
// This address line is 0, so don't translate this bit to the cell
|
|
|
|
// address.
|
2021-03-03 18:39:47 +08:00
|
|
|
if ((bel_address & (1 << bel_pin_idx)) == 0) {
|
2021-02-25 06:02:21 +08:00
|
|
|
// This pin is unused, so the line will be tied high, this
|
|
|
|
// address is unreachable.
|
2021-03-03 18:39:47 +08:00
|
|
|
if ((used_pins & (1 << bel_pin_idx)) == 0) {
|
2021-02-25 06:02:21 +08:00
|
|
|
address_reachable = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto cell_pin_idx = pin_map[bel_pin_idx];
|
|
|
|
|
|
|
|
// Is this BEL pin used for this cell?
|
2021-03-03 18:39:47 +08:00
|
|
|
if (cell_pin_idx < 0) {
|
2021-02-25 06:02:21 +08:00
|
|
|
// This BEL pin is not used for the LUT cell, skip
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell_address |= (1 << cell_pin_idx);
|
|
|
|
}
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
if (!address_reachable) {
|
2021-02-25 06:02:21 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
if (lut_cell.equation.get(cell_address)) {
|
2021-02-25 06:02:21 +08:00
|
|
|
NPNR_ASSERT(level == LL_One);
|
|
|
|
} else {
|
|
|
|
NPNR_ASSERT(level == LL_Zero);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
void LutElement::compute_pin_order()
|
|
|
|
{
|
2021-02-25 06:02:21 +08:00
|
|
|
pins.clear();
|
|
|
|
pin_to_index.clear();
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
for (auto &lut_bel_pair : lut_bels) {
|
|
|
|
auto &lut_bel = lut_bel_pair.second;
|
2021-02-25 06:02:21 +08:00
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
for (size_t pin_idx = 0; pin_idx < lut_bel.pins.size(); ++pin_idx) {
|
2021-02-25 06:02:21 +08:00
|
|
|
IdString pin = lut_bel.pins[pin_idx];
|
|
|
|
auto result = pin_to_index.emplace(pin, pin_idx);
|
2021-03-03 18:39:47 +08:00
|
|
|
if (!result.second) {
|
2021-02-25 06:02:21 +08:00
|
|
|
// Not sure when this isn't true, but check it for now!
|
|
|
|
NPNR_ASSERT(result.first->second == pin_idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pins.resize(pin_to_index.size());
|
2021-03-03 18:39:47 +08:00
|
|
|
for (auto &pin_pair : pin_to_index) {
|
2021-02-25 06:02:21 +08:00
|
|
|
pins.at(pin_pair.second) = pin_pair.first;
|
|
|
|
}
|
|
|
|
|
2021-03-03 18:39:47 +08:00
|
|
|
for (auto &lut_bel_pair : lut_bels) {
|
|
|
|
auto &lut_bel = lut_bel_pair.second;
|
2021-02-25 06:02:21 +08:00
|
|
|
lut_bel.min_pin = pin_to_index.at(lut_bel.pins.front());
|
|
|
|
lut_bel.max_pin = pin_to_index.at(lut_bel.pins.back());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NEXTPNR_NAMESPACE_END
|